cli
Extend Invoke for Calcipy.
Classes⚓︎
CalcipyConfig ⚓︎
Bases: Config
Opinionated Config with better defaults.
Source code in calcipy/cli.py
class CalcipyConfig(Config):
"""Opinionated Config with better defaults."""
@staticmethod
def global_defaults() -> Dict: # type: ignore[type-arg] # pragma: no cover
"""Override the global defaults."""
invoke_defaults = Config.global_defaults()
calcipy_defaults = {
'run': {
'echo': True,
'echo_format': '\033[2;3;37mRunning: {command}\033[0m',
'pty': use_pty(),
},
}
return merge_dicts(invoke_defaults, calcipy_defaults)
Functions⚓︎
global_defaults
staticmethod
⚓︎
global_defaults()
Override the global defaults.
Source code in calcipy/cli.py
@staticmethod
def global_defaults() -> Dict: # type: ignore[type-arg] # pragma: no cover
"""Override the global defaults."""
invoke_defaults = Config.global_defaults()
calcipy_defaults = {
'run': {
'echo': True,
'echo_format': '\033[2;3;37mRunning: {command}\033[0m',
'pty': use_pty(),
},
}
return merge_dicts(invoke_defaults, calcipy_defaults)
Functions⚓︎
start_program ⚓︎
start_program(pkg_name, pkg_version, module=None, collection=None)
Run the customized Invoke Program.
FYI: recommendation is to extend the core_args
method, but this won’t parse positional arguments:
https://docs.pyinvoke.org/en/stable/concepts/library.html#modifying-core-parser-arguments
Source code in calcipy/cli.py
@beartype
def start_program( # noqa: CAC001
pkg_name: str,
pkg_version: str,
module: Optional[ModuleType] = None,
collection: Optional[Union[Collection, InvokeCollection]] = None,
) -> None: # pragma: no cover
"""Run the customized Invoke Program.
FYI: recommendation is to extend the `core_args` method, but this won't parse positional arguments:
https://docs.pyinvoke.org/en/stable/concepts/library.html#modifying-core-parser-arguments
"""
# Manipulate 'sys.argv' to hide arguments that invoke can't parse
_gto = GlobalTaskOptions()
sys_argv: List[str] = sys.argv[:1]
last_argv = ''
for argv in sys.argv[1:]:
if not last_argv.startswith('-') and Path(argv).is_file():
_gto.file_args.append(Path(argv))
# Check for CLI flags
elif argv in {'-v', '-vv', '-vvv', '--verbose'}:
_gto.verbose = argv.count('v')
elif argv == '--keep-going':
_gto.keep_going = True
# Check for CLI arguments with values
elif last_argv == '--working-dir':
_gto.working_dir = Path(argv).resolve()
elif argv != '--working-dir':
sys_argv.append(argv)
last_argv = argv
_gto.file_args = [
_f if _f.is_absolute() else Path.cwd() / _f
for _f in _gto.file_args
]
sys.argv = sys_argv
class _CalcipyConfig(CalcipyConfig):
gto: GlobalTaskOptions = _gto
if module and collection:
raise ValueError('Only one of collection or module can be specified')
_CalcipyProgram(
name=pkg_name,
version=pkg_version,
namespace=Collection.from_module(module) if module else collection,
config_class=_CalcipyConfig,
).run()
task ⚓︎
task(*dec_args, **dec_kwargs)
Marks wrapped callable object as a valid Invoke task.
Source code in calcipy/cli.py
def task(*dec_args: Any, **dec_kwargs: Any) -> Callable: # type: ignore[type-arg]
"""Marks wrapped callable object as a valid Invoke task."""
def wrapper(func: Any) -> Callable: # type: ignore[type-arg]
# Attach arguments for Task
setattr(func, TASK_ARGS_ATTR, dec_args)
setattr(func, TASK_KWARGS_ATTR, dec_kwargs)
# Attach public attributes from invoke that are expected
func.help = dec_kwargs.pop('help', {})
def _with_kwargs(**extra_kwargs: Any) -> Callable: # type: ignore[type-arg] # nosem
"""Support building partial tasks."""
if extra_kwargs:
# Set a unique name when 'extra_kwargs' was provided
# https://github.com/pyinvoke/invoke/blob/07b836f2663bb073a7bcef3d6c454e1dc6b867ae/invoke/tasks.py#L81-L104
encoded = b64encode(str(extra_kwargs).encode())
func.__name__ = f'{func.__name__}_{encoded.decode().rstrip("=")}'
@wraps(func) # nosem
def _with_kwargs_inner(*args: Any, **kwargs: Any) -> Any:
return func(*args, **kwargs, **extra_kwargs)
return _with_kwargs_inner
func.with_kwargs = _with_kwargs
@wraps(func) # nosem
def _inner(*args: Any, **kwargs: Any) -> Any:
return func(*args, **kwargs)
return _inner
# Handle the case when the decorator is called without arguments
if (
len(dec_args) == 1
and callable(dec_args[0])
and not hasattr(dec_args[0], TASK_ARGS_ATTR)
):
return wrapper(dec_args[0])
return wrapper