Microsoft for Python Developers Blog https://devblogs.microsoft.com/python/ Read the latest updates about all things Python at Microsoft Fri, 19 Jun 2026 22:52:14 +0000 en-US hourly 1 https://devblogs.microsoft.com/python/wp-content/uploads/sites/12/2018/10/Microsoft-Favicon.png Microsoft for Python Developers Blog https://devblogs.microsoft.com/python/ 32 32 PyCon US 2026 https://devblogs.microsoft.com/python/pycon-us-2026/ Thu, 14 May 2026 00:18:13 +0000 https://devblogs.microsoft.com/python/?p=10321 PyCon US 2026

The post PyCon US 2026 appeared first on Microsoft for Python Developers Blog.

]]>
Come See Us at PyCon US 2026!

Microsoft and GitHub will be at PyCon US 2026, May 14–17 in Long Beach, CA. Stop by our booth, say hello, and tell us about your experience with our tools and services. We’d love to meet you.

Don’t miss the Meta booth on Saturday at 1 p.m., where we’ll be showing off the integration of Pylance with Meta’s new Pyrefly type checker. The integration is currently in early preview in our Insiders build, and we can’t wait to bring it to all our users later this year.

Hands-on Labs at the Booth

Drop in for 10-minute interactive labs covering:

  • GitHub Copilot
  • Azure DocumentDB
  • Microsoft Foundry
  • Microsoft Agent Framework
  • Azure PostgreSQL
  • Azure AI Search

Talks and Sessions

Date & Time Room Session Speaker
Wed, May 13 · 9:00 a.m.–12:30 p.m. 101A Build your first MCP server in Python Pamela Fox
Wed, May 13 · 1:30 p.m.–2:30 p.m. 201B Dungeons and Databases: Build NPC agents to work with data in DocumentDB and Postgres (Microsoft Sponsor session) Marko Hotti, Patty Chow
Thu, May 14 · 2:40 p.m.–3:05 p.m. 104C Education Summit: Big Lessons from Small Models, Teaching Python AI with SLMs Gwyneth Peña-Siguenza
Thu, May 14 · 3:40 p.m.–4:05 p.m. 104C Education Summit: Your Slides, But Faster, Building an AI-powered presentation workflow Pamela Fox
Fri, May 15 · 3:30 p.m.–4:00 p.m. 104C PyCharlas: Cómo pasé de perdida a enseñar Python + IA a miles, en un año Gwyneth Peña-Siguenza
Sat, May 16 · 2:30 p.m.–3:45 p.m. 201A Maintainer Summit Tools Track: Dev Containers Sarah Kaiser
Sun, May 17 · 1:00 p.m.–1:30 p.m. Grand Ballroom A A bridge over (not) troubled waters: Collecting marine data from your couch Sarah Kaiser

Can’t wait to see you there!

The post PyCon US 2026 appeared first on Microsoft for Python Developers Blog.

]]>
Introducing Apache Arrow Support in mssql-python https://devblogs.microsoft.com/python/introducing-apache-arrow-support-in-mssql-python/ Mon, 04 May 2026 04:33:00 +0000 https://devblogs.microsoft.com/python/?p=10301 Reviewed by Sumit Sarabhai Fetching a million rows from SQL Server into a Polars DataFrame used to mean a million Python objects, a million GC allocations, and then throwing it all away to build a DataFrame. Not anymore. mssql-python now supports fetching SQL Server data directly as Apache Arrow structures – a faster and more […]

The post Introducing Apache Arrow Support in mssql-python appeared first on Microsoft for Python Developers Blog.

]]>

c1014e61 a66d 4807 ab58 655671044f49 image

Reviewed by Sumit Sarabhai

Fetching a million rows from SQL Server into a Polars DataFrame used to mean a million Python objects, a million GC allocations, and then throwing it all away to build a DataFrame. Not anymore. mssql-python now supports fetching SQL Server data directly as Apache Arrow structures – a faster and more memory-efficient path for anyone working with SQL Server data in Polars, Pandas, DuckDB, or any other Arrow-native library. This feature was contributed by community developer Felix Graßl (@ffelixg), and we are thrilled to ship it.

Key Terms

API (Application Programming Interface): a source-code contract that defines how to call a function or library.

ABI (Application Binary Interface): a binary-level contract that specifies how compiled code is laid out in memory. Two programs built in different languages can share an ABI and exchange data directly – no serialization is needed.

Arrow C Data Interface: Apache Arrow’s ABI specification – the standard that makes zero-copy data exchange between languages possible.

What Is Apache Arrow?

The key insight behind Apache Arrow is zero-copy language interoperability. Arrow defines a stable shared-memory layout – the Arrow C Data Interface, a cross-language ABI – that any language can produce or consume by exchanging a pointer, with no serialization, no copies, and no re-parsing. A C++ database driver and a Python DataFrame library can work on the exact same memory without either one knowing about the other.

Built on top of that, Arrow uses a columnar in-memory format: instead of representing a table as a list of rows, each row a collection of Python objects, Arrow stores all values for a column contiguously in a typed buffer. Nulls are tracked in a compact bitmap rather than per-cell None objects.

For a database driver, this means the entire fetch loop can run in C++ and write values directly into Arrow buffers – no Python object creation per row, no garbage-collector pressure. The DataFrame library receives a pointer to that memory and can begin operating on it immediately. Crucially, subsequent operations – filters, joins, aggregations – also work in-place on those same buffers. A Polars pipeline reading from mssql-python never needs to materialize intermediate Python objects at any stage, making Arrow the right foundation for high-throughput data processing pipelines.

For users of mssql-python, this translates into four concrete benefits:

  • Speed: The columnar fetch path avoids Python object creation per row, which should make fetching noticeably faster for many SQL Server types – especially temporal types like DATETIME and DATETIMEOFFSET, where Python-side per-value conversions are eliminated entirely.
  • Lower memory usage: A column of one million integers is a single contiguous C array, not a million individual Python objects.
  • Seamless interoperability: Polars, Pandas (via ArrowDtype), DuckDB, Hugging Face datasets, and many other libraries all speak Arrow natively. Zero-copy hand-off between mssql-python and those tools.
  • Purely additive: Your existing fetchone, fetchmany, and fetchall code is completely unaffected. You opt in only where you need it.

Try it here: pip install mssql-python

Calling all Python + SQL developers! We invite the community to try out mssql-python and help us shape the future of high-performance SQL Server connectivity in Python.!

The Arrow Fetch APIs

Three APIs have been added to the Cursor object.

1. cursor.arrow_batch(batch_size=8192)pyarrow.RecordBatch

Fetches the next batch of up to batch_size rows as an Arrow RecordBatch and advances the cursor. RecordBatches are the building block for more high-level Arrow data types like tables and the batch reader interface.

import mssql_python

conn   = mssql_python.connect(conn_str)
cursor = conn.cursor()
cursor.execute("SELECT * FROM SalesData")

partial_data = cursor.arrow_batch(batch_size=50000)
process(partial_data)   # pyarrow.RecordBatch

2. cursor.arrow(batch_size=8192)pyarrow.Table

Eagerly fetches the entire result set into a single Arrow Table. This is the simplest path and works well for analytics queries where the result fits comfortably in memory. However, because it materialises the full result set at once, it can cause high peak RAM usage or out-of-memory errors on very large or unbounded queries. For large exports or ETL workloads, prefer cursor.arrow_reader() (streaming, fetches lazily) or cursor.arrow_batch() (fetch one batch at a time). In both cases, batch_size is a tuning knob: larger batches improve throughput but increase peak memory; smaller batches reduce memory at the cost of slightly more per-batch overhead.

