Frequently Asked Questions¶
In this section, we answer some of the most common questions about wingpy, organized by feature. If you have a question that isn't covered here, please feel free to reach out on our GitHub Issues Page, and we'll be happy to help and add it to this FAQ!
Session Maintenance¶
Your sessions are safe with wingpy.
How do I use the clients as context managers?
All clients support the context manager protocol.
Use with
to ensure resources are cleaned up:
Should I refresh my tokens if they expire?
No, wingpy clients automatically handle token refresh and session maintenance for you. Just create a client instance and use it as needed. If a token expires, the client will re-authenticate automatically.
Error Handling¶
Comprehensive error handling with clear exceptions for common issues.
What exceptions should I handle?
Wingpy's logging module logs all errors, of course depending on your configured log level.
If you want to handle specific exceptions in your code, here are the exceptions you might encounter from wingpy clients:
AuthenticationFailure: Raised if authentication fails (e.g., wrong credentials or invalid token). Includes the HTTP response for debugging.InvalidEndpointError: Raised if you use an unsupported or invalid endpoint path. Includes details about the client and endpoint.UnsupportedMethodError: Raised if you call a method not supported by a client (e.g.,.put()on a client that doesn't implement it). Includes the method and client name.InvalidResponseError: Raised when the API returns an invalid or unexpected HTTP response.UnexpectedPayloadError: Raised when the API returns a payload with an unexpected data structure.MissingPathParameterError: Raised when a required path parameter is missing for URL construction.URLSchemaError: Raised when the provided base URL does not include a valid schema (httporhttps).URLNetlocError: Raised when the provided base URL does not include a valid network location.URLPathError: Raised when the provided base URL ends with a forward slash (/).ValueError: Raised for invalid API endpoint paths (e.g., APIC paths must end with.jsonor.xml), or if required arguments/environment variables are missing.
All custom exceptions inherit from WingpyException and provide detailed context for debugging. See the User Guide: Exceptions for usage examples.
Are there some examples of error handling?
Certainly! Here's an example of how to handle authentication failures and unsupported methods:
from wingpy import CiscoFMC
from wingpy.exceptions import AuthenticationFailure, UnsupportedMethodError
try:
fmc = CiscoFMC(base_url="https://fmc.example.com", username="user", password="wrong-password")
fmc.put("/api/some-endpoint") # Assuming put() is not supported
except AuthenticationFailure as auth_err:
print(f"Authentication failed: {auth_err}")
print (f"Response details: {auth_err.response.status_code} - {auth_err.response.text}")
As you can see the AuthenticationFailure exception provides access to the HTTP response, which can help diagnose issues.
The UnsupportedMethodError will inform you if you try to use a method not supported by the client.
I would also like to log other exceptions, is there a utility?
Yes, wingpy provides a utility function to log exceptions in a standardized way.
You can use the log_exception function from the wingpy.logging module to log exceptions with detailed context.
Here's an example of how to use it to log all exceptions in a debugging scenario:
import wingpy
from wingpy.logging import log_exception
try:
fmc = wingpy.CiscoFMC(base_url="https://fmc.example.com", username="user", password="wrong-password")
fmc.get("/api/some-endpoint")
except Exception as e:
log_exception(e)
Per default, log_exception logs the exception message and stack trace at the ERROR level.
You can customize the log level by passing the severity argument.
Environment Variables¶
Configure clients using environment variables for sensitive data.
How do I configure authentication using environment variables?
Each client requires credentials (base_url, username, password, or token). You can provide these as arguments or set the appropriate environment variables:
This way, you can keep sensitive information out of your codebase, and can instantiate clients without hardcoding credentials.
Am I really supposed to write my password on the command line?!
While you can set environment variables directly in your shell, it's often NOT RECOMMENDED to do so for sensitive information like passwords or tokens. Lots of ways exist to manage environment variables securely.
- dotenv loads a single
.envfile with variables with a single line in your Python script. - autoenv automatically loads environment variables when you
cdinto a project directory.
We use both tools in our development workflow. autoenv's GH repository is worth visiting for the gif in the README alone!
I have already set the correct environment variables, how do I create a client?
Simply instantiate the client without passing credentials:
If you do not provide credentials as arguments, the client will look for the appropriate environment variables and raise an error if any are missing.Rate Limit Handling¶
Built-in support for rate limiting and retry logic. Mostly you should not have to worry about HTTP 429 errors or implementing your own retry logic.
Wingpy automatically detects rate limit responses and retries requests with exponential backoff. In the odd case you need to customize this behavior,
you can adjust the retries and timeout parameters in the client constructor.
Modify timeout or retry behavior
You can set timeout, retries, and other related parameters in the client constructor. Example:
Authentication¶
Simplified authentication process with support for multiple methods.
How do I configure authentication?
It's very simple. You can provide credentials as arguments when instantiating a client, or set the appropriate environment variables (see above).
More examples of authentication methods can be found in the User Guide: Authentication or in each client's API reference.
How do I use environment variables for configuration?
Path Building¶
Easy-to-use path building for API endpoints.
How do I build API paths?
Each client has a path_params attribute that helps you build API paths with required parameters. Example:
import wingpy
fmc = wingpy.CiscoFMC(base_url=..., username=..., password=...)
path = fmc.get_all(
"/api/fmc_config/v1/domain/{domainUUID}/devices/devicerecords",
path_params={"domainUUID": "12345678-1234-1234-1234-1234567890ab"})
In this case {domainUUID} in the path is replaced with the value provided in path_params.
With FMC you don't actually need to provide domainUUID as it defaults to the "global" domain, but this is just an example of how path_params works.
But why would I even use this, f-strings exist?!
While f-strings are useful for simple cases, using path_params provides several advantages:
-
You can copy and paste API paths directly from official documentation without modification. This means that when you debug your code or read logs, the paths match exactly with the documentation, making it easier to verify correctness. It also makes it easy to open the relevant documentation page based on the code alone, as you can simply search the path in the docs as shown.
-
Using
path_paramsensures that all required parameters are provided and correctly formatted. It also improves code readability and maintainability, especially for complex paths with multiple parameters. Additionally, it helps prevent errors related to missing or incorrect path segments.
Type Hints and Development Experience¶
Type hints for better development experience.
How do I know if a method is supported?
VS Code picks up type hints from the library, providing autocompletion and inline documentation. This makes it easier to discover available methods and their parameters. In addition, docstrings provide detailed information about method usage, parameters, and return types, enhancing the overall development experience.
This should provide a smooth experience when working with wingpy in modern IDEs. Unsupported methods will raise an UnsupportedMethodError at runtime,
but are also flagged in your editor via docstrings.
If you prefer looking in the API documentation:
Click your client of choice under the API Reference to get started --- then click the HTTP method name.
Example: Meraki Dashboard's API client
documentation that does not support patch().
Concurrency¶
Supports asynchronous operations for better performance.
How do I run requests concurrently?
All clients have a .tasks attribute (a
TaskRunner instance), which lets you schedule requests for concurrent execution. Use
.tasks.schedule() to queue up requests, then
.tasks.run() to execute them in parallel.
Note: get_all will automatically use concurrency for paging where supported, so you often do not need to manage this manually.
RuntimeError: Cannot run the event loop while another loop is running
This error occurs when you try to run an asynchronous operation in an environment that already has an event loop running (e.g. if you're using FastAPI or asyncio). To fix this, see the concurrency section example. The example shows how to use nest_asyncio to allow nested event loops.
Pagination¶
Automatically handles pagination for large datasets.
How do I fetch all results from a paginated API?
Use the get_all() method on APIC, Catalyst Center, FMC, ISE, and Hyperfabric clients. This method will automatically handle paging and return a list of all items.
For ISE, paging is only supported on OpenAPI and ERS endpoints (not XML).
Note: get_all will automatically use concurrency to speed up data retrieval.
Headers¶
You never have to worry about headers - they are automatically set for you.
How do I customize request headers?
You can set default headers on the .headers attribute of a client instance, or pass headers per request. Setting headers in the constructor is not supported.
How do I set custom headers per request?
How do I set default headers for all requests?
You can modify the .headers attribute of the client instance to set default headers that will be included in all requests:
import wingpy
with wingpy.CiscoISE(base_url=..., username=..., password=...) as ise:
ise.headers["X-Custom-Header"] = "MyValue"
response = ise.get("/api/path") # This request will include the custom header
response2 = ise.post("/api/other-path", data={"key": "value"}) # This request will also include the custom header
Logging¶
Configurable, flexible and very detailed - for debugging and monitoring.
How do I debug or log requests?
The library uses loguru for logging. You can configure the log level and handlers in your script. Use TRACE or DEBUG for detailed request/response logs.
wingpy provides helper functions to configure logging easily. See the User Guide: Logging for more details.
How do I handle or debug connection errors?
Set logging level to DEBUG or TRACE to see detailed logs of connection attempts and errors. This can help diagnose issues like timeouts or DNS resolution failures.
You can also catch exceptions and log them using the log_exception utility from wingpy.logging. See the Error Handling section for more details.
SSL Verification¶
The verify argument controls SSL certificate verification.
How do I handle SSL verification?
The verify argument controls SSL certificate verification. Set verify=False to disable or provide a custom ssl.SSLContext for custom CAs. You can use the built-in ssl module to create a context . Example:
API Versioning¶
Most clients expose a .version attribute after authentication.
How do I check the API version or capabilities at runtime?
Most clients expose a .version attribute after authentication. You can use this to check the API version and adjust your logic accordingly.