This is my package structure:
.
├── src
│ ├── damastes
│ │ ├── __init__.py
│ │ ├── main.py
│ │ └── run.py
__init__.py
:
from .run import *
run.py
:
...
_ARGS
...
def _path_compare(path_x: Path, path_y: Path) -> Ord:
return (
...
if _ARGS.sort_lex
else ...
)
...
def run()
...
I can import whatever I wish from the run
module, but not the module run
itself. It did not inconvenience me until I had to provide the module for monkey patching:
test.py
:
from src.damastes.run import _path_compare
...
def test_path_compare(monkeypatch):
args = RestrictedDotDict(copy.deepcopy(CLEAN_CONTEXT_PARAMS))
args.sort_lex = True
monkeypatch.setattr(src.damastes.run, "_ARGS", args)
assert _path_compare("alfa", "alfa") == 0
My trouble is that monkeypatch.setattr()
requires module as a first parameter, but I can't supply it. src.damastes.run
is actually a function. As it should be. The "short-circuit" is intentional.
The error:
AttributeError: <function run at 0x7f3392b9f790> has no attribute '_ARGS'
Experimentally, I supply src.damastes
:
AttributeError: <module 'src.damastes' from '/src/damastes/__init__.py'> has no attribute '_ARGS'
Of course it has not. Is there a way to supply the run
module to monkeypatch.setattr()
without restructuring the existing package/import solution?
from src.damastes.run import _path_compare
part somehow works, by the way.
Given that from src.damastes.run import _path_compare
works, it's clear that src.damastes.run
is a valid module identifier.
But it looks like the run
function is shadowing the run
module. So consider using one of these tricks to access the module specifically:
from src.damastes.run import _path_compare
# Consider using the sys.modules.
# This is a dictionary that maps module names to modules which have already been loaded.
# this should work because of the `from src.damastes.run import ...` statement above
import sys
run_module = sys.modules["src.damastes.run"]
# or you could use the `importlib` module:
import importlib
run_module = importlib.import_module("src.damastes.run")
# Once you have the module bound to a variable
# you can patch it:
monkeypatch.setattr(run_module, "_ARGS", "TESTING!")
assert run_module._ARGS == "TESTING!"