Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-injector for openSUSE:Factory 
checked in at 2023-12-08 22:31:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-injector (Old)
 and      /work/SRC/openSUSE:Factory/.python-injector.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-injector"

Fri Dec  8 22:31:57 2023 rev:10 rq:1131714 version:0.21.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-injector/python-injector.changes  
2022-09-29 18:14:53.899436112 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-injector.new.25432/python-injector.changes   
    2023-12-08 22:32:13.136365269 +0100
@@ -1,0 +2,12 @@
+Thu Dec  7 22:09:22 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 0.21.0:
+  * Improved the documentation, thanks to jonathanmach and Jakub
+    Wilk
+  * Fixed a thread-safety regression
+  * Improved the type annotations, thanks to David Pärsson
+  * Fixed singleton scope behavior with parent/child injectors,
+   thanks to David Pärsson
+  * Stopped using a deprecated test function, thanks to ljnsn
+
+-------------------------------------------------------------------

Old:
----
  0.20.1.tar.gz

New:
----
  0.21.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-injector.spec ++++++
--- /var/tmp/diff_new_pack.c9WQQK/_old  2023-12-08 22:32:13.720386757 +0100
+++ /var/tmp/diff_new_pack.c9WQQK/_new  2023-12-08 22:32:13.720386757 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-injector
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %define skip_python2 1
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-injector
-Version:        0.20.1
+Version:        0.21.0
 Release:        0
 Summary:        Python dependency injection framework, inspired by Guice
 License:        BSD-3-Clause

++++++ 0.20.1.tar.gz -> 0.21.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/.github/workflows/ci.yml 
new/injector-0.21.0/.github/workflows/ci.yml
--- old/injector-0.20.1/.github/workflows/ci.yml        2022-08-17 
01:03:10.000000000 +0200
+++ new/injector-0.21.0/.github/workflows/ci.yml        2023-07-27 
02:44:06.000000000 +0200
@@ -8,7 +8,7 @@
     strategy:
       matrix:
         os: [ubuntu-latest]
-        python-version: [3.7, 3.8, 3.9, "3.10", "pypy3.7", "pypy3.8", 
"pypy3.9"]
+        python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "pypy3.7", "pypy3.8", 
"pypy3.9", "pypy3.10"]
     steps:
     - uses: actions/checkout@v2
     - name: Set up Python ${{ matrix.python-version }}
@@ -17,7 +17,7 @@
         python-version: ${{ matrix.python-version }}
     - name: Install dependencies
       run: |
-        pip install --upgrade -r requirements.txt -r requirements-dev.txt
+        pip install --upgrade -r requirements-dev.txt
         pip install .
     - name: Run tests
       run: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/.gitignore 
new/injector-0.21.0/.gitignore
--- old/injector-0.20.1/.gitignore      2022-08-17 01:03:10.000000000 +0200
+++ new/injector-0.21.0/.gitignore      2023-07-27 02:44:06.000000000 +0200
@@ -1,3 +1,8 @@
+/.*
+
+!/.gitignore
+!/.github
+
 .cache/
 __pycache__/
 docs/_build/
@@ -9,4 +14,3 @@
 coverage.xml
 /dist/
 /injector.egg-info/
-/.coverage
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/CHANGES new/injector-0.21.0/CHANGES
--- old/injector-0.20.1/CHANGES 2022-08-17 01:03:10.000000000 +0200
+++ new/injector-0.21.0/CHANGES 2023-07-27 02:44:06.000000000 +0200
@@ -1,6 +1,15 @@
 Injector Change Log
 ===================
 
+0.21.0
+------
+
+- Improved the documentation, thanks to jonathanmach and Jakub Wilk
+- Fixed a thread-safety regression
+- Improved the type annotations, thanks to David Pärsson
+- Fixed singleton scope behavior with parent/child injectors, thanks to David 
Pärsson
+- Stopped using a deprecated test function, thanks to ljnsn
+
 0.20.1
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/MANIFEST.in 
new/injector-0.21.0/MANIFEST.in
--- old/injector-0.20.1/MANIFEST.in     2022-08-17 01:03:10.000000000 +0200
+++ new/injector-0.21.0/MANIFEST.in     2023-07-27 02:44:06.000000000 +0200
@@ -1,5 +1,6 @@
 include *.py
 include *.toml
+include requirements-dev.in
 include *.txt
 include CHANGES
 include COPYING
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/README.md 
new/injector-0.21.0/README.md
--- old/injector-0.20.1/README.md       2022-08-17 01:03:10.000000000 +0200
+++ new/injector-0.21.0/README.md       2023-07-27 02:44:06.000000000 +0200
@@ -7,7 +7,7 @@
 Introduction
 ------------
 
-While dependency injection is easy to do in Python due to its support for 
keyword arguments, the ease with which objects can be mocked and its dynamic 
nature, a framework for assisting in this process can remove a lot of 
boiler-plate from larger applications. That's where Injector can help. It 
automatically and transitively provides dependencies for you. As an added 
benefit, Injector encourages nicely compartmentalised code through the use of 
:ref:`modules <module>`.
+While dependency injection is easy to do in Python due to its support for 
keyword arguments, the ease with which objects can be mocked and its dynamic 
nature, a framework for assisting in this process can remove a lot of 
boiler-plate from larger applications. That's where Injector can help. It 
automatically and transitively provides dependencies for you. As an added 
benefit, Injector encourages nicely compartmentalised code through the use of 
modules.
 
 If you're not sure what dependency injection is or you'd like to learn more 
about it see:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/docs/index.rst 
new/injector-0.21.0/docs/index.rst
--- old/injector-0.20.1/docs/index.rst  2022-08-17 01:03:10.000000000 +0200
+++ new/injector-0.21.0/docs/index.rst  2023-07-27 02:44:06.000000000 +0200
@@ -50,6 +50,8 @@
   a different configuration and each with different objects in different 
scopes. Code like this
   won't work for this very reason::
 
+    # This will NOT work:
+
     class MyClass:
         @inject
         def __init__(self, t: SomeType):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/docs/scopes.rst 
new/injector-0.21.0/docs/scopes.rst
--- old/injector-0.20.1/docs/scopes.rst 2022-08-17 01:03:10.000000000 +0200
+++ new/injector-0.21.0/docs/scopes.rst 2023-07-27 02:44:06.000000000 +0200
@@ -24,6 +24,8 @@
         def provide_thing(self) -> Thing:
             return Thing()
 
+If using hierarchies of injectors, classes decorated with `@singleton` will be 
created by and bound to the parent/ancestor injector closest to the root that 
can provide all of its dependencies.
+
 Implementing new Scopes
 ```````````````````````
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/injector/__init__.py 
new/injector-0.21.0/injector/__init__.py
--- old/injector-0.20.1/injector/__init__.py    2022-08-17 01:03:10.000000000 
+0200
+++ new/injector-0.21.0/injector/__init__.py    2023-07-27 02:44:06.000000000 
+0200
@@ -61,7 +61,7 @@
 
 
 __author__ = 'Alec Thomas <a...@swapoff.org>'
-__version__ = '0.20.1'
+__version__ = '0.21.0'
 __version_tag__ = ''
 
 log = logging.getLogger('injector')
@@ -254,7 +254,7 @@
         raise NotImplementedError  # pragma: no cover
 
 
-class ClassProvider(Provider):
+class ClassProvider(Provider, Generic[T]):
     """Provides instances from a given class, created using an Injector."""
 
     def __init__(self, cls: Type[T]) -> None:
@@ -264,7 +264,7 @@
         return injector.create_object(self._cls)
 
 
-class CallableProvider(Provider):
+class CallableProvider(Provider, Generic[T]):
     """Provides something using a callable.
 
     The callable is called every time new value is requested from the provider.
@@ -305,7 +305,7 @@
         return '%s(%r)' % (type(self).__name__, self._callable)
 
 
-class InstanceProvider(Provider):
+class InstanceProvider(Provider, Generic[T]):
     """Provide a specific instance.
 
     ::
@@ -379,6 +379,13 @@
         return _get_origin(_punch_through_alias(self.interface)) in {dict, 
list}
 
 
+@private
+class ImplicitBinding(Binding):
+    """A binding that was created implicitly by auto-binding."""
+
+    pass
+
+
 _InstallableModuleType = Union[Callable[['Binder'], None], 'Module', 
Type['Module']]
 
 
@@ -392,7 +399,9 @@
     _bindings: Dict[type, Binding]
 
     @private
-    def __init__(self, injector: 'Injector', auto_bind: bool = True, parent: 
'Binder' = None) -> None:
+    def __init__(
+        self, injector: 'Injector', auto_bind: bool = True, parent: 
Optional['Binder'] = None
+    ) -> None:
         """Create a new Binder.
 
         :param injector: Injector we are binding for.
@@ -460,7 +469,7 @@
         self,
         interface: Type[List[T]],
         to: Union[List[T], Callable[..., List[T]], Provider[List[T]]],
-        scope: Union[Type['Scope'], 'ScopeDecorator'] = None,
+        scope: Union[Type['Scope'], 'ScopeDecorator', None] = None,
     ) -> None:  # pragma: no cover
         pass
 
@@ -469,12 +478,12 @@
         self,
         interface: Type[Dict[K, V]],
         to: Union[Dict[K, V], Callable[..., Dict[K, V]], Provider[Dict[K, V]]],
-        scope: Union[Type['Scope'], 'ScopeDecorator'] = None,
+        scope: Union[Type['Scope'], 'ScopeDecorator', None] = None,
     ) -> None:  # pragma: no cover
         pass
 
     def multibind(
-        self, interface: type, to: Any, scope: Union['ScopeDecorator', 
Type['Scope']] = None
+        self, interface: type, to: Any, scope: Union['ScopeDecorator', 
Type['Scope'], None] = None
     ) -> None:
         """Creates or extends a multi-binding.
 
@@ -555,7 +564,7 @@
         instance(self)
 
     def create_binding(
-        self, interface: type, to: Any = None, scope: Union['ScopeDecorator', 
Type['Scope']] = None
+        self, interface: type, to: Any = None, scope: Union['ScopeDecorator', 
Type['Scope'], None] = None
     ) -> Binding:
         provider = self.provider_for(interface, to)
         scope = scope or getattr(to or interface, '__scope__', NoScope)
@@ -643,12 +652,18 @@
             # The special interface is added here so that requesting a special
             # interface with auto_bind disabled works
             if self._auto_bind or self._is_special_interface(interface):
-                binding = self.create_binding(interface)
+                binding = ImplicitBinding(*self.create_binding(interface))
                 self._bindings[interface] = binding
                 return binding, self
 
         raise UnsatisfiedRequirement(None, interface)
 
+    def has_binding_for(self, interface: type) -> bool:
+        return interface in self._bindings
+
+    def has_explicit_binding_for(self, interface: type) -> bool:
+        return self.has_binding_for(interface) and not 
isinstance(self._bindings[interface], ImplicitBinding)
+
     def _is_special_interface(self, interface: type) -> bool:
         # "Special" interfaces are ones that you cannot bind yourself but
         # you can request them (for example you cannot bind 
ProviderOf(SomeClass)
@@ -782,10 +797,25 @@
         try:
             return self._context[key]
         except KeyError:
-            provider = InstanceProvider(provider.get(self.injector))
+            instance = self._get_instance(key, provider, self.injector)
+            provider = InstanceProvider(instance)
             self._context[key] = provider
             return provider
 
+    def _get_instance(self, key: Type[T], provider: Provider[T], injector: 
'Injector') -> T:
+        if injector.parent and not 
injector.binder.has_explicit_binding_for(key):
+            try:
+                return self._get_instance_from_parent(key, provider, 
injector.parent)
+            except (CallError, UnsatisfiedRequirement):
+                pass
+        return provider.get(injector)
+
+    def _get_instance_from_parent(self, key: Type[T], provider: Provider[T], 
parent: 'Injector') -> T:
+        singleton_scope_binding, _ = parent.binder.get_binding(type(self))
+        singleton_scope = singleton_scope_binding.provider.get(parent)
+        provider = singleton_scope.get(key, provider)
+        return provider.get(parent)
+
 
 singleton = ScopeDecorator(SingletonScope)
 
@@ -829,7 +859,7 @@
                             % (function.__name__, type(self), e)
                         ) from e
                     return_type = annotations['return']
-                    binding = function.__func__.__binding__ = Binding(
+                    binding = cast(Any, function.__func__).__binding__ = 
Binding(
                         interface=return_type, provider=binding.provider, 
scope=binding.scope
                     )
                 bind_method = binder.multibind if binding.is_multibinding() 
else binder.bind
@@ -864,9 +894,9 @@
 
     def __init__(
         self,
-        modules: Union[_InstallableModuleType, 
Iterable[_InstallableModuleType]] = None,
+        modules: Union[_InstallableModuleType, 
Iterable[_InstallableModuleType], None] = None,
         auto_bind: bool = True,
-        parent: 'Injector' = None,
+        parent: Optional['Injector'] = None,
     ) -> None:
         # Stack of keys currently being injected. Used to detect circular
         # dependencies.
@@ -896,7 +926,8 @@
     def _log_prefix(self) -> str:
         return '>' * (len(self._stack) + 1) + ' '
 
-    def get(self, interface: Type[T], scope: Union[ScopeDecorator, 
Type[Scope]] = None) -> T:
+    @synchronized(lock)
+    def get(self, interface: Type[T], scope: Union[ScopeDecorator, 
Type[Scope], None] = None) -> T:
         """Get an instance of the given interface.
 
         .. note::
@@ -940,7 +971,8 @@
         log.debug(
             '%sInjector.get(%r, scope=%r) using %r', self._log_prefix, 
interface, scope, binding.provider
         )
-        result = scope_instance.get(interface, binding.provider).get(self)
+        provider_instance = scope_instance.get(interface, binding.provider)
+        result = provider_instance.get(self)
         log.debug('%s -> %r', self._log_prefix, result)
         return result
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/injector_test.py 
new/injector-0.21.0/injector_test.py
--- old/injector-0.20.1/injector_test.py        2022-08-17 01:03:10.000000000 
+0200
+++ new/injector-0.21.0/injector_test.py        2023-07-27 02:44:06.000000000 
+0200
@@ -294,6 +294,141 @@
     a1 = injector1.get(A)
     a2 = injector1.get(A)
     assert a1.b is a2.b
+    assert a1 is not a2
+
+
+def test_injecting_an_auto_bound_decorated_singleton_class():
+    class A:
+        @inject
+        def __init__(self, b: SingletonB):
+            self.b = b
+
+    injector1 = Injector()
+    a1 = injector1.get(A)
+    a2 = injector1.get(A)
+    assert a1.b is a2.b
+    assert a1 is not a2
+
+
+def 
test_a_decorated_singleton_is_shared_between_parent_and_child_injectors_when_parent_creates_it_first():
+    parent_injector = Injector()
+
+    child_injector = parent_injector.create_child_injector()
+
+    assert parent_injector.get(SingletonB) is child_injector.get(SingletonB)
+
+
+def 
test_a_decorated_singleton_is_shared_between_parent_and_child_injectors_when_child_creates_it_first():
+    parent_injector = Injector()
+
+    child_injector = parent_injector.create_child_injector()
+
+    assert child_injector.get(SingletonB) is parent_injector.get(SingletonB)
+
+
+# Test for https://github.com/python-injector/injector/issues/207
+def test_a_decorated_singleton_is_shared_among_child_injectors():
+    parent_injector = Injector()
+
+    child_injector_1 = parent_injector.create_child_injector()
+    child_injector_2 = parent_injector.create_child_injector()
+
+    assert child_injector_1.get(SingletonB) is child_injector_2.get(SingletonB)
+
+
+def test_a_decorated_singleton_should_not_override_explicit_binds():
+    parent_injector = Injector()
+
+    child_injector = parent_injector.create_child_injector()
+    grand_child_injector = child_injector.create_child_injector()
+
+    bound_singleton = SingletonB()
+    child_injector.binder.bind(SingletonB, to=bound_singleton)
+
+    assert parent_injector.get(SingletonB) is not bound_singleton
+    assert child_injector.get(SingletonB) is bound_singleton
+    assert grand_child_injector.get(SingletonB) is bound_singleton
+
+
+def 
test_binding_a_singleton_to_a_child_injector_does_not_affect_the_parent_injector():
+    parent_injector = Injector()
+
+    child_injector = parent_injector.create_child_injector()
+    child_injector.binder.bind(EmptyClass, scope=singleton)
+
+    assert child_injector.get(EmptyClass) is child_injector.get(EmptyClass)
+    assert child_injector.get(EmptyClass) is not 
parent_injector.get(EmptyClass)
+    assert parent_injector.get(EmptyClass) is not 
parent_injector.get(EmptyClass)
+
+
+def test_a_decorated_singleton_should_not_override_a_child_provider():
+    parent_injector = Injector()
+
+    provided_instance = SingletonB()
+
+    class MyModule(Module):
+        @provider
+        def provide_name(self) -> SingletonB:
+            return provided_instance
+
+    child_injector = parent_injector.create_child_injector([MyModule])
+
+    assert child_injector.get(SingletonB) is provided_instance
+    assert parent_injector.get(SingletonB) is not provided_instance
+    assert parent_injector.get(SingletonB) is parent_injector.get(SingletonB)
+
+
+# Test for https://github.com/python-injector/injector/issues/207
+def 
test_a_decorated_singleton_is_created_as_close_to_the_root_where_dependencies_fulfilled():
+    class NonInjectableD:
+        @inject
+        def __init__(self, required) -> None:
+            self.required = required
+
+    @singleton
+    class SingletonC:
+        @inject
+        def __init__(self, d: NonInjectableD):
+            self.d = d
+
+    parent_injector = Injector()
+
+    child_injector_1 = parent_injector.create_child_injector()
+
+    child_injector_2 = parent_injector.create_child_injector()
+    child_injector_2_1 = child_injector_2.create_child_injector()
+
+    provided_d = NonInjectableD(required=True)
+    child_injector_2.binder.bind(NonInjectableD, to=provided_d)
+
+    assert child_injector_2_1.get(SingletonC) is 
child_injector_2.get(SingletonC)
+    assert child_injector_2.get(SingletonC).d is provided_d
+
+    with pytest.raises(CallError):
+        parent_injector.get(SingletonC)
+
+    with pytest.raises(CallError):
+        child_injector_1.get(SingletonC)
+
+
+def 
test_a_bound_decorated_singleton_is_created_as_close_to_the_root_where_it_exists_when_auto_bind_is_disabled():
+    parent_injector = Injector(auto_bind=False)
+
+    child_injector_1 = parent_injector.create_child_injector(auto_bind=False)
+
+    child_injector_2 = parent_injector.create_child_injector(auto_bind=False)
+    child_injector_2_1 = 
child_injector_2.create_child_injector(auto_bind=False)
+
+    child_injector_2.binder.bind(SingletonB)
+
+    assert child_injector_2_1.get(SingletonB) is 
child_injector_2_1.get(SingletonB)
+    assert child_injector_2_1.get(SingletonB) is 
child_injector_2.get(SingletonB)
+
+    with pytest.raises(UnsatisfiedRequirement):
+        parent_injector.get(SingletonB)
+
+    with pytest.raises(UnsatisfiedRequirement):
+        child_injector_1.get(SingletonB)
 
 
 def test_threadlocal():
@@ -627,7 +762,6 @@
 
 
 def test_custom_scope():
-
     injector = Injector([RequestModule()], auto_bind=False)
 
     with pytest.raises(UnsatisfiedRequirement):
@@ -819,7 +953,7 @@
 
 
 class TestThreadSafety:
-    def setup(self):
+    def setup_method(self):
         self.event = threading.Event()
 
         def configure(binder):
@@ -1433,6 +1567,30 @@
     assert injector.get(Data).name == 'data'
 
 
+def test_binder_does_not_have_a_binding_for_an_unbound_type():
+    injector = Injector()
+    assert not injector.binder.has_binding_for(int)
+    assert not injector.binder.has_explicit_binding_for(int)
+
+
+def test_binder_has_binding_for_explicitly_bound_type():
+    def configure(binder):
+        binder.bind(int, to=123)
+
+    injector = Injector([configure])
+    assert injector.binder.has_binding_for(int)
+    assert injector.binder.has_explicit_binding_for(int)
+
+
+def test_binder_has_implicit_binding_for_implicitly_bound_type():
+    injector = Injector()
+
+    injector.get(int)
+
+    assert injector.binder.has_binding_for(int)
+    assert not injector.binder.has_explicit_binding_for(int)
+
+
 def test_get_bindings():
     def function1(a: int) -> None:
         pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/requirements-dev.in 
new/injector-0.21.0/requirements-dev.in
--- old/injector-0.20.1/requirements-dev.in     1970-01-01 01:00:00.000000000 
+0100
+++ new/injector-0.21.0/requirements-dev.in     2023-07-27 02:44:06.000000000 
+0200
@@ -0,0 +1,14 @@
+# Our direct dependencies used in development/CI.
+#
+# We generate requirements-dev.txt from this file by running
+#
+#     pip install -r requirements-dev.in && pip freeze > requirements-dev.txt
+#
+# and then modifying the file manually to restrict black and mypy to CPython
+
+pytest
+pytest-cov>=2.5.1
+mypy;implementation_name=="cpython"
+black;implementation_name=="cpython"
+check-manifest
+typing_extensions>=3.7.4;python_version<"3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/injector-0.20.1/requirements-dev.txt 
new/injector-0.21.0/requirements-dev.txt
--- old/injector-0.20.1/requirements-dev.txt    2022-08-17 01:03:10.000000000 
+0200
+++ new/injector-0.21.0/requirements-dev.txt    2023-07-27 02:44:06.000000000 
+0200
@@ -1,6 +1,18 @@
-pytest
-pytest-cov>=2.5.1
-dataclasses;python_version<"3.7"
-mypy;implementation_name=="cpython"
-black;implementation_name=="cpython"
-check-manifest
+black==23.3.0;implementation_name=="cpython"
+build==0.10.0
+check-manifest==0.49
+click==8.1.3
+coverage==7.2.7
+exceptiongroup==1.1.1
+iniconfig==2.0.0
+mypy==1.4.1;implementation_name=="cpython"
+mypy-extensions==1.0.0
+packaging==23.1
+pathspec==0.11.1
+platformdirs==3.8.0
+pluggy==1.2.0
+pyproject_hooks==1.0.0
+pytest==7.4.0
+pytest-cov==4.1.0
+tomli==2.0.1
+typing_extensions==4.7.0

Reply via email to