Archive

How to use Worksheet.Next in the xlwings API way

In Excel’s object model, the Next property of a Worksheet object is a property that returns a Worksheet object representing the next sheet in the workbook. This is useful for programmatically navigating through worksheets in sequence without relying on specific sheet names. The Next property is part of the Excel interop and is accessible through xlwings, a Python library that allows you to automate Excel from Python. It is often used in loops or when you need to process multiple sheets in order.

The Next property is read-only and returns None if the current worksheet is the last sheet in the workbook. In xlwings, you can access this property via the api attribute, which provides direct access to the underlying Excel object model. This allows for seamless integration with Excel’s native functionality.

Functionality:
The primary function of the Next property is to retrieve the worksheet that immediately follows the current one in the workbook’s tab order. This can be helpful for tasks such as iterating through all sheets, comparing data between consecutive sheets, or performing batch operations across multiple worksheets. It simplifies navigation by avoiding the need to hardcode sheet indices or names.

Syntax:
In xlwings, the syntax for accessing the Next property is as follows:

next_worksheet = current_worksheet.api.Next

Here, current_worksheet is an xlwings Sheet object representing the active worksheet. The .api attribute exposes the native Excel VBA object model, allowing you to call properties like Next. The return value is an Excel Worksheet object, which can be wrapped in an xlwings Sheet object if needed for further operations. Note that if there is no next worksheet, the property returns None.

Parameters:
The Next property does not take any parameters. It is a simple property that relies on the workbook’s sheet order. The sheet order is determined by the position of the tabs in Excel, which can be changed manually by the user or programmatically via other methods.

Example Usage:
Below is a code example demonstrating how to use the Next property with xlwings to iterate through worksheets and print their names. This example assumes you have an Excel workbook open with multiple sheets.

import xlwings as xw

# Connect to the active Excel workbook
wb = xw.books.active

# Start with the first worksheet
current_sheet = wb.sheets[0]

# Loop through worksheets using the Next property
while current_sheet is not None:
print(f"Current sheet name: {current_sheet.name}")

# Get the next worksheet using the Excel object model
next_sheet = current_sheet.api.Next

if next_sheet is not None:
    # Wrap the Excel Worksheet object in an xlwings Sheet object
    current_sheet = xw.Sheet(next_sheet)
else:
    current_sheet = None

print("Finished iterating through all sheets.")

In this example, we start from the first sheet (index 0) and use a while loop to navigate through each subsequent sheet via the Next property. The loop continues until Next returns None, indicating the last sheet has been reached. This approach is efficient for sequential processing and ensures compatibility with Excel’s native behavior.

Another practical use case is to compare data between consecutive sheets. For instance, you might want to check if the values in cell A1 are the same across all sheets:

import xlwings as xw

wb = xw.books.active
current_sheet = wb.sheets[0]
reference_value = current_sheet.range('A1').value

while current_sheet is not None:
if current_sheet.range('A1').value != reference_value:
print(f"Mismatch found in sheet: {current_sheet.name}")

next_sheet = current_sheet.api.Next
if next_sheet is not None:
current_sheet = xw.Sheet(next_sheet)
else:
break

How to use Worksheet.Names in the xlwings API way

In Excel object model, the Names collection refers to all defined names within a workbook, including workbook-level and worksheet-level names. However, in xlwings, the Worksheet object does not have a direct Names property. Instead, you can access defined names via the Book (or Workbook) object. Specifically, you can use Book.names to retrieve all defined names in the workbook. To get or manage names that are scoped to a particular worksheet, you can filter the Book.names collection based on the name’s scope.

The primary functionality of the Names collection in xlwings is to create, read, update, or delete defined names, which are useful for referencing specific ranges, constants, or formulas in a workbook. This can simplify formulas, improve readability, and make your code more maintainable.

Syntax and Usage:
In xlwings, you interact with defined names through the Book.names property. Here’s the basic syntax:

  • book.names: Returns a collection of all defined names in the workbook. Each item in the collection is a Name object.
  • To access a specific name, you can use indexing or the get method: book.names['MyName'] or book.names.get('MyName').
  • To create a new name, use book.names.add(name, refers_to), where name is the string identifier for the name, and refers_to is the formula or range it references (e.g., “=Sheet1!$A$1:$B$10”). You can specify the scope by including the worksheet name in the refers_to parameter or by setting properties after creation.

For worksheet-level names, you can filter by checking the name.scope property. For example, to get all names scoped to a specific worksheet, you can iterate through book.names and compare the scope. However, note that xlwings does not provide a direct Worksheet.names property, so this filtering is done manually.

Example Code:
Here’s a practical example using xlwings to work with defined names, focusing on a worksheet context:

import xlwings as xw

# Connect to an existing workbook or create a new one
wb = xw.Book('example.xlsx') # or xw.Book() for a new workbook
ws = wb.sheets['Sheet1']

# Add a worksheet-level defined name for a range in Sheet1
# The refers_to string includes the worksheet name to scope it
wb.names.add(name='MyRange', refers_to=f"={ws.name}!$A$1:$D$10")

# Access the defined name and print its details
my_name = wb.names['MyRange']
print(f"Name: {my_name.name}")
print(f"Refers to: {my_name.refers_to}")
print(f"Scope: {my_name.scope}") # This might return the workbook or worksheet, depending on setup

# List all defined names scoped to the specific worksheet (Sheet1)
worksheet_names = []
for name in wb.names:
    # Check if the name's scope matches the worksheet; note: scope may be a string or object
    if hasattr(name.scope, 'name') and name.scope.name == ws.name:
        worksheet_names.append(name.name)
    elif isinstance(name.scope, str) and name.scope == ws.name:
        worksheet_names.append(name.name)
        print(f"Names in {ws.name}: {worksheet_names}")

# Use the defined name in a formula or operation
# For example, set a value in the named range
ws.range('MyRange').value = [[1, 2, 3, 4] for _ in range(10)] # Fills the range with data

# Delete a defined name if needed
wb.names['MyRange'].delete()

# Save and close
wb.save()
wb.close()

How to use Worksheet.Name in the xlwings API way

The Name property of a Worksheet object in the Excel object model is a fundamental attribute used to get or set the name of a worksheet. In xlwings, this property is accessed directly through the Worksheet object, allowing for straightforward retrieval and modification of sheet names within a workbook. This capability is essential for tasks such as dynamically referencing sheets, organizing data across multiple sheets, or automating sheet management processes.

Functionality:
The primary function is to read or change the name of a worksheet. This is useful in scenarios where sheet names need to be updated based on data content, user input, or automated workflows. For example, you might rename sheets after importing data to reflect the dataset’s source or date.

Syntax in xlwings:
In xlwings, the Name property is accessed as an attribute of a Worksheet object. The syntax is simple:

  • To get the current name: sheet_name = ws.name
  • To set a new name: ws.name = "NewSheetName"
    Here, ws represents a Worksheet object obtained via wb.sheets['Sheet1'] or similar. The name must be a string and adhere to Excel’s naming conventions (e.g., no more than 31 characters, and characters like :, \, /, ?, *, [, ] are not allowed). If an invalid name is provided, xlwings will raise an error.

Code Examples:
Below are practical examples demonstrating the use of the Name property with xlwings.

  1. Retrieving a Worksheet Name:
    This example opens an existing workbook and prints the name of the first worksheet.
import xlwings as xw
# Open an existing workbook
wb = xw.Book('example.xlsx')
# Access the first worksheet
ws = wb.sheets[0]
# Get and print the worksheet name
current_name = ws.name
print(f"The worksheet name is: {current_name}")
  1. Renaming a Worksheet:
    This example renames a specific worksheet to “DataSummary”.
import xlwings as xw
# Open an existing workbook
wb = xw.Book('example.xlsx')
# Access a worksheet by its current name
ws = wb.sheets['Sheet1']
# Change the worksheet name
ws.name = "DataSummary"
# Save the workbook to persist changes
wb.save()
  1. Dynamic Renaming Based on Content:
    This example renames all worksheets in a workbook based on a list of new names, demonstrating batch processing.
import xlwings as xw
# Open an existing workbook
wb = xw.Book('data.xlsx')
# Define new names for each worksheet
new_names = ["January", "February", "March"]
# Iterate through worksheets and rename them
for i, ws in enumerate(wb.sheets):
    if i < len(new_names):
        ws.name = new_names[i]
# Save the workbook
wb.save()

How to use Worksheet.MailEnvelope in the xlwings API way

The MailEnvelope property of a Worksheet object in Excel VBA is used to control email-related features when sending a worksheet via email. In xlwings, this functionality is accessed through the api property, which provides direct access to the underlying Excel object model. The MailEnvelope object allows you to customize the email subject, recipients, and message body when using Excel’s built-in email integration, typically via the SendMail method. It is particularly useful for automating email reports directly from an Excel workbook.

Syntax and Parameters
In xlwings, you access the MailEnvelope property via the api property of a Worksheet object. The basic syntax is:

worksheet.api.MailEnvelope

This returns a MailEnvelope object, which has several key properties and methods. The most commonly used include:

  • Subject: Sets or gets the email subject line as a string.
  • To: Sets or gets the primary recipients as a string (multiple addresses can be separated by semicolons).
  • CC: Sets or gets the carbon copy recipients as a string.
  • BCC: Sets or gets the blind carbon copy recipients as a string.
  • Introduction: Sets or gets the introductory text in the email body as a string. This text appears above the worksheet in the email.
  • Item.Send(): Sends the email. Note that this method may require an email client (like Outlook) to be configured and running.

These properties are straightforward to set by assigning string values. For example, worksheet.api.MailEnvelope.Subject = "Monthly Report" sets the subject. The Introduction property is especially useful for adding descriptive text.

Code Example
Below is a practical xlwings example that sets up and sends a worksheet via email. This assumes you have an active workbook and an email client set up.

import xlwings as xw

# Connect to the active workbook
wb = xw.books.active
# Access the first worksheet
ws = wb.sheets[0]

# Access the MailEnvelope property via api
envelope = ws.api.MailEnvelope

# Set email properties
envelope.Subject = "Q4 Sales Data"
envelope.To = "manager@example.com; team@example.com"
envelope.CC = "supervisor@example.com"
envelope.Introduction = "Please find the attached Q4 sales report. Key highlights include a 15% increase in revenue."

# Optional: Save or update the workbook before sending
wb.save()

# Send the email
envelope.Item.Send()

How to use Worksheet.ListObjects in the xlwings API way

In Excel, the ListObjects collection represents all the tables (ListObject) on a specific worksheet. Tables are powerful features for managing and analyzing structured data, offering built-in filtering, sorting, and easy referencing. Through the ListObjects property of a Worksheet object in xlwings, you can programmatically access, create, and manipulate these tables, enabling automation of data organization and analysis tasks.

Functionality:
The ListObjects property provides access to the collection of tables within a worksheet. You can use it to:

  • Retrieve a specific table by its name or index.
  • Iterate through all tables to perform batch operations.
  • Add new tables based on a given range of data.
  • Check the number of tables present.

Syntax:
In xlwings, the ListObjects property is accessed from a Worksheet object. The general call format is:

worksheet.api.ListObjects

This returns a COM object representing the Excel ListObjects collection. To work with it more intuitively in xlwings, you often use methods like add() or access items directly.

To create a new table:

worksheet.api.ListObjects.Add(SourceType, Source, LinkSource, HasHeaders, Destination)
  • SourceType: Specifies the source of the data. Typically use 1 (xlSrcRange) for a worksheet range.
  • Source: The range address as a string (e.g., “A1:D10”) or an xlwings Range object.
  • LinkSource: Usually False for data within the workbook.
  • HasHeaders: Set to True if the range includes headers; False otherwise.
  • Destination: Optional; used if SourceType is xlSrcExternal. Can be omitted for range sources.

To reference an existing table by name:

table = worksheet.api.ListObjects("TableName")

Example:
Consider a worksheet with sales data in the range A1:C5. The following xlwings code demonstrates using ListObjects to create a table, access its properties, and iterate through tables.

import xlwings as xw

# Connect to the active workbook and worksheet
wb = xw.Book.active
ws = wb.sheets['Sheet1']

# Create a table from the range A1:C5
source_range = ws.range('A1:C5')
table = ws.api.ListObjects.Add(
SourceType=1, # xlSrcRange
Source=source_range.api,
LinkSource=False,
HasHeaders=True,
Destination=None
)
table.Name = 'SalesTable' # Set a name for the table

# Access the table by name
sales_table = ws.api.ListObjects('SalesTable')
print(f"Table range: {sales_table.Range.Address}")

# Iterate through all tables in the worksheet
for tbl in ws.api.ListObjects:
    print(f"Found table: {tbl.Name}")

# Count the number of tables
table_count = ws.api.ListObjects.Count
print(f"Total tables: {table_count}")

# Add a total row to the table
sales_table.ShowTotals = True
sales_table.ListColumns(3).TotalsCalculation = -4157 # xlTotalsCalculationSum

# Resize the table to include new data (e.g., extending to row 6)
sales_table.Resize(ws.range('A1:C6').api)

How to use Worksheet.Index in the xlwings API way

The Index member of the Worksheet object in xlwings provides a read-only property that returns the index number of the worksheet within its parent workbook’s Worksheets collection. This index is a 1-based integer, meaning the first worksheet in a workbook has an Index of 1, the second has an index of 2, and so on. This property is particularly useful when you need to programmatically reference or manipulate worksheets based on their positional order, rather than relying on their names. It can be essential for loops, conditional logic, or when organizing sheets dynamically.

Functionality:
The primary function is to retrieve the positional index of a worksheet. This index reflects the sheet’s order as seen in the Excel application’s tab bar. It is determined by the sheet’s position from left to right. If sheets are rearranged, their index values change accordingly. The Index property is often used in conjunction with the Worksheets collection to access specific sheets.

Syntax:
In xlwings, the property is accessed directly from a Worksheet object. The syntax is straightforward as it does not accept any parameters.

worksheet.index
  • worksheet: This is an xlwings Sheet object representing the target worksheet. It is typically obtained via wb.sheets['SheetName'] or wb.sheets[0].
  • The property returns an integer (int).

Example Usage:
Consider a workbook with three worksheets named “Data”, “Summary”, and “Chart”, in that order from left to right.

import xlwings as xw

# Connect to an existing workbook
wb = xw.Book("report.xlsx")

# Get a worksheet by its name
data_sheet = wb.sheets['Data']
summary_sheet = wb.sheets['Summary']

# Retrieve their indices
print(f"Index of 'Data' sheet: {data_sheet.index}") # Output: 1
print(f"Index of 'Summary' sheet: {summary_sheet.index}") # Output: 2

# Example 1: Using index in a loop to perform an action on every other sheet
for i in range(1, len(wb.sheets) + 1, 2): # Start at 1, step by 2
    sheet = wb.sheets[i-1] # xlwings collection is 0-based for indexing
    print(f"Processing sheet at workbook index {i}: {sheet.name}")

# Example 2: Conditionally act based on sheet position
if summary_sheet.index > data_sheet.index:
    print("The Summary sheet is to the right of the Data sheet.")

# Example 3: Activating a specific sheet by its known index (e.g., the first sheet)
wb.sheets[0].activate() # Uses 0-based index for the collection
# This is equivalent to wb.sheets[wb.sheets[0].index - 1].activate()

How to use Worksheet.Hyperlinks in the xlwings API way

The Hyperlinks member of the Worksheet object in the Excel object model provides access to a collection of all hyperlinks on a specific worksheet. Through xlwings, this collection can be manipulated to add, modify, or retrieve hyperlinks programmatically, enabling dynamic linking to web pages, documents, email addresses, or other cells within the workbook. This functionality is essential for creating interactive and navigable Excel reports.

In xlwings, the Hyperlinks collection is accessed via the api property of a worksheet object. The syntax is ws.api.Hyperlinks, where ws is an xlwings Sheet object representing the worksheet. The Hyperlinks collection has several key methods, most notably Add. The Add method creates a new hyperlink and has the following parameters:

  • Anchor: A required parameter specifying the range where the hyperlink will be placed. This is typically a Range object.
  • Address: The target address of the hyperlink (e.g., a URL like “https://www.example.com”).
  • SubAddress: An optional parameter for linking to a specific location within a file, such as a named range or a cell reference (e.g., “Sheet2!A1”).
  • ScreenTip: Optional text that appears when the user hovers over the hyperlink.
  • TextToDisplay: The optional visible text for the hyperlink. If omitted, the Address is displayed.

To retrieve an existing hyperlink, you can iterate through ws.api.Hyperlinks or access a specific one by index. Each hyperlink object in the collection has properties like Address, SubAddress, ScreenTip, and Range, which can be read or modified.

Below are practical xlwings code examples demonstrating the use of the Hyperlinks member:

import xlwings as xw

# Connect to an existing workbook and worksheet
wb = xw.Book('example.xlsx')
ws = wb.sheets['Sheet1']

# Example 1: Add a hyperlink to a website in cell A1
link_range = ws.range('A1')
ws.api.Hyperlinks.Add(Anchor=link_range.api,
Address='https://www.python.org',
ScreenTip='Visit Python Website',
TextToDisplay='Python.org')

# Example 2: Add a hyperlink to another cell in the same workbook
ws.api.Hyperlinks.Add(Anchor=ws.range('B2').api,
Address='',
SubAddress='Sheet2!C5',
TextToDisplay='Go to Sheet2')

# Example 3: Loop through all hyperlinks on the worksheet and print their addresses
for link in ws.api.Hyperlinks:
    print(f"Hyperlink at {link.Range.Address}: {link.Address}")

# Example 4: Modify an existing hyperlink (e.g., the first one)
if ws.api.Hyperlinks.Count > 0:
    first_link = ws.api.Hyperlinks(1) # Index is 1-based
    first_link.Address = 'https://www.xlwings.org'
    first_link.TextToDisplay = 'xlwings Docs'

# Save and close
wb.save()
wb.close()

How to use Worksheet.HPageBreaks in the xlwings API way

The HPageBreaks member of the Worksheet object in the Excel object model provides access to the collection of horizontal page breaks within a worksheet. In xlwings, this collection is accessible via the api property, which exposes the underlying Excel VBA object model. This allows for programmatic control over where pages break when the worksheet is printed, enabling precise formatting for reports and documents. The primary use is to add, delete, or query horizontal page breaks, which are essential for managing print layout in multi-page data sets.

Syntax and Parameters

In xlwings, you access the HPageBreaks collection through a worksheet object’s api property:

hpagebreaks = ws.api.HPageBreaks

The collection is 1-indexed, similar to Excel VBA. Key methods and properties include:

  • Add(Before): Adds a new horizontal page break.
  • Before: A required parameter of type Object. It specifies the range above which the page break will be inserted. You typically pass an xlwings Range object’s .api property (e.g., ws.range("A10").api). The break is inserted above the top edge of this range.
  • Count (Property): Returns a Long representing the number of horizontal page breaks in the collection.
  • Item(Index): Returns a single HPageBreak object from the collection.
  • Index: The index number of the page break (1-indexed).
  • Location (Property of an HPageBreak object): Returns a Range object representing the cell where the page break is set (the cell immediately below the break line). This is read/write, allowing you to move an existing break.

Code Examples

  1. Adding a Horizontal Page Break:
    Inserts a horizontal page break above row 15.
import xlwings as xw
wb = xw.Book("report.xlsx")
ws = wb.sheets["Sheet1"]
# Add a page break above cell A15
ws.api.HPageBreaks.Add(Before=ws.range("A15").api)
  1. Counting and Listing Page Breaks:
    Prints the count and location of each horizontal page break.
import xlwings as xw
wb = xw.Book.active
ws = wb.sheets[0]
hbreaks = ws.api.HPageBreaks
print(f"Number of horizontal page breaks: {hbreaks.Count}")
for i in range(1, hbreaks.Count + 1):
    break_obj = hbreaks.Item(i)
    # The Location property returns the cell below the break
    location_cell = break_obj.Location.Address
    print(f" Break {i}: Above row {break_obj.Location.Row} (at {location_cell})")
  1. Deleting All Horizontal Page Breaks:
    Clears all manually set horizontal page breaks from the sheet. Note: This does not remove automatic breaks inserted by Excel based on page margins and size.
import xlwings as xw
wb = xw.Book.active
ws = wb.sheets[0]
hbreaks = ws.api.HPageBreaks
# Loop backwards to avoid index shifting when deleting
for i in range(hbreaks.Count, 0, -1):
    # The HPageBreak object itself doesn't have a .Delete() method.
    # You delete it by clearing the break from its location.
    hbreaks.Item(i).Location.PageBreak = -4142 # xlPageBreakNone
    # Alternatively, reset all page breaks on the sheet:
    # ws.api.ResetAllPageBreaks()
  1. Moving an Existing Page Break:
    Changes the position of the first horizontal page break to be above row 25.
import xlwings as xw
wb = xw.Book.active
ws = wb.sheets[0]
hbreaks = ws.api.HPageBreaks
if hbreaks.Count >= 1:
    first_break = hbreaks.Item(1)
    first_break.Location = ws.range("A25").api

How to use Worksheet.FilterMode in the xlwings API way

The FilterMode property of a Worksheet object in the xlwings API is a read-only property that returns a Boolean value indicating whether the worksheet currently has any active autofilters applied. Specifically, it checks if the worksheet is in “filter mode,” meaning one or more columns have filter dropdowns enabled due to an autofilter being turned on. This is useful for programmatically determining the state of filters before performing operations like data processing or clearing filters, ensuring that your automation scripts can adapt dynamically to the worksheet’s condition.

Syntax and Parameters:
In xlwings, you access this property through a Sheet object (which corresponds to an Excel worksheet). The property does not take any arguments.

sheet.api.FilterMode

Here, sheet is an xlwings Sheet object. The .api attribute provides direct access to the underlying Excel object model (via COM on Windows or AppleScript on macOS), allowing you to use properties like FilterMode as defined in the Excel VBA documentation. The property returns True if the worksheet is in filter mode, and False otherwise.

Code Examples:
Below are practical examples of using the FilterMode property in xlwings:

  1. Checking Filter Mode State:
    This example opens an Excel workbook, selects a specific sheet, and checks if filters are active.
import xlwings as xw

# Open the workbook and reference the sheet
wb = xw.Book("example.xlsx")
sheet = wb.sheets["Sheet1"]

# Check if the sheet is in filter mode
if sheet.api.FilterMode:
    print("The worksheet has active autofilters.")
else:
    print("No autofilters are currently applied.")
  1. Conditional Operations Based on Filter Mode:
    This script uses FilterMode to decide whether to clear existing filters before applying new ones, preventing errors or unintended behavior.
import xlwings as xw

wb = xw.Book("data.xlsx")
sheet = wb.sheets[0]

# If filters are already on, clear them
if sheet.api.FilterMode:
    sheet.api.AutoFilterMode = False # Turn off autofilter mode
    print("Existing filters cleared.")

# Apply a new autofilter to a range (e.g., A1:D100)
sheet.range("A1:D100").api.AutoFilter(1)
print("New autofilter applied.")
  1. Monitoring Filter Changes:
    In a more dynamic scenario, you might loop through multiple sheets to report their filter status.
import xlwings as xw

wb = xw.Book("report.xlsx")

for sheet in wb.sheets:
    status = "Active" if sheet.api.FilterMode else "Inactive"
    print(f"Sheet '{sheet.name}' has filters: {status}")

How to use Worksheet.EnableSelection in the xlwings API way

The Worksheet.EnableSelection property in the xlwings API provides control over the types of selections a user can make within a worksheet via the user interface. This property is particularly useful when you want to protect a worksheet but still allow users to interact with specific cells, such as unlocked cells in a form or template. By setting EnableSelection, you can restrict users from selecting locked cells, unlocked cells, or any cells at all, even when sheet protection is enabled. This enhances data integrity and user experience in shared or sensitive workbooks by preventing accidental modifications to critical data.

In xlwings, you access this property through the api property of a Worksheet object, which exposes the underlying Excel object model. The syntax for using EnableSelection is:
worksheet.api.EnableSelection = value
Here, worksheet is an xlwings Worksheet object, and value is an integer that specifies the selection type. The possible values for value are defined in the Excel enumeration xlEnableSelection, which includes:

  • xlNoSelection (value: -4142): Prevents any selection in the worksheet.
  • xlNoRestrictions (value: 0): Allows selection of all cells (default behavior when protection is off).
  • xlUnlockedCells (value: 1): Permits selection only of unlocked cells.

To use these values in xlwings, you can import the constants from the win32com.client module if you are on Windows, or use their numeric equivalents directly for cross-platform compatibility. For example, xlUnlockedCells corresponds to the integer 1. This property is often set in conjunction with the Protect method to customize protection settings.

Below are code examples demonstrating the usage of Worksheet.EnableSelection with xlwings. Ensure you have an active workbook and worksheet object before running these snippets.

Example 1: Allow selection only of unlocked cells after protecting the worksheet. This is common in forms where users should only edit specific input fields.

import xlwings as xw
# Open an existing workbook or create a new one
wb = xw.Book('example.xlsx')
ws = wb.sheets['Sheet1']
# First, unlock some cells that users are allowed to edit (e.g., range A1:B2)
ws.range('A1:B2').api.Locked = False
# Protect the worksheet with a password (optional) and set EnableSelection
ws.api.Protect(Password='yourpassword', DrawingObjects=True, Contents=True, Scenarios=True)
ws.api.EnableSelection = 1 # xlUnlockedCells
# Now, users can only select and edit the unlocked cells A1:B2

Example 2: Disable all selections in a protected worksheet to make it completely read-only, preventing users from even clicking on cells.

import xlwings as xw
wb = xw.Book('example.xlsx')
ws = wb.sheets['Sheet1']
# Protect the worksheet without allowing any selections
ws.api.Protect(Password='secure123')
ws.api.EnableSelection = -4142 # xlNoSelection
# Users cannot select any cells, ensuring no accidental interactions

Example 3: Remove restrictions and allow full selection, which might be useful when temporarily disabling protection for editing.

import xlwings as xw
wb = xw.Book('example.xlsx')
ws = wb.sheets['Sheet1']
# If the worksheet is protected, unprotect it first
if ws.api.ProtectContents:
    ws.api.Unprotect(Password='yourpassword')
    # Set EnableSelection to allow all selections
    ws.api.EnableSelection = 0 # xlNoRestrictions
    # Users can now select any cell freely