Skip to content

Commit

Permalink
Add Pyramid API docs
Browse files Browse the repository at this point in the history
  • Loading branch information
hynek committed Aug 8, 2023
1 parent 0f9740b commit fa7bfbb
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 31 deletions.
56 changes: 55 additions & 1 deletion docs/pyramid.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ You can use `svcs.pyramid.close_registry(config)` to close the registry that is
These functions only work from within an **active** Pyramid request.
:::

Despite being [discouraged](https://docs.pylonsproject.org/projects/pyramid/en/main/narr/threadlocals.html), you can use Pyramid's thread locals to access the active container, or even services:
Despite being [discouraged], you can use Pyramid's thread locals to access the active container, or even services

So this:

```python
def view(request):
Expand All @@ -55,4 +57,56 @@ def view(request):
service2 = svcs.pyramid.get_abstract(AbstractService)
```

is equivalent to this:

```python
def view(request):
container = request.svcs
service1 = request.svcs.get(Service)
service2 = request.svcs.get_abstract(AbstractService)
```

[Tween]: https://docs.pylonsproject.org/projects/pyramid/en/main/glossary.html#term-tween


## API Reference

### Application Life Cycle

```{eval-rst}
.. module:: svcs.pyramid
.. autofunction:: init
.. autofunction:: close_registry
.. autofunction:: get_container
.. autofunction:: get_registry
.. autoclass:: RegistryHaver()
```


### Registering Services

```{eval-rst}
.. autofunction:: register_factory
.. autofunction:: register_value
```


### Service Acquisition

Generally, you should use the `request.svcs` to access services.
But Pyramid _does_ also support to find the request and the registry using thread locals, so here's helper methods for that.
It's [discouraged] by the Pyramid developers, though.

```{eval-rst}
.. function:: get(svc_types)
Same as :meth:`svcs.Container.get()`, but uses thread locals to find the
current request.
.. autofunction:: get_abstract
```

[discouraged]: https://docs.pylonsproject.org/projects/pyramid/en/main/narr/threadlocals.html
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ docs = [
"myst-parser",
"sphinx-notfound-page",
"flask",
"pyramid",
"sybil",
"pytest",
]
Expand Down
44 changes: 14 additions & 30 deletions src/svcs/pyramid.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ def init(
"""
Configure *config* to work with *svcs*.
*svcs* uses a Tween_ to manage the life cycle of the container. You can
affect its position by passing *tween_under* and *tween_over*.
*svcs* uses a :term:`Tween` to manage the life cycle of the container. You
can affect its position by passing *tween_under* and *tween_over*.
.. _Tween: https://docs.pylonsproject.org/projects/pyramid/en/main/glossary.html#term-tween
Args:
config: Pyramid configurator object.
Expand All @@ -32,8 +34,6 @@ def init(
tween_over: Passed unchanged to
:meth:`pyramid.config.Configurator.add_tween()` as *over*.
.. _Tween: https://docs.pylonsproject.org/projects/pyramid/en/main/glossary.html#term-tween
"""
config.registry[_KEY_REGISTRY] = svcs.Registry()

Expand Down Expand Up @@ -97,7 +97,7 @@ def register_value(

def close_registry(config: Configurator) -> None:
"""
Close the registry on *app* if present.
Close the registry on *app*, if present.
Ideal for :func:`atexit.register()` handlers.
"""
Expand All @@ -109,14 +109,9 @@ def get_container(request: Request | None = None) -> svcs.Container:
"""
Get the current container either from *request* or from thread locals.
.. note::
The Pyramid developers discourage_ the use of thread locals outside of
tests.
Please also note that the container is guaranteed to be
``request.svcs`` if *svcs* is set up correctly.
Arguments:
.. _discourage: https://docs.pylonsproject.org/projects/pyramid/en/main/narr/threadlocals.html
request: If None, thread locals are used.
"""
if request:
return request.svcs # type: ignore[no-any-return]
Expand All @@ -126,8 +121,9 @@ def get_container(request: Request | None = None) -> svcs.Container:

class RegistryHaver(Protocol):
"""
This is both true for apps (:class:`pyramid.interfaces.IRouter`) and
:class:`pyramid.config.Configurator`.
An object with a :class:`pyramid.registry.Registry` as a ``registry``
attribute. For example a :class:`~pyramid.config.Configurator` or an
application.
"""

registry: dict[str, Any]
Expand All @@ -137,11 +133,8 @@ def get_registry(rh: RegistryHaver | None = None) -> svcs.Registry:
"""
Get the registry from *rh* or thread locals.
.. note::
The Pyramid developers discourage_ the use of thread locals outside of
tests.
.. _discourage: https://docs.pylonsproject.org/projects/pyramid/en/main/narr/threadlocals.html
Arguments:
rh: If None, thread locals are used.
"""
if rh:
return rh.registry[_KEY_REGISTRY] # type: ignore[no-any-return]
Expand All @@ -151,12 +144,8 @@ def get_registry(rh: RegistryHaver | None = None) -> svcs.Registry:

def get_abstract(*svc_types: type) -> Any:
"""
Like :func:`get` but is annotated to return `Any` which allows it to be
used with abstract types like :class:`typing.Protocol` or :mod:`abc`
classes.
Note:
See https://github.com/python/mypy/issues/4717 why this is necessary.
Same as :meth:`svcs.Container.get_abstract()`, but uses container on
thread locals.
"""
return get(*svc_types)

Expand Down Expand Up @@ -292,10 +281,5 @@ def get(*svc_types: type) -> object:
"""
Same as :meth:`svcs.Container.get()`, but uses thread locals to find the
current request.
.. note::
The Pyramid developers discourage_ this kind of usage outside of tests.
.. discourage: https://docs.pylonsproject.org/projects/pyramid/en/main/narr/threadlocals.html
"""
return get_container().get(*svc_types)

0 comments on commit fa7bfbb

Please sign in to comment.