Tutorial: 01 - First Steps¶
Let’s start with the basics: defining a dependency and injecting it into a function that needs it.
But first, let’s install Picodi if you haven’t done so already.
pip install picodi # or with your favorite package manager
Defining a Dependency¶
In Picodi, a dependency is simply a Python function (or any callable) that returns a value. This function typically has no required arguments.
Let’s define a dependency that provides a simple configuration setting:
# dependencies.py
def get_api_base_url() -> str:
"""Provides the base URL for an external API."""
print("Creating API base URL dependency")
return "https://api.example.com"
This is a standard Python function. Picodi doesn’t require any special base classes or decorators just to define a dependency.
Injecting the Dependency¶
Now, let’s create a function that needs this API base URL to perform its task.
We’ll use Picodi’s inject() decorator and Provide() marker
to tell Picodi how to supply the dependency.
# services.py
from picodi import Provide, inject
# Assume dependencies.py is in the same directory or Python path
# from dependencies import get_api_base_url
@inject
def call_external_api(
endpoint: str, base_url: str = Provide(get_api_base_url) # Inject here!
) -> str:
"""Calls an endpoint on the external API."""
full_url = f"{base_url}/{endpoint.lstrip('/')}"
print(f"Calling API at: {full_url}")
# In a real app, you'd use an HTTP client here
return f"Response from {full_url}"
Explanation:
@inject: This decorator modifies
call_external_apiso that Picodi can manage its dependencies before the function’s actual code runs. It should generally be the first decorator applied (closest to thedef).Provide(get_api_base_url): This is used as the default value for the
base_urlparameter. It tells@inject: “Whencall_external_apiis called, if no value is explicitly passed forbase_url, call theget_api_base_urlfunction and use its return value for this parameter.”
Using the Injected Function¶
Now you can call call_external_api like a regular function. Picodi handles the injection automatically.
# main.py
# from services import call_external_api
response = call_external_api("users")
print(response)
response_2 = call_external_api("products")
print(response_2)
Output:
Creating API base URL dependency
Calling API at: https://api.example.com/users
Response from https://api.example.com/users
Creating API base URL dependency
Calling API at: https://api.example.com/products
Response from https://api.example.com/products
Notice that get_api_base_url was called each time call_external_api was invoked.
This is the default behavior (using NullScope).
We’ll explore how to change this later using scopes.
Dependencies Depending on Others¶
Dependencies can also depend on other dependencies. Picodi automatically resolves the entire chain.
Let’s define a configuration dependency and have our URL dependency use it:
# dependencies.py
from picodi import Provide, inject
def get_config() -> dict:
"""Provides application configuration."""
print("Loading config")
return {"api_url": "https://api.config.com"}
@inject # Inject config here
def get_api_base_url(config: dict = Provide(get_config)) -> str:
"""Provides the base URL from config."""
print("Creating API base URL from config")
return config["api_url"]
# services.py
# (call_external_api remains the same, using get_api_base_url)
# from dependencies import get_api_base_url
from picodi import Provide, inject
@inject
def call_external_api(endpoint: str, base_url: str = Provide(get_api_base_url)) -> str:
"""Calls an endpoint on the external API."""
full_url = f"{base_url}/{endpoint.lstrip('/')}"
print(f"Calling API at: {full_url}")
return f"Response from {full_url}"
# main.py
# from services import call_external_api
response = call_external_api("orders")
print(response)
Output:
Loading config
Creating API base URL from config
Calling API at: https://api.config.com/orders
Response from https://api.config.com/orders
Picodi first called get_config, then injected its result into get_api_base_url
when resolving the dependencies for call_external_api, and finally injected the
result of get_api_base_url into the call_external_api execution.
Next Steps¶
You’ve learned the basics of defining and injecting simple dependencies. Next, we’ll look at dependencies that need cleanup after they are used: Yield Dependencies.