From aafcec82d53d19c94e18523755de8e8ed269a9c6 Mon Sep 17 00:00:00 2001 From: Josh Orr Date: Wed, 2 Nov 2022 16:30:35 -0600 Subject: [PATCH] feat: renamed `resource()` into `grab()`, a simpler and more obvious name for what it does. --- README.md | 28 ++++++------ docs/advanced.md | 4 +- docs/dataclasses.md | 17 ++++--- docs/index.md | 16 +++---- pyproject.toml | 2 +- tests/test_context.py | 30 ++++++------ tests/test_resource.py | 20 ++++---- udepend/context.py | 98 ++++++++++++++++++++-------------------- udepend/dependency.py | 78 ++++++++++++++++---------------- udepend/proxy.py | 20 ++++---- udepend/pytest_plugin.py | 2 +- 11 files changed, 157 insertions(+), 158 deletions(-) diff --git a/README.md b/README.md index 82b60cb..a209371 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ from udepend import Dependency # This is a example Dependency class, the intent with this class is to treat -# it as a semi-singleton shared resource. +# it as a semi-singleton shared dependency/resource. class MyResource(Dependency): # It's important to allow resources to be allocated with @@ -129,29 +129,29 @@ class MyResource(Dependency): # # Next, we get value of `some_attribute` off of it. # Prints 'my-default-value' -print(MyResource.resource().name) +print(MyResource.grab().name) -# Change the value of the name attribute on current resource -MyResource.resource().name = 'changing-the-value' +# Change the value of the name attribute on current dependency +MyResource.grab().name = 'changing-the-value' # Now prints 'changing-the-value' -print(MyResource.resource().name) +print(MyResource.grab().name) -# You can temporarily override a resource via a python context manager: +# You can temporarily inject your own version of a dependency via a python context manager: with MyResource(name='my-temporary-name'): - # When someone askes for the current resource of `MyResource`, + # When someone asks for the current dependency of `MyResource`, # they will get back the one I created in `with` statement above. # # Now prints 'my-temporary-name' - print(MyResource.resource().name) + print(MyResource.grab().name) # Object we created and temporary activated by above `with` statement # has been deactivated (ie: thrown out). # Old one that was the active one previously is the one that is now used when -# the current resource for `MyResource` is asked for. +# the current dependency for `MyResource` is asked for. # # prints 'changing-the-value' -print(MyResource.resource().name) +print(MyResource.grab().name) ``` @@ -176,9 +176,9 @@ class DataResource(Dependency): another_optional_field: str = "hello!" -# Get current DataResource resource, print it's another_optional_field; +# Get current DataResource dependency, print it's another_optional_field; # will print out `hello!`: -print(DataResource.resource().another_optional_field) +print(DataResource.grab().another_optional_field) ``` ### Thread Safety @@ -237,7 +237,7 @@ from xyn_config import Config 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): +# (no imports are needed, just call the class method on any Dependency subclass): config = Config.resource_proxy() ``` @@ -255,7 +255,7 @@ active resource for `Config`. So it's the equivalent of doing this: ```python from xyn_config import Config -get_method = Config.resource().get +get_method = Config.grab().get value = get_method('some_config_var') ``` diff --git a/docs/advanced.md b/docs/advanced.md index 3a5ff58..e370196 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -56,7 +56,7 @@ from xyn_config import Config 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): +# (no imports are needed, just call the class method on any Dependency class): config = Config.resource_proxy() ``` @@ -74,7 +74,7 @@ active resource for `Config`. So it's the equivalent of doing this: ```python from xyn_config import Config -get_method = Config.resource().get +get_method = Config.grab().get value = get_method('some_config_var') ``` diff --git a/docs/dataclasses.md b/docs/dataclasses.md index 78308fe..27dd188 100644 --- a/docs/dataclasses.md +++ b/docs/dataclasses.md @@ -20,20 +20,19 @@ 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!" + # 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; +# Get current DataResource dependency, print it's another_optional_field; # will print out `hello!`: -print(DataResource.resource().another_optional_field) +print(DataResource.grab().another_optional_field) +DataResource.grab() -DataResource.depend() +DataResource.grab() -DataResource.dependency() - -DataResource.resource() +DataResource.grab() ``` diff --git a/docs/index.md b/docs/index.md index 3c0e6db..075210e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -41,7 +41,7 @@ Tge subclass will inherit some nice features that make it easier to use. from udepend import Dependency # This is an example Dependency class, the intent with this class -# is to treat it as a semi-singleton shared resource. +# is to treat it as a semi-singleton shared dependency. class MyUniversalDependency(Dependency): # It's important to allow resources to be allocated with @@ -61,28 +61,28 @@ class MyUniversalDependency(Dependency): # # Next, we get value of it's `name` attribute: -assert MyUniversalDependency.resource().name == 'original-value' +assert MyUniversalDependency.grab().name == 'original-value' -# Change the value of the name attribute on current resource -MyUniversalDependency.resource().name = 'changed-value' +# Change the value of the name attribute on current dependency +MyUniversalDependency.grab().name = 'changed-value' # We still have access to the same object, so it has the new value: -assert MyUniversalDependency.resource().name == 'changed-value' +assert MyUniversalDependency.grab().name == 'changed-value' # Inherit from Dependency allows you to use them as a context manager. # This allows you to easily/temporarily inject dependencies: with MyUniversalDependency(name='injected-value'): - # When someone asks for the current resource of `MyResource`, + # When someone asks for the current dependency of `MyResource`, # they will get the one I created in `with` statement above. - assert MyUniversalDependency.resource().name == 'injected-value' + assert MyUniversalDependency.grab().name == 'injected-value' # Object we created and temporary activated/injected # by above `with` statement has been deactivated/uninjected. # So, the previous object is what is now used: -assert MyUniversalDependency.resource().name == 'changed-value' +assert MyUniversalDependency.grab().name == 'changed-value' ``` There is also a way to get a proxy-object that represents the diff --git a/pyproject.toml b/pyproject.toml index d57a6b6..f32900d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.poetry.plugins] -# Pytest plugin to support automatic clearing of all current resource between each test. +# Pytest plugin to support automatic clearing of all current dependency resources between each test. pytest11 = {glazy_pytest_plugin = "glazy.pytest_plugin"} [tool.black] diff --git a/tests/test_context.py b/tests/test_context.py index 61a71db..f52c5b6 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -43,7 +43,7 @@ def test_ensure_pytest_plugin_context_autouse_fixture_working(): # instead of indirectly. @UContext(resources=[SomeDependency(my_name='first-name')]) def test_decorator_on_context_object(): - first_resource = SomeDependency.resource() + first_resource = SomeDependency.grab() assert first_resource.my_name == 'first-name' decorated_context = UContext.current() @@ -51,8 +51,8 @@ def test_decorator_on_context_object(): with UContext(resources=[new_resource]) as with_context: assert with_context is not decorated_context, "Should be new context" # I created new UContext and manually added new instance of SomeDependency; - # check to see if it's the current resource and looks intact. - inside_resource = SomeDependency.resource() + # check to see if it's the current dependency and looks intact. + inside_resource = SomeDependency.grab() assert inside_resource is not first_resource assert inside_resource is new_resource assert inside_resource.my_name == 'new-name' @@ -62,7 +62,7 @@ def test_decorator_on_context_object(): assert with_context is not decorated_context, "Should be new context" # Check to see if when adding new UContext, we still get the same SomeDependency # instance, and that they still look intact with the correct values. - assert SomeDependency.resource() is first_resource + assert SomeDependency.grab() is first_resource assert first_resource.my_name == 'first-name' assert new_resource.my_name == 'new-name' @@ -120,29 +120,29 @@ def test_module_level_context(glazy_test_context): # Ensure that when we used the module-level-context, ensure it still uses the current # context as it's first parent. the `create=False` will ensure it won't add this looked - # up resource to it's self. + # up dependency to it's self. assert module_level_context.resource(for_type=float, create=False) == 1.2 assert module_level_context is not UContext.current() - # Ensure that we have not float resource in the outer-module version (since create=False). + # Ensure that we have not float dependency in the outer-module version (since create=False). assert float not in module_level_context._resources # See if the copied-context has the same resources still - assert SomeDependency.resource().my_name == "start-name" + assert SomeDependency.grab().my_name == "start-name" assert UContext.current(for_type=int) == 20 assert UContext.current(for_type=str) == "hello-str" def test_initial_context_resources_with_dict(): my_context = UContext( - resources={int: 'string-as-int-resource', float: False, SomeDependency: 'str-instead'} + resources={int: 'string-as-int-dependency', float: False, SomeDependency: 'str-instead'} ) with my_context: # SomeDependency was replaced by a direct-string 'str-instead', testing replacing # resources with a completely different type (if you want to mock/test something specific). - assert SomeDependency.resource() == 'str-instead' - assert UContext.current(for_type=int) == 'string-as-int-resource' + assert SomeDependency.grab() == 'str-instead' + assert UContext.current(for_type=int) == 'string-as-int-dependency' assert UContext.current(for_type=float) is False @@ -157,7 +157,7 @@ class TestDependency(Dependency): my_name: str = 'hello!' -module_level_test_resource = TestDependency.resource() +module_level_test_resource = TestDependency.grab() print(module_level_test_resource) module_level_test_resource.my_name = "module-level-change" @@ -166,14 +166,14 @@ class TestDependency(Dependency): @pytest.mark.parametrize("test_run", [1, 2]) def test_module_level_resource_in_unit_test(test_run): # Make sure we have a different TestDependency instance. - assert module_level_test_resource is not TestDependency.resource() + assert module_level_test_resource is not TestDependency.grab() # Check values, see if they are still at the module-level value - assert TestDependency.resource().my_name == "hello!" + assert TestDependency.grab().my_name == "hello!" # Do a unit-test change, ensure we don't see it in another unit test. - TestDependency.resource().my_name = "unit-test-change" - assert TestDependency.resource().my_name == "unit-test-change" + TestDependency.grab().my_name = "unit-test-change" + assert TestDependency.grab().my_name == "unit-test-change" def test_each_unit_test_starts_with_a_single_parentless_root_like_context(): diff --git a/tests/test_resource.py b/tests/test_resource.py index d08fda6..cad32c5 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -45,8 +45,8 @@ def assert_myclass(param): assert my_class.my_method() == param assert my_class_via_proxy_method.my_prop == param assert my_class_via_proxy_method.my_method() == param - assert MyClass.resource().my_prop == param - assert MyClass.resource().my_method() == param + assert MyClass.grab().my_prop == param + assert MyClass.grab().my_method() == param def test_shared_threaded_resource(): @@ -59,11 +59,11 @@ class ThreadSharableDependency(Dependency): class NonThreadSharableResource(PerThreadDependency): hello2 = "a" - ThreadSharableDependency.resource().hello = "3" - NonThreadSharableResource.resource().hello2 = "b" + ThreadSharableDependency.grab().hello = "3" + NonThreadSharableResource.grab().hello2 = "b" - assert ThreadSharableDependency.resource().hello == "3" - assert NonThreadSharableResource.resource().hello2 == "b" + assert ThreadSharableDependency.grab().hello == "3" + assert NonThreadSharableResource.grab().hello2 == "b" thread_out_sharable = None thread_out_nonsharable = None @@ -74,12 +74,12 @@ def thread_func(): nonlocal thread_out_sharable nonlocal thread_out_nonsharable - # This should produce an '3', since resource can be shared between threads. - thread_out_sharable = ThreadSharableDependency.resource().hello + # This should produce an '3', since dependency can be shared between threads. + thread_out_sharable = ThreadSharableDependency.grab().hello - # This should produce an 'a', since the resource is NOT shared between threads; + # This should produce an 'a', since the dependency is NOT shared between threads; # the setting of it to 'b' above is in another thread and is NOT shared. - thread_out_nonsharable = NonThreadSharableResource.resource().hello2 + thread_out_nonsharable = NonThreadSharableResource.grab().hello2 import threading diff --git a/udepend/context.py b/udepend/context.py index be58769..ab4b387 100644 --- a/udepend/context.py +++ b/udepend/context.py @@ -32,8 +32,8 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a >>> class SomeResource(Dependency): >>> my_attribute = "default-value" >>> ->>> # Normally code would do this to interact with current resource object: ->>> SomeResource.resource().my_attribute = "change-value" +>>> # Normally code would do this to interact with current Dependency subclass object: +>>> SomeResource.grab().my_attribute = "change-value" Another convenient way to get the current resource is via the `glazy.resource.ActiveResourceProxy`. This class lets you create an object @@ -113,9 +113,9 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a The easiest way to get the current resource for the type in this case is to call `glazy.resource.Resource.resource` on it's type like so: ->>> SomeResourceType.resource().some_value +>>> SomeResourceType.grab().some_value 'hello!' ->>> SomeResourceType.resource().ident +>>> SomeResourceType.grab().ident 0 When a Context does not have the resource, by default it will create it for you, as you @@ -128,7 +128,7 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a and then ask it for the resource like below. This works for any type, including types that don't inherit from `glazy.resource.Resource`: ->>> UContext.current().resource(SomeResourceType).some_value +>>> UContext.current().grab(SomeResourceType).some_value 'hello!' If you pass a type into `Context.current`, it will do the above ^ for you: @@ -157,13 +157,13 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a >>> class MyResource(Dependency): >>> some_value = 'default-value' >>> ->>> assert MyResource.resource().some_value == 'default-value' +>>> assert MyResource.grab().some_value == 'default-value' - Use desired `glazy.resource.Resource` subclass as a method decorator: >>> @MyResource(some_value='new-value') >>> def my_method(): - >>> assert MyResource.resource().some_value == 'new-value' + >>> assert MyResource.grab().some_value == 'new-value' ## Activating New Context @@ -186,7 +186,7 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a Here are examples of the four ways to create/activate a new context: >>> with UContext(): -... SomeResourceType.resource().ident +... SomeResourceType.grab().ident 1 This is stack-able as well; as in this can keep track of a stack of contexts, in a @@ -198,12 +198,12 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a >>> @UContext(): >>> def a_decorated_method(): -... return SomeResourceType.resource().ident +... return SomeResourceType.grab().ident >>> a_decorated_method() 2 >>> a_decorated_method() 3 ->>> SomeResourceType.resource().ident +>>> SomeResourceType.grab().ident 0 As you can see, after the method exits the old context takes over, and it already had the @@ -216,7 +216,7 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a >>> UContext().make_current() ->>> SomeResourceType.resource().ident +>>> SomeResourceType.grab().ident 4 With the context test fixture, it creates a brand new parent-less context every time a test runs @@ -224,7 +224,7 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a >>> from udepend.fixtures import context >>> def test_some_text(context): -... SomeResourceType.resource() +... SomeResourceType.grab() @@ -280,20 +280,20 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a >>> class MySingleton(SomeResourceType, Dependency): ... pass ->>> MySingleton.resource().ident +>>> MySingleton.grab().ident 5 Now watch as I do this: >>> with UContext(): -... MySingleton.resource().ident +... MySingleton.grab().ident 5 The same resource is kept when making a child-context. However, if you make a parent-less context: >>> with UContext(parent=None): -... MySingleton.resource().ident +... MySingleton.grab().ident 6 The `glazy.resource.Resource` will not see pased the parent-less context, @@ -314,8 +314,8 @@ class provides a class method `glazy.resource.Resource.resource` to easily get a C = TypeVar('C') ResourceTypeVar = TypeVar('ResourceTypeVar') """ -Some sort of resource, I am usuallyemphasizingg with this that you need to pass in the -`Type` or `Class` of the resource you want. +Some sort of Dependency, I am usually emphasizing with this that you need to pass in the +`Type` or `Class` of the Dependency you want. """ @@ -615,7 +615,7 @@ def __init__( If you pass in None for parent, no parent will be used/consulted. Normally you'll only want to do this for a root context. Also, useful for unit testing to isolate testing - method resources from other unit tests. Right now, the unit-test resource isolation + method resources from other unit tests. Right now, the unit-test Dependency isolation happens automatically via an auto-use fixture (`udepend.ptest_plugin.glazy_test_context`). A non-activated context will return `guards.default.Default` as it's `UContext.parent` @@ -627,7 +627,7 @@ def __init__( `UContext` your creating have an initial list of resources you can pass them in here. - It can be a single resource, or a list of resources, or a mapping of resources. + It can be a single Dependency, or a list of resources, or a mapping of resources. Mainly useful for unit-testing, but could be useful elsewhere too. @@ -636,9 +636,9 @@ def __init__( If you use a dict/mapping, we will use the following for `UContext.add_resource`: - Dict-key as the `for_type' method parameter. - - Dict-value as the `resource` method parameter. + - Dict-value as the `Dependency` method parameter. - This allows you to map some standard resource type into a completely different + This allows you to map some standard Dependency type into a completely different type (useful for unit-testing). By default, no resources are initially added to a new UContext. @@ -738,11 +738,11 @@ def __init__( for for_type, resource in resources.items(): self.add_resource(resource, for_type=for_type) elif isinstance(resources, list): - # We have one or more resource values, add each one. + # We have one or more Dependency values, add each one. for resource in resources: self.add_resource(resource) elif resources is not None: - # Otherwise, we have a single resource value. + # Otherwise, we have a single Dependency value. self.add_resource(resources) # todo: Make it so if there is a parent context, and the current config has no property @@ -762,14 +762,14 @@ def add_resource( >>> >>> @UContext().add_resource(2) >>> def some_method() - ... print(f"my int resource: {UContext.resource(int)}") + ... print(f"my int dependency: {UContext.dependency(int)}") Output: "my int resource: 2" As as side-note, you can easily add resources to a new `Context` via: >>> @UContext(resources=[2]) >>> def some_method() - ... print(f"my int resource: {UContext.resource(int)}") + ... print(f"my int dependency: {UContext.dependency(int)}") Output: "my int resource: 2" With the `Context.add_resource` method, you can subsitute resource for other @@ -778,7 +778,7 @@ def add_resource( >>> def some_method() ... context = UContext() ... context.add_resource(3, for_type=str) - ... print(f"my str resource: {UContext.resource(str)}") + ... print(f"my str dependency: {UContext.dependency(str)}") Output: "my str resource: 3" If you need to override a resource, you can create a new context and set me as it's @@ -823,7 +823,7 @@ def add_resource( return self # todo: complete/figure out comment! # if not rep - raise XynResourceError(f"Trying to add resource ({resource}), but already have one!") + raise XynResourceError(f"Trying to add dependency ({resource}), but already have one!") self._resources[resource_type] = resource return self @@ -848,8 +848,8 @@ class provides a class method `udepend.resource.Resource.resource` to easily get >>> class SomeResource(Dependency): >>> pass - >>> # Normally code would do this to get current resource object: - >>> SomeResource.resource() + >>> # Normally code would do this to get current Dependency object: + >>> SomeResource.grab() Another convenient way to get the current resource is via the `udepend.resource.ActiveResourceProxy`. This class lets you create an object @@ -934,7 +934,7 @@ class provides a class method `udepend.resource.Resource.resource` to easily get return obj # If we are the root context for the entire app (ie: app-root between all threads) - # then we check to see if resource is thread-sharable. + # then we check to see if dependency is thread-sharable. # If it is then we continue as normal. # If NOT, then we always return None. # This will indicate to the thread-specific UContext that is calling us to allocate @@ -945,7 +945,7 @@ class provides a class method `udepend.resource.Resource.resource` to easily get # # In Reality, the only thing that should be calling the app-root context # is a thread-root context. Thread root-contexts should never return None when asked - # for a resource. + # for a dependency. # So, code using a Dependency in general should never have to worry about this None case. if self._is_root_context_for_app: from udepend import Dependency @@ -976,14 +976,14 @@ class provides a class method `udepend.resource.Resource.resource` to easily get if parent: parent_value = parent.resource(for_type, create=create) - # If we can't create the resource, we can ask the resoruce to potetially create more of + # If we can't create the dependency, we can ask the resoruce to potetially create more of # it's self. # We should also not put any value we find in self either. # Simply return the parent_value, whatever it is (None or otherwise) if not create: return parent_value - # We next create resource if we don't have an existing one. + # We next create dependency if we don't have an existing one. obj = self._create_or_reuse_resource(for_type=for_type, parent_value=parent_value) # Store in self for future reuse. @@ -998,15 +998,15 @@ def _create_or_reuse_resource( ) -> T: """ This tries to reuse parent_value if possible; - otherwise will create new resource of `for_type` and returns it. + otherwise will create new dependency of `for_type` and returns it. Args: for_type: A class/type to create if needed. parent_value: If `parent_value` is not None and inherits from `Dependency` will ask parent_value to decide if it wants to reuse it's self or create a - new resource object. + new dependency object. - See `udepend.resource.Dependency.context_resource_for_child` + See `udepend.dependency.Dependency.context_resource_for_child` for more details if you want to customize this behavior. """ from udepend import Dependency @@ -1015,20 +1015,20 @@ def _create_or_reuse_resource( if parent_value is None: return for_type() - # If we have a context-resource AND a parent_value; + # If we have a context-dependency AND a parent_value; # then ask parent_value Dependency to do whatever it wants to do. - # By default, `udepend.resource.Dependency.context_resource_for_child` + # By default, `udepend.dependency.Dependency.context_resource_for_child` # returns `self` - # to reuse resource value. + # to reuse dependency value. if parent_value and isinstance(parent_value, Dependency): return parent_value.context_resource_for_child(child_context=self) except TypeError as e: # Python will add the `e` as the `from` exception to this new one. raise XynResourceError( - f"I had trouble creating/getting resource ({for_type}) due to TypeError({e})." + f"I had trouble creating/getting dependency ({for_type}) due to TypeError({e})." ) - # If we have a parent value that is not a `udepend.resource.Dependency`; + # If we have a parent value that is not a `udepend.dependency.Dependency`; # default to reusing it: return parent_value @@ -1039,21 +1039,21 @@ def resource_chain( Returns a python generator yielding resources in self and in each parent; returns them in order. - This won't create a resource if none exist unless you pass True into `create`, so it's + This won't create a dependency if none exist unless you pass True into `create`, so it's possible for no results to be yielded if it's never been created and `create` == False. - .. warning:: This is mostly used by `udepend.resource.Dependency` subclasses + .. warning:: This is mostly used by `udepend.dependency.Dependency` subclasses (internally). - Not normally used elsewhere. It can help the udepend.resource.Dependency` + Not normally used elsewhere. It can help the udepend.dependency.Dependency` subclass to find it's list of parent resources to consult on it's own. Real Example: `xyn_config.config.Config` uses this to construct it's parent-chain. Args: - for_type (Type[ResourceTypeVar]): The resource type to look for. - create (bool): If we should create resource at each context if it does not already + for_type (Type[ResourceTypeVar]): The dependency type to look for. + create (bool): If we should create dependency at each context if it does not already exist. Yields: Generator[ResourceTypeVar, None, None]: Resources that were found in the self/parent @@ -1067,7 +1067,7 @@ def resource_chain( def __copy__(self): """ Makes a copy of self, gives an opportunity for resources to do something special while they are copied if needed via - `udepend.resource.Dependency.context_resource_for_copy`. + `udepend.dependency.Dependency.context_resource_for_copy`. We copy `UContext` implicitly and make that copy the 'active' context when it's made current/activated via a: @@ -1104,7 +1104,7 @@ def __copy__(self): # Copy current resources from self into new UContext; # This uses `self` as a template for the new UContext. # See doc comment on: `UContext.__call__` and - # `udepend.resource.Dependency.context_resource_for_copy`. + # `udepend.dependency.Dependency.context_resource_for_copy`. new_resources = {} for k, v in self._resources.items(): if isinstance(v, Dependency): @@ -1172,7 +1172,7 @@ def __enter__(self, use_a_copy_of_self: bool = True): You MUST ensure that a context that is directly activated and with no copy made is not currently active right now. - Generally, `udepend.resource.Dependency.__enter__` will set to this + Generally, `udepend.dependency.Dependency.__enter__` will set to this False because it always creates a blank context just for it's self. No need to create two context's. """ diff --git a/udepend/dependency.py b/udepend/dependency.py index 81b9af4..3f2a643 100644 --- a/udepend/dependency.py +++ b/udepend/dependency.py @@ -54,9 +54,9 @@ An easy way to get the current resource for the type in this case is to call the class method `Resource.resource` on its type like so: ->>> SomeResourceType.resource().some_value +>>> SomeResourceType.grab().some_value 'hello!' ->>> SomeResourceType.resource().ident +>>> SomeResourceType.grab().ident 0 ### Activating New Resource @@ -76,13 +76,13 @@ >>> class MyResource(Dependency): >>> some_value = 'default-value' >>> ->>> assert MyResource.resource().some_value == 'default-value' +>>> assert MyResource.grab().some_value == 'default-value' - Use desired `glazy.resource.Resource` subclass as a method decorator: >>> @MyResource(some_value='new-value') >>> def my_method(): - >>> assert MyResource.resource().some_value == 'new-value' + >>> assert MyResource.grab().some_value == 'new-value' ## Active Resource Proxy @@ -164,7 +164,7 @@ class Dependency: >>> class MyConfig(Dependency): ... some_setting: str = "default-setting-string" >>> - >>> MyConfig.resource().some_setting + >>> MyConfig.grab().some_setting By default, Resource's act like a singletons; in that child contexs will simply get the same instance of the resource that the parent context has. @@ -191,7 +191,7 @@ class Dependency: >>> class MyResource(Dependency): >>> pass >>> - >>> MyResource.resource() + >>> MyResource.grab() When that last line is executed, and the current or any parent context has a `MyResource` resource; `UContext` will simply create one via calling the resource type: @@ -266,8 +266,8 @@ class Dependency: This can be dynamic if needed, by default it's consulted on the object each time it's copied - (to see where it's used, look at `udepend.resource.Dependency.__copy__` and - `udepend.resource.Dependency.__deepcopy__`) + (to see where it's used, look at `udepend.dependency.Dependency.__copy__` and + `udepend.dependency.Dependency.__deepcopy__`) """ resource_thread_safe = True @@ -280,15 +280,15 @@ class Dependency: It accomplishes this by the lazy-creation mechanism. When something asks for a Dependency that does not currently exist, - the parent-UContext is asked for the resource, and then the parent's parent will be + the parent-UContext is asked for the dependency, and then the parent's parent will be asked and so on. Eventually the app-root context will be asked for the Dependency. If the app-root already has the Dependency, it will return it. - When app-root does not have the resource, it potentially needs to lazily create the - resource depending on if Dependency is thread-safe. + When app-root does not have the dependency, it potentially needs to lazily create the + dependency depending on if Dependency is thread-safe. So at this point, if `resource_thread_safe` value is (as a class attribute): @@ -316,7 +316,7 @@ class Dependency: """ @classmethod - def resource(cls: Type[T], for_context: UContext = Default) -> T: + def grab(cls: Type[T], for_context: UContext = Default) -> T: """ Gets a potentially shared resource from the current `UContext`. If context is Default/False [default], uses the current context. @@ -329,7 +329,7 @@ def resource(cls: Type[T], for_context: UContext = Default) -> T: ... def get_resource_via(self, some_key: str) -> SomeResourceType: ... # Lookup and return something ... pass - >>> SomeResourceManager.resource().get_resource_via("some-hash-key") + >>> SomeResourceManager.grab().get_resource_via("some-hash-key") SomeResourceType(ident: ...) """ if not for_context: @@ -345,7 +345,7 @@ def resource_proxy(cls: Type[R]) -> R: def context_resource_for_child(self, child_context: UContext): """ - Called by `Context` when it does not have a resource of a particular type but it does + Called by `Context` when it does not have a dependency of a particular type but it does have a value from a parent-context (via it's parent-chain). Gives opportunity for the `Dependency` to do something special if it wants. @@ -360,26 +360,26 @@ def context_resource_for_child(self, child_context: UContext): You can think of this as making a `Dependency` act like a singleton by default, as only one instance (at the root-context) would ever 'normally' be created. - It's still possible to get a second instance of the resource, however: + It's still possible to get a second instance of the dependency, however: - - If someone created a new resource themselves manually and adds it to a new Context + - If someone created a new dependency themselves manually and adds it to a new Context and then activates the context, - that resource they created and added themselves could be a second instance. - (for more details, see [Activating New Dependency](#activating-new-resource)) + that dependency they created and added themselves could be a second instance. + (for more details, see [Activating New Dependency](#activating-new-dependency)) THis is because the Dependency that was manually created was not given an opportunity to reused the parent value. However, this is usually desirable as whatever manually created the object probably - wants to override the resource with it's own configured object. + wants to override the dependency with it's own configured object. - If a new `Context` was created at some point later via `Context(parent=None)` - and then activated. When a resource is next asked for, it must create a new one as + and then activated. When a dependency is next asked for, it must create a new one as any previous `Context` would be unreachable until the context was deactivated. (for more details, see [Activating New Context](#activating-new-context)) Args: - child_context (UContext): A child context that is needing the resource. + child_context (UContext): A child context that is needing the dependency. """ return self @@ -391,13 +391,13 @@ def context_resource_for_copy( decorator it will copy it's self for use during the `with` statement (ie: it will act as sort of a `template`). - It will go though and call this method on each resource in the original 'template' context. + It will go though and call this method on each dependency in the original 'template' context. By default we simply return self (by default, UContext resources generally try to maintain themselves as singletons). If a `Dependency` needs to do more, they can override us - - `Dependency.context_resource_for_copy`: Overridable by a resource if non-singleton + - `Dependency.context_resource_for_copy`: Overridable by a dependency if non-singleton (or other behavior) is desired. """ return self @@ -413,10 +413,10 @@ def __copy__(self): If you want different behavior, then override. - A resource could also use `deepcopy` instead when making a copy, if desirable. + A dependency could also use `deepcopy` instead when making a copy, if desirable. - Copying a resource may be useful if you want activate a new resource but have it's - configuration similar to a current resource (with some tweaks/modifications). + Copying a dependency may be useful if you want activate a new dependency but have it's + configuration similar to a current dependency (with some tweaks/modifications). """ clone = type(self)() dict_copy = self.__dict__.copy() @@ -467,7 +467,7 @@ def __deepcopy__(self, memo=None): _context_manager_stack: List[UContext] = None """ Keeps track of context's we created when self (ie: `Dependency`) is used in a `with` - statement. This MUST be reset when doing a copy of the resource. + statement. This MUST be reset when doing a copy of the dependency. """ def __enter__(self: R) -> R: @@ -516,9 +516,9 @@ def __call__(self, func = None): I will raise an error with a descriptive error message if we don't get a callable. We should get a callable if Resource subclass is used like in the example below. - (Config being a resource subclass). + (Config being a dependency subclass). - In this example, a new Config resource is being created and we tell it to only use + In this example, a new Config dependency is being created and we tell it to only use the `EnvironmentalProvider` and we use it as a function decorator. This means while the `some_method` function is executing, that Config object is made the current one. @@ -553,11 +553,11 @@ def __call__(self, func = None): if not callable(func): raise XynResourceError( f"Attempt to calling a Dependency of type ({self}) as a callable function. " - f"By default (unless resource subclass does/says otherwise) you need to use " + f"By default (unless dependency subclass does/says otherwise) you need to use " f"it as a decorator when calling it. " f"When using a Dependency subclass as a decorator, Python will call the Dependency " - f"and pass in a callable function. The resource will then make self the current " - f"resource via `with self` and call the passed in function inside that with " + f"and pass in a callable function. The dependency will then make self the current " + f"dependency via `with self` and call the passed in function inside that with " f"statement, returning the result of calling the passed in function." ) @@ -574,12 +574,12 @@ class PerThreadDependency(Dependency): this means when an instance of us is created by the system lazily, it will not be shared between threads. - Basically, when some other thread asks for this resource, + Basically, when some other thread asks for this dependency, the system will lazily create another one just for that thread to use. - This happens when a particular thread asks for the resource for the first time. + This happens when a particular thread asks for the dependency for the first time. - When the same thread asks for the resource a second time, it will not create a new one but - return the resource instance that was originally created just for that thread. + When the same thread asks for the dependency a second time, it will not create a new one but + return the dependency instance that was originally created just for that thread. ## Details @@ -588,15 +588,15 @@ class PerThreadDependency(Dependency): which each thread's root-context has set as its parent. This makes the object available to be seen/used by other threads. - When a resource makes a subclass from `PerThreadDependency` or otherwise set's + When a dependency makes a subclass from `PerThreadDependency` or otherwise set's the `Dependency.resource_thread_safe` to False at the Dependency class-level. - When a thread asks for that resource for first time it will be lazily created like expected, + When a thread asks for that dependency for first time it will be lazily created like expected, but the resulting object is placed in the root-context instead (and NOT the app-root-context). That way, only the specific thread the Dependency was lazily created on will see the object; no other thread will. - Therefore, when other threads also ask for the resource, they will each create their own + Therefore, when other threads also ask for the dependency, they will each create their own the first time they ask for it, and place it in their thread-root `udepend.context.UContext`. """ diff --git a/udepend/proxy.py b/udepend/proxy.py index 76b88da..6a3685c 100644 --- a/udepend/proxy.py +++ b/udepend/proxy.py @@ -4,12 +4,12 @@ It will in reality, always lookup currently active version of a Dependency and use that each time it's asked anything. -This makes it 'act' like the current version of some resource, +This makes it 'act' like the current version of some dependency, code and just use it like a normal object. See one of these for more details: -- [Active Dependency Proxy - pydoc](./#active-resource-proxy) +- [Active Dependency Proxy - pydoc](./#active-dependency-proxy) - [Active Dependency Proxy - github] (https://github.com/xyngular/py-glazy#active-resource-proxy) @@ -33,7 +33,7 @@ class ActiveResourceProxy(Generic[R]): Typically, to access attributes of a particular Rsource subclass you would have to do this: - >>> MyClass.resource().my_method() + >>> MyClass.dependency().my_method() With ProxyActive you can do this instead: @@ -66,7 +66,7 @@ def wrap(cls, resource_type: Type[R]) -> R: into this method. A simpler/alternate way to wrap a Dependency with a `ActiveResourceProxy` is via the - `udepend.resource.Dependency.resource_proxy` convenience method. + `udepend.dependency.Dependency.resource_proxy` convenience method. """ # noinspection PyTypeChecker return cls(resource_type=resource_type) @@ -82,13 +82,13 @@ def __init__(self, resource_type: Type[R], grabber: Callable[[R], Any] = None): Will act like the current/active object of Dependency type `resource_type`. you can optionally provide a grabber function, that will be called with the current - resource passed to it. You can then grab something from that resource and return it. + dependency passed to it. You can then grab something from that dependency and return it. If you pass in a grabber function, this ProxyActive will act like a proxy of whatever is returned from the grabber method. Args: - resource_type: Type of resource to proxy. - grabber: Optional callable, if you wish to grab a specific attribute off the resource + resource_type: Type of dependency to proxy. + grabber: Optional callable, if you wish to grab a specific attribute off the dependency and act like a proxy for that, you can pass in a method here to do so. Whatever is returned from the grabber is what is used to as the object to 'proxy'. """ @@ -105,8 +105,8 @@ def __init__(self, resource_type: Type[R], grabber: Callable[[R], Any] = None): pass def _get_active(self): - # Get current/active instance of resource type - value = self._resource_type.resource() + # Get current/active instance of dependency type + value = self._resource_type.grab() if self._grabber: return self._grabber(value) return value @@ -125,5 +125,5 @@ def __setattr__(self, key, value): # and not on the current config object. return super().__setattr__(key, value) - # Otherwise, we set it on the current/active resource object. + # Otherwise, we set it on the current/active dependency object. return setattr(self._get_active(), key, value) diff --git a/udepend/pytest_plugin.py b/udepend/pytest_plugin.py index 2817192..3bc747e 100644 --- a/udepend/pytest_plugin.py +++ b/udepend/pytest_plugin.py @@ -58,6 +58,6 @@ def glazy_test_context(): # Yield the current thread-root context as the fixture-value. yield UContext.current() - # Ensure app+thread root-contexts do not have leftover resource objects from unit test. + # Ensure app+thread root-contexts do not have leftover dependency objects from unit test. _setup_blank_app_and_thread_root_contexts_globals()