Skip to content

Commit

Permalink
Implement Registry.__iter__ (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
hynek authored Oct 15, 2024
1 parent 32ddce2 commit c016b37
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/

- Python 3.13 support.

- `svcs.Registry` now implements a `__iter__` method that allows to iterate over its registered services.
[#106](https://github.com/hynek/svcs/pull/106)


### Removed

Expand Down
4 changes: 3 additions & 1 deletion docs/core-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,15 @@ You can see that the datetime factory and the str value have both been registere
.. module:: svcs
.. autoclass:: Registry()
:members: register_factory, register_value, close, aclose, __contains__
:members: register_factory, register_value, close, aclose, __contains__, __iter__
.. autoclass:: Container()
:members: get, aget, get_abstract, aget_abstract, register_local_factory, register_local_value, close, aclose, get_pings, __contains__
.. autoclass:: ServicePing()
:members: name, ping, aping, is_async
.. autoclass:: RegisteredService()
.. autoclass:: svcs.exceptions.ServiceNotFoundError
```
31 changes: 30 additions & 1 deletion src/svcs/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import logging
import warnings

from collections.abc import Awaitable, Callable
from collections.abc import Awaitable, Callable, Iterator
from contextlib import (
AbstractAsyncContextManager,
AbstractContextManager,
Expand Down Expand Up @@ -48,6 +48,26 @@ def _full_name(obj: object) -> str:

@attrs.frozen
class RegisteredService:
"""
A recipe for creating a service.
.. warning::
Strictly read-only.
Attributes:
svc_type: The type under which the type has been registered.
factory: Callable that creates the service.
takes_container:
Whether the factory takes a container as its first argument.
enter: Whether context managers returned by the factory are entered.
ping: See :ref:`health`.
"""

svc_type: type
factory: Callable = attrs.field(hash=False)
takes_container: bool
Expand Down Expand Up @@ -161,6 +181,15 @@ def __contains__(self, svc_type: type) -> bool:
"""
return svc_type in self._services

def __iter__(self) -> Iterator[RegisteredService]:
"""
Returns:
An iterator over registered services.
.. versionadded:: 24.2.0
"""
return iter(self._services.values())

def __enter__(self) -> Registry:
return self

Expand Down
14 changes: 14 additions & 0 deletions tests/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,20 @@ def test_contains(self, registry):
assert Service in registry
assert AnotherService not in registry

def test_iterate(self, registry):
"""
It's possible to iterate over the registered services.
"""
registry.register_factory(Service, Service)
registry.register_factory(AnotherService, AnotherService)

assert {
svcs.RegisteredService(Service, Service, False, True, None),
svcs.RegisteredService(
AnotherService, AnotherService, False, True, None
),
} == {rs for rs in registry} # noqa: C416 -- explicit on purpose

def test_gc_warning(self, recwarn):
"""
If a registry is gc'ed with pending cleanups, a warning is raised.
Expand Down

0 comments on commit c016b37

Please sign in to comment.