cursor.execute("SELECT customer_id, order_date, amount FROM Orders")
table = cursor.arrow()

# Zero-copy conversion to Polars
import polars as pl
df = pl.DataFrame(table)

# Or to Pandas with Arrow-backed dtypes
import pandas as pd
df = table.to_pandas(types_mapper=pd.ArrowDtype)

3. cursor.arrow_reader(batch_size=8192)pyarrow.RecordBatchReader

Returns a lazy RecordBatchReader. Batches are fetched only when the reader is iterated, enabling streaming over very large result sets. RecordBatchReader is also accepted directly by DuckDB, Lance, and other Arrow-native libraries.

cursor.execute("SELECT * FROM LargeEventLog")
reader = cursor.arrow_reader(batch_size=100000)

for batch in reader:
    sink.write(batch)

Testing

We validated the Arrow fetch path against the standard Python row fetch path across a range of SQL Server types — numeric, temporal, string, and UUID – for both single-column and wide (20-column) tables. The full test script and results are available in the Resources section; we encourage you to run them on your own hardware to see the difference for your workload.

In our testing, the Arrow path was consistently faster for most SQL Server types. Temporal types showed the largest gains: types like DATETIME and DATETIMEOFFSET benefit significantly because the Arrow path handles timezone normalization and value encoding entirely in C++, eliminating per-value Python-side conversions. DATETIMEOFFSET in particular showed some of the most pronounced speedups we observed.

JSON Serialization Bonus

The Arrow path can also benefit API workloads that serialize results to JSON. Instead of fetchall() + json.dumps(), fetch via cursor.arrow(), wrap in a Polars DataFrame, and call df.write_json() – the entire pipeline bypasses Python objects and can be noticeably faster, especially for types like DATETIMEOFFSET.

NVARCHAR on Linux

Our Linux tests show longer fetch times for NVARCHAR due to the current UTF-16 → UTF-8 conversion path. On Windows, NVARCHAR fetches consistently faster with Arrow. A fix is targeted for a follow-up release.

Getting Started

Install or upgrade mssql-python, then add pyarrow:

pip install mssql-python pyarrow

For IDE type hints and static type checking:

pip install pyarrow-stubs

Then swap in cursor.arrow() wherever you would have called fetchall() and converted to a DataFrame. Your existing code is completely unaffected — Arrow support is purely additive.

import mssql_python
import polars as pl

conn   = mssql_python.connect(conn_str)
cursor = conn.cursor()

cursor.execute("SELECT * FROM dbo.LargeSalesTable")
df = pl.DataFrame(cursor.arrow())

print(df.describe())

What’s Next

One known area we are actively working on to improve is NVARCHAR performance on Linux. SQL Server returns Unicode string data in UTF-16 encoding, which the driver must convert to UTF-8 before handing it to Arrow. On Windows this conversion uses a native system API that is very fast, but the current Linux code path goes through a slower chain of intermediate steps. As a result, NVARCHAR columns on Linux show longer fetch times compared to the Python fetch path — the opposite of every other type. A fix using a more efficient codec is in progress for a follow-up release. On Windows, our tests show NVARCHAR fetching noticeably faster with Arrow, and Linux will follow.

A Note of Thanks

This feature was contributed by Felix Graßl (@ffelixg), the author of zodbc, his own Zig-based ODBC driver. His deep familiarity with ODBC and Arrow made this a thorough, well-tested contribution covering both Linux and Windows, and all three fetch patterns. We are very grateful for his work and the care he brought to this feature.

Resources

Try It and Share Your Feedback! 

We invite you to: 

  1. Check-out the mssql-python driver and integrate it into your projects. 
  2. Share your thoughts: Open issues, suggest features, and contribute to the project. 
  3. Join the conversation: GitHub Discussions | SQL Server Tech Community

Use Python Driver with Free Azure SQL Database

You can use the Python Driver with the free version of Azure SQL Database!

✅ Deploy Azure SQL Database for free

✅ Deploy Azure SQL Managed Instance for free Perfect for testing, development, or learning scenarios without incurring costs.

Have questions or feedback? Open an issue or discussion on GitHub, or reach out to the team at mssql-python@microsoft.com

The post Introducing Apache Arrow Support in mssql-python appeared first on Microsoft for Python Developers Blog.

]]>
Python Environments Extension for VS Code- April Update https://devblogs.microsoft.com/python/python-in-visual-studio-code-april-2026-release/ Mon, 27 Apr 2026 20:07:30 +0000 https://devblogs.microsoft.com/python/?p=10297 The April 2026 release update includes the Python Environments extension... Keep on reading to learn more!

The post Python Environments Extension for VS Code- April Update appeared first on Microsoft for Python Developers Blog.

]]>
Python Environments — April 2026 Release

We’re excited to announce the latest update to the Python Environments extension for Visual Studio Code. This release focuses on startup performance, reliability, and quality-of-life improvements for terminals and package management.

Faster startup

Activation is now noticeably snappier, especially on remote and containerized workspaces. We made three key changes:

Lazy manager discovery. Pipenv, pyenv, and poetry environments are no longer discovered eagerly on startup. Instead, detection is deferred until you actually interact with one of those managers — for example, by opening a project that uses a Pipfile or pyproject.toml with a poetry backend. This eliminates unnecessary work for the majority of users who rely on venv, uv, or conda. (#1423, #1408)

Faster environment resolution. The path from “extension activated” to “interpreter ready” is shorter. Resolution during startup and interpreter selection now completes with less overhead. (#1419)

Narrower default workspace scanning. The default search pattern for virtual environments was ./**/.venv, which triggered a recursive scan of the entire workspace tree. On large projects — and especially over Remote-SSH — this could cause the Python Environment Tools (PET) process to hang for 30+ seconds during configuration, leading to cascading timeouts and restart loops (see #1460, #1434). The default is now .venv and */.venv, which covers the standard layout without deep traversal. If you have virtual environments nested more than one level deep, you can add custom paths via the python-envs.workspaceSearchPaths setting. (#1419)

Improved reliability

PET crash recovery. When the PET process crashed mid-refresh, the extension could end up in a broken state with no environments visible. We now retry the refresh after a crash and handle empty or malformed responses defensively, so a transient PET failure no longer leaves you with a blank environment list. (#1442, #1447, #1444)

Conda base environment fix. After a window reload, the conda base environment could be incorrectly restored as a different named environment — making it appear that your interpreter selection had silently changed. This is now fixed. (#1412)

Environment updates and terminals

Auto-refreshing package lists. You no longer need to manually refresh the package view after running pip install or pip uninstall. The extension now watches for metadata changes in site-packages and updates the package list automatically. (#1420)

Multi-project terminal creation. In workspaces with multiple Python projects, creating a new terminal now prompts you to choose which project’s environment to activate, rather than picking one silently. (#1401)

PowerShell activation on Windows. Virtual environment activation via PowerShell could fail if the system execution policy blocked scripts. The extension now sets a process-scoped execution policy before running activation, so .ps1 activate scripts work out of the box without requiring system-wide policy changes. (#1414)


Try the update today and let us know how it works for you. If you run into issues, please file them on GitHub.

The post Python Environments Extension for VS Code- April Update appeared first on Microsoft for Python Developers Blog.

]]>
Write SQL Your Way: Dual Parameter Style Benefits in mssql-python https://devblogs.microsoft.com/python/write-sql-your-way-dual-parameter-style-benefits-in-mssql-python/ Tue, 07 Apr 2026 16:12:05 +0000 https://devblogs.microsoft.com/python/?p=10280 Reviewed by: Sumit Sarabhai If you’ve been writing SQL in Python, you already know the debate: positional parameters (?) or named parameters (%(name)s)? Some developers swear by the conciseness of positional. Others prefer the clarity of named. With mssql-python, you no longer need to choose – we support both.  We’ve added dual parameter style support to mssql-python, enabling both qmark and pyformat parameter styles in Python […]

The post Write SQL Your Way: Dual Parameter Style Benefits in mssql-python appeared first on Microsoft for Python Developers Blog.

]]>
Python SQL img image

Reviewed by: Sumit Sarabhai

If you’ve been writing SQL in Python, you already know the debate: positional parameters (?) or named parameters (%(name)s)? Some developers swear by the conciseness of positional. Others prefer the clarity of named. With mssql-python, you no longer need to choose  we support both. 
 
We’ve added dual parameter style support to mssql-python, enabling both qmark and pyformat parameter styles in Python applications that interact with SQL Server and Azure SQL. This feature is especially useful if you’re building complex queries, dynamically assembling filters, or migrating existing code that already uses named parameters with other DBAPI drivers.

Try it here

You can install driver using pip install mssql-python

Calling all Python + SQL developers! We invite the community to try out mssql-python and help us shape the future of high-performance SQL Server connectivity in Python.!

What Are Parameter Styles? 

The DB-API 2.0 specification (PEP 249) defines several ways to pass parameters to SQL queries. The two most popular are: 

  • qmark – Positional ? placeholders with a tuple/list of values. 
  • pyformat – Named %(name)s placeholders with a dictionary of values.

    # qmark style 
    cursor.execute("SELECT * FROM users WHERE id = ? AND status = ?", (42, "active")) 
     
    # pyformat style 
    cursor.execute("SELECT * FROM users WHERE id = %(id)s AND status = %(status)s", 
                   {"id": 42, "status": "active"}) 

Business Requirement 

Previously, mssql-python only supported qmark. It works fine for simple queries, but as parameters multiply, tracking their order becomes error-prone: 

# Which ? corresponds to which value? 
cursor.execute( 
    "UPDATE users SET name=?, email=?, age=? WHERE id=? AND status=?", 
    (name, email, age, user_id, status) 
) 

Mix up the order and it’s easy to introduce subtle, hard to spot bugs. 

Why Named Parameters? 

  • Self-documenting queries – No more guessing which ? maps to what: 
qmark — 6 parameters, which is which? 
cursor.execute( """INSERT INTO employees (first_name, last_name, email, department, salary, hire_date) VALUES (?, ?, ?, ?, ?, ?)""", ("Jane", "Doe", "jane.doe@company.com", "Engineering", 95000, "2025-03-01") ) 
pyformat — every value is labeled 
cursor.execute( """INSERT INTO employees (first_name, last_name, email, department, salary, hire_date) VALUES (%(first_name)s, %(last_name)s, %(email)s, %(dept)s, %(salary)s, %(hire_date)s)""", {"first_name": "Jane", "last_name": "Doe", "email": "jane.doe@company.com", "dept": "Engineering", "salary": 95000, "hire_date": "2025-03-01"} ) 
  • Parameter reuse – Use the same value multiple times without repeating it: 
Audit log: record who made the change and when 
cursor.execute( """UPDATE orders SET status = %(new_status)s, modified_by = %(user)s, approved_by = %(user)s, modified_at = %(now)s, approved_at = %(now)s WHERE order_id = %(order_id)s""", {"new_status": "approved", "user": "admin@company.com", "now": datetime.now(), "order_id": 5042} ) 
3 unique values, used 5 times — no duplication needed 
  • Dynamic query building – Add filters without tracking parameter positions:
def search_orders(customer=None, status=None, min_total=None, date_from=None): 
    query_parts = ["SELECT * FROM orders WHERE 1=1"] 
    params = {} 
  
    if customer: 
        query_parts.append("AND customer_id = %(customer)s") 
        params["customer"] = customer 
  
    if status: 
        query_parts.append("AND status = %(status)s") 
        params["status"] = status 
  
    if min_total is not None: 
        query_parts.append("AND total >= %(min_total)s") 
        params["min_total"] = min_total 
  
    if date_from: 
        query_parts.append("AND order_date >= %(date_from)s") 
        params["date_from"] = date_from 
  
    query_parts.append("ORDER BY order_date DESC") 
    cursor.execute(" ".join(query_parts), params) 
    return cursor.fetchall() 
  
# Callers use only the filters they need 
recent_big_orders = search_orders(min_total=500, date_from="2025-01-01") 
pending_for_alice = search_orders(customer=42, status="pending") 
  • Dictionary Reuse Across Queries 

The same parameter dictionary can drive multiple queries:

report_params = {"region": "West", "year": 2025, "status": "active"} 
  
# Summary count 
cursor.execute( 
    """SELECT COUNT(*) FROM customers 
       WHERE region = %(region)s AND status = %(status)s""", 
    report_params 
) 
total = cursor.fetchone()[0] 
  
# Revenue breakdown 
cursor.execute( 
    """SELECT department, SUM(revenue) 
       FROM sales 
       WHERE region = %(region)s AND fiscal_year = %(year)s 
       GROUP BY department 
       ORDER BY SUM(revenue) DESC""", 
    report_params 
) 
breakdown = cursor.fetchall() 
  
# Top performers 
cursor.execute( 
    """SELECT name, revenue 
       FROM sales_reps 
       WHERE region = %(region)s AND fiscal_year = %(year)s AND status = %(status)s 
       ORDER BY revenue DESC""", 
    report_params 
) 
top_reps = cursor.fetchall() 
# Same dict, three different queries — change the filters once, all queries update 

The Solution: Automatic Detection 

mssql-python now detects which style you’re using based on the parameter type: 

  • tuple/list → qmark (?) 
  • dict → pyformat (%(name)s) 

No configuration needed. Existing qmark code requires zero changes. 

from mssql_python import connect 
 
# qmark - works exactly as before 
cursor.execute("SELECT * FROM users WHERE id = ?", (42,)) 
 
# pyformat - just pass a dict! 
cursor.execute("SELECT * FROM users WHERE id = %(id)s", {"id": 42})

How It Works 

When you pass a dict to execute(), the driver: 

  1. Scans the SQL for %(name)s placeholders (context-aware – skips string literals, comments, and bracketed identifiers). 
  2. Validates that every placeholder has a matching key in the dict. 
  3. Builds a positional tuple in placeholder order (duplicating values for reused parameters). 
  4. Replaces each %(name)s with ? and sends the rewritten query to ODBC. 
User Code                                  ODBC Layer 
─────────                                  ────────── 
cursor.execute(                            SQLBindParameter(1, "active") 
  "WHERE status = %(status)s               SQLBindParameter(2, "USA") 
   AND country = %(country)s",      →      SQLExecute( 
  {"status": "active",                       "WHERE status = ? 
   "country": "USA"}                          AND country = ?" 
)                                          ) 

The ODBC layer always works with positional ? placeholders. The pyformat conversion is purely a developer-facing convenience with zero overhead to database communication. 

Clear Error Messages 

Mismatched styles or missing parameters produce actionable errors – not cryptic database exceptions: 

cursor.execute("WHERE id = %(id)s AND name = %(name)s", {"id": 42}) 
# KeyError: Missing required parameter(s): 'name'. 
 
cursor.execute("WHERE id = ?", {"id": 42}) 
# TypeError: query uses positional placeholders (?), but dict was provided. 
 
cursor.execute("WHERE id = %(id)s", (42,)) 
# TypeError: query uses named placeholders (%(name)s), but tuple was provided.

Real-World Examples 

Example 1: Web Application

def add_user(name, email): 
    with connect(connection_string) as conn: 
        with conn.cursor() as cursor: 
            cursor.execute( 
                "INSERT INTO users (name, email) VALUES (%(name)s, %(email)s)", 
                {"name": name, "email": email} 
            ) 

Example 2: Batch Operations 

cursor.executemany( 
    "INSERT INTO users (name, age) VALUES (%(name)s, %(age)s)", 
    [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}] 
) 

Example 3: Financial Transactions 

def transfer_funds(from_acct, to_acct, amount): 
    with connect(connection_string) as conn: 
        with conn.cursor() as cursor: 
            cursor.execute( 
                "UPDATE accounts SET balance = balance - %(amount)s WHERE id = %(id)s", 
                {"amount": amount, "id": from_acct} 
            ) 
            cursor.execute( 
                "UPDATE accounts SET balance = balance + %(amount)s WHERE id = %(id)s", 
                {"amount": amount, "id": to_acct} 
            ) 
    # Automatic commit on success, rollback on failure 

Things to Keep in Mind 

  • Don’t mix styles in one query. Use either ? or %(name)s, not both. The driver determines which style you’re using from the parameter type (tuple vs dict), not from the SQL text. If placeholders don’t match the parameter type, you’ll get a clear TypeError explaining the mismatch. If both placeholder types appear in the SQL, only one set gets substituted, leading to parameter count mismatches at execution time. 
# Mixing styles - raises TypeError 
cursor.execute( "SELECT * FROM users WHERE id = ? AND name = %(name)s", {"name": "Alice"} # Driver finds %(name)s but also sees unmatched ? ) 
# ODBC error: parameter count mismatch (2 placeholders, 1 value) 
# Pick one style and use it consistently 
cursor.execute( "SELECT * FROM users WHERE id = %(id)s AND name = %(name)s", {"id": 42, "name": "Alice"} ) 
  • Extra dict keys are OK.  Unused parameters are silently ignored, this is by design to enable parameter dictionary reuse across different queries. 
  • SQL injection safe. Both styles use ODBC parameter binding under the hood. Values are never interpolated into the SQL string, they are always safely bound by the driver. 
  • Literal % in SQL. Use %% to escape if you need a literal %(…)s pattern in your query text. 
cursor.execute( 
    "SELECT * FROM users WHERE name LIKE %(pattern)s", 
    {"pattern": "%alice%"}  # The % inside the VALUE is fine 
) 
 
# But if you need a literal %(...)s in SQL text itself, use %% 
cursor.execute( 
    "SELECT '%%(example)s' AS literal WHERE id = %(id)s", 
    {"id": 42} 
)  
  • mssql_python.paramstyle reports “pyformat”. The DB-API 2.0 spec only allows a single value for this module-level constant. We set it to pyformat because it’s the more expressive style and the one we recommend for new code. But qmark is fully supported at runtime, the driver accepts both styles transparently based on whether you pass a tuple or a dict. Think of paramstyle = “pyformat” as the advertised default, not a limitation. 

Compatibility at a Glance 

Feature  qmark (?)  pyformat (%(name)s) 
cursor.execute()  ✅  ✅ 
cursor.executemany()  ✅  ✅ 
connection.execute()  ✅  ✅ 
Parameter reuse  ❌  ✅ 
Stored procedures  ✅  ✅ 
All SQL data types  ✅  ✅ 
Backward compatible with qmark paramstyle  ✅  N/A (new) 

Takeaway 

Use ? for quick, simple queries. Use %(name)s for complex, multi-parameter queries where clarity and reuse matter. You don’t have to pick a side – use whichever fits the situation. The driver handles the rest. 

Whether you’re building dynamic queries, or simply want more readable SQL, dual paramstyle support makes mssql-python work the way you already think. 

Try It and Share Your Feedback! 

We invite you to:

  1. Check-out the mssql-python driver and integrate it into your projects.
  2. Share your thoughts: Open issues, suggest features, and contribute to the project.
  3. Join the conversation: GitHub Discussions | SQL Server Tech Community.

Use Python Driver with Free Azure SQL Database

You can use the Python Driver with the free version of Azure SQL Database!

✅ Deploy Azure SQL Database for free

✅ Deploy Azure SQL Managed Instance for free Perfect for testing, development, or learning scenarios without incurring costs.

 

The post Write SQL Your Way: Dual Parameter Style Benefits in mssql-python appeared first on Microsoft for Python Developers Blog.

]]>
Python in Visual Studio Code – March 2026 Release https://devblogs.microsoft.com/python/python-in-visual-studio-code-march-2026-release/ Thu, 02 Apr 2026 00:27:15 +0000 https://devblogs.microsoft.com/python/?p=10276 The March 2026 release of the Python and Jupyter extensions for Visual Studio Code is now available. Keep on reading to learn more!

The post Python in Visual Studio Code – March 2026 Release appeared first on Microsoft for Python Developers Blog.

]]>
We’re excited to announce that the March 2026 release of the Python extension for Visual Studio Code are now available!

This release includes the following announcements:

  • Search Python Symbols in Installed Packages
  • Experimental: Rust-Based Parallel Indexer

If you’re interested, you can check the full list of improvements in our changelogs for the Python, and Pylance extensions.

Search Python Symbols in Installed Packages

When working in a new codebase or exploring an unfamiliar library, one of the most common needs is quickly locating where a function or class is defined — even if it lives outside your workspace. With this release, Pylance can now include symbols from packages installed in your active virtual environment in Workspace Symbol search (Cmd/Ctrl+T).

This is controlled by a new setting:

Python › Analysis: Include Venv In Workspace Symbols

 

When enabled:

  • Workspace Symbol search surfaces symbols from packages in your active virtual environment’s site-packages
  • You can navigate into third-party libraries without leaving VS Code or reaching for external documentation
  • For libraries without py.typed, only symbols exported via __init__.py or __all__ are included, keeping results focused and relevant

Because indexing installed packages can affect performance, this feature is opt-in by design. You can fine-tune the depth of indexing per-package using Python › Analysis: Package Index Depths, which controls how deeply Pylance searches into sub-modules.

This gives you richer code exploration when you need it, without changing the default experience for everyone else.

To try it:

  1. Open Settings (Cmd+, / Ctrl+,)
  2. Search for “Include Venv In Workspace Symbols”
  3. Check the box under Python › Analysis

Experimental: Rust-Based Parallel Indexer

We’re shipping an experimental setting that switches Pylance’s indexer — the engine behind completions, auto-imports, and workspace symbol search — to a new Rust-based parallel implementation that runs out-of-process.

In our testing, this indexer is on average 10× faster on large Python projects, which means faster completions after workspace open and a more responsive IntelliSense experience overall.

Python › Analysis: Enable Parallel Indexing

This is intentionally experimental. We want to validate the performance gains and reliability across the wide variety of project setups and environments our users have before making it the default.

To try it:

  1. Open Settings (Cmd+, / Ctrl+,)
  2. Search for “Parallel Indexing”
  3. Check Enable Parallel Indexing (Experimental) under Python › Analysis

Or add this to your settings.json:

"python.analysis.enableParallelIndexing": true

After enabling, reload VS Code (Cmd/Ctrl+Shift+PReload Window) to ensure the new indexer starts cleanly. This setting has the most impact on larger projects — small projects may see little difference.

We want your feedback. If you try it and notice faster completions, slower behavior, or anything unexpected, please let us know by filing an issue on the Pylance GitHub repo. Your real-world reports are what will help us get this to stable.

This is an experimental feature. If you run into issues, you can disable it at any time by unchecking the setting.

Python Environments extension

  • Various bug fixes in the Python Environments extension for env file notifications and environment manager selection priority:
  • The workspace’s saved interpreter selection now takes precedence over terminal-activated virtual or conda environments across restarts.
  • The env file change notification now includes a “Don’t Show Again” option to permanently dismiss it. vscode-python#25867, vscode-python-environments#1347, vscode-python-environments#1393
  • The Python Environments extension now recommends the community Pixi extension when Pixi environments are detected, and includes Pixi in the environment manager priority order. vscode-python-environments#1291

Try out these new improvements by downloading the Python extension and the Pylance extension from the Marketplace, or install them directly from the extensions view in Visual Studio Code (Ctrl + Shift + X or ⌘ + ⇧ + X). You can learn more about Python support in Visual Studio Code in the documentation. If you run into any problems or have suggestions, please file an issue on the Python VS Code GitHub page.

The post Python in Visual Studio Code – March 2026 Release appeared first on Microsoft for Python Developers Blog.

]]>
Python Environments Extension for VS Code https://devblogs.microsoft.com/python/python-in-visual-studio-code-february-2026-release/ https://devblogs.microsoft.com/python/python-in-visual-studio-code-february-2026-release/#comments Wed, 18 Feb 2026 22:00:22 +0000 https://devblogs.microsoft.com/python/?p=10243 The February 2026 release This release includes the Python Environments extension... Keep on reading to learn more!

The post Python Environments Extension for VS Code appeared first on Microsoft for Python Developers Blog.

]]>
Introducing the Python Environments Extension for VS Code

Python development in VS Code now has a unified, streamlined workflow for managing environments, interpreters, and packages. The Python Environments extension brings consistency and clarity to a part of Python development that has historically been fragmented across tools like venv, conda, pyenv, poetry, and pipenv. After a year in preview—refined through community feedback and real-world usage—the extension is being rolled out for general availability. Users can expect to have all environment workflows automatically switched to using the environments extension in the next few weeks or can opt in immediately with the setting python.useEnvsExtension.  The extension works alongside the Python extension and requires no setup—open a Python file and your environments are discovered automatically.

A Unified Environment Experience

PythonProject image

The extension automatically discovers environments from all major managers:

  • venv
  • conda
  • pyenv
  • poetry
  • pipenv
  • System Python installs

Discovery is powered by PET (Python Environment Tool), a fast Rust-based scanner that finds environments reliably across platforms by checking your PATH, known installation locations, and configurable search paths. PET already powers environment discovery in the Python extension today, so this is the same proven engine—now with a dedicated UI built around it. You can create, delete, switch, and manage environments from a single UI—regardless of which tool created them.

For most users, everything just works out of the box. If you have environments in non-standard locations, you can configure workspace-level search paths with glob patterns or set global search paths for shared directories outside your workspace.

Faster Environment Creation with uv

If uv is installed, the extension uses it automatically for creating venv environments and installing packages—significantly faster than standard tools, especially in large projects. This is enabled by default via the python-envs.alwaysUseUv setting.

Quick Create and Custom Create

Getting a new environment up and running is now just a click away. Quick Create (the + button in the Environment Managers view) builds an environment using your default manager, the latest Python version, and any workspace dependencies it finds in requirements.txt or pyproject.toml. You get a working environment in seconds.

When you need more control, Custom Create (via Python: Create Environment in the Command Palette) lets you choose your environment manager, Python version, environment name, and which dependency files to install from. Both venv and conda support creating environments directly from VS Code; for other managers like pyenv, poetry, and pipenv, the extension discovers environments you create with their respective CLI tools.

Python Projects: Environments That Match Your Code Structure

Environment Manager Tree image

Python Projects let you map environments to specific folders or files. This solves common problems in monorepos, multi-service workspaces, mixed script/package repositories, and multi-version testing scenarios.

Adding a project is straightforward: right-click a folder in the Explorer and select Add as Python Project, or use Auto Find to discover folders with pyproject.toml or setup.py. Once a folder is a project, you can assign it its own environment—and that environment is used automatically for running, debugging, testing, and terminal activation within that folder.

Portable by design

When you assign an environment to a project, the extension stores the environment manager type—not hardcoded interpreter paths. This means your .vscode/settings.json is portable across machines, operating systems, and teammates. No more fixing broken paths after cloning a repo. Teammates can commit the settings, clone the workspace, run Quick Create, and be up and running immediately.

Scaffold new projects from templates

The Python Envs: Create New Project from Template command scaffolds a new project with the right structure. Choose between a Package template (with pyproject.toml, package directory, and tests) or a Script template (a standalone .py file with inline dependency metadata using PEP 723).

Multi-Project Testing

The Python extension now uses the Python Environments API to support multi-project testing. Each project gets its own test root, its own interpreter, and its own test discovery settings. This prevents cross-contamination between services and ensures each project uses the correct environment. For details, see the Multi-Project Testing guide.

Smarter Terminal Activation

The extension introduces a new terminal activation model with three modes, controlled by the python-envs.terminal.autoActivationType setting:

  • shellStartup — Activates your environment using VS Code terminal integration, so it’s ready before the first command runs. This is especially important if you use GitHub Copilot to run terminal commands, and will become the default in a future release.
  • command — Runs the activation command visibly in the terminal after it opens (currently the default).
  • off — No automatic activation, for users who prefer manual control.

You can also open a terminal with any environment activated by right-clicking an environment in the Environment Managers view and selecting Open in Terminal.

Predictable Interpreter Selection

Interpreter selection now follows a simple, deterministic priority order:

  1. A project’s configured environment manager
  2. The workspace’s default environment manager (only if you’ve explicitly set it)
  3. python.defaultInterpreterPath (legacy)
  4. Auto-discovery (.venv → system Python)

Only settings you explicitly configure are used. Defaults never override your choices. And importantly, opening a workspace never writes to your settings—the extension only modifies settings.json when you make an explicit change like selecting an interpreter or creating an environment.

Built-In Package Management

You can manage packages directly from the Environment Managers view—search and install packages, uninstall packages, or install from requirements.txt, pyproject.toml, or environment.yml. The extension automatically uses the correct package manager for each environment type (pip for venv, conda for conda environments, or uv pip when uv is enabled).

.env File Support

For developers who use environment variables during development, the extension supports .env files. Set python.terminal.useEnvFile to true and your variables are injected into terminals when they’re created—great for development credentials and configuration that shouldn’t live in source control. Configuring the path to the environment file with python.envFilePath is supported with the previous setting turned on.

Extensible by Design

The Python Environments extension isn’t just for the built-in managers. Its API is designed so that any environment or package manager can build an extension that plugs directly into the Python sidebar, appearing alongside venv, conda, and the rest. The community is already building on this—check out the Pixi Extension as an example of what’s possible.

Known Limitations

There are a couple of areas where integration is still catching up. We want to be upfront so you know what to expect. For the full list, see known issues in the documentation. If you run into an issue, report a bug — your VS Code version, Python extension version, and steps to reproduce help us resolve issues faster. If you need to get back to a stable state quickly, you can disable the extension without affecting the core Python extension.

What’s Next

This is just the beginning. The Python Environments extension lays the foundation for a more integrated, intelligent Python development experience in VS Code. Try the extension, share your feedback, and help us shape the future of Python tooling in VS Code.

Try out these new improvements by downloading the Python Environments extension from the Marketplace, or install them directly from the extensions view in Visual Studio Code (Ctrl + Shift + X or ⌘ + ⇧ + X). You can learn more about Python support in Visual Studio Code in the documentation. If you run into any problems or have suggestions, please file an issue on the Python VS Code GitHub page.

The post Python Environments Extension for VS Code appeared first on Microsoft for Python Developers Blog.

]]>
https://devblogs.microsoft.com/python/python-in-visual-studio-code-february-2026-release/feed/ 2
Python in Visual Studio Code – November 2025 Release https://devblogs.microsoft.com/python/python-in-visual-studio-code-november-2025-release/ Thu, 13 Nov 2025 18:41:50 +0000 https://devblogs.microsoft.com/python/?p=10225 The November 2025 release brings new Pylance features including improvements to Copilot Hover Summaries and a Code Action to convert wildcard imports to explicit imports. Keep on reading to learn more!

The post Python in Visual Studio Code – November 2025 Release appeared first on Microsoft for Python Developers Blog.

]]>
We’re excited to announce that the November 2025 release of the Python extension for Visual Studio Code is now available!

This release includes the following announcements:

  • Add Copilot Hover Summaries as docstring
  • Localized Copilot Hover Summaries
  • Convert wildcard imports Code Action
  • Debugger support for multiple interpreters via the Python Environments Extension

If you’re interested, you can check the full list of improvements in our changelogs for the Python and Pylance extensions.

Add Copilot Hover Summaries as docstring

You can now add your AI-generated documentation directly into your code as a docstring using the new Add as docstring command in Copilot Hover Summaries. When you generate a summary for a function or class, navigate to the symbol definition and hover over it to access the Add as docstring command, which inserts the summary below your cursor formatted as a proper docstring.

This streamlines the process of documenting your code, allowing you to quickly enhance readability and maintainability without retyping.

Add as docstring command in Copilot Hover Summaries

Localized Copilot Hover Summaries

GitHub Copilot Hover Summaries inside Pylance now respect your display language within VS Code. When you invoke an AI-generated summary, you’ll get strings in the language you’ve set for your editor, making it easier to understand the generated documentation.

Copilot Hover Summary generated in Portuguese

Convert wildcard imports into Code Action

Wildcard imports (from module import *) are often discouraged in Python because they can clutter your namespace and make it unclear where names come from, reducing code clarity and maintainability. Pylance now helps you clean up modules that still rely on from module import * via a new Code Action. It replaces the wildcard with the explicit symbols, preserving aliases and keeping the import to a single statement. To try it out, you can click on the line with the wildcard import and press Ctrl + . (or Cmd + . on macOS) to select the Convert to explicit imports Code Action.

Convert wildcard imports Code Action

Debugger support for multiple interpreters via the Python Environments Extension

The Python Debugger extension now leverages the APIs from the Python Environments Extension (vscode-python-debugger#849). When enabled, the debugger can recognize and use different interpreters for each project within a workspace. If you have multiple folders configured as projects—each with its own interpreter – the debugger will now respect these selections and use the interpreter shown in the status bar when debugging.

To enable this functionality, set “python.useEnvironmentsExtension”: true in your user settings. The new API integration is only active when this setting is turned on.

Please report any issues you encounter to the Python Debugger repository.

Other Changes and Enhancements

We have also added small enhancements and fixed issues requested by users that should improve your experience working with Python in Visual Studio Code. Some notable changes include:

  • Resolve unexpected blocking during PowerShell command activation (vscode-python-environments#952)
  • The Python Environments Extension now respects the existing python.poetryPath user setting to specify which Poetry executable to use (vscode-python-environments#918)
  • The Python Environments Extension now detects both requirements.txt and dev-requirements.txt files when creating a new virtual environment for automatic dependency installation (vscode-python-environments#506)

We would also like to extend special thanks to this month’s contributors:

Try out these new improvements by downloading the Python extension from the Marketplace, or install them directly from the extensions view in Visual Studio Code (Ctrl + Shift + X or ⌘ + ⇧ + X). You can learn more about Python support in Visual Studio Code in the documentation. If you run into any problems or have suggestions, please file an issue on the Python VS Code GitHub page.

The post Python in Visual Studio Code – November 2025 Release appeared first on Microsoft for Python Developers Blog.

]]>
Python in Visual Studio Code – October 2025 Release https://devblogs.microsoft.com/python/python-in-visual-studio-code-october-2025-release/ Fri, 10 Oct 2025 17:55:26 +0000 https://devblogs.microsoft.com/python/?p=10209 The October 2025 release of the Python and Jupyter extensions for Visual Studio Code are now available. This release includes improvements to the Python Environments extension, Copy Test ID functionality, and enhanced environment activation when using Copilot Chat. Keep on reading to learn more!

The post Python in Visual Studio Code – October 2025 Release appeared first on Microsoft for Python Developers Blog.

]]>
We’re excited to announce that the October 2025 release of the Python extensions for Visual Studio Code are now available!

This release includes the following announcements:

  • Python Environments extension improvements
  • Enhanced testing workflow with Copy Test ID in gutter menu
  • Shell startup improvements for Python environment activation

If you’re interested, you can check the full list of improvements in our changelogs for the Python and Pylance extensions.

Python Environments Extension Improvements

The Python Environments extension received several fixes and updates to enhance your Python development experience in VS Code. Highlights include improved performance and reliability when working with conda environments – now lauching code directly without conda run, a smoother environment flow with Python versions now sorted in descending order for easier acces to the latest releases, fixes for crashes when running Python files that use input(), and improvements to false-positive environment configuration warnings.

The extension also now automatically refreshes environment managers when expanding tree nodes, keeping your environment list up to date without any extra steps.

We appreciate the community feedback that helped identify and prioritize these improvements. Please continue to share your thoughts, suggestions and bug reports on the Python Environments GitHub repository as we continue rolling out this extension.

Enhanced Testing Workflow with Copy Test ID

We’ve improved the testing experience by adding a “Copy Test ID” option to the gutter icon context menu for test functions. This feature allows you to quickly copy test identifiers in pytest format directly from the editor gutter, making it easier to run specific tests from the command line or share test references with teammates.

Copy test id

Improved Shell Startup for Python Environment Activation

We have made improvements to shell start up to reduce issues where terminals created by GitHub Copilot weren’t properly activating Python virtual environments. With the new shell startup approach, you’ll get a more reliable environment activation across terminal creation methods while reducing redundant permission prompts.

Additionally, virtual environment prompts such as (.venv) now appear correctly when PowerShell is activated through shell integration, and we have resolved issues with activation in WSL.

To benefit from these improvements, set your python-envs.terminal.autoActivationType to shellStartup in your VS Code settings.

Other Changes and Enhancements

We have also added small enhancements and fixed issues requested by users that should improve your experience working with Python and Jupyter Notebooks in Visual Studio Code. Some notable changes include:

  • Enhanced contributor experience with new Copilot Chat instruction files that provide guidance for testing features and understanding VS Code components when contributing to the Python extension (#25473, #25477)
  • Updated debugpy to version 1.8.16 (#795)

We would also like to extend special thanks to this month’s contributors:

  • Morikko: Upgraded jedi-language-server to 0.45.1 (#25450)
  • cnaples79: Fixed mypy diagnostics parsing from stderr in non-interactive mode (#375)
  • renan-r-santos: Display activate button when a terminal is moved to the editor window (#764)
  • lev-blit: Added py.typed to debugpy distributed package (#1960)

Try out these new improvements by downloading the Python extension and the Jupyter extension from the Marketplace, or install them directly from the extensions view in Visual Studio Code (Ctrl + Shift + X or ⌘ + ⇧ + X). You can learn more about Python support in Visual Studio Code in the documentation. If you run into any problems or have suggestions, please file an issue on the Python VS Code GitHub page.

The post Python in Visual Studio Code – October 2025 Release appeared first on Microsoft for Python Developers Blog.

]]>
Simplifying Resource Management in mssql-python through Context Manager https://devblogs.microsoft.com/python/simplifying-resource-management-in-mssql-python-through-context-manager/ https://devblogs.microsoft.com/python/simplifying-resource-management-in-mssql-python-through-context-manager/#comments Fri, 26 Sep 2025 09:49:51 +0000 https://devblogs.microsoft.com/python/?p=10158 Reviewed by: Sumit Sarabhai and Gaurav Sharma If you’ve worked with databases in Python, you know the boilerplate: open a connection, create a cursor, run queries, commit or rollback transactions, close cursors and connection. Forgetting just one cleanup step can lead to resource leaks (open connections) or even inconsistent data. That’s where context managers step […]

The post Simplifying Resource Management in mssql-python through Context Manager appeared first on Microsoft for Python Developers Blog.

]]>
Python SQL img image

Reviewed by: Sumit Sarabhai and Gaurav Sharma

If you’ve worked with databases in Python, you know the boilerplate: open a connection, create a cursor, run queries, commit or rollback transactions, close cursors and connection. Forgetting just one cleanup step can lead to resource leaks (open connections) or even inconsistent data. That’s where context managers step in.

We’ve introduced context manager support in mssql‑python driver, enabling Python applications to interact with SQL Server and Azure SQL more safely, cleanly, and in a truly Pythonic way.

Try it here

You can install driver using pip install mssql-python

Calling all Python + SQL developers! We invite the community to try out mssql-python and help us shape the future of high-performance SQL Server connectivity in Python.!

Why Context Managers?

In Python, the with statement is syntactic sugar for resource management. It actively sets up resources when you enter a block and automatically cleans them up when you exit — even if an exception is raised.

Think of it as hiring a helper:

  • They prepare the workspace before you begin.
  • They pack everything up when you’re done.
  • If something breaks midway, they handle the cleanup for you.

 

The Problem: Managing Connections and Cursors

Earlier, working with Python applications and SQL server/Azure SQL looked something like this:

from mssql_python import connect

conn = connect(connection_string)
cursor = conn.cursor()

try:
    cursor.execute("SELECT * FROM users")
    for row in cursor:
        print(row)
finally:
    cursor.close()
    conn.close()

This works perfectly fine. But imagine if your code had multiple cursors, multiple queries, and exception handling sprinkled all over. Closing every connection and cursor manually becomes tedious and error-prone. Miss a close() somewhere, and you have a resource leak.

That’s where Python’s with statement — the context manager — comes to the rescue. mssql_python not only supports it for connections but also for cursors, which makes resource management nearly effortless.

 

Using Context Managers with Connections

Now comes the real magic — connection-level context managers. When you wrap a connection in a with block, several things happen under the hood:

  1. If everything succeeds, the transaction is committed.
  2. If an exception occurs, the transaction is rolled back.
  3. The connection is always closed when leaving the block.

Example:

from mssql_python import connect

with connect(connection_string) as conn:
    cursor = conn.cursor()
    cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
    # If no exception → commit happens automatically
    # If exception → rollback happens automatically
# Connection is closed automatically here

Equivalent traditional approach:

conn = connect(connection_string)
try:
    cursor = conn.cursor()
    cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
    if not conn.autocommit:
        conn.commit()
except:
    if not conn.autocommit:
        conn.rollback()
    raise
finally:
    conn.close()

 

How It Works Internally

  • Entering the block
    • Connection is opened and assigned to conn.
    • All operations inside the block run using this connection.
  • Exiting the block
    • No exception: If autocommit=False, transactions are committed.
    • Exception raised: If autocommit=False, uncommitted changes are rolled back. The exception propagates unless handled.
  • Cleanup: Connection is always closed, preventing resource leaks.

Use case: Perfect for transactional code — inserts, updates, deletes — where you want automatic commit/rollback.

 

Using Context Managers with Cursors

Cursors in mssql_python now support the with statement. The context here is tied to the cursor resource, not the transaction.

with conn.cursor() as cursor:
    cursor.execute("SELECT * FROM users")
    for row in cursor:
        print(row)
# Cursor is automatically closed here

What happens here?

  • Entering the block: A new cursor is created.
  • Inside the block: All SQL statements execute using this cursor.
  • Exiting the block: The cursor is automatically closed — no need to call cursor.close() manually.
  • Transactions: The cursor itself doesn’t manage transactions. Commit/rollback is controlled by the connection.
    • If autocommit=False, changes are committed or rolled back at the connection level.
    • If autocommit=True, each statement is committed immediately as it executes.

Above code is equivalent to the traditional try-finally approach:

cursor = conn.cursor()
try:
    cursor.execute("SELECT * FROM users")
    for row in cursor:
        print(row)
finally:
    cursor.close()

Use case: Best for read-only queries where you don’t want to worry about cursor leaks.

Important

If you just want to ensure the cursor closes properly without worrying about transactions, this is the simplest and safest approach.

Context Manager Blog Image

Image 1: Workflow of Context Manager in Connections and Cursor

 

Practical Examples

Example 1: Safe SELECT Queries

with connect(connection_string) as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT * FROM users WHERE age > 25")
        for row in cursor:
            print(row)
    # Cursor closed, connection still open until block ends
# Connection is closed    

Example 2: Multiple Operations in One Transaction

with connect(connection_string) as conn:
    with conn.cursor() as cursor:
        cursor.execute("INSERT INTO users (name) VALUES ('Bob')")
        cursor.execute("UPDATE users SET age = age + 1 WHERE name = 'Alice'")
# Everything committed automatically if no exception

Example 3: Handling Exceptions Automatically

try:
    with connect(connection_string) as conn:
        with conn.cursor() as cursor:
            cursor.execute("INSERT INTO users (name) VALUES ('Charlie')")
            # Simulate error
            raise ValueError("Oops, something went wrong")
except ValueError as e:
    print("Transaction rolled back due to:", e)
# Connection closed automatically, rollback executed

 

Real-Life Scenarios

Example 1: Web Applications

In a web app where each request inserts or fetches data:

def add_user(name):
    with connect(connection_string) as conn:
        with conn.cursor() as cursor:
            cursor.execute("INSERT INTO users (name) VALUES (?)", (name,))
  • Guarantees commit/rollback automatically.
  • No open connections piling up.
  • Clean, readable, and safe code for high-traffic scenarios.

Example 2: Data Migration / ETL

Migrating data between tables:

with connect(connection_string) as conn:
    with conn.cursor() as cursor:
        cursor.execute("INSERT INTO archive_users SELECT * FROM users WHERE inactive=1")
        cursor.execute("DELETE FROM users WHERE inactive=1")
  • If any statement fails, rollback happens automatically.
  • Prevents partial migration, keeping data consistent.

Example 3: Automated Reporting

Running multiple queries for analytics:

with connect(connection_string) as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT COUNT(*) FROM users")
        user_count = cursor.fetchone()[0]
        cursor.execute("SELECT department, COUNT(*) FROM employees GROUP BY department")
        for row in cursor:
            print(row)
  • Cursors closed automatically after each block.
  • Makes scripts modular and maintainable.

Example 4: Financial Transactions

Simple bank transfer example:

def transfer_funds(from_account, to_account, amount):
    with connect(connection_string) as conn:
        with conn.cursor() as cursor:
            cursor.execute("UPDATE accounts SET balance = balance - ? WHERE id=?", (amount, from_account))
            cursor.execute("UPDATE accounts SET balance = balance + ? WHERE id=?", (amount, to_account))
  • Automatic rollback on failure ensures money isn’t lost or double-counted.
  • Eliminates verbose error-handling boilerplate.

Example 5: Ad-Hoc Data Exploration

When exploring data in scripts or notebooks:

with connect(connection_string) as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT AVG(salary) FROM employees")
        print("Average salary:", cursor.fetchone()[0])
  • Perfect for quick queries.
  • No forgotten close() calls.
  • Encourages clean, reusable query blocks.

 

Takeaway

Python’s philosophy is “simple is better than complex.” With context managers in mssql_python, we’ve brought that simplicity to SQL Server interactions with python apps making lives of the developers easier.

Next time you’re working with mssql_python, try wrapping your connections and cursors with with. You’ll write less code, make fewer mistakes, and your future self will thank you. Whether it’s a high-traffic web application, an ETL script, or exploratory analysis, context managers simplify life, make code safer, and reduce errors.

Remember, context manager will help you with:

  1. Less boilerplate code: No longer try-finally for cursors or connections.
  2. Automatic transaction management: Commit or rollback is handled based on success or failure.
  3. Safe resource cleanup: Prevents resource leaks with automatic closing.
  4. Readable and Pythonic: Nested with blocks clearly show the scope of cursor and connection usage.

 

Try It and Share Your Feedback! 

We invite you to:

  1. Check-out the mssql-python driver and integrate it into your projects.
  2. Share your thoughts: Open issues, suggest features, and contribute to the project.
  3. Join the conversation: GitHub Discussions | SQL Server Tech Community.

Use Python Driver with Free Azure SQL Database

You can use the Python Driver with the free version of Azure SQL Database!

✅ Deploy Azure SQL Database for free

✅ Deploy Azure SQL Managed Instance for free Perfect for testing, development, or learning scenarios without incurring costs.

The post Simplifying Resource Management in mssql-python through Context Manager appeared first on Microsoft for Python Developers Blog.

]]>
https://devblogs.microsoft.com/python/simplifying-resource-management-in-mssql-python-through-context-manager/feed/ 1
Python in Visual Studio Code – September 2025 Release https://devblogs.microsoft.com/python/python-in-visual-studio-code-september-2025-release/ Mon, 15 Sep 2025 18:22:18 +0000 https://devblogs.microsoft.com/python/?p=10141 The September 2025 release includes pipenv support in the Python Environment Extension, a new experimental hover feature with GitHub Copilot and Pylance, and more!

The post Python in Visual Studio Code – September 2025 Release appeared first on Microsoft for Python Developers Blog.

]]>
We’re excited to announce the September 2025 release of the Python, Pylance and Jupyter extensions for Visual Studio Code!

This release includes the following announcements:

  • Experimental AI-powered hover summaries with Pylance
  • Run Code Python Snippet AI tool
  • Python Environments extension improvements, including pipenv support

If you’re interested, you can check the full list of improvements in our changelogs for the Python, Jupyter and Pylance extensions.

This month you can also help shape the future of Python typing by filling out the 2025 Python Type System and Tooling Survey: https://jb.gg/d7dqty

Experimental AI-powered hover summaries with Pylance

A new experimental AI Hover Summaries feature is now available for Python files when using the pre-release version of Pylance with GitHub Copilot. When you enable the setting(python.analysis.aiHoverSummaries) setting, you can get helpful summaries on the fly for symbols that do not already have documentation. This makes it easier to understand unfamiliar code and boosts productivity as you explore Python projects. At the moment, AI Hover Summaries are currently available to GitHub Copilot Pro, Pro+, and Enterprise users.

We look forward to bringing this experimental experience to the stable version soon!

AI-powered hover summaries with Pylance

Run Code Snippet AI tool

The Pylance Run Code Snippets tool is a powerful feature designed to streamline your Python experience with GitHub Copilot. Instead of relying on terminal commands like python -c "code" or creating temporary files to be executed, this tool allows GitHub Copilot to execute Python snippets entirely in memory. It automatically uses the correct Python interpreter configured for your workspace, and it eliminates common issues with shell escaping and quoting that sometimes arise during terminal execution.

One of the standout benefits is the clean, well-formatted output it provides, with both stdout and stderr interleaved for clarity. This makes it ideal when using Agent mode with GitHub Copilot to test small blocks of code, run quick scripts, validate Python expressions, or checking imports, all within the context of your workspace.

To try it out, make sure you’re using the latest pre-release version of Pylance. Then, you can select the pylancerunCodeSnippet tool via the Add context… menu in the VS Code Chat panel.

Note: As with all AI-generated code, please make sure to inspect the generated code before allowing this tool to be executed. Reviewing the logic and intent of the code ensures it aligns with your project’s goals and maintains safety and correctness.

pylance-run-code-snippet

Python Environments extension improvements

We appreciate your feedback and are excited to share several enhancements to the Python Environments extension. Thank you to everyone who submitted bug reports and suggestions to help us improve!

Improvements to Conda experience

We focused on removing friction and unexpected behavior when working with Conda environments:

  • When creating a new Conda environment through the UI, you can now pick the Python version up front.
  • Conda activation and sourcing has been improved across different OS and shell types, with clearer logging.
  • The Copy Interpreter Path action now returns the actual Python binary instead of a conda run wrapper
  • The proper Conda and Pixi executables are used when debugging.

Pipenv support

Pipenv environments are now discovered and listed in the Environments Manager view.

Better diagnostics and control

We’ve made it easier to identify and resolve environment-related issues. When there are issues with the default environment manager, such as missing executables, clear warnings are now surfaced to guide you through resolution.

Additionally, there’s a new Run Python Environment Tool (PET) in Terminal command which gives you direct access to running the back-end environment tooling by hand. This tool simplifies troubleshooting by allowing you to manually trigger detection operations, making it easier to diagnose and fix edge cases in environment setup.

Quality of life improvements

We also reduced paper cuts to make your experience with the extension smoother. These include:

  • Add as Python project menu item is now always available, enabling a more consistent flow for setting a folder as a Python project.
  • Interpreter paths with spaces are now properly handled when debugging.
  • Environments are now always refreshed on new project creation.
  • Conda activation logic is consolidated with clearer logging.
  • We audited and removed shell profile edits which are outdated or no longer needed given VS Code core shell integration improvements.
  • We tightened the logic that resolves the default interpreter so it honors your defaultInterpreterPath (including script wrappers) without silently “correcting” it.
  • We have a new setting called python.useEnvFile which controls whether environment variables from .env files and the python.envFile setting are injected into terminals when the Python Environments extension is enabled.
  • venvFolders are now included in the extension’s search path. Please note that we plan to deprecate the python.venvFolders setting in favour of a new one in the future, to enable better flexibility when setting up environment search paths.

We are continuing to roll-out the extension. To use it, make sure the extension is installed and add the following to your VS Code settings.json file: "python.useEnvironmentsExtension": true. If you are experiencing issues with the extension, please report issues in our repo, and you can disable the extension by setting "python.useEnvironmentsExtension": false in your settings.json file.

Call for Community Feedback

This month, the Python community is coming together to gather insights on how type annotations are used in Python. Whether you’re a seasoned user or have never used types at all, your input is valuable! Take a few minutes to help shape the future of Python typing by participating in the 2025 Python Type System and Tooling Survey: https://jb.gg/d7dqty.

Other Changes and Enhancements

We have also added small enhancements and fixed issues requested by users that should improve your experience working with Python and Jupyter Notebooks in Visual Studio Code. Some notable changes include:

  • The python.analysis.supportAllPythonDocuments setting has been removed, making Pylance IntelliSense now enabled in all Python documents by default, including diff views and Python terminals.

We would also like to extend special thanks to this month’s contributors:

Try out the new improvements by downloading the Python extension and the Jupyter extension from the Marketplace, or install them directly from the extensions view in Visual Studio Code (Ctrl + Shift + X or ⌘ + ⇧ + X). You can learn more about Python support in Visual Studio Code in the documentation. If you run into any problems or have suggestions, please file an issue on the Python VS Code GitHub page.

The post Python in Visual Studio Code – September 2025 Release appeared first on Microsoft for Python Developers Blog.

]]>