Skip to content

Commit

Permalink
fix: fixes a bug where if you activate a dependency before the thread…
Browse files Browse the repository at this point in the history
…-root context is created.
  • Loading branch information
joshorr committed Dec 13, 2022
1 parent e775c81 commit 0bb778c
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ in an easy to understand and self-documenting way.

# Documentation

**[📄 Detailed Documentation](https://xyngular.github.io/py-xinject/latest/)** | **[🐍 PyPi](https://pypi.org/project/py-xinject/)**
**[📄 Detailed Documentation](https://xyngular.github.io/py-xinject/latest/)** | **[🐍 PyPi](https://pypi.org/project/xinject/)**

# Install

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Lazy dependency injection."
authors = ["Josh Orr <[email protected]>"]
packages = [{include = "xinject"}]
readme = "README.md"
license = "MIT-0"
license = "MIT"
repository = "https://github.com/xyngular/py-xinject"
keywords = ["dependency", "injection", "lazy", "resource"]
classifiers = [
Expand Down
21 changes: 21 additions & 0 deletions tests/test_dependency.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import dataclasses

import pytest as pytest

from xinject import CurrentDependencyProxy, XContext, Dependency
from xinject.context import _setup_blank_app_and_thread_root_contexts_globals
from xinject.dependency import DependencyPerThread


Expand Down Expand Up @@ -99,3 +102,21 @@ def thread_func():
# Check to see if the thread safe/unsafe dependencies worked correctly.
assert thread_out_sharable == "3"
assert thread_out_nonsharable == "a"


def test_dep_as_decorator():
@dataclasses.dataclass
class MyDep(Dependency):
some_value: str = 'my-value'

# This ensures we don't have any thread-root context's,
# which is important for testing to make sure a specific bug is fixed.
# (the pytest-plugin already creates a blank thread-root-context for us, so we clear it again here)
_setup_blank_app_and_thread_root_contexts_globals()

@MyDep(some_value='new-value')
def my_func():
return MyDep.grab().some_value

assert my_func() == 'new-value'

40 changes: 19 additions & 21 deletions xinject/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,23 +438,21 @@ def _make_current_and_get_reset_token(
Only returns None when this is True.
"""
if is_thread_root_context:
# For debugging purposes, so you know which one was truly the thread-root context
# if there is another root-like-context made (for unit tests).
self._is_root_context_for_thread = True
assert self._parent is Default, "See my methods doc-comment for details."

if is_app_root_context:
self._is_root_context_for_app = True
assert self._parent is _TreatAsRootParent, "See my methods doc-comment for details."
elif is_thread_root_context:
# For debugging purposes, so you know which one was truly the thread-root context
# if there is another root-like-context made (for unit tests).
self._is_root_context_for_thread = True

# We set parent to use app-root-context if we are the thread-root-context.
self._parent = _app_root_context

if self._parent is Default:
# Side Note: This will be `None` if we are the first XContext on current thread.
self._parent = XContext._current_without_creating_thread_root()

if self._parent is None:
# We set parent to use app-root-context if we are the thread-root-context.
self._parent = _app_root_context
self._parent = XContext.grab()
elif self._parent is _TreatAsRootParent:
# When you activate a context who should be treated as root, we have a None
# parent and we set `_originally_passed_none_for_parent` to False
Expand Down Expand Up @@ -522,17 +520,17 @@ def parent(self) -> Optional["XContext"]:
if parent in (_TreatAsRootParent, None):
return None

raise XInjectError(
f"Somehow we have a XContext that is not active "
f"(ie: ever activated via decorator `@` or via `with` or activating a "
f"`xinject.dependency.Dependency` via `@` or `with`) but has a specific parent "
f"(ie: not None or _TreatAsRootParent or Default). "
f"This indicates some sort of programming error or bug with XContext. "
f"A XContext should only have an explicit parent if they have "
f"been activated via `@` or `with` or activating a `xinject.dependency.Dependency` "
f"via `@` or `with` "
f"(side note: you can look at XContext._is_active for more internal details)."
)
# raise XInjectError(
# f"Somehow we have a XContext that is not active "
# f"(ie: ever activated via decorator `@` or via `with` or activating a "
# f"`xinject.dependency.Dependency` via `@` or `with`) but has a specific parent "
# f"(ie: not None or _TreatAsRootParent or Default). "
# f"This indicates some sort of programming error or bug with XContext. "
# f"A XContext should only have an explicit parent if they have "
# f"been activated via `@` or `with` or activating a `xinject.dependency.Dependency` "
# f"via `@` or `with` "
# f"(side note: you can look at XContext._is_active for more internal details)."
# )

@property
def name(self) -> str:
Expand Down

0 comments on commit 0bb778c

Please sign in to comment.