Skip to content

Commit

Permalink
feat: rearranged docs to make them more clear.
Browse files Browse the repository at this point in the history
  • Loading branch information
joshorr committed Nov 19, 2022
1 parent 9e71da1 commit 2d55d38
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 42 deletions.
40 changes: 6 additions & 34 deletions docs/advanced.md → docs/dependency-proxy.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,10 @@
---
title: REST API
description: Core utility
title: Dependency Proxy
---

## 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 `xinject.dependency.ThreadUnsafeResource` instead,
or by setting the **class attribute** (on your custom subclass of Dependency)
`xinject.dependency.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.

Example for which you would want a separate dependency instance/object per-thread:

- `requests` library session
- Requests libraries session object is not thread-safe, there is issue that's been around for 7 years
to make it thread safe that's still open. For now, you need a seperate requests Session per-thread.
- `requests-mock` also needs the session created after it's setup, so after unit test runs.
- boto client/dependency
- Library says it's not thread-safe, you need to use a different object per-thread.
- Moto mocking library for AWS services needs you to allocate a client after it's setup,
(so lazily allocate client/dependency from boto).

## Active Dependency Proxy

You can use the convenience method `xinject.dependency.Dependency.proxy` to easily get a
proxy object.
You can use the method
[`Dependency.proxy()`](api/xinject/dependency.html#xinject.dependency.Dependency.proxy){target=_blank}
to easily get a proxy object.

All non-dunder attributes/methods will be grabbed/set on the current object instead of the proxy.

Expand Down Expand Up @@ -83,7 +55,7 @@ if __name__ == '__main__':
s3.resource.Bucket("my-bucket").download_file(file_name, dest_path)
```

You can use the proxy objecy like a normal object.
You can use the proxy object like a normal object.

The only things not forwarded are any method/attribute that starts
with a `_`, which conveays the attribute as private/internal.
Expand All @@ -95,5 +67,5 @@ Only use the proxy object for normal attribute/properties/methods.
If you need do use an attribute/method that starts with an underscore `_`,
grab the current object directly via `S3.grab()`.

The [`grab`](api/xinject/dependency.html#xinject.dependency.Dependency.grab)
The [`grab()`](api/xinject/dependency.html#xinject.dependency.Dependency.grab){target=_blank}
method returns the current real object each time it's called (and not a proxy).
10 changes: 5 additions & 5 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ in an easy to understand and self-documenting way.
documentation.

When you're done here and want more details go to [API Reference](api/xinject)
or directly to [`Dependency API Refrence`](api/xinject/dependency.html#xinject.dependency.Dependency)
or directly to [`Dependency API Refrence`](api/xinject/dependency.html#xinject.dependency.Dependency){target=_blank}
for more detailed reference-type documentation.

## Quick Start

Although it's not required, most of the time you'll want to subclass [`Dependency`](api/xinject/dependency.html#xinject.dependency.Dependency).
Although it's not required, most of the time you'll want to subclass [`Dependency`](api/xinject/dependency.html#xinject.dependency.Dependency){target=_blank}.
The subclass will inherit some nice features that make it easier to use.

The following is a specific usecase followed by a more generalized example
Expand All @@ -50,7 +50,7 @@ We have a choice to inherit from ether Dependency, or DependencyPerThread.
The normal `Dependency` class lets the dependency be shared between threads, so more of a true singleton type
of object where under normal/default circomstances there would ever only be one instance of a partculare `Dependency`.

Using [`DependencyPerThread`](api/xinject/dependency.html#xinject.dependency.DependencyPerThread) will automatically get a
Using [`DependencyPerThread`](api/xinject/dependency.html#xinject.dependency.DependencyPerThread){target=_blank} will automatically get a
separate dependency object per-thread (ie: separate instance per-thread).
It simply inherits from Dependency and configures it to not be thread sharable.

Expand Down Expand Up @@ -204,7 +204,7 @@ XContext.grab().add(s3_mocking_obj, for_type=S3)

### Generalized/Generic Example

Although it's not required, most of the time you'll want to subclass [`Dependency`](api/xinject/dependency.html#xinject.dependency.Dependency).
Although it's not required, most of the time you'll want to subclass [`Dependency`](api/xinject/dependency.html#xinject.dependency.Dependency){target=_blank}.
The subclass will inherit some nice features that make it easier to use.

```python
Expand Down Expand Up @@ -283,7 +283,7 @@ with MyUniversalDependency(name='injected-value'):

## Overview

The main class used most of the time is [`Dependency`](api/xinject/dependency.html#xinject.dependency.Dependency).
The main class used most of the time is [`Dependency`](api/xinject/dependency.html#xinject.dependency.Dependency){target=_blank}.

Allows you to create sub-classes that act as sharable singleton-type objects that
we are calling resources here.
Expand Down
40 changes: 40 additions & 0 deletions docs/thread-safety.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: Thread Safety
---

There is a concept of an app-root, and thread-root [`XContext`](api/xinject/context.html#xinject.context.XContext){target=_blank}.
The app-root stores dependecies that can be shared between threads, whule the thread-root context stores dependence
for a specific thread.

By default, each Dependency subclass can 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 `xinject.dependency.DependencyPerThread` instead,
or by setting the **class attribute** (on your subclass of Dependency)
`thread_sharable` to `False`; ie:

```python
from xinject import Dependency, DependencyPerThread

class MyThreadUnsafeDependencyOpt1(DependencyPerThread):
...

class MyThreadUnsafeDependencyOpt2(Dependency, thread_sharable=False):
...
```


Things that are probably not thread-safe in general
are resources that contain network/remote type connections/sessions/clients.

Example for which you would want a separate dependency instance/object per-thread:

- `requests` library session
- Requests libraries session object is not thread-safe, there is issue that's been around for 7 years
to make it thread safe that's still open. For now, you need a seperate requests Session per-thread.
- `requests-mock` also needs the session created after it's setup, so after unit test runs.
- boto client/dependency
- Library says it's not thread-safe, you need to use a different object per-thread.
- Moto mocking library for AWS services needs you to allocate a client after it's setup,
(so lazily allocate client/dependency from boto).
2 changes: 1 addition & 1 deletion docs/unit-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ This means that by default, at the start of each running unit test function ther
so as long as xinject is installed in the environment as a dependency it will find this
and autoload this fixture for each unit test.

If curious The [`xinject_test_context`](api/xinject/pytest_plugin.html#xinject.pytest_plugin.xinject_test_context)
If curious The [`xinject_test_context`](api/xinject/pytest_plugin.html#xinject.pytest_plugin.xinject_test_context){target=_blank}
fixture is how it's implemented.


Expand Down
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ nav:
- index.md
- Unit Testing: unit-testing.md
- Data Classes: dataclasses.md
- Advanced Use Cases: advanced.md
- thread-safety.md
- dependency-proxy.md
- API Reference: api/xinject/" target="_blank
- Changelog: changelog.md

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "xinject"
version = "0.3.0"
description = "Inject universal resources/dependencies lazily."
description = "Lazy dependency injection."
authors = ["Josh Orr <[email protected]>"]
packages = [{include = "xinject"}]

Expand Down

0 comments on commit 2d55d38

Please sign in to comment.