Skip to content

Commit

Permalink
Merge pull request #517 from Salehbigdeli/Bugfix-patch-classmethod-in…
Browse files Browse the repository at this point in the history
…heritance
  • Loading branch information
jph00 authored Apr 26, 2024
2 parents c435c31 + 93c6d9c commit c5e6754
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 47 deletions.
3 changes: 3 additions & 0 deletions fastcore/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@
'fastcore.basics._SelfCls.__getattr__': ('basics.html#_selfcls.__getattr__', 'fastcore/basics.py'),
'fastcore.basics._SelfCls.__getitem__': ('basics.html#_selfcls.__getitem__', 'fastcore/basics.py'),
'fastcore.basics._access': ('basics.html#_access', 'fastcore/basics.py'),
'fastcore.basics._clsmethod': ('basics.html#_clsmethod', 'fastcore/basics.py'),
'fastcore.basics._clsmethod.__get__': ('basics.html#_clsmethod.__get__', 'fastcore/basics.py'),
'fastcore.basics._clsmethod.__init__': ('basics.html#_clsmethod.__init__', 'fastcore/basics.py'),
'fastcore.basics._eval_type': ('basics.html#_eval_type', 'fastcore/basics.py'),
'fastcore.basics._get_op': ('basics.html#_get_op', 'fastcore/basics.py'),
'fastcore.basics._ispy3_10': ('basics.html#_ispy3_10', 'fastcore/basics.py'),
Expand Down
39 changes: 22 additions & 17 deletions fastcore/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,11 @@ def copy_func(f):
return fn

# %% ../nbs/01_basics.ipynb 366
class _clsmethod:
def __init__(self, f): self.f = f
def __get__(self, _, f_cls): return MethodType(self.f, f_cls)

# %% ../nbs/01_basics.ipynb 367
def patch_to(cls, as_prop=False, cls_method=False):
"Decorator: add `f` to `cls`"
if not isinstance(cls, (tuple,list)): cls=(cls,)
Expand All @@ -946,52 +951,52 @@ def _inner(f):
for o in functools.WRAPPER_ASSIGNMENTS: setattr(nf, o, getattr(f,o))
nf.__qualname__ = f"{c_.__name__}.{nm}"
if cls_method:
setattr(c_, nm, MethodType(nf, c_))
setattr(c_, nm, _clsmethod(nf))
else:
setattr(c_, nm, property(nf) if as_prop else nf)
# Avoid clobbering existing functions
return globals().get(nm, builtins.__dict__.get(nm, None))
return _inner

# %% ../nbs/01_basics.ipynb 377
# %% ../nbs/01_basics.ipynb 378
def patch(f=None, *, as_prop=False, cls_method=False):
"Decorator: add `f` to the first parameter's class (based on f's type annotations)"
if f is None: return partial(patch, as_prop=as_prop, cls_method=cls_method)
ann,glb,loc = get_annotations_ex(f)
cls = union2tuple(eval_type(ann.pop('cls') if cls_method else next(iter(ann.values())), glb, loc))
return patch_to(cls, as_prop=as_prop, cls_method=cls_method)(f)

# %% ../nbs/01_basics.ipynb 385
# %% ../nbs/01_basics.ipynb 386
def patch_property(f):
"Deprecated; use `patch(as_prop=True)` instead"
warnings.warn("`patch_property` is deprecated and will be removed; use `patch(as_prop=True)` instead")
cls = next(iter(f.__annotations__.values()))
return patch_to(cls, as_prop=True)(f)

# %% ../nbs/01_basics.ipynb 387
# %% ../nbs/01_basics.ipynb 390
def compile_re(pat):
"Compile `pat` if it's not None"
return None if pat is None else re.compile(pat)

# %% ../nbs/01_basics.ipynb 389
# %% ../nbs/01_basics.ipynb 392
class ImportEnum(enum.Enum):
"An `Enum` that can have its values imported"
@classmethod
def imports(cls):
g = sys._getframe(1).f_locals
for o in cls: g[o.name]=o

# %% ../nbs/01_basics.ipynb 392
# %% ../nbs/01_basics.ipynb 395
class StrEnum(str,ImportEnum):
"An `ImportEnum` that behaves like a `str`"
def __str__(self): return self.name

# %% ../nbs/01_basics.ipynb 394
# %% ../nbs/01_basics.ipynb 397
def str_enum(name, *vals):
"Simplified creation of `StrEnum` types"
return StrEnum(name, {o:o for o in vals})

# %% ../nbs/01_basics.ipynb 396
# %% ../nbs/01_basics.ipynb 399
class Stateful:
"A base class/mixin for objects that should not serialize all their state"
_stateattrs=()
Expand All @@ -1011,37 +1016,37 @@ def _init_state(self):
"Override for custom init and deserialization logic"
self._state = {}

# %% ../nbs/01_basics.ipynb 402
# %% ../nbs/01_basics.ipynb 405
class PrettyString(str):
"Little hack to get strings to show properly in Jupyter."
def __repr__(self): return self

# %% ../nbs/01_basics.ipynb 408
# %% ../nbs/01_basics.ipynb 411
def even_mults(start, stop, n):
"Build log-stepped array from `start` to `stop` in `n` steps."
if n==1: return stop
mult = stop/start
step = mult**(1/(n-1))
return [start*(step**i) for i in range(n)]

# %% ../nbs/01_basics.ipynb 410
# %% ../nbs/01_basics.ipynb 413
def num_cpus():
"Get number of cpus"
try: return len(os.sched_getaffinity(0))
except AttributeError: return os.cpu_count()

defaults.cpus = num_cpus()

# %% ../nbs/01_basics.ipynb 412
# %% ../nbs/01_basics.ipynb 415
def add_props(f, g=None, n=2):
"Create properties passing each of `range(n)` to f"
if g is None: return (property(partial(f,i)) for i in range(n))
return (property(partial(f,i), partial(g,i)) for i in range(n))

# %% ../nbs/01_basics.ipynb 415
# %% ../nbs/01_basics.ipynb 418
def _typeerr(arg, val, typ): return TypeError(f"{arg}=={val} not {typ}")

# %% ../nbs/01_basics.ipynb 416
# %% ../nbs/01_basics.ipynb 419
def typed(f):
"Decorator to check param and return types at runtime"
names = f.__code__.co_varnames
Expand All @@ -1058,21 +1063,21 @@ def _f(*args,**kwargs):
return res
return functools.update_wrapper(_f, f)

# %% ../nbs/01_basics.ipynb 424
# %% ../nbs/01_basics.ipynb 427
def exec_new(code):
"Execute `code` in a new environment and return it"
pkg = None if __name__=='__main__' else Path().cwd().name
g = {'__name__': __name__, '__package__': pkg}
exec(code, g)
return g

# %% ../nbs/01_basics.ipynb 426
# %% ../nbs/01_basics.ipynb 429
def exec_import(mod, sym):
"Import `sym` from `mod` in a new environment"
# pref = '' if __name__=='__main__' or mod[0]=='.' else '.'
return exec_new(f'from {mod} import {sym}')

# %% ../nbs/01_basics.ipynb 427
# %% ../nbs/01_basics.ipynb 430
def str2bool(s):
"Case-insensitive convert string `s` too a bool (`y`,`yes`,`t`,`true`,`on`,`1`->`True`)"
if not isinstance(s,str): return bool(s)
Expand Down
Loading

0 comments on commit c5e6754

Please sign in to comment.