mirror of
https://github.com/emilybache/GildedRose-Refactoring-Kata.git
synced 2026-02-08 03:01:24 +00:00
84 lines
2.3 KiB
Python
84 lines
2.3 KiB
Python
from operator import setitem
|
|
from typing import Any, Callable, Optional, Tuple
|
|
|
|
from testfixtures import not_there
|
|
|
|
|
|
# Should be Literal[setattr, getattr] but Python 3.8 only.
|
|
Setter = Callable[[Any, str, Any], None]
|
|
|
|
|
|
class Resolved:
|
|
|
|
def __init__(self, container: Any, setter: Setter, name: str, found: Any):
|
|
self.container: Any = container
|
|
self.setter: Setter = setter
|
|
self.name: str = name
|
|
self.found: Any = found
|
|
|
|
def key(self) -> Tuple[int, Setter, str]:
|
|
return id(self.container), self.setter, self.name
|
|
|
|
def __repr__(self):
|
|
return f'<Resolved: {self.found}>'
|
|
|
|
|
|
def resolve(dotted_name: str, container: Optional[Any] = None, sep: str = '.') -> Resolved:
|
|
names = dotted_name.split(sep)
|
|
used = names.pop(0)
|
|
if container is None:
|
|
found = __import__(used)
|
|
container = found
|
|
else:
|
|
assert not used, 'Absolute traversal not allowed when container supplied'
|
|
used = ''
|
|
found = container
|
|
setter = None
|
|
name = None
|
|
for name in names:
|
|
container = found
|
|
used += '.' + name
|
|
try:
|
|
found = getattr(found, name)
|
|
setter = setattr
|
|
except AttributeError:
|
|
try:
|
|
if sep != '.':
|
|
raise ImportError
|
|
__import__(used)
|
|
except ImportError:
|
|
setter = setitem
|
|
try:
|
|
found = found[name] # pragma: no branch
|
|
except KeyError:
|
|
found = not_there # pragma: no branch
|
|
except TypeError:
|
|
try:
|
|
name = int(name)
|
|
except ValueError:
|
|
setter = setattr
|
|
found = not_there
|
|
else:
|
|
found = found[name] # pragma: no branch
|
|
else:
|
|
found = getattr(found, name)
|
|
setter = getattr
|
|
if found is not_there:
|
|
break
|
|
return Resolved(container, setter, name, found)
|
|
|
|
|
|
class _Reference:
|
|
|
|
@classmethod
|
|
def classmethod(cls): # pragma: no cover
|
|
pass
|
|
|
|
@staticmethod
|
|
def staticmethod(cls): # pragma: no cover
|
|
pass
|
|
|
|
|
|
class_type = type(_Reference)
|
|
classmethod_type = type(_Reference.classmethod)
|