Skip to content

Instantly share code, notes, and snippets.

@apua
Created October 7, 2023 08:12
Show Gist options
  • Save apua/19fea59748fa66d0c87a82e9fef952ef to your computer and use it in GitHub Desktop.
Save apua/19fea59748fa66d0c87a82e9fef952ef to your computer and use it in GitHub Desktop.

命題: https://x.com/pipichih/status/1709248514033909778

Improved

from functools import partial
from inspect import signature
from os.path import join


class PathDef:
    @staticmethod
    def scope(project):
        return ScopedPathDef(project)

    @staticmethod
    def codebase():
        return __file__.split('/root/')[0]

    @staticmethod
    def build_dir(project):
        return join(PathDef.codebase(), 'build', project)

    @staticmethod
    def output_bin_dir(project, module):
        return join(PathDef.build_dir(project), 'bin', module)
    
    
class ScopedPathDef:  # PathHelper
    def __init__(self, project):
        self.project = project
        
    def __getattr__(self, name):
        attr = getattr(PathDef, name)
        if isinstance(attr, str):
            return attr
        nargs = len(signature(attr).parameters)
        return partial(attr, *(self.project,)[:nargs])

Decorate instance method to be static

r"""
>>> PathDef.codebase = Path('codebase')

>>> PathDef.codebase
PosixPath('codebase')
>>> PathDef(scope='project').codebase
PosixPath('codebase')

>>> PathDef.build_dir(scope='project')
PosixPath('codebase/build/project')
>>> PathDef(scope='project').build_dir()
PosixPath('codebase/build/project')

>>> PathDef.output_bin_dir('module', scope='project')
PosixPath('codebase/build/project/bin/module')
>>> PathDef(scope='project').output_bin_dir('module')
PosixPath('codebase/build/project/bin/module')


TypeErrors:

>>> PathDef()
Traceback (most recent call last):
  ...
TypeError: __init__() missing 1 required keyword-only argument: 'scope'
>>> PathDef('project')
Traceback (most recent call last):
  ...
TypeError: __init__() takes 1 positional argument but 2 were given
>>> PathDef(scoping='project')
Traceback (most recent call last):
  ...
TypeError: __init__() got an unexpected keyword argument 'scoping'
>>> PathDef.output_bin_dir('module')
Traceback (most recent call last):
  ...
TypeError: output_bin_dir() missing 1 required keyword-only argument: 'scope'
>>> PathDef.output_bin_dir(scope='project')
Traceback (most recent call last):
  ...
TypeError: output_bin_dir() missing 1 required positional argument: 'module'
"""

from functools import wraps
from pathlib import Path


class PathDef:
    codebase = Path(__file__.split('/root/')[0])

    def __init__(self, *, scope):
        self.project = scope

    def scope(method):
        @wraps(method)
        def new_method(*a, **kw):
            if a and isinstance(a[0], PathDef):
                return method(*a, **kw)
            else:
                if 'scope' not in kw:
                    raise TypeError('%s() missing 1 required keyword-only argument: %r' % (method.__name__, 'scope'))
                return method(PathDef(scope=kw.pop('scope')), *a, **kw)
        return new_method

    @scope
    def build_dir(self):
        return self.codebase / 'build' / self.project

    @scope
    def output_bin_dir(self, module):
        return self.build_dir() / 'bin' / module

The way to get argument information of a function.

>>> def func(a, b, c='cc', *d, e=ee, **f): pass
...    

>>> for member in dir(func.__code__): member, getattr(func.__code__, member)
... 
('__class__', <class 'code'>)
...
('co_argcount', 3)  # a, b, c which are positional
...
('co_kwonlyargcount', 1)  # 'e' in this case
...
('co_nlocals', 6)  # a, b, c, d, e, f which appears to be local variables
...
('co_varnames', ('a', 'b', 'c', 'e', 'd', 'f'))
...

>>> for member in dir(func): member, getattr(func, member)
... 
('__defaults__', ('cc',))
...
('__kwdefaults__', {'e': 'ee'})
...

>>> from inspect import signature
>>> sig = signature(func)
>>> sig
<Signature (a, b, c='cc', *d, e='ee', **f)>
>>> for p in sig.parameters.values(): p, p.kind.description
... 
(<Parameter "a">, 'positional or keyword')
(<Parameter "b">, 'positional or keyword')
(<Parameter "c='cc'">, 'positional or keyword')
(<Parameter "*d">, 'variadic positional')
(<Parameter "e='ee'">, 'keyword-only')
(<Parameter "**f">, 'variadic keyword')

References

Consider the same type during arithmetic

from pathlib import Path

build_path = lambda codebase, project: Path(codebase, 'build', project)
build_bin_path = lambda codebase, project: build_path(codebase, project) / 'bin'
module_log_path = lambda codebase, project, module: build_path(codebase, project) / module / 'log'

assert build_path('codebase', 'project') == Path('codebase/build/project')
assert build_bin_path('codebase', 'project') == Path('codebase/build/project/bin')
assert module_log_path('codebase', 'project', 'module') == Path('codebase/build/project/module/log')

Origin code

from os.path import join


class partial_func_obj:
    def __init__(self, func, *args):
        self.func = func
        self.args = tuple(arg for arg in args if arg)
        self.nargs = len(args)

    def __call__(self, *args):
        acc_args = (
                tuple(arg for arg in (self.args + args) if arg) +
                (None,) * self.nargs
                )[:self.nargs]
        return partial(self.func, *acc_args)

def partial(func, *args):
    if None not in args:
        return func(*args)
    return partial_func_obj(func, *args)


def build_dir(codebase, project):
    return join(codebase, 'build', project)

def build_bin_dir(codebase, project):
    return join(build_dir(codebase, project), 'bin')

def module_log_dir(codebase, project, module):
    return join(build_dir(codebase, project), module, 'log')


assert build_dir('codebase', 'project') == 'codebase/build/project'
assert build_bin_dir('codebase', 'project') == 'codebase/build/project/bin'
assert module_log_dir('codebase', 'project', 'module') == 'codebase/build/project/module/log'

assert isinstance(partial(build_dir, None, None), partial_func_obj)
assert isinstance(partial(build_dir, 'codebase', None), partial_func_obj)

assert partial(build_dir, 'codebase', 'project') == 'codebase/build/project'
assert partial(module_log_dir, 'codebase', None, None)('project', 'module') == 'codebase/build/project/module/log'
assert partial(module_log_dir, 'codebase', None, None)('project')('module') == 'codebase/build/project/module/log'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment