Repository: near/docs
Pull request #2494: feat: Add information about the Python SDK
Author: login: r-near
Created: 2025-03-06T02:10:38Z | Merged: 2025-03-20T14:41:17Z

This PR adds comprehensive Python SDK documentation to the NEAR smart contract sections, making Python a first-class citizen alongside JavaScript and Rust. The changes include:

## Overview
- Added Python examples across all smart contract anatomy pages
- Introduced Python equivalent code for actions, cross-contract calls, storage, collections, and more
- Added Python-specific best practices and optimization guidelines
- Updated code examples in the quickstart guide to include Python SDK instructions

## Key Additions
- Complete examples for core contract functionality:
  - Function decorators (@view, @call, @init, @callback)
  - State management and storage patterns
  - Collections (Vector, UnorderedMap, LookupMap, etc.)
  - Cross-contract calls and promise chaining
  - Actions (transfer, create account, deploy contract)
  - Environment access and context handling

## Implementation Details
- Added Python tabs to all existing code examples
- Preserved the existing JS/Rust examples while adding Python equivalents
- Ensured consistent formatting and style across all language examples
- Added Python-specific notes and tips where the implementation differs from other SDKs

These changes will help Python developers get started with NEAR smart contract development with the same level of documentation support as JavaScript and Rust developers.


Diff:
diff --git a/docs/smart-contracts/anatomy/actions.md b/docs/smart-contracts/anatomy/actions.md
index a68aae8525d..86000987ec8 100644
--- a/docs/smart-contracts/anatomy/actions.md
+++ b/docs/smart-contracts/anatomy/actions.md
@@ -57,6 +57,22 @@ You can send $NEAR from your contract to any other account on the network. The G
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Contract
+from near_sdk_py.promises import Promise
+
+class ExampleContract(Contract):
+    @call
+    def transfer(self, to, amount):
+        """Transfers NEAR to another account"""
+        # Create a promise to transfer NEAR
+        return Promise.create_batch(to).transfer(amount)
+```
+
+</TabItem>
+
 </Tabs>
 
 :::tip Why is there no callback?
@@ -161,6 +177,44 @@ right in the callback.
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, callback, Contract
+from near_sdk_py.promises import CrossContract, Promise, PromiseResult
+from near_sdk_py.constants import ONE_TGAS
+
+# Constants
+HELLO_NEAR = "hello-nearverse.testnet"
+NO_DEPOSIT = 0
+CALL_GAS = 10 * ONE_TGAS
+
+class ExampleContract(Contract):
+    @call
+    def call_method(self):
+        """Call a method on an external contract with a callback"""
+        # Create a contract reference
+        hello = CrossContract(HELLO_NEAR)
+        
+        # Call the external contract and use our callback to process the result
+        return hello.call("set_greeting", {"message": "howdy"}).then("callback")
+    
+    @callback
+    def callback(self, result: PromiseResult):
+        """Handle the result of the external contract call"""
+        # The @callback decorator automatically handles success/failure checking
+        if not result.success:
+            # The remote call failed
+            self.log_error("Promise failed...")
+            return False
+        
+        # The remote call succeeded
+        self.log_info("Success!")
+        return True
+```
+
+</TabItem>
+
 </Tabs>
 
 :::warning
@@ -224,6 +278,31 @@ Sub-accounts are simply useful for organizing your accounts (e.g. `dao.project.n
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Contract
+from near_sdk_py.promises import Promise
+from near_sdk_py.constants import ONE_NEAR
+
+# Minimum amount needed for storage
+MIN_STORAGE = ONE_NEAR // 1000  # 0.001Ⓝ
+
+class ExampleContract(Contract):
+    @call
+    def create(self, prefix):
+        """Create a subaccount"""
+        # Generate the new account ID
+        account_id = f"{prefix}.{self.current_account_id}"
+        
+        # Create the new account and transfer some NEAR for storage
+        return Promise.create_batch(account_id)\
+            .create_account()\
+            .transfer(MIN_STORAGE)
+```
+
+</TabItem>
+
 </Tabs>
 
 :::tip
@@ -301,6 +380,39 @@ the `create_account` method of `near` or `testnet` root contracts.
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Contract
+from near_sdk_py.promises import Promise
+from near_sdk_py.constants import ONE_NEAR, ONE_TGAS
+
+# Constants
+MIN_STORAGE = int(1.82 * ONE_NEAR / 1000)  # 0.00182Ⓝ
+CALL_GAS = 28 * ONE_TGAS
+
+class ExampleContract(Contract):
+    @call
+    def create_account(self, account_id, public_key):
+        """Create a testnet account by calling the testnet contract"""
+        # Create the arguments for the create_account method
+        args = {
+            "new_account_id": account_id,
+            "new_public_key": public_key
+        }
+        
+        # Call the testnet contract to create the account
+        return Promise.create_batch("testnet")\
+            .function_call(
+                "create_account",
+                args,
+                MIN_STORAGE,
+                CALL_GAS
+            )
+```
+
+</TabItem>
+
 </Tabs>
 
 ---
@@ -336,6 +448,36 @@ When creating an account you can also batch the action of deploying a contract t
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Context, Contract
+from near_sdk_py.promises import Promise 
+from near_sdk_py.constants import ONE_NEAR
+
+class ExampleContract(Contract):
+    @call
+    def deploy_contract(self, prefix):
+        """Create an account and deploy a contract to it"""
+        # This would require loading the contract bytes in Python
+        # Load contract bytes - for example purposes only
+        # In a real implementation, you'd need to read this from storage or include it
+        contract_bytes = b'...'  # This should be actual WASM bytes
+        
+        MIN_STORAGE = 1.1 * ONE_NEAR  # 1.1Ⓝ
+        
+        # Generate the new account ID
+        account_id = f"{prefix}.{self.current_account_id}"
+        
+        # Create batch of actions
+        return Promise.create_batch(account_id)\
+            .create_account()\
+            .transfer(MIN_STORAGE)\
+            .deploy_contract(contract_bytes)
+```
+
+</TabItem>
+
 </Tabs>
 
 :::tip
@@ -406,6 +548,32 @@ There are two options for adding keys to the account:
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Contract
+from near_sdk_py.promises import Promise
+from near_sdk_py.constants import ONE_NEAR
+
+# Minimum amount needed for storage
+MIN_STORAGE = ONE_NEAR // 1000  # 0.001Ⓝ
+
+class ExampleContract(Contract):
+    @call
+    def create_with_key(self, prefix, public_key):
+        """Create a subaccount with a full access key"""
+        # Generate the new account ID
+        account_id = f"{prefix}.{self.current_account_id}"
+        
+        # Create the new account, transfer some NEAR, and add a key
+        return Promise.create_batch(account_id)\
+            .create_account()\
+            .transfer(MIN_STORAGE)\
+            .add_full_access_key(public_key)
+```
+
+</TabItem>
+
 </Tabs>
 
 Notice that what you actually add is a "public key". Whoever holds its private counterpart, i.e. the private-key, will be able to use the newly access key.
@@ -483,6 +651,39 @@ There are two scenarios in which you can use the `delete_account` action:
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Contract
+from near_sdk_py.promises import Promise
+from near_sdk_py.constants import ONE_NEAR
+
+# Minimum amount needed for storage
+MIN_STORAGE = ONE_NEAR // 1000  # 0.001Ⓝ
+
+class ExampleContract(Contract):
+    @call
+    def create_delete(self, prefix, beneficiary):
+        """Create an account and immediately delete it, sending funds to a beneficiary"""
+        # Generate the new account ID
+        account_id = f"{prefix}.{self.current_account_id}"
+        
+        # Create the account, transfer funds, then delete it
+        return Promise.create_batch(account_id)\
+            .create_account()\
+            .transfer(MIN_STORAGE)\
+            .delete_account(beneficiary)
+    
+    @call
+    def self_delete(self, beneficiary):
+        """Delete this contract's account"""
+        # Delete the account and send remaining funds to beneficiary
+        return Promise.create_batch(self.current_account_id)\
+            .delete_account(beneficiary)
+```
+
+</TabItem>
+
 </Tabs>
 
 :::warning Token Loss
diff --git a/docs/smart-contracts/anatomy/anatomy.md b/docs/smart-contracts/anatomy/anatomy.md
index c0ecea85abe..453e1aefde5 100644
--- a/docs/smart-contracts/anatomy/anatomy.md
+++ b/docs/smart-contracts/anatomy/anatomy.md
@@ -3,6 +3,7 @@ id: anatomy
 title: Basic Anatomy
 hide_table_of_contents: true
 ---
+
 import Tabs from '@theme/Tabs';
 import TabItem from '@theme/TabItem';
 import {CodeTabs, Language, Github} from "@site/src/components/codetabs"
@@ -10,9 +11,9 @@ import {ExplainCode, Block, File} from '@site/src/components/CodeExplainer/code-
 
 Let's illustrate the basic anatomy of a simple "Hello World" contract. The code on this page comes from our [Hello NEAR repository](https://github.com/near-examples/hello-near-examples) on GitHub.
 
-<ExplainCode languages="js,rust" >
+<ExplainCode languages="js,rust,python" >
 
-<Block highlights='{"js": "1", "rust": "1"}' fname="hello-near">
+<Block highlights='{"js": "1", "rust": "1", "python": "1"}' fname="hello-near">
 
     ### Importing the SDK
     All contracts will import the **NEAR SDK**, enabling them to [access the execution environment](./environment.md), [call other contracts](./crosscontract.md), [transfer tokens](./actions.md), and much more.
@@ -21,7 +22,7 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
 
 </Block>
 
-<Block highlights='{"js": "5-22", "rust":"5-7,20-31"}' fname="hello-near">
+<Block highlights='{"js": "5-22", "rust":"5-7,20-31", "python": "5-19"}' fname="hello-near">
 
     ### Contract's Main Structure
     The contract is described through a structure:
@@ -33,7 +34,7 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
 <Block highlights='{"js": "3"}' fname="hello-near">
 
     ### Contract Class Decorator
-    
+
     Note that the contract's class is decorated with `@NearBindgen`. This decorator tells the SDK which class defines the contract, so it knows:
     1. What to fetch from storage when the contract is loaded
     2. What to store when the contract is done executing
@@ -44,12 +45,22 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
 
 </Block>
 
+<Block highlights='{"python": "4"}' fname="hello-near">
+
+    ### Python Class Structure
+
+    In Python, we use a class to define our contract. Unlike JavaScript or Rust, there isn't a specific decorator for the class itself. Instead, each method that should be exposed to the blockchain is decorated with the appropriate decorator (`@view`, `@call`, or `@init`).
+
+    The contract's state is managed through instance variables and can be persisted using the Storage API or collections.
+
+</Block>
+
 <Block highlights='{"rust": "4,19"}' fname="hello-near">
 
     ### Contract Struct Macro
-    
+
     Note that the contract's struct definition and the implementation are decorated with macros
-    
+
     The `#[near(contract_state)]` macro tell the SDK that this structure defines the contract's state, so it knows:
     1. What to fetch from storage when the contract is loaded
     2. What to store when the contract is done executing
@@ -76,11 +87,11 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
 
 </Block>
 
-<Block highlights='{"js": "5", "rust": "6,10-16"}' fname="hello-near">
+<Block highlights='{"js": "5", "rust": "6,10-16", "python": "7-8"}' fname="hello-near">
 
     ### Storage (State)
     We call the data stored in the contract [the contract's state](./storage.md).
-    
+
     In our Hello World example, the contract stores a single string (`greeting`), and the state starts initialized with the default value `"Hello"`.
 
     **Note:** We will cover more about the contract's state in the [state section](./storage.md).
@@ -93,7 +104,16 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
 
 </Block>
 
-<Block highlights='{"js": "12-14", "rust": "22-24"}' fname="hello-near">
+<Block highlights='{"python": "5-5,10-10,15-15"}' fname="hello-near">
+
+    ### Method Decorators
+
+    In Python, contract methods are decorated with `@view`, `@call`, or `@init` to define how they can be accessed.
+    These decorators handle input parsing and serializing return values automatically.
+
+</Block>
+
+<Block highlights='{"js": "12-14", "rust": "22-24", "python": "10-13"}' fname="hello-near">
 
     ### Read Only Functions
     Contract's functions can be read-only, meaning they don't modify the state. Calling them is free for everyone, and does not require to have a NEAR account.
@@ -102,7 +122,7 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
 
 </Block>
 
-<Block highlights='{"js": "17-20", "rust": "27-30"}' fname="hello-near">
+<Block highlights='{"js": "17-20", "rust": "27-30", "python": "15-19"}' fname="hello-near">
 
     ### State Mutating Functions
     Functions that modify the state or call other contracts are considered state mutating functions. It is necessary to have a NEAR account to call them, as they require a transaction to be sent to the network.
@@ -119,4 +139,5 @@ Let's illustrate the basic anatomy of a simple "Hello World" contract. The code
     url="https://github.com/near-examples/hello-near-examples/blob/main/contract-rs/src/lib.rs"
     start="2" end="32" />
 
+<File language="python" fname="hello-near" url="https://github.com/r-near/near-py-examples/blob/main/hello-near.py" start="2" end="32" />
 </ExplainCode>
diff --git a/docs/smart-contracts/anatomy/best-practices.md b/docs/smart-contracts/anatomy/best-practices.md
index 35427927e6b..230669ce7a4 100644
--- a/docs/smart-contracts/anatomy/best-practices.md
+++ b/docs/smart-contracts/anatomy/best-practices.md
@@ -2,9 +2,14 @@
 id: best-practices
 title: "Best Practices"
 ---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
 
 # Best practices
 
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="rust" label="🦀 Rust">
+
 Here we lay out some best practices for writing smart contracts on NEAR, such as:
 
 - [Enable overflow checks](#enable-overflow-checks)
@@ -149,3 +154,164 @@ impl Contract {
 
 Workspaces allow you to automate workflows and run tests for multiple contracts and cross-contract calls in a sandbox or testnet environment.
 Read more, [workspaces-rs](https://github.com/near/workspaces-rs) or [workspaces-js](https://github.com/near/workspaces-js).
+
+  </TabItem>
+  <TabItem value="python" label="🐍 Python">
+
+Here we lay out some best practices for writing smart contracts in Python on NEAR:
+
+- [Validate early](#validate-early)
+- [Use proper logging](#use-proper-logging)
+- [Return Promises](#return-promises)
+- [Handle storage efficiently](#handle-storage-efficiently)
+- [Use type hints](#use-type-hints)
+- [Follow security patterns](#follow-security-patterns)
+
+---
+
+## Validate early
+
+Validate inputs, context, and state as early as possible in your functions. This saves gas by failing fast before executing expensive operations.
+
+```python
+from near_sdk_py import call, Context
+
+class Contract:
+    def __init__(self):
+        self.owner_id = Context.current_account_id()
+        
+    @call
+    def set_config(self, config_data):
+        # Validate permissions early
+        if Context.predecessor_account_id() != self.owner_id:
+            raise Exception("Only owner can modify config")
+            
+        # Validate inputs early
+        if "parameter" not in config_data or not isinstance(config_data["parameter"], int):
+            raise Exception("Invalid config: missing or invalid parameter")
+            
+        # Only proceed after validation
+        self._update_config(config_data)
+```
+
+## Use proper logging
+
+Use the `Log` utility for structured logging. This allows external services to parse events from your contract easily.
+
+```python
+from near_sdk_py import call, Log
+
+@call
+def transfer(self, receiver_id, amount):
+    # Business logic here...
+    
+    # Use informational logs for regular updates
+    Log.info(f"Transferred {amount} tokens to {receiver_id}")
+    
+    # Use structured event logging for indexable events
+    Log.event("transfer", {
+        "sender": Context.predecessor_account_id(),
+        "receiver": receiver_id,
+        "amount": amount
+    })
+```
+
+## Return Promises
+
+When making cross-contract calls, return the Promise object to let the caller track the result. This is especially important for transactions that need to be monitored.
+
+```python
+from near_sdk_py import call
+from near_sdk_py.promises import Contract
+
+@call
+def withdraw(self, amount, receiver_id):
+    # Perform validations and business logic...
+    
+    # Return the promise for better caller experience
+    return Contract(receiver_id).call(
+        "deposit",
+        amount=amount,
+        sender=Context.predecessor_account_id()
+    )
+```
+
+## Handle storage efficiently
+
+Use the SDK collections for efficient storage handling, especially for growing data sets.
+
+```python
+from near_sdk_py.collections import UnorderedMap, Vector
+
+class TokenContract:
+    def __init__(self):
+        # Use SDK collections for efficient storage
+        self.tokens = Vector("t")  # Efficiently stores ordered items
+        self.balances = UnorderedMap("b")  # Efficiently stores key-value pairs
+        
+    @call
+    def mint(self, token_id):
+        # Add to vector without loading all tokens
+        self.tokens.append(token_id)
+        
+        # Update balance without loading all balances
+        current = self.balances.get(Context.predecessor_account_id(), 0)
+        self.balances[Context.predecessor_account_id()] = current + 1
+```
+
+## Use type hints
+
+Python's type hints improve code readability and can help catch errors during development.
+
+```python
+from typing import Dict, List, Optional
+from near_sdk_py import view, call
+
+class Contract:
+    def __init__(self):
+        self.data: Dict[str, int] = {}
+        
+    @view
+    def get_value(self, key: str) -> Optional[int]:
+        return self.data.get(key)
+        
+    @call
+    def set_values(self, updates: Dict[str, int]) -> List[str]:
+        updated_keys = []
+        for key, value in updates.items():
+            self.data[key] = value
+            updated_keys.append(key)
+        return updated_keys
+```
+
+## Follow security patterns
+
+Apply security best practices to protect your contract from common vulnerabilities.
+
+```python
+from near_sdk_py import call, Context
+from near_sdk_py.constants import ONE_NEAR
+
+class Contract:
+    def __init__(self):
+        self.owner = Context.current_account_id()
+        self.minimum_deposit = ONE_NEAR // 100  # 0.01 NEAR
+        
+    @call
+    def deposit(self):
+        # Check sufficient deposit to prevent spam
+        deposit = Context.attached_deposit()
+        if deposit < self.minimum_deposit:
+            raise Exception(f"Minimum deposit is {self.minimum_deposit}")
+            
+        # Re-entrancy protection pattern
+        current_balance = self.balances.get(Context.predecessor_account_id(), 0)
+        # Update state before external calls
+        self.balances[Context.predecessor_account_id()] = current_balance + deposit
+        
+        # Only after state update, perform any external calls
+        # ...
+```
+
+  </TabItem>
+</Tabs>
diff --git a/docs/smart-contracts/anatomy/collections.md b/docs/smart-contracts/anatomy/collections.md
index 8ecf351ae91..2aee3de5ca4 100644
--- a/docs/smart-contracts/anatomy/collections.md
+++ b/docs/smart-contracts/anatomy/collections.md
@@ -136,6 +136,21 @@ The `near_sdk::collections` is now deprecated in favor of `near_sdk::store`. To
 | `collections::LazyOption<T>`                       | `Option<T>`                        | Optional value in storage. This value will only be read from storage when interacted with. This value will be `Some<T>` when the value is saved in storage, and `None` if the value at the prefix does not exist.                                  |
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+| SDK Collection | Native Equivalent | Description                                                                                                                                                                         |
+| -------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Vector`       | `list`            | A growable array type. The values are sharded in memory and can be used for iterable and indexable values that are dynamically sized.                                               |
+| `LookupMap`    | `dict`            | A non-iterable key-value store. This structure does not track keys for iteration, so it is optimized for lookups but cannot provide collection operations like keys or values.      |
+| `UnorderedMap` | `dict`            | Similar to `LookupMap`, except that it stores additional data to be able to iterate through elements and supports dictionary-like operations such as keys(), values(), and items(). |
+| `IterableMap`  | `dict`            | An alias for `UnorderedMap` provided for compatibility with Rust SDK naming conventions.                                                                                            |
+| `LookupSet`    | `set`             | A non-iterable set of unique values. This structure cannot be iterated over and can only be used for membership testing.                                                            |
+| `UnorderedSet` | `set`             | An iterable equivalent of `LookupSet` which stores additional metadata to allow iteration over the values in the set.                                                               |
+| `IterableSet`  | `set`             | An alias for `UnorderedSet` provided for compatibility with Rust SDK naming conventions.                                                                                            |
+| `TreeMap`      | `SortedDict`      | An ordered key-value store where keys are maintained in sorted order. Provides operations for range queries, finding nearest keys, and efficient min/max operations.                |
+
+</TabItem>
+
 </Tabs>
 
 <hr class="subsection" />
@@ -221,6 +236,43 @@ Do not forget to use the `schema` to define how your contract's state is structu
 
   </TabItem>
 
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import Vector, LookupMap, UnorderedMap, LookupSet, UnorderedSet
+
+class MyContract:
+@init
+def new(self): # Create a Vector with prefix "v"
+self.my_vector = Vector("v")
+
+        # Create a LookupMap with prefix "m"
+        self.my_lookup_map = LookupMap("m")
+
+        # Create an UnorderedMap with prefix "um"
+        self.my_unordered_map = UnorderedMap("um")
+
+        # Create a LookupSet with prefix "s"
+        self.my_lookup_set = LookupSet("s")
+
+        # Create an UnorderedSet with prefix "us"
+        self.my_unordered_set = UnorderedSet("us")
+
+        # For nested collections, use different prefixes
+        self.nested_maps = UnorderedMap("nested")
+
+        return True
+
+    @call
+    def create_nested_map(self, key: str):
+        # Create a new map that will be stored inside another map
+        inner_map = UnorderedMap(f"inner_{key}")
+        self.nested_maps[key] = inner_map
+        return {"success": True}
+
+````
+  </TabItem>
+
 </Tabs>
 
 :::danger
@@ -249,6 +301,37 @@ Implements a [vector/array](https://en.wikipedia.org/wiki/Array_data_structure)
     <Github fname="vector.rs" language="rust"
             url="https://github.com/near-examples/storage-examples/blob/main/collections-rs/legacy/src/vector.rs" start="6" end="31"/>
   </TabItem>
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import Vector
+
+class VectorExample:
+    @init
+    def new(self):
+        # Create a Vector with prefix "v"
+        self.my_vector = Vector("v")
+        
+    @call
+    def add_number(self, number):
+        # Append a value to the vector
+        self.my_vector.append(number)
+        return len(self.my_vector)
+        
+    @view
+    def get_number(self, index):
+        # Get a value at specific index
+        try:
+            return self.my_vector[index]
+        except Exception:
+            return None
+            
+    @view
+    def get_all_numbers(self):
+        # Convert entire vector to a list
+        return [num for num in self.my_vector]
+```
+  </TabItem>
 </Tabs>
 
 <hr className="subsection" />
@@ -267,6 +350,37 @@ Implements a [map/dictionary](https://en.wikipedia.org/wiki/Associative_array) w
     <Github fname="lookup_map.rs" language="rust"
           url="https://github.com/near-examples/storage-examples/blob/main/collections-rs/store/src/lookup_map.rs" start="4" end="22"/>
   </TabItem>
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import LookupMap
+
+class LookupMapExample:
+    @init
+    def new(self):
+        # Create a LookupMap with prefix "m"
+        self.balances = LookupMap("m")
+        
+    @call
+    def set_balance(self, account_id, amount):
+        # Set a value for a key
+        self.balances[account_id] = amount
+        return True
+        
+    @view
+    def get_balance(self, account_id):
+        # Get a value for a key with a default
+        return self.balances.get(account_id, 0)
+        
+    @call
+    def remove_balance(self, account_id):
+        # Remove a key
+        if account_id in self.balances:
+            del self.balances[account_id]
+            return True
+        return False
+```
+  </TabItem>
 </Tabs>
 
 <hr className="subsection" />
@@ -285,6 +399,41 @@ Implements a [map/dictionary](https://en.wikipedia.org/wiki/Associative_array) w
     <Github fname="iterable_map.rs" language="rust"
           url="https://github.com/near-examples/storage-examples/blob/main/collections-rs/store/src/iterable_map.rs" start="4" end="29"/>
   </TabItem>
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import UnorderedMap
+
+class UnorderedMapExample:
+    @init
+    def new(self):
+        # Create an UnorderedMap with prefix "um"
+        self.user_data = UnorderedMap("um")
+        
+    @call
+    def set_user_data(self, account_id, data):
+        # Set a value for a key
+        self.user_data[account_id] = data
+        return True
+        
+    @view
+    def get_user_data(self, account_id):
+        # Get a value for a key
+        try:
+            return self.user_data[account_id]
+        except Exception:
+            return None
+        
+    @view
+    def list_all_users(self):
+        # Iterate through keys and values
+        return {
+            "keys": self.user_data.keys(),
+            "values": self.user_data.values(),
+            "items": self.user_data.items()
+        }
+```
+  </TabItem>
 </Tabs>
 
 <hr className="subsection" />
@@ -304,6 +453,39 @@ Implements a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) which
       <Github fname="lookup_set.rs" language="rust"
         url="https://github.com/near-examples/storage-examples/blob/main/collections-rs/store/src/lookup_set.rs" start="4" end="18"/>
   </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import LookupSet
+
+class LookupSetExample:
+    @init
+    def new(self):
+        # Create a LookupSet with prefix "s"
+        self.whitelist = LookupSet("s")
+        
+    @call
+    def add_to_whitelist(self, account_id):
+        # Add a value to the set
+        self.whitelist.add(account_id)
+        return True
+        
+    @view
+    def is_whitelisted(self, account_id):
+        # Check if a value exists in the set
+        return account_id in self.whitelist
+        
+    @call
+    def remove_from_whitelist(self, account_id):
+        # Remove a value from the set
+        try:
+            self.whitelist.remove(account_id)
+            return True
+        except Exception:
+            return False
+```
+  </TabItem>
 
 </Tabs>
 
@@ -323,6 +505,40 @@ Implements a [map/dictionary](https://en.wikipedia.org/wiki/Associative_array) w
     <Github fname="iterable_set.rs" language="rust"
           url="https://github.com/near-examples/storage-examples/blob/main/collections-rs/store/src/iterable_set.rs" start="4" end="26"/>
   </TabItem>
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import UnorderedSet
+
+class UnorderedSetExample:
+    @init
+    def new(self):
+        # Create an UnorderedSet with prefix "us"
+        self.owners = UnorderedSet("us")
+        
+    @call
+    def register_owner(self, account_id):
+        # Add a value to the set
+        self.owners.add(account_id)
+        return True
+        
+    @view
+    def is_owner(self, account_id):
+        # Check if a value exists in the set
+        return account_id in self.owners
+        
+    @view
+    def list_all_owners(self):
+        # Get all values as a list
+        return self.owners.values()
+        
+    @call
+    def remove_owner(self, account_id):
+        # Try to remove a value if it exists
+        self.owners.discard(account_id)
+        return True
+```
+  </TabItem>
 </Tabs>
 
 <hr className="subsection" />
@@ -336,6 +552,43 @@ An ordered equivalent of Map. The underlying implementation is based on an [AVL]
     <Github fname="tree.rs" language="rust"
           url="https://github.com/near-examples/storage-examples/blob/main/collections-rs/legacy/src/tree.rs" start="6" end="24"/>
   </TabItem>
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import TreeMap
+
+class TreeMapExample:
+    @init
+    def new(self):
+        # Create a TreeMap with prefix "tm"
+        self.scores = TreeMap("tm")
+        
+    @call
+    def add_score(self, user_id, score):
+        # Set score for a user
+        self.scores[user_id] = score
+        return True
+        
+    @view
+    def get_top_scores(self, limit=10):
+        # Get top scores using ordered keys
+        # This returns highest scores first
+        top_users = []
+        max_key = self.scores.max_key()
+        current_key = max_key
+        count = 0
+        
+        while current_key is not None and count < limit:
+            top_users.append({
+                "user": current_key,
+                "score": self.scores[current_key]
+            })
+            current_key = self.scores.floor_key(current_key - 1)  # Get next highest key
+            count += 1
+            
+        return top_users
+```
+  </TabItem>
 </Tabs>
 
 <hr class="subsection" />
@@ -375,8 +628,57 @@ When nesting SDK collections, be careful to **use different prefixes** for all c
   :::
 
   </TabItem>
-</Tabs>
+  
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import UnorderedMap, Vector
+from near_sdk_py.collections import create_prefix_guard
+
+class NestedCollectionsExample:
+    @init
+    def new(self):
+        # Main map of users to their assets
+        self.user_assets = UnorderedMap("users")
+
+    @call
+    def add_asset(self, user_id, asset_id, metadata):
+        # Get or create the user's assets vector with a unique prefix
+        if user_id not in self.user_assets:
+            # Create a prefix guard to ensure unique prefixes for this user
+            prefix = f"assets:{user_id}"
+            # Create a new vector for this user's assets
+            self.user_assets[user_id] = Vector(prefix)
+
+        # Add the asset to the user's assets vector
+        user_assets = self.user_assets[user_id]
+        user_assets.append({
+            "asset_id": asset_id,
+            "metadata": metadata
+        })
+
+        # Update the vector in the map
+        self.user_assets[user_id] = user_assets
+        return True
+
+    @view
+    def get_user_assets(self, user_id):
+        if user_id not in self.user_assets:
+            return []
+
+        # Get all assets for the user
+        user_assets = self.user_assets[user_id]
+        return [asset for asset in user_assets]
+````
 
+:::tip
+
+In Python, we create unique prefixes for nested collections by including the parent's identifier in the prefix string. The SDK also provides a `create_prefix_guard` utility to help manage prefixes.
+
+:::
+
+  </TabItem>
+</Tabs>
 
 ---
 
@@ -525,8 +827,6 @@ Persistent collections such as `IterableMap/UnorderedMap`, `IterableSet/Unordere
 contain more elements than the amount of gas available to read them all.
 In order to expose them all through view calls, we can use pagination.
 
-
-
 <Tabs groupId="code-tabs">
   <TabItem value="js" label="🌐 JavaScript">
     With JavaScript this can be done using iterators with [`toArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/toArray) and [`slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice).
@@ -566,15 +866,44 @@ In order to expose them all through view calls, we can use pagination.
           }
       }
     ```
+
+  </TabItem>
+
+  <TabItem value="python" label="🐍 Python">
+    ```python
+    # With Python this can be done using standard list slicing.
+
+    @view
+    def get_updates(self, from_index: int = 0, limit: int = 50) -> list:
+        """Returns multiple elements from the collection with pagination.
+        
+        Args:
+            from_index: The index to start from
+            limit: The maximum number of elements to return
+            
+        Returns:
+            A list of elements from the collection
+        """
+        # Get all values from the collection
+        all_items = self.status_updates.values()
+        
+        # Apply pagination with list slicing
+        start = min(from_index, len(all_items))
+        end = min(start + limit, len(all_items))
+        
+        return all_items[start:end]
+    ```
   </TabItem>
 </Tabs>
 
 ---
 
 ## Storage Cost
+
 Your contract needs to lock a portion of their balance proportional to the amount of data they stored in the blockchain. This means that:
+
 - If more data is added and the **storage increases ↑**, then your contract's **balance decreases ↓**.
-- If data is deleted and the **storage decreases ↓**, then your contract's **balance increases ↑**. 
+- If data is deleted and the **storage decreases ↓**, then your contract's **balance increases ↑**.
 
 Currently, it costs approximately **1 Ⓝ** to store **100kb** of data.
 
diff --git a/docs/smart-contracts/anatomy/crosscontract.md b/docs/smart-contracts/anatomy/crosscontract.md
index 0f3ff05b23a..8a308c96855 100644
--- a/docs/smart-contracts/anatomy/crosscontract.md
+++ b/docs/smart-contracts/anatomy/crosscontract.md
@@ -53,6 +53,56 @@ While making your contract, it is likely that you will want to query information
 
 </Language>
 
+<Language value="python" language="python">
+```python
+from near_sdk_py import call, view, Contract, callback, PromiseResult, CrossContract, init
+
+class CrossContractExample(Contract):
+    # Contract we want to interact with
+    hello_contract = "hello-near.testnet"
+        
+    @init
+    def new(self):
+        """Initialize the contract"""
+        # Any initialization logic goes here
+        pass
+        
+    @view
+    def query_greeting_info(self):
+        """View function showing how to make a cross-contract call"""
+        # Create a reference to the Hello NEAR contract
+        # This is a simple call that will execute in the current transaction
+        hello = CrossContract(self.hello_contract)
+        return hello.call("get_greeting").value()
+    
+    @call
+    def query_greeting(self):
+        """Calls Hello NEAR contract to get the greeting with a callback"""
+        # Create a reference to the Hello NEAR contract
+        hello = CrossContract(self.hello_contract)
+        
+        # Call get_greeting and chain a callback
+        # The Promise API handles serialization and callback chaining
+        promise = hello.call("get_greeting").then("query_greeting_callback")
+        
+        return promise.value()
+    
+    @callback
+    def query_greeting_callback(self, result: PromiseResult):
+        """Processes the greeting result from Hello NEAR contract"""
+        # The @callback decorator automatically parses the promise result
+        # result will have a data property and a success boolean
+        if not result.success:
+            return {"success": False, "message": "Failed to get greeting"}
+            
+        return {
+            "success": True,
+            "greeting": result.data,
+            "message": f"Successfully got greeting: {result.data}"
+        }
+```
+</Language>
+
 </CodeTabs>
 
 ---
@@ -84,6 +134,50 @@ Calling another contract passing information is also a common scenario. Below yo
 
 </Language>
 
+<Language value="python" language="python">
+```python
+from near_sdk_py import call, Contract, callback, PromiseResult, CrossContract
+
+class CrossContractExample(Contract):
+    # Contract we want to interact with
+    hello_contract = "hello-near.testnet"
+        
+    @call
+    def change_greeting(self, new_greeting):
+        """Changes the greeting on the Hello NEAR contract"""
+        # Create a reference to the Hello NEAR contract
+        hello = CrossContract(self.hello_contract)
+        
+        # Create a promise to call set_greeting with the new greeting
+        # Pass context data to the callback directly as kwargs
+        promise = hello.call(
+            "set_greeting", 
+            message=new_greeting
+        ).then(
+            "change_greeting_callback",
+            original_greeting=new_greeting  # Additional context passed to callback
+        )
+        
+        return promise.value()
+    
+    @callback
+    def change_greeting_callback(self, result: PromiseResult, original_greeting):
+        """Processes the result of set_greeting"""
+        # The original_greeting parameter is passed from the change_greeting method
+        if not result.success:
+            return {
+                "success": False, 
+                "message": f"Failed to set greeting to '{original_greeting}'"
+            }
+            
+        return {
+            "success": True,
+            "message": f"Successfully set greeting to '{original_greeting}'",
+            "result": result.data
+        }
+```
+</Language>
+
 </CodeTabs>
 
 ---
@@ -99,7 +193,7 @@ Both promises will contain the following information:
 - The function that you want to execute
 - The (**encoded**) arguments to pass to the function
 - The amount of GAS to use (deducted from the **attached Gas**)
-- The amount of NEAR to attach (deducted from **your contract’s balance**)
+- The amount of NEAR to attach (deducted from **your contract's balance**)
 
 :::tip
 
@@ -184,6 +278,39 @@ You can attach an unused GAS weight by specifying the `.with_unused_gas_weight()
 </details>
 
   </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+
+    ```python
+    from near_sdk_py import Contract, Context, ONE_TGAS
+    
+    # High-level Contract API (recommended)
+    CrossContract("external_address").call(
+        "function_name",  # Method to call
+        arg1="value1",    # Keyword arguments for the method
+        arg2="value2"
+    ).then(
+        "callback_name",  # Method name in this contract to use as callback
+        context_data="saved_for_callback"  # Additional context data for the callback
+    ).value()
+    
+    # Lower-level Promise API
+    from near_sdk_py import Promise
+    
+    Promise.create_batch("external_address").function_call(
+        "function_name", 
+        {"arg1": "value1", "arg2": "value2"},  # Arguments as a dictionary
+        amount=0,   # Deposit in yoctoNEAR
+        gas=5 * ONE_TGAS  # Gas allowance
+    ).then(
+        Context.current_account_id()  # The contract to call for the callback
+    ).function_call(
+        "callback_name",  # Method name for callback
+        {"context_data": "saved_for_callback"}  # Arguments for the callback
+    ).value()
+    ```
+
+  </TabItem>
 </Tabs>
 
 :::info
@@ -222,6 +349,42 @@ In the callback function you will have access to the result, which will contain
 
 </Language>
 
+<Language value="python" language="python">
+```python
+from near_sdk_py import callback, PromiseResult, Contract
+
+class CrossContractExample(Contract):
+    @callback
+    def query_greeting_callback(self, result: PromiseResult, additional_context=None):
+        """
+        Process the result of a cross-contract call.
+        The @callback decorator automatically:
+        1. Reads the promise result data
+        2. Handles serialization/deserialization 
+        3. Provides proper error handling
+        
+        Parameters:
+        - result: The PromiseResult object with status and data
+        - additional_context: Optional context passed from the calling function
+        """
+        if not result.success:
+            # This means the external call failed or returned nothing
+            return {
+                "success": False, 
+                "message": "Failed to get greeting",
+                "context": additional_context
+            }
+            
+        # Process successful result
+        return {
+            "success": True,
+            "greeting": result.data,
+            "message": f"Successfully got greeting: {result.data}",
+            "context": additional_context
+        }
+```
+</Language>
+
 </CodeTabs>
 
 :::info Callback with always execute
@@ -261,15 +424,15 @@ operation if necessary.
 
 ## Concatenating Functions and Promises
 
-✅ Promises can be concatenate using the `.and` operator: `P1.and(P2).and(P3).then(P4)`: `P1`, `P2`, and `P3` execute in parallel, after they finish, `P4` will execute and have access to all their results
+✅ Promises can be concatenate using the `.join` operator: `P1.join([P2, P3], "callback")`: `P1`, `P2`, and `P3` execute in parallel, after they finish, the callback will execute and have access to all their results
 
-⛔ You cannot **return** a joint promise without a callback: `return P1.and(P2)` is invalid since it misses the `then`
+⛔ You cannot **return** a joint promise without a callback: `return P1.join([P2])` is invalid since it misses the callback parameter
 
-✅ You can concatenate `then` promises: `P1.then(P2).then(P3)`: `P1` executes, then `P2` executes with the result of `P1`, then `P3` executes with the result of `P2`
+✅ You can concatenate `then` promises: `P1.then("callback1").then("callback2")`: `P1` executes, then callback1 executes with the result of `P1`, then callback2 executes with the result of callback1
 
-⛔ You cannot use an `and` within a `then`: `P1.then(P2.and(P3))` is invalid
+⛔ You cannot use a `join` within a `then`: `P1.then(P2.join([P3]))` is invalid
 
-⛔ You cannot use a `then` within a `then`: `P1.then(P2.then(P3))` is invalid
+⛔ You cannot use a `then` within a `then`: `P1.then(P2.then("callback"))` is invalid
 
 <hr class="subsection" />
 
@@ -294,6 +457,54 @@ An important property of batch calls is that they **act as a unit**: they execut
         start="8" end="20" />
 
   </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Context, Contract, callback, PromiseResult, ONE_TGAS, CrossContract, init
+
+class BatchCallsExample(Contract):
+    # Contract we want to interact with
+    hello_contract = "hello-near.testnet"
+    
+    @init
+    def new(self):
+        """Initialize the contract"""
+        pass
+        
+    @call
+    def call_multiple_methods(self, greeting1, greeting2):
+        """Call multiple methods on the same contract in a batch"""
+        # Create a contract instance
+        hello = CrossContract(self.hello_contract)
+        
+        # Create a batch for the hello contract
+        batch = hello.batch()
+        
+        # Add function calls to the batch
+        batch.function_call("set_greeting", {"message": greeting1})
+        batch.function_call("another_method", {"arg1": greeting2})
+        
+        # Add a callback to process the result
+        promise = batch.then(Context.current_account_id()).function_call(
+            "batch_callback", 
+            {"original_data": [greeting1, greeting2]},
+            gas=10 * ONE_TGAS
+        )
+        
+        return promise.value()
+        
+    @callback
+    def batch_callback(self, result: PromiseResult, original_data=None):
+        """Process batch result - only gets the result of the last operation"""
+        return {
+            "success": result.success,
+            "result": result.data,
+            "original_data": original_data
+        }
+```
+
+  </TabItem>
 </Tabs>
 
 :::tip
@@ -323,6 +534,62 @@ You can also call multiple functions in **different contracts**. These functions
         start="17" end="55" />
 
   </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Contract, multi_callback, PromiseResult, CrossContract, init
+
+class MultiContractExample(Contract):
+    # Contract addresses we want to interact with
+    contract_a = "contract-a.testnet"
+    contract_b = "contract-b.testnet"
+    
+    @init
+    def new(self):
+        """Initialize the contract"""
+        pass
+        
+    @call
+    def call_multiple_contracts(self):
+        """Calls multiple different contracts in parallel"""
+        # Create promises for each contract
+        contract_a = CrossContract(self.contract_a)
+        promise_a = contract_a.call("method_a")
+        
+        contract_b = CrossContract(self.contract_b)  
+        promise_b = contract_b.call("method_b")
+        
+        # Join the promises and add a callback
+        # The first promise's join method can combine multiple promises
+        combined_promise = promise_a.join(
+            [promise_b],
+            "multi_contract_callback",
+            contract_ids=[self.contract_a, self.contract_b]  # Context data
+        )
+        
+        return combined_promise.value()
+        
+    @multi_callback
+    def multi_contract_callback(self, results, contract_ids=None):
+        """Process results from multiple contracts"""
+        # results is an array containing all promise results in order
+        return {
+            "contract_a": {
+                "id": contract_ids[0],
+                "result": results[0].data,
+                "success": results[0].success
+            },
+            "contract_b": {
+                "id": contract_ids[1],
+                "result": results[1].data,
+                "success": results[1].success
+            },
+            "success": all(result.success for result in results)
+        }
+```
+
+  </TabItem>
 </Tabs>
 
 :::tip
@@ -350,4 +617,4 @@ We have a whole [security section](../security/callbacks.md) dedicated to these
 
 :::warning
 Not following these basic security guidelines could expose your contract to exploits. Please check the [security section](../security/callbacks.md), and if still in doubt, [join us in Discord](https://near.chat).
-:::
+:::
\ No newline at end of file
diff --git a/docs/smart-contracts/anatomy/environment.md b/docs/smart-contracts/anatomy/environment.md
index 47facb3c7d3..d3f8d660908 100644
--- a/docs/smart-contracts/anatomy/environment.md
+++ b/docs/smart-contracts/anatomy/environment.md
@@ -61,6 +61,22 @@ Every method execution has an environment associated with information such as:
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+| Variable Name          | SDK Variable                       | Description                                                                          |
+|------------------------|------------------------------------|--------------------------------------------------------------------------------------|
+| Predecessor            | `Context.predecessor_account_id()` | Account ID that called this method                                                   |
+| Current Account        | `Context.current_account_id()`     | Account ID of this smart contract                                                    |
+| Signer                 | `Context.signer_account_id()`      | Account ID that signed the transaction leading to this execution                     |
+| Attached Deposit       | `Context.attached_deposit()`       | Amount in yoctoNEAR attached to the call by the predecessor                          |
+| Prepaid Gas            | `Context.prepaid_gas()`            | Amount of gas available for execution                                                |
+| Used Gas               | `Context.used_gas()`               | Amount of gas used for execution                                                     |
+| Block Height           | `Context.block_height()`           | Current block height                                                                 |
+| Timestamp              | `Context.block_timestamp()`        | Current timestamp (number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC) |
+| Current Epoch          | `Context.epoch_height()`           | Current epoch in the blockchain                                                      |
+
+</TabItem>
+
 </Tabs>
 
 ---
@@ -172,6 +188,20 @@ assert!(env::prepaid_gas() >= REQUIRED_GAS, "Please attach at least 20 TGas");
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+```python
+from near_sdk_py import call, Context
+
+@call
+def check_gas(required_gas=20_000_000_000_000):  # 20 TGas
+    if Context.prepaid_gas() < required_gas:
+        raise Exception(f"Please attach at least {required_gas} gas")
+    return "Sufficient gas attached"
+```
+
+</TabItem>
+
 </Tabs>
 
 :::
@@ -217,6 +247,21 @@ Besides environmental variables, the SDK also exposes some functions to perform
 
 </TabItem>
 
+<TabItem value="python" label="🐍 Python">
+
+| Function Name         | SDK method                               | Description                                                                                                                                                                                                                                                                                                                      |
+|-----------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| SHA 256               | `near.sha256(value)`                     | Hashes a sequence of bytes using sha256.                                                                                                                                                                                                                                                                                         |
+| Keccak 256            | `near.keccak256(value)`                  | Hashes a sequence of bytes using keccak256.                                                                                                                                                                                                                                                                                      |
+| Keccak 512            | `near.keccak512(value)`                  | Hashes a sequence of bytes using keccak512.                                                                                                                                                                                                                                                                                      |
+| Log Info              | `Log.info(message)`                      | Logs an informational message. This message is stored on chain.                                                                                                                                                                                                                                                                 |
+| Log Warning           | `Log.warning(message)`                   | Logs a warning message. This message is stored on chain.                                                                                                                                                                                                                                                                      |
+| Log Error             | `Log.error(message)`                     | Logs an error message. This message is stored on chain.                                                                                                                                                                                                                                                                       |
+| Log Event             | `Log.event(event_type, data)`            | Logs a structured event following the NEP standard for events. This is useful for indexers and frontend applications.                                                                                                                                                                                                          |
+| Raise Exception       | `raise Exception(message)`               | Terminates the execution of the function with an error message. Similar to panic in other languages.                                                                                                                                                                                                                          |
+
+</TabItem>
+
 </Tabs>
 
 :::info
diff --git a/docs/smart-contracts/anatomy/functions.md b/docs/smart-contracts/anatomy/functions.md
index b49382304b4..3479d3cc427 100644
--- a/docs/smart-contracts/anatomy/functions.md
+++ b/docs/smart-contracts/anatomy/functions.md
@@ -12,9 +12,9 @@ import {ExplainCode, Block, File} from '@site/src/components/CodeExplainer/code-
 
 Smart contracts expose functions so users can interact with them. There are different types of functions including `read-only`, `private` and `payable`.
 
-<ExplainCode languages="js,rust">
+<ExplainCode languages="js,rust,python">
 
-<Block highlights='{"js": "16-20,23-42,45-50,53-55,58-60", "rust": "24-34,37-62,64-75,77-79,81-83"}' fname="auction">
+<Block highlights='{"js": "16-20,23-42,45-50,53-55,58-60", "rust": "24-34,37-62,64-75,77-79,81-83", "python": "4-22,25-62,65-94,97-99,102-104,107-121"}' fname="auction">
 
 ### Contract's Interface
 
@@ -41,13 +41,15 @@ impl MyTrait for MyContractStructure {
     }
 }
 ```
+
 </details>
 
 </Block>
 
-<Block highlights='{"js":"15-20", "rust": "22-34"}' fname="auction">
+<Block highlights='{"js":"15-20", "rust": "22-34", "python": "4-22"}' fname="auction">
 
 ### Initialization Functions
+
 A contract can opt to have an initialization function. If present, this function must be called before any other to [initialize the contract](./storage.md).
 
 </Block>
@@ -55,6 +57,7 @@ A contract can opt to have an initialization function. If present, this function
 <Block highlights='{"js": "15"}' fname="auction">
 
 #### `@initialize({ privateFunction: true })`
+
 The initialization function is marked with the `@initialize` decorator.
 
 </Block>
@@ -62,13 +65,23 @@ The initialization function is marked with the `@initialize` decorator.
 <Block highlights='{"rust": "22"}' fname="auction">
 
 #### `#[init]`
+
 The initialization function is marked with the `#[init]` macro.
 
 </Block>
 
-<Block highlights='{"js":"22-42,44-50", "rust": "37-62,64-75"}' fname="auction">
+<Block highlights='{"python": "3"}' fname="auction">
+
+#### `@init`
+
+The initialization function is marked with the `@init` decorator in Python.
+
+</Block>
+
+<Block highlights='{"js":"22-42,44-50", "rust": "37-62,64-75", "python": "25-62,65-94"}' fname="auction">
 
 ### State Changing Functions
+
 The functions that modify the [state](./storage.md) or perform [actions](./actions.md) need to be called by a user with a NEAR account, since a transaction is required to execute them.
 
 </Block>
@@ -76,6 +89,7 @@ The functions that modify the [state](./storage.md) or perform [actions](./actio
 <Block highlights='{"js": "22,44"}' fname="auction">
 
 #### `@call`
+
 State changing functions are marked with the `@call` decorator.
 
 </Block>
@@ -83,11 +97,20 @@ State changing functions are marked with the `@call` decorator.
 <Block highlights='{"rust": "37,64"}' fname="auction">
 
 #### `&mut self`
+
 State changing functions are those that take a **mutable** reference to `self` in Rust.
 
 </Block>
 
-<Block highlights='{"js": "25,28,29", "rust": "40,45,46"}' fname="auction" type='info'>
+<Block highlights='{"python": "24,64"}' fname="auction">
+
+#### `@call`
+
+State changing functions are marked with the `@call` decorator in Python.
+
+</Block>
+
+<Block highlights='{"js": "25,28,29", "rust": "40,45,46", "python": "109"}' fname="auction" type='info'>
 
 :::tip
 
@@ -97,9 +120,10 @@ The SDK provides [contextual information](./environment.md), such as which accou
 
 </Block>
 
-<Block highlights='{"js":"52-55,57-60", "rust": "77-79,81-83"}' fname="auction">
+<Block highlights='{"js":"52-55,57-60", "rust": "77-79,81-83", "python": "97-99,102-104,107-121"}' fname="auction">
 
 ### Read-Only Functions
+
 Contract's functions can be read-only, meaning they don't modify the state. Calling them is free for everyone, and does not require to have a NEAR account.
 
 </Block>
@@ -107,6 +131,7 @@ Contract's functions can be read-only, meaning they don't modify the state. Call
 <Block highlights='{"js": "52,57"}' fname="auction">
 
 #### `@view`
+
 Read-only functions are marked with the `@view` decorator in TS/JS.
 
 </Block>
@@ -114,13 +139,23 @@ Read-only functions are marked with the `@view` decorator in TS/JS.
 <Block highlights='{"rust": "77,81"}' fname="auction">
 
 #### `&self`
+
 Read-only functions are those that take an **immutable** reference to `self` in Rust.
 
 </Block>
 
-<Block highlights='{"js":"15", "rust": "23"}' fname="auction">
+<Block highlights='{"python": "96,101,106"}' fname="auction">
+
+#### `@view`
+
+Read-only functions are marked with the `@view` decorator in Python.
+
+</Block>
+
+<Block highlights='{"js":"15", "rust": "23", "python": "2"}' fname="auction">
 
 ### Private Functions
+
 Many times you will want to have functions that **are exposed** as part of the contract's interface, but **should not be called directly** by users.
 
 Besides initialization functions, [callbacks from cross-contract calls](./crosscontract.md) should always be `private`.
@@ -132,6 +167,7 @@ These functions are marked as `private` in the contract's code, and can only be
 <Block highlights='{"js": "15"}' fname="auction">
 
 #### `decorator({privateFunction: true})`
+
 Private functions are marked by setting `privateFunction: true` in the `@call` or `@initialize` decorators.
 
 </Block>
@@ -139,13 +175,23 @@ Private functions are marked by setting `privateFunction: true` in the `@call` o
 <Block highlights='{"rust": "23"}' fname="auction">
 
 #### [#private]
+
 Private functions are marked using the `#[private]` macro in Rust.
 
 </Block>
 
-<Block highlights='{"js":"22,28", "rust": "36,45"}' fname="auction">
+<Block highlights='{"python": "2"}' fname="auction">
+
+#### Private Functions in Python
+
+In Python, you can create callbacks by using the `@callback` decorator, which is designed specifically for handling cross-contract call results. For general private functions that should only be called by the contract, you can use validation inside the function to check that the caller is the contract itself.
+
+</Block>
+
+<Block highlights='{"js":"22,28", "rust": "36,45", "python": "25"}' fname="auction">
 
 ### Payable Functions
+
 By default, functions will panic if the user attaches NEAR Tokens to the call. Functions that accept NEAR Tokens must be marked as `payable`.
 
 Within the function, the user will have access to the [attached deposit](./environment.md).
@@ -155,6 +201,7 @@ Within the function, the user will have access to the [attached deposit](./envir
 <Block highlights='{"js": "22,28"}' fname="auction">
 
 #### `@call({payableFunction: true})`
+
 Payable functions are marked by setting `payableFunction: true` in the `@call` decorator.
 
 </Block>
@@ -162,13 +209,23 @@ Payable functions are marked by setting `payableFunction: true` in the `@call` d
 <Block highlights='{"rust": "36,45"}' fname="auction">
 
 #### [#payable]
+
 Payable functions are marked using the `#[payable]` macro in Rust.
 
 </Block>
 
+<Block  fname="auction">
+
+#### Handling payments in Python
+
+In Python, you need to check the deposit manually using the Context API. There isn't a specific decorator for payable functions, so you'll need to verify the deposit amount in your function code.
+
+</Block>
+
 <Block highlights='{"js":"3-5"}' fname="example">
 
 ### Internal Functions
+
 All the functions we covered so far are part of the interface, meaning they can be called by an external actor.
 
 However, contracts can also have private internal functions - such as helper or utility functions - that are **not exposed** to the outside world.
@@ -180,6 +237,7 @@ To create internal private methods in a JS contract, simply omit the `@view` and
 <Block highlights='{"rust": "5-7"}' fname="example">
 
 ### Internal Functions
+
 All the functions we covered so far are part of the interface, meaning they can be called by an external actor.
 
 However, contracts can also have private internal functions - such as helper or utility functions - that are **not exposed** to the outside world.
@@ -188,36 +246,48 @@ To create internal private methods in a Rust contract, do not declare them as pu
 
 </Block>
 
+<Block highlights='{"python": "2-5"}' fname="example">
+
+### Internal Functions
+
+All the functions we covered so far are part of the interface, meaning they can be called by an external actor.
+
+However, contracts can also have private internal functions - such as helper or utility functions - that are **not exposed** to the outside world.
+
+To create internal private methods in a Python contract, simply define normal methods without the `@view`, `@call`, or `@init` decorators.
+
+</Block>
+
 <Block highlights='{"rust": "5-7"}' fname="example" type='details'>
 
   <details>
   <summary> Separate impl block </summary>
 
-  Another way of not exporting methods is by having a separate `impl Contract` section, that is not marked with `#[near]`.
+Another way of not exporting methods is by having a separate `impl Contract` section, that is not marked with `#[near]`.
 
-  ```rust
-  #[near]
-  impl Contract {
-      pub fn increment(&mut self) {
-          self.internal_increment();
-      }
-  }
-  impl Contract {
-      /// This methods is still not exported.
-      pub fn internal_increment(&mut self) {
-          self.counter += 1;
-      }
-  }
-  ```
+```rust
+#[near]
+impl Contract {
+    pub fn increment(&mut self) {
+        self.internal_increment();
+    }
+}
+impl Contract {
+    /// This methods is still not exported.
+    pub fn internal_increment(&mut self) {
+        self.counter += 1;
+    }
+}
+```
 
   </details>
 
 </Block>
 
-
-<Block highlights='{"rust": "9-11,13-15"}' fname="example">
+<Block highlights='{"rust": "9-11,13-15", "python": "12-15"}' fname="example">
 
 ### Pure Functions
+
 Pure functions are a special kind of function that do not require to access data from the state.
 
 They are useful to return hardcoded values on the contract.
@@ -228,6 +298,8 @@ They are useful to return hardcoded values on the contract.
 
 <File language="rust" fname="auction" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/01-basic-auction/src/lib.rs" start="2" end="84" />
 
+<File language="python" fname="auction" url="https://github.com/r-near/near-py-examples/blob/main/auction.py" start="2" end="140" />
+
 <CodeBlock language="js" fname="example">
 
 ```js
@@ -274,4 +346,26 @@ impl MyContractStructure {
 
 </CodeBlock>
 
+<CodeBlock language="python" fname="example">
+
+```python
+class Contract:
+    def helper_function(self, params...):
+        # This function cannot be called from the outside
+        # as it has no decorator
+        pass
+
+    @call
+    def validate_owner(self):
+        if Context.predecessor_account_id() != self.owner_id:
+            raise Exception("Only the owner can call this method")
+
+    @view
+    def get_static_value(self):
+        # This function returns a hardcoded value
+        return 42
+```
+
+</CodeBlock>
+
 </ExplainCode>
diff --git a/docs/smart-contracts/anatomy/reduce-size.md b/docs/smart-contracts/anatomy/reduce-size.md
index a322eb7b367..267d246ab16 100644
--- a/docs/smart-contracts/anatomy/reduce-size.md
+++ b/docs/smart-contracts/anatomy/reduce-size.md
@@ -3,9 +3,14 @@ id: reduce-size
 title: "Reducing Contract Size"
 ---
 import {Github} from "@site/src/components/codetabs"
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
 
 # Reducing a contract's size
 
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="rust" label="🦀 Rust">
+
 ## Advice & examples
 
 This page is made for developers familiar with lower-level concepts who wish to reduce their contract size significantly, perhaps at the expense of code readability.
@@ -171,3 +176,127 @@ For a `no_std` approach to minimal contracts, observe the following examples:
 </details>
 
 :::
+  </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+
+## Optimizing Python Contracts
+
+Since Python smart contracts on NEAR are interpreted rather than compiled to WebAssembly directly, the optimization strategies differ from Rust contracts. The Python interpreter itself is already optimized, but you can still make your contract more efficient.
+
+### Reducing Contract Size
+
+#### 1. Minimize Dependencies
+
+Only import the modules and functions you need:
+
+```python
+# Less efficient - imports everything
+from near_sdk_py import *
+
+# More efficient - imports only what's needed
+from near_sdk_py import view, call, Context
+```
+
+#### 2. Use Efficient Data Structures
+
+Choose the right data structure for your needs:
+
+```python
+# Less efficient for lookups
+user_list = []  # O(n) lookup time
+for user in user_list:
+    if user["id"] == user_id:
+        return user
+
+# More efficient for lookups
+user_dict = {}  # O(1) lookup time
+if user_id in user_dict:
+    return user_dict[user_id]
+```
+
+#### 3. Optimize Storage Usage
+
+The NEAR SDK collections are optimized for on-chain storage. For large data sets, use these instead of native Python collections:
+
+```python
+# Native collection - loaded entirely into memory
+self.users = {}  # Loaded entirely on each method call
+
+# SDK collection - lazily loaded
+from near_sdk_py.collections import UnorderedMap
+self.users = UnorderedMap("u")  # Only loads what's needed
+```
+
+#### 4. Reduce String Operations
+
+String operations can be expensive. Minimize them when possible:
+
+```python
+# Less efficient
+result = ""
+for i in range(100):
+    result += str(i)  # Creates many intermediate strings
+
+# More efficient
+parts = []
+for i in range(100):
+    parts.append(str(i))
+result = "".join(parts)  # Creates strings once
+```
+
+#### 5. Avoid Recursion
+
+Deep recursion can lead to stack overflow issues. Consider iterative approaches instead:
+
+```python
+# Recursive - could cause issues with deep structures
+def process_tree(node):
+    result = process_node(node)
+    for child in node.children:
+        result += process_tree(child)
+    return result
+
+# Iterative - more efficient
+def process_tree(root):
+    result = 0
+    queue = [root]
+    while queue:
+        node = queue.pop(0)
+        result += process_node(node)
+        queue.extend(node.children)
+    return result
+```
+
+#### 6. Use Python's Built-in Functions
+
+Python's built-in functions are often optimized and more efficient:
+
+```python
+# Less efficient
+sum_value = 0
+for num in numbers:
+    sum_value += num
+
+# More efficient
+sum_value = sum(numbers)
+```
+
+#### 7. Split Complex Logic
+
+If you have a very large contract, consider splitting it into multiple contracts with focused responsibilities. This can improve maintainability and reduce the cost of individual calls.
+
+#### 8. Profile and Optimize Hot Paths
+
+Focus optimization efforts on the most frequently called functions or those that handle large amounts of data:
+
+```python
+@call
+def frequently_called_method(self, data):
+    # Optimize this code carefully
+    # Consider using more efficient algorithms and data structures
+    pass
+```
+
+  </TabItem>
+</Tabs>
diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md
index 52806bff361..d79bb719a19 100644
--- a/docs/smart-contracts/anatomy/reproducible-builds.md
+++ b/docs/smart-contracts/anatomy/reproducible-builds.md
@@ -2,11 +2,40 @@
 id: reproducible-builds
 title: Reproducible Builds
 ---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
 
 Reproducible builds let different people build the same program and get the exact same outputs as one another. It helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract user can build it themselves and check that the binaries are identical.
 
 ## Problem
+
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="rust" label="🦀 Rust">
+  
 If you will build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billion other factors in your build environment. Rust community has a long story of fighting this issue but still, [it is not achieved yet](https://github.com/rust-lang/rust/labels/A-reproducibility).
 
-## CI solution
+### CI solution
+
 We recommend you to build your contracts with the use of our [Contract Builder](https://github.com/near/near-sdk-rs/tree/master/contract-builder). It's is using Docker, controlled and sharable environment that can be used by both you and your users. Docker image is available [here](https://hub.docker.com/r/nearprotocol/contract-builder). The contract built in it will result in a binary that is the same if built on other machines.
+
+  </TabItem>
+  <TabItem value="python" label="🐍 Python">
+  
+For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime.
+
+When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact.
+
+### Ensuring Reproducible Python Contracts
+
+To ensure your Python contracts are reproducible:
+
+1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions.
+
+2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting.
+
+3. **Document Python version**: Make sure to document which Python version your contract was developed with.
+
+4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems.
+
+  </TabItem>
+</Tabs>
diff --git a/docs/smart-contracts/anatomy/storage.md b/docs/smart-contracts/anatomy/storage.md
index 3711ec87f64..d27e402ec18 100644
--- a/docs/smart-contracts/anatomy/storage.md
+++ b/docs/smart-contracts/anatomy/storage.md
@@ -4,6 +4,7 @@ title: State
 sidebar_label: State (Storage)
 hide_table_of_contents: true
 ---
+
 import Tabs from '@theme/Tabs';
 import TabItem from '@theme/TabItem';
 import {CodeTabs, Language, Github} from "@site/src/components/codetabs";
@@ -15,13 +16,13 @@ It is important to know that the account's **code** and account's **storage** ar
 
 <hr class="subsection" />
 
-<ExplainCode languages="js,rust" >
+<ExplainCode languages="js,rust,python" >
 
-<Block highlights='{"js": "3-6,10-13"}' fname="auction">
+<Block highlights='{"js": "3-6,10-13", "python": "7,10-14,17,20"}' fname="auction">
 
     ### Defining the State
     The attributes of the `class` marked as the contract define the data that will be stored.
-    
+
     The contract can store all native types (e.g. `number`, `string`, `Array`, `Map`) as well as complex objects.
 
     For example, our Auction contract stores when the auction ends, and an object representing the highest bid.
@@ -36,7 +37,7 @@ It is important to know that the account's **code** and account's **storage** ar
     The attributes of the `struct` marked as the contract define the data that will be stored.
 
     The contract can store all native types (e.g. `u8`, `string`, `HashMap`, `Vector`) as well as complex objects.
-    
+
     For example, our Auction contract stores when the auction ends, and an object representing the highest bid.
 
     **Note:** The structures that will be saved need a special macro, that tells the SDK to store them [serialized in Borsh](./serialization.md).
@@ -45,19 +46,19 @@ It is important to know that the account's **code** and account's **storage** ar
 
 </Block>
 
-<Block highlights='{"js":"", "rust": ""}' fname="auction" type='info'>
+<Block highlights='{"js":"", "rust": "", "python": ""}' fname="auction" type='info'>
 
 :::warning
 
 Contracts pay for their storage by locking part of their balance.
-    
+
 It currently costs ~**1Ⓝ** to store **100KB** of data.
 
 :::
 
 </Block>
 
-<Block highlights='{"js": "", "rust": ""}' fname="auction" >
+<Block highlights='{"js": "", "rust": "", "python": ""}' fname="auction" >
 
     ### Initializing the State
     After the contract is deployed, its state is empty and needs to be initialized with
@@ -69,22 +70,22 @@ It currently costs ~**1Ⓝ** to store **100KB** of data.
 
 </Block>
 
-<Block highlights='{"js": "8,15-20"}' fname="auction">
+<Block highlights='{"js": "8,15-20", "python": "3-22"}' fname="auction">
 
     ### I. Initialization Functions
     An option to initialize the state is to create an `initialization` function, which needs to be called before executing any other function.
 
     In our Auction example, the contract has an initialization function that sets when the auction ends. Note the `@initialization` decorator, and the forced initialization on `NearBindgen`.
-    
+
     **Note:** It is a good practice to mark initialization functions as private. We will cover function types in the [functions section](./functions.md).
 
 </Block>
 
-<Block highlights='{"js": "10-13"}' fname="auction" type='info'>
+<Block highlights='{"python": "15-30", "js": "10-13"}' fname="auction" type='info'>
 
 :::warning
 
-In TS/JS you still **must** set default values for the attributes, so the SDK can infer their types.
+In Python, you need to manage the state initialization explicitly. The SDK doesn't enforce that initialization happens before other methods are called - you'll need to add your own checks if required.
 
 :::
 
@@ -96,12 +97,12 @@ In TS/JS you still **must** set default values for the attributes, so the SDK ca
     An option to initialize the state is to create an `initialization` function, which needs to be called before executing any other function.
 
     In our Auction example, the contract has an initialization function that sets when the auction ends. The contract derives the `PanicOnDefault`, which forces the user to call the init method denoted by the `#[init]` macro.
-    
+
     **Note:** It is a good practice to mark initialization functions as private. We will cover function types in the [functions section](./functions.md).
 
 </Block>
 
-<Block highlights='{"js": "5"}' fname="hello">
+<Block highlights='{"js": "5", "python": "5"}' fname="hello">
 
     ### II. Default State
     Another option to initialize the state is to set default values for the attributes of the class.
@@ -118,7 +119,7 @@ In TS/JS you still **must** set default values for the attributes, so the SDK ca
 
     ### II. Default State
     Another option to initialize the state is to create a `Default` version of our contract's `struct`.
-    
+
     For example, our "Hello World" contract has a default state with a `greeting` set to `"Hello"`.
 
     The first time the contract executes, the `Default` will be stored in the state, and the state will be considered initialized.
@@ -127,7 +128,7 @@ In TS/JS you still **must** set default values for the attributes, so the SDK ca
 
 </Block>
 
-<Block highlights='{"js": "", "rust":""}' fname="hello">
+<Block highlights='{"js": "", "rust":"", "python": ""}' fname="hello">
 
     ### Lifecycle of the State
     When a function is called, the contract's state is loaded from the storage and put into memory.
@@ -138,12 +139,12 @@ In TS/JS you still **must** set default values for the attributes, so the SDK ca
 
 </Block>
 
-<Block highlights='{"js": "", "rust":""}' fname="hello" type='info'>
+<Block highlights='{"js": "", "rust":"", "python": ""}' fname="hello" type='info'>
 
 :::warning State and Code
 
 In NEAR, the contract's code and contract's storage are **independent**.
-    
+
 Updating the code of a contract does **not erase** the state, and can indeed lead to unexpected behavior or errors.
 
 Make sure to read the [updating a contract](../release/upgrade.md) if you run into issues.
@@ -168,4 +169,8 @@ Make sure to read the [updating a contract](../release/upgrade.md) if you run in
     url="https://github.com/near-examples/hello-near-examples/blob/main/contract-rs/src/lib.rs"
     start="2" end="32" />
 
+<File language="python" fname="auction" url="https://github.com/r-near/near-py-examples/blob/main/auction.py" start="2" end="122"></File>
+
+<File language="python" fname="hello" url="https://github.com/r-near/near-py-examples/blob/main/hello-near.py" start="5" end="20"></File>
+
 </ExplainCode>
diff --git a/docs/smart-contracts/anatomy/types.md b/docs/smart-contracts/anatomy/types.md
index acd4a3b994c..01f4e895481 100644
--- a/docs/smart-contracts/anatomy/types.md
+++ b/docs/smart-contracts/anatomy/types.md
@@ -3,6 +3,7 @@ id: types
 title: SDK Types
 hide_table_of_contents: true
 ---
+
 import Tabs from '@theme/Tabs';
 import TabItem from '@theme/TabItem';
 import {CodeTabs, Language, Github} from "@site/src/components/codetabs";
@@ -12,7 +13,7 @@ import {ExplainCode, Block, File} from '@site/src/components/CodeExplainer/code-
 
 Lets discuss which types smart contracts use to input and output data, as well as how such data is stored and handled in the contract's code.
 
-<ExplainCode languages="js,rust">
+<ExplainCode languages="js,rust,python">
 
 <Block highlights='{"js":"5,8,13"}' fname="hello-near">
 
@@ -41,6 +42,22 @@ Lets discuss which types smart contracts use to input and output data, as well a
 
 </Block>
 
+<Block highlights='{"python":"11,16"}' fname="hello-near">
+
+    ### Native Types
+    Smart contracts can receive, store and return data using the following Python types:
+    - `str`
+    - `int`
+    - `float`
+    - `bool`
+    - `list`
+    - `dict`
+    - `set`
+    - `bytes`
+    - `None`
+
+</Block>
+
 <Block highlights='{"rust": "1,15,24,81"}' fname="auction" type='info'>
 
 :::warning `U64/U128`
@@ -53,7 +70,17 @@ To simplify development, the SDK provides the `U64` and `U128` types which are a
 
 </Block>
 
-<Block highlights='{"js":"3-6", "rust": "6-9"}' fname="auction">
+<Block highlights='{"python": "26,28"}' fname="auction" type='info'>
+
+:::tip Python Large Numbers
+
+Python's `int` type has unlimited precision, so it can handle large integers (like yoctoNEAR values) without any special handling. All values are automatically serialized and deserialized correctly.
+
+:::
+
+</Block>
+
+<Block highlights='{"js":"3-6", "rust": "6-9", "python": "10-13"}' fname="auction">
 
     ### Complex Objects
     Smart contracts can store and return complex objects
@@ -71,6 +98,15 @@ To simplify development, the SDK provides the `U64` and `U128` types which are a
 
 </Block>
 
+<Block highlights='{"python": "7,14,17,20"}' fname="auction">
+
+    #### Serialization
+    Python objects are automatically serialized and deserialized using JSON for input/output and Pickle for internal storage.
+
+    Complex nested objects like lists and dictionaries can be used directly without additional configuration.
+
+</Block>
+
 <Block highlights='{"js": "5,10,28"}' fname="auction">
 
     ### Handling Tokens
@@ -89,13 +125,31 @@ To simplify development, the SDK provides the `U64` and `U128` types which are a
 
 </Block>
 
-<Block highlights='{"js": "4,29", "rust": "7,46"}' fname="auction">
+<Block highlights='{"python": ""}' fname="auction">
+
+    ### Handling Tokens
+    `$NEAR` tokens are represented as integers in Python, with values in `yoctoNEAR`.
+    The `near_sdk_py.constants` module provides `ONE_NEAR` and `ONE_TGAS` constants.
+
+    **Note:** 1 NEAR = 10^24 yoctoNEAR
+
+</Block>
+
+<Block highlights='{"js": "4,29", "rust": "7,46", "python": ""}' fname="auction">
 
     ### Account
     The SDK exposes a special type to handle NEAR Accounts, which automatically checks if the account address is valid
 
 </Block>
 
+<Block highlights='{"python": ""}' fname="auction">
+
+    ### Account IDs
+    In Python, NEAR account IDs are represented as `str` types. The SDK performs validation
+    when account IDs are used in contract calls or cross-contract interactions.
+
+</Block>
+
 <File language="js" fname="hello-near"
     url="https://github.com/near-examples/hello-near-examples/blob/main/contract-ts/src/contract.ts"
     start="2" end="18" />
@@ -104,6 +158,8 @@ To simplify development, the SDK provides the `U64` and `U128` types which are a
     url="https://github.com/near-examples/hello-near-examples/blob/main/contract-rs/src/lib.rs"
     start="2" end="32" />
 
+<File language="python" fname="hello-near" url="https://github.com/r-near/near-py-examples/blob/main/hello-near.py" start="2" end="18"></File>
+
 <File language="js" fname="auction"
     url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-ts/01-basic-auction/src/contract.ts"
     start="2" end="61" />
@@ -111,5 +167,6 @@ To simplify development, the SDK provides the `U64` and `U128` types which are a
 <File language="rust" fname="auction"
     url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/01-basic-auction/src/lib.rs"
     start="2" end="84" />
+<File language="python" fname="auction" url="https://github.com/r-near/near-py-examples/blob/main/auction.py" start="2" end="122"></File>
 
 </ExplainCode>
diff --git a/docs/smart-contracts/anatomy/yield-resume.md b/docs/smart-contracts/anatomy/yield-resume.md
index 432e3e2ad6e..f12023e5bcf 100644
--- a/docs/smart-contracts/anatomy/yield-resume.md
+++ b/docs/smart-contracts/anatomy/yield-resume.md
@@ -3,6 +3,8 @@ id: yield-resume
 title: Yield and Resume
 ---
 import {CodeTabs, Language, Github} from '@site/src/components/codetabs'
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
 
 NEAR smart contracts can **yield** execution, until an **external** service **resumes** them. In practice, the contract yields a **cross-contract call** to itself, until an external service executes a function and the contract decides to resume.
 
@@ -20,18 +22,68 @@ Contract can wait for 200 blocks - around 4 minutes - after which the yielded fu
 
 Let's look at an example that takes a prompt from a user (e.g. "What is 2+2"), and yields the execution until an external service provides a response.
 
-<CodeTabs>
-  <Language value="rust" language="rust">
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="rust" label="🦀 Rust">
     <Github fname="lib.rs"
             url="https://github.com/near-examples/yield-resume/blob/main/contract/src/lib.rs"
             start="43" end="70" />
-  </Language>
-</CodeTabs>
+  </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import call, view, near, Context
+from near_sdk_py.collections import UnorderedMap
+import json
+
+class YieldResumeContract:
+    def __init__(self):
+        # Store pending requests
+        self.requests = UnorderedMap("r")
+        self.request_id = 0
+    
+    @call
+    def ask_assistant(self, prompt):
+        """
+        Creates a yielded promise that will be resumed when an external service responds
+        
+        Args:
+            prompt: The question to ask the assistant
+        """
+        # Create a new request ID
+        request_id = self.request_id
+        self.request_id += 1
+        
+        # Create arguments for the callback function
+        callback_args = json.dumps({"request_id": request_id})
+        
+        # Create a yielded promise to call return_external_response on this contract
+        yield_id = near.promise_create(
+            Context.current_account_id(),
+            "return_external_response",
+            callback_args,
+            0,  # No deposit
+            30000000000000  # Gas
+        )
+        
+        # Store the yield ID and prompt for the external service to find
+        self.requests[str(request_id)] = {
+            "yield_id": yield_id,
+            "prompt": prompt
+        }
+        
+        # Return the yield_id and request_id for tracking
+        return {
+            "yield_id": yield_id,
+            "request_id": request_id
+        }
+```
+  </TabItem>
+</Tabs>
 
 #### Creating a Yielded Promise
 In the example above, we are creating a [`Promise`](./crosscontract.md#promises) to call the contract's function `return_external_response`.
 
-Notice that we create the `Promise` using `env::promise_yield_create`, which will create an **identifier** for the yielded promise in the `YIELD_REGISTER`.
+Notice that we create the `Promise` using `env::promise_yield_create` in Rust or `near.promise_create` in Python (the Python SDK uses standard promises for yielding), which will create an **identifier** for the yielded promise in the `YIELD_REGISTER`.
 
 #### Retrieving the Yielded Promise ID
 We read the `YIELD_REGISTER` to retrieve the `ID` of our yielded promise. We store the `yield_id` and the user's `prompt` so the external service query them (the contract exposes has a function to list all requests).
@@ -53,15 +105,24 @@ Since we only use it to simplify the process of keeping track of the requests, y
 
 ## Signaling the Resume
 
-The `env::promise_yield_resume` function allows us to signal which yielded promise should execute, as well as which parameters to pass to the resumed function.
+The `env::promise_yield_resume` function in Rust or `near.promise_yield_resume` in Python allows us to signal which yielded promise should execute, as well as which parameters to pass to the resumed function.
 
-<CodeTabs>
-  <Language value="rust" language="rust">
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="rust" label="🦀 Rust">
     <Github fname="lib.rs"
             url="https://github.com/near-examples/yield-resume/blob/main/contract/src/lib.rs"
             start="72" end="75" />
-  </Language>
-</CodeTabs>
+  </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+```python
+@call
+def respond(self, yield_id, response):
+    """Called by the external service to provide a response to a prompt"""
+    return near.promise_yield_resume(yield_id, json.dumps({"response": response}))
+```
+  </TabItem>
+</Tabs>
 
 In the example above, the `respond` function would be called by an external service, passing which promise should be resume (`yield_id`), and the response to the prompt. 
 
@@ -77,18 +138,47 @@ Since the function used to signal the resume is public, developers must make sur
 
 The function being resumed will have access to all parameters passed to it, including those passed during the yield creation, or the external service response.
 
-<CodeTabs>
-  <Language value="rust" language="rust">
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="rust" label="🦀 Rust">
     <Github fname="lib.rs"
             url="https://github.com/near-examples/yield-resume/blob/main/contract/src/lib.rs"
             start="77" end="89" />
-  </Language>
-</CodeTabs>
-
-In the example above, the `return_external_response` receives two parameters:
+  </TabItem>
+  
+  <TabItem value="python" label="🐍 Python">
+```python
+@call
+def return_external_response(self, request_id, response=None):
+    """
+    Function that gets called when the yielded promise resumes
+    
+    Args:
+        request_id: The ID of the request (passed when promise was created)
+        response: The response from the external service (or None if timed out)
+    """
+    # Remove the request from our tracking
+    request_data = self.requests.get(str(request_id))
+    if request_data:
+        del self.requests[str(request_id)]
+    
+    # Handle timeout case
+    if response is None:
+        return {"error": "Timeout waiting for external service", "request_id": request_id}
+    
+    # Return the response from the external service
+    return {
+        "request_id": request_id,
+        "response": response,
+        "success": True
+    }
+```
+  </TabItem>
+</Tabs>
+
+In the example above, the `return_external_response` receives parameters:
 
 1. A `request_id` - passed on [creation](#creating-a-yielded-promise) - which is used to remove the request from the state
-2. A `response` - passed when [signaling to resume](#signaling-the-resume) - which contains the external response, or a `PromiseError` if the contract timed out while waiting
+2. A `response` - passed when [signaling to resume](#signaling-the-resume) - which contains the external response, or `None` if the contract timed out while waiting
 
 :::tip There's plenty of time
 
@@ -102,4 +192,146 @@ Notice that, in this particular example, we choose to return a value both if the
 
 The reason to not raise an error, is because we are changing the state (removing the request in line `#7`), and raising an error would revert this state change
 
-:::
\ No newline at end of file
+:::
+
+---
+
+## Complete Example
+
+Here's a more complete implementation of a yield-resume pattern in Python:
+
+<Tabs className="language-tabs" groupId="code-tabs">
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, near, Context
+from near_sdk_py.collections import UnorderedMap
+import json
+
+class AIAssistantContract:
+    def __init__(self):
+        # Track all pending requests
+        self.requests = UnorderedMap("r")
+        self.request_counter = 0
+    
+    @call
+    def ask_question(self, question):
+        """
+        Ask a question to the AI assistant
+        
+        The execution will yield until an external AI service responds
+        """
+        # Create a unique ID for this request
+        request_id = self.request_counter
+        self.request_counter += 1
+        
+        # Create callback args - will be passed to our callback function
+        callback_args = json.dumps({
+            "request_id": request_id
+        })
+        
+        # Create the promise - this will yield until resumed
+        promise_id = near.promise_create(
+            Context.current_account_id(),  # Call this contract
+            "process_ai_response",         # Call this method when resumed
+            callback_args,                 # Pass these arguments
+            0,                             # No attached deposit
+            30000000000000                 # Gas for execution (30 TGas)
+        )
+        
+        # Store the request for the external service to find
+        self.requests[str(request_id)] = {
+            "prompt": question,
+            "promise_id": promise_id,
+            "user": Context.predecessor_account_id(),
+            "timestamp": Context.block_timestamp()
+        }
+        
+        return {
+            "request_id": request_id,
+            "status": "processing"
+        }
+    
+    @view
+    def get_pending_requests(self):
+        """Returns all pending requests for the AI service to process"""
+        return [
+            {
+                "request_id": int(req_id), 
+                "data": self.requests[req_id]
+            } 
+            for req_id in self.requests.keys()
+        ]
+    
+    @call
+    def provide_ai_response(self, request_id, response):
+        """
+        Called by the AI service to provide a response
+        
+        Args:
+            request_id: ID of the request being answered
+            response: The AI's response to the question
+        """
+        request_id_str = str(request_id)
+        
+        # Verify the request exists
+        if request_id_str not in self.requests:
+            raise Exception(f"No pending request with ID {request_id}")
+        
+        # Get the request data
+        request = self.requests[request_id_str]
+        
+        # Resume the promise with the AI's response
+        result = near.promise_yield_resume(
+            request["promise_id"],
+            json.dumps({"ai_response": response})
+        )
+        
+        return {"success": result}
+    
+    @call
+    def process_ai_response(self, request_id, ai_response=None):
+        """
+        Called when a yielded promise resumes
+        
+        This is either called by provide_ai_response or by a timeout
+        
+        Args:
+            request_id: ID of the request
+            ai_response: The AI's response or None if timed out
+        """
+        request_id_str = str(request_id)
+        
+        # Cleanup - remove from pending requests
+        if request_id_str in self.requests:
+            request = self.requests[request_id_str]
+            del self.requests[request_id_str]
+        else:
+            request = None
+        
+        # Handle timeout case
+        if ai_response is None:
+            return {
+                "request_id": request_id,
+                "status": "timeout",
+                "message": "The AI service did not respond in time"
+            }
+        
+        # Return the AI's response
+        return {
+            "request_id": request_id,
+            "status": "complete",
+            "question": request["prompt"] if request else "Unknown",
+            "answer": ai_response,
+            "user": request["user"] if request else "Unknown"
+        }
+```
+  </TabItem>
+</Tabs>
+
+This example demonstrates a complete yield-resume pattern for an AI assistant contract where:
+
+1. A user asks a question through `ask_question`
+2. The contract creates a yielded promise and stores the question
+3. An external AI service periodically checks for new questions using `get_pending_requests`
+4. When the AI has an answer, it calls `provide_ai_response` to resume the yielded promise
+5. The `process_ai_response` function executes with the AI's answer (or timeout) and returns the result
diff --git a/docs/smart-contracts/quickstart.md b/docs/smart-contracts/quickstart.md
index 13d7e5918de..dddf41872c0 100644
--- a/docs/smart-contracts/quickstart.md
+++ b/docs/smart-contracts/quickstart.md
@@ -61,6 +61,42 @@ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/release
 
 </TabItem>
 
+<TabItem value="py" label="🐍 Python">
+
+```bash
+# Install Python (if not already installed)
+# Use your system's package manager or download from https://www.python.org/downloads/
+
+# Install Emscripten (required for compiling Python contracts to WebAssembly)
+# For Linux/macOS:
+git clone https://github.com/emscripten-core/emsdk.git
+cd emsdk
+./emsdk install latest
+./emsdk activate latest
+source ./emsdk_env.sh
+# Add to your .bashrc or .zshrc for permanent installation:
+# echo 'source "/path/to/emsdk/emsdk_env.sh"' >> ~/.bashrc
+cd ..
+
+# For Windows:
+# Download and extract: https://github.com/emscripten-core/emsdk
+# Then in Command Prompt:
+# cd emsdk
+# emsdk install latest
+# emsdk activate latest
+# emsdk_env.bat
+
+# Verify installation with:
+emcc --version
+
+# Install uv for Python package management
+curl -LsSf https://astral.sh/uv/install.sh | sh
+
+# Install NEAR CLI-RS to deploy and interact with the contract
+curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh
+```
+
+</TabItem>
 </Tabs>
 
 :::note
@@ -143,6 +179,46 @@ hello-near
 
 </TabItem>
 
+<TabItem value="py" label="🐍 Python">
+
+Create a new project using `uv init`:
+
+```bash
+uv init hello-near
+cd hello-near
+```
+
+This creates a Python project with the following structure:
+
+```bash
+hello-near
+├── .git                 # Git repository
+├── .gitignore           # Git ignore file
+├── .python-version      # Python version file
+├── README.md            # README
+├── main.py              # Main Python file
+└── pyproject.toml       # Project configuration
+```
+
+Now, add the NEAR SDK to your project:
+
+```bash
+uv add near-sdk-py
+```
+
+:::tip
+
+`hello-near` is the name we chose for this project so the tutorial is simpler to follow, but for future projects feel free to use any name you prefer
+
+:::
+
+:::important
+
+Ensure you have [Emscripten](https://emscripten.org/) properly installed and available in your `PATH`. The compilation process requires it to convert Python code to WebAssembly.
+
+:::
+
+</TabItem>
 </Tabs>
 
 
@@ -171,6 +247,15 @@ The `Hello World` smart contract stores a greeting in its state, and exposes two
 
   </TabItem>
 
+  <TabItem value="py" label="🐍 Python">
+
+  Create a `greeting_contract.py` file for your contract:
+
+    <Github fname="contract.py" language="python"
+            url="https://github.com/near-examples/hello-near-examples/blob/main/contract-py/greeting_contract.py"
+            start="3" end="30" />
+
+  </TabItem>
 </Tabs>
 
 :::tip
@@ -207,7 +292,34 @@ Building and testing the contract is as simple as running the `test` command. Th
   ```
 
   </TabItem>
+  
+  <TabItem value="py" label="🐍 Python">
+
+  Create a test file for your contract:
+
+  ```bash
+  # Create a tests directory
+  mkdir tests
+  touch tests/test_greeting.py
+  ```
+
+  Add the following content to `tests/test_greeting.py`:
+
+  <Github fname="contract.py" language="python"
+        url="https://github.com/near-examples/hello-near-examples/blob/main/contract-py/tests/test_greeting.py"
+        start="1" end="52" />
 
+  Run the test:
+
+  ```bash
+  # Add near-pytest to your project
+  uv add near-pytest
+  
+  # Run the test
+  uv run pytest tests/test_greeting.py -v
+  ```
+
+  </TabItem>
 </Tabs>
 
 In the background, these commands are calling the build tools for each language and using a [Sandbox](./testing/integration-test.md) to test the contract.
@@ -308,7 +420,34 @@ When you are ready to create a build of the contract run a one-line command depe
   :::
 
   </TabItem>
+  
+  <TabItem value="py" label="🐍 Python">
 
+  ```bash
+  # Build with nearc through the uv executor (no installation needed)
+  uvx nearc
+  ```
+  
+  The above command will compile your Python contract into WebAssembly (WASM) that can be deployed to the NEAR blockchain.
+  
+  :::info
+  
+  The default `nearc` build configuration is appropriate for most contracts. You don't need to install nearc separately as we're using `uvx` to run it directly.
+  
+  :::
+
+  :::important
+  
+  This step requires [Emscripten](https://emscripten.org/) to be installed and accessible in your `PATH`. If you encounter errors during compilation, verify that Emscripten is properly installed with `emcc --version`.
+  
+  Common compilation errors and solutions:
+  - `emcc: command not found` - Emscripten is not in your PATH. Run `source /path/to/emsdk/emsdk_env.sh` to add it temporarily.
+  - `error: invalid version of emscripten` - Your Emscripten version might be too old. Try updating with `./emsdk install latest && ./emsdk activate latest`.
+  - `Could not find platform micropython-dev-wasm32` - This typically means the Emscripten installation is incomplete or not properly activated.
+  
+  :::
+
+  </TabItem>
 </Tabs>
 
 ---
@@ -356,12 +495,97 @@ Having our account created, we can now deploy the contract:
       </TabItem>
     </Tabs>
   </TabItem>
+  
+  <TabItem value="py" label="🐍 Python">
+    <Tabs groupId="cli-tabs">
+      <TabItem value="short" label="Short">
+
+        ```bash
+        near deploy <created-account> ./greeting_contract.wasm
+        ```
+
+      </TabItem>
+
+      <TabItem value="full" label="Full">
+
+        ```bash
+        near contract deploy <created-account> use-file ./greeting_contract.wasm without-init-call network-config testnet sign-with-keychain send
+        ```
+
+      </TabItem>
+    </Tabs>
+  </TabItem>
 </Tabs>
 
 **Congrats**! Your contract now lives in the NEAR testnet network.
 
 ---
 
+## Initializing the Contract
+
+After deploying, you'll need to initialize the contract:
+
+<Tabs groupId="cli-tabs">
+  <TabItem value="js" label="🌐 JavaScript">
+    <Tabs groupId="cli-tabs">
+      <TabItem value="short" label="Short">
+
+        ```bash
+        near call <created-account> new '{}' --accountId <created-account>
+        ```
+
+      </TabItem>
+      <TabItem value="full" label="Full">
+
+        ```bash
+        near contract call-function as-transaction <created-account> new json-args '{}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
+        ```
+
+      </TabItem>
+    </Tabs>
+  </TabItem>
+  <TabItem value="rust" label="🦀 Rust">
+
+    <Tabs groupId="cli-tabs">
+      <TabItem value="short" label="Short">
+
+        ```bash
+        near call <created-account> new '{}' --accountId <created-account>
+        ```
+
+      </TabItem>
+
+      <TabItem value="full" label="Full">
+
+        ```bash
+        near contract call-function as-transaction <created-account> new json-args '{}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
+        ```
+
+      </TabItem>
+    </Tabs>
+  </TabItem>
+  
+  <TabItem value="py" label="🐍 Python">
+    <Tabs groupId="cli-tabs">
+      <TabItem value="short" label="Short">
+
+        ```bash
+        near call <created-account> initialize '{"default_message":"Hello, NEAR world!"}' --accountId <created-account>
+        ```
+
+      </TabItem>
+
+      <TabItem value="full" label="Full">
+
+        ```bash
+        near contract call-function as-transaction <created-account> initialize json-args '{"default_message":"Hello, NEAR world!"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
+        ```
+
+      </TabItem>
+    </Tabs>
+  </TabItem>
+</Tabs>
+
 ## Interacting with the Contract
 
 To interact with your deployed smart contract, you can call its functions through the command line.
@@ -376,7 +600,7 @@ Let's start by fetching the greeting stored in the contract. The `get_greeting`
 
     ```bash
     > near view <created-account> get_greeting
-    # "Hello"
+    # "Hello, NEAR world!"
     ```
   </TabItem>
 
@@ -384,7 +608,7 @@ Let's start by fetching the greeting stored in the contract. The `get_greeting`
 
     ```bash
     > near contract call-function as-read-only <created-account> get_greeting json-args {} network-config testnet now
-    # "Hello"
+    # "Hello, NEAR world!"
     ```
   </TabItem>
 </Tabs>
@@ -400,7 +624,7 @@ We can now change the greeting stored in the contract. The `set_greeting` method
 
   ```bash
   > near call <created-account> set_greeting '{"greeting": "Hola"}' --accountId <created-account>
-  # Log: Saving greeting "Hola"
+  # {"success": true}
   ```
   </TabItem>
 
@@ -408,7 +632,7 @@ We can now change the greeting stored in the contract. The `set_greeting` method
 
     ```bash
     > near contract call-function as-transaction <created-account> set_greeting json-args '{"greeting": "Hola"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
-    #Log: Saving greeting "Hola"
+    # {"success": true}
     ```
   </TabItem>
 </Tabs>
@@ -440,5 +664,9 @@ At the time of this writing, this example works with the following versions:
 - rustc: `1.81.0`
 - near-cli-rs: `0.17.0`
 - cargo-near: `0.13.2`
+- Python: `3.11`
+- near-sdk-py: `0.4.1`
+- uvx nearc: `0.1.0`
+- emscripten: `4.0.3` (required for Python contracts)
 
 :::
diff --git a/website/src/components/CodeExplainer/code-explainer.js b/website/src/components/CodeExplainer/code-explainer.js
index 45c38608e3a..17688b034fa 100644
--- a/website/src/components/CodeExplainer/code-explainer.js
+++ b/website/src/components/CodeExplainer/code-explainer.js
@@ -10,6 +10,7 @@ export const lang2label = {
   "rust": "🦀 RS",
   "js": "🌐 JS",
   "ts": "🌐 TS",
+  "python": "🐍 PY"
 }
 
 export function ExplainCode({ children, languages }) {


Reviews:
user: login: bucanero
body: hello @r-near 

could you sync with the master branch so we can review/merge the PR?

Recently we moved content from `docs/2.build/2.smart-contracts/` to `docs/smart-contracts`.  It should be Ok once the files are moved to the current location.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T11:28:53Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T14:58:18Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T15:01:26Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T15:03:02Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T15:06:47Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T15:07:02Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T22:31:17Z
user: login: bucanero
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T16:33:18Z
user: login: bucanero
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T13:28:04Z

Review comments:
diff_hunk: @@ -61,6 +61,20 @@ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/release
 
 </TabItem>
 
+<TabItem value="py" label="🐍 Python">
+
+```bash
+# Install Python (if not already installed)
+# Use your system's package manager or download from https://www.python.org/downloads/
+
+# Install uv for Python package management
+curl -LsSf https://astral.sh/uv/install.sh | sh
+
+# Install NEAR CLI-RS to deploy and interact with the contract
+curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh
+```
+
path: docs/smart-contracts/quickstart.md
user: login: bucanero
body: It needs to be added that `emscripten` has to be installed so the Python contract can be compiled.

Currently it's not mentioned anywhere, and it will bring errors later when following the tutorial.
created_at: 2025-03-18T14:58:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -171,6 +219,42 @@ The `Hello World` smart contract stores a greeting in its state, and exposes two
 
   </TabItem>
 
+  <TabItem value="py" label="🐍 Python">
+
+```python
+from near_sdk_py import Contract, view, call, init
+
+class GreetingContract(Contract):
+    """
+    A simple greeting contract that stores and returns a message.
+    """
+    
+    @init
+    def initialize(self, default_message="Hello, NEAR world!"):
+        """
+        Initialize the contract with a default greeting message.
+        """
+        self.storage["greeting"] = default_message
+        return {"success": True}
+    
+    @call
+    def set_greeting(self, message: str):
+        """
+        Change the greeting message.
+        """
+        self.storage["greeting"] = message
+        self.log_info(f"Saving greeting: {message}")
+        return {"success": True}
+    
+    @view
+    def get_greeting(self):
+        """
+        Retrieve the current greeting message.
+        """
+        return self.storage.get("greeting", "Hello, NEAR world!")
+```
+
path: docs/smart-contracts/quickstart.md
user: login: bucanero
body: can we upload all this code to a GitHub repo, so it can be linked directly to the original source code? (as we are currently doing for JS and Rust)

also it needs to be mentioned that the file name must be `greeting_contract.py`. Right now I think people will end up assuming the code goes into `main.py` and the following tests and build won't work.
created_at: 2025-03-18T15:01:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -308,7 +470,23 @@ When you are ready to create a build of the contract run a one-line command depe
   :::
 
   </TabItem>
+  
+  <TabItem value="py" label="🐍 Python">
 
+  ```bash
+  # Build with nearc through the uv executor (no installation needed)
+  uvx nearc build greeting_contract.py -o greeting_contract.wasm
path: docs/smart-contracts/quickstart.md
user: login: bucanero
body: the `build` command for nearc doesn't exist. Maybe you meant `--rebuild`?:

```suggestion
  uvx nearc --rebuild greeting_contract.py -o greeting_contract.wasm
```


created_at: 2025-03-18T15:03:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -399,16 +662,16 @@ We can now change the greeting stored in the contract. The `set_greeting` method
   <TabItem value="short" label="Short">
 
   ```bash
-  > near call <created-account> set_greeting '{"greeting": "Hola"}' --accountId <created-account>
-  # Log: Saving greeting "Hola"
+  > near call <created-account> set_greeting '{"message": "Hola"}' --accountId <created-account>
path: docs/smart-contracts/quickstart.md
user: login: bucanero
body: The contract stores the value as `greeting`:

```suggestion
  > near call <created-account> set_greeting '{"greeting": "Hola"}' --accountId <created-account>
```
created_at: 2025-03-18T15:06:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -399,16 +662,16 @@ We can now change the greeting stored in the contract. The `set_greeting` method
   <TabItem value="short" label="Short">
 
   ```bash
-  > near call <created-account> set_greeting '{"greeting": "Hola"}' --accountId <created-account>
-  # Log: Saving greeting "Hola"
+  > near call <created-account> set_greeting '{"message": "Hola"}' --accountId <created-account>
+  # {"success": true}
   ```
   </TabItem>
 
   <TabItem value="full" label="Full">
 
     ```bash
-    > near contract call-function as-transaction <created-account> set_greeting json-args '{"greeting": "Hola"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
-    #Log: Saving greeting "Hola"
+    > near contract call-function as-transaction <created-account> set_greeting json-args '{"message": "Hola"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
path: docs/smart-contracts/quickstart.md
user: login: bucanero
body: ```suggestion
    > near contract call-function as-transaction <created-account> set_greeting json-args '{"greeting": "Hola"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as <created-account> network-config testnet sign-with-keychain send
```
created_at: 2025-03-18T15:07:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -171,6 +219,42 @@ The `Hello World` smart contract stores a greeting in its state, and exposes two
 
   </TabItem>
 
+  <TabItem value="py" label="🐍 Python">
+
+```python
+from near_sdk_py import Contract, view, call, init
+
+class GreetingContract(Contract):
+    """
+    A simple greeting contract that stores and returns a message.
+    """
+    
+    @init
+    def initialize(self, default_message="Hello, NEAR world!"):
+        """
+        Initialize the contract with a default greeting message.
+        """
+        self.storage["greeting"] = default_message
+        return {"success": True}
+    
+    @call
+    def set_greeting(self, message: str):
+        """
+        Change the greeting message.
+        """
+        self.storage["greeting"] = message
+        self.log_info(f"Saving greeting: {message}")
+        return {"success": True}
+    
+    @view
+    def get_greeting(self):
+        """
+        Retrieve the current greeting message.
+        """
+        return self.storage.get("greeting", "Hello, NEAR world!")
+```
+
path: docs/smart-contracts/quickstart.md
user: login: bucanero
body: @r-near  I have created a PR on the `hello-near-examples` repository (where the Rust and JS sample code is stored), adding the Python example contract, so everything remains consistent: https://github.com/near-examples/hello-near-examples/pull/28

Please feel free to review and suggest changes to that PR, and then we can link to those python files from our docs.
created_at: 2025-03-18T22:31:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -375,15 +628,66 @@ When nesting SDK collections, be careful to **use different prefixes** for all c
   :::
 
   </TabItem>
-</Tabs>
+  
+  <TabItem value="python" label="🐍 Python">
+```python
+from near_sdk_py import view, call, init
+from near_sdk_py.collections import UnorderedMap, Vector
+from near_sdk_py.collections import create_prefix_guard
+
+class NestedCollectionsExample:
+    @init
+    def new(self):
+        # Main map of users to their assets
+        self.user_assets = UnorderedMap("users")
+
+    @call
+    def add_asset(self, user_id, asset_id, metadata):
+        # Get or create the user's assets vector with a unique prefix
+        if user_id not in self.user_assets:
+            # Create a prefix guard to ensure unique prefixes for this user
+            prefix = f"assets:{user_id}"
+            # Create a new vector for this user's assets
+            self.user_assets[user_id] = Vector(prefix)
+
+        # Add the asset to the user's assets vector
+        user_assets = self.user_assets[user_id]
+        user_assets.append({
+            "asset_id": asset_id,
+            "metadata": metadata
+        })
+
+        # Update the vector in the map
+        self.user_assets[user_id] = user_assets
+        return True
+
+    @view
+    def get_user_assets(self, user_id):
+        if user_id not in self.user_assets:
+            return []
+
+        # Get all assets for the user
+        user_assets = self.user_assets[user_id]
+        return [asset for asset in user_assets]
+````
 
+:::tip
+
+In Python, we create unique prefixes for nested collections by including the parent's identifier in the prefix string. The SDK also provides a `create_prefix_guard` utility to help manage prefixes.
+
+:::
+
+  </TabItem>
+</Tabs>
 
 ---
 
 ## Error prone patterns
 
 Because the values are not kept in memory and are lazily loaded from storage, it's important to make sure if a collection is replaced or removed, that the storage is cleared. In addition, it is important that if the collection is modified, the collection itself is updated in state because most collections will store some metadata.
 
+Because the values are not kept in memory and are lazily loaded from storage, it's important to make sure if a collection is replaced or removed, that the storage is cleared. In addition, it is important that if the collection is modified, the collection itself is updated in state because most collections will store some metadata.
+
path: docs/smart-contracts/anatomy/collections.md
user: login: bucanero
body: duplicate paragraph
```suggestion
```
created_at: 2025-03-19T16:33:18Z
author_association: CONTRIBUTOR

PR comments:
user: login: r-near
created_at: 2025-03-20T05:01:05Z
body: @race-of-sloths
author_association: CONTRIBUTOR
user: login: race-of-sloths
created_at: 2025-03-20T05:01:48Z
body: @r-near Thank you for your contribution! Your pull request is now a part of the [Race of Sloths](https://race-of-sloths.com)!


[<picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://race-of-sloths.com/images/bot-banner-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="https://race-of-sloths.com/images/bot-banner-light.svg">
    <img alt="Shows inviting banner with latest news." src="https://race-of-sloths.com/images/bot-banner-light.svg">
</picture>](https://race-of-sloths.com/latest-news)

[<picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://badge.race-of-sloths.com/r-near?type=bot&pr=near/docs/2494&theme=dark">
    <source media="(prefers-color-scheme: light)" srcset="https://badge.race-of-sloths.com/r-near?type=bot&pr=near/docs/2494&theme=light">
    <img alt="Shows profile picture for the author of the PR" src="https://badge.race-of-sloths.com/r-near?type=bot&pr=near/docs/2494&theme=white">
</picture>](https://race-of-sloths.com/profile/r-near)





<details><summary>Current status: <i>executed</i></summary>

| Reviewer | Score |
|--------|--------|
| @bucanero  | 13 |


Your contribution is much appreciated with a final score of 13!
You have received 130 Sloth points for this contribution

@bucanero received 25 Sloth Points for reviewing and scoring this pull request.

We would appreciate your feedback or contribution idea that you can submit [here](https://github.com/NEAR-DevHub/race-of-sloths/issues/new/choose)
</details><details><summary>What is the Race of Sloths</summary>
<p>
Race of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow

For contributors:

- Tag @race-of-sloths inside your pull requests
- Wait for the maintainer to review and score your pull request
- Check out your position in the [Leaderboard](https://race-of-sloths.com/leaderboard)
- Keep weekly and monthly streaks to reach higher positions
- Boast your contributions with a dynamic picture of your [Profile](https://race-of-sloths.com/profile/r-near)

For maintainers:
- Score pull requests that participate in the Race of Sloths and receive a reward
- Engage contributors with fair scoring and fast responses so they keep their streaks
- Promote the Race to the point where the Race starts promoting you
- Grow the community of your contributors

Feel free to check [our website](https://race-of-sloths.com) for additional details!
</p>
</details> 

<details>
<summary>Bot commands</summary>

- For contributors
  - **Include a PR:** `@race-of-sloths include` to enter the Race with your PR
- For maintainers:
  - **Invite contributor** `@race-of-sloths invite` to invite the contributor to participate in a race or include it, if it's already a runner.
  - **Assign points:** `@race-of-sloths score [1/2/3/5/8/13]` to award points based on your assessment.
  - **Reject this PR:** `@race-of-sloths exclude` to send this PR back to the drawing board.
  - **Exclude repo:** `@race-of-sloths pause` to stop bot activity in this repo until `@race-of-sloths unpause` command is called

</details>

author_association: NONE
user: login: race-of-sloths
created_at: 2025-03-20T14:41:48Z
body: 🥁  __Score it!__

@bucanero, please score the PR with `@race-of-sloths score [1/2/3/5/8/13]`. The contributor deserves it.
If no scoring is provided within 24 hours, this PR will be scored as 2 🦥
author_association: NONE
user: login: bucanero
created_at: 2025-03-20T15:30:25Z
body: @race-of-sloths score 13
author_association: CONTRIBUTOR