-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: splitting up docs into multiple files.
- Loading branch information
Showing
4 changed files
with
220 additions
and
186 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
|
||
|
||
## Thread Safety | ||
|
||
There is a concept of an app-root, and thread-root contexts. | ||
|
||
By default, each Dependency subclass will be shared between different threads, | ||
ie: it's assumed to be thread-safe. | ||
|
||
You can indicate a Dependency subclass should not be shared between threads | ||
by inheriting from `udepend.resource.ThreadUnsafeResource` instead, | ||
or by setting the **class attribute** (on your custom sub-class of Dependency) | ||
`udepend.resource.Dependency.resource_thread_sharable` to `False`. | ||
|
||
Things that are probably not thread-safe in general | ||
are resources that contain network/remote type connections/sessions/clients. | ||
|
||
Concrete Examples In Code Base: | ||
|
||
- Requests library session | ||
- xyn_model_rest uses a Dependency to wrap requests library session, so it can automatically | ||
reuse connections on same thread, but use new session if on different thread. | ||
Also helps with unit testing, when Mocking requests URL calls. | ||
- boto client/resource | ||
- Library says it's not thread-safe, you need to use a diffrent object per-thread. | ||
- Moto mocking library for AWS services needs you to allocate a client after it's setup, | ||
(so lazily allocate client/resource from boto). | ||
- Use `xyn_aws` for easy to use Dependency's that wrap boto client/resources that | ||
accomplish being both lazy and will allocate a new one per-thread for you automatically. | ||
|
||
## Active Dependency Proxy | ||
|
||
You can use the convenience method `udepend.resource.Dependency.resource_proxy` to easily get a | ||
proxy object. | ||
|
||
Or you can use `udepend.proxy.ActiveResourceProxy.wrap` to create an object that will act | ||
like the current resource. | ||
All non-dunder attributes/methods will be grabbed/set on the current object instead of the proxy. | ||
|
||
This means you can call all non-special methods and access normal attributes, | ||
as if the object was really the currently active resource instance. | ||
|
||
Any methods/attributes that start with a `_` will not be used on the proxied object, | ||
but will be used on only the proxy-object it's self. | ||
This means, you should not ask/set any attributes that start with `_` (underscore) | ||
when using the proxy object. | ||
|
||
A real-world example is `xyn_config.config.config`, it uses this code for that object: | ||
|
||
```python | ||
from udepend import ActiveResourceProxy | ||
from xyn_config import Config | ||
|
||
# The `xny_resource.proxy.ActiveResourceProxy.wrap` method to get a correctly type-hinted (for IDE) | ||
# proxy back: | ||
config = ActiveResourceProxy.wrap(Config) | ||
|
||
# This is a simpler way to get the same proxy | ||
# (no imports are needed, just call the class method on any resource class): | ||
config = Config.resource_proxy() | ||
``` | ||
|
||
Now someone can import and use it as-if it's the current config object: | ||
|
||
```python | ||
from xyn_config import config | ||
|
||
value = config.get('some_config_var') | ||
``` | ||
|
||
When you ask `config` for it's `get` attribute, it will get it from the current | ||
active resource for `Config`. So it's the equivalent of doing this: | ||
|
||
```python | ||
from xyn_config import Config | ||
|
||
get_method = Config.resource().get | ||
value = get_method('some_config_var') | ||
``` | ||
|
||
The code then executes the method that was attached to the `get` attribute. | ||
This makes the call-stack clean, if an error happens it won't be going through | ||
the ActiveResourceProxy. | ||
The `udepend.proxy.ActiveResourceProxy` already return the `get` method and is finished. | ||
The outer-code is the one that executed/called the method. | ||
|
||
Another read-world example is in the `xyn_aws`. | ||
|
||
See `udepend.proxy.ActiveResourceProxy` for more ref-doc type details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
## Dependency + Dataclasses | ||
|
||
You can use the built-in dataclasses with Dependency without a problem. | ||
Just ensure all fields are optional (ie: they all have default values), | ||
so they are not required when creating/init'ing the object. | ||
|
||
You can also provide a `__post_init__` method on your `Dependency` | ||
subclass to help you initialize the values into a good default state | ||
(a standard feature of dataclasses). | ||
|
||
The purpose to enable lazily creation of the Dependency object | ||
the very first time it's asked for. | ||
|
||
Example: | ||
|
||
```python | ||
from udepend import Dependency | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass | ||
class DataResource(Dependency): | ||
# Making all fields optional, so DataResource can be created lazily: | ||
my_optional_field: str = None | ||
another_optional_field: str = "hello!" | ||
|
||
|
||
# Get current DataResource resource, print it's another_optional_field; | ||
# will print out `hello!`: | ||
print(DataResource.resource().another_optional_field) | ||
|
||
|
||
DataResource.depend() | ||
|
||
DataResource.dependency() | ||
|
||
DataResource.resource() | ||
|
||
``` |
Oops, something went wrong.