util

runcommands.util.get_commands_in_namespace(namespace=None, level=1)[source]

Get commands in namespace.

Parameters:
  • namespace (dict|module) – Typically a module. If not passed, the globals from the call site will be used.
  • level (int) – If not called from the global scope, set this appropriately to account for the call stack.
Returns:

The commands found in the namespace, ordered by

name.

Return type:

OrderedDict

Can be used to create __all__ lists:

__all__ = list(get_commands_in_namespace())
class runcommands.util.Data(**data)[source]

A bucket for arbitrary data.

Data can be added and retrieved as attributes (dot notation) or items (bracket notation).

When a dict is added, it will be converted to an instance of Data.

class runcommands.util.Color[source]

An enumeration.

class runcommands.util.StreamOptions[source]

Choices for stream handling.

runcommands.util.flatten_args(args: list, join=False, *, empty=(None, [](), '')) → list[source]

Flatten args and remove empty items.

Parameters:
  • args – A list of items (typically but not necessarily strings), which may contain sub-lists, that will be flattened into a single list with empty items removed. Empty items include None and empty lists, tuples, and strings.
  • join – If True or a string, the final flattened list will be joined into a single string. The default join string is a space.
  • empty – Items that are considered empty.
Returns:

The list of args flattened with empty items removed

and the remaining items converted to strings. If join is specified, the list of flattened args will be joined into a single string.

Return type:

list|str

Examples:

>>> flatten_args([])
[]
>>> flatten_args(())
[]
>>> flatten_args([(), (), [(), ()]])
[]
>>> flatten_args(
...     [
...         'executable',
...         '--flag' if True else None,
...         ('--option', 'value'),
...         [None],
...     ]
... )
['executable', '--flag', '--option', 'value']
>>> flatten_args(['executable', '--option', 0])
['executable', '--option', '0']
runcommands.util.format_if(value, format_kwargs)[source]

Apply format args to value if value or return value as is.

runcommands.util.is_mapping(obj)[source]

Is the object a mapping?

This mirrors is_sequence().

runcommands.util.is_sequence(obj)[source]

Is the object a non-str sequence?

Checking whether an object is a non-string sequence is a bit unwieldy. This makes it simple.

runcommands.util.is_type(obj, type)[source]

Is the object a subclass of the specified type?

This is similar to the builtin issubclass but also ensures the object is a type first.

runcommands.util.load_object(obj) → object[source]

Load an object.

Parameters:obj (str|object) –

Load the indicated object if this is a string; otherwise, return the object as is.

To load a module, pass a dotted path like ‘package.module’; to load an an object from a module pass a path like ‘package.module:name’.

Returns:object
runcommands.util.merge_dicts(*dicts)[source]

Merge all dicts.

Dicts later in the list take precedence over dicts earlier in the list.

runcommands.util.abs_path(path, format_kwargs={}, relative_to=None, keep_slash=False)[source]

Get abs. path for path.

path may be a relative or absolute file system path or an asset path. If path is already an abs. path, it will be returned as is. Otherwise, it will be converted into a normalized abs. path.

If relative_to is passed and path is not absolute, the path will be joined to the specified prefix before it’s made absolute.

If path ends with a slash, it will be stripped unless keep_slash is set (for use with rsync, for example).

>>> file_path = os.path.normpath(__file__)
>>> dir_name = os.path.dirname(file_path)
>>> file_name = os.path.basename(file_path)
>>> os.chdir(dir_name)
>>>
>>> abs_path(file_name) == file_path
True
>>> abs_path('runcommands.util:') == dir_name
True
>>> abs_path('runcommands.util:path.py') == file_path
True
>>> abs_path('/{xyz}', format_kwargs={'xyz': 'abc'})
'/abc'
>>> abs_path('banana', relative_to='/usr')
'/usr/banana'
>>> abs_path('/usr/banana/')
'/usr/banana'
>>> abs_path('banana/', relative_to='/usr', keep_slash=True)
'/usr/banana/'
>>> abs_path('runcommands.util:banana/', keep_slash=True) == (dir_name + '/banana/')
True
runcommands.util.asset_path(path, format_kwargs={}, keep_slash=False)[source]

Get absolute path to asset in package.

path can be just a package name like ‘package’ or it can be a package name and a relative file system path like ‘package:util’.

If path ends with a slash, it will be stripped unless keep_slash is set (for use with rsync, for example).

>>> file_path = os.path.normpath(__file__)
>>> dir_name = os.path.dirname(file_path)
>>> file_name = os.path.basename(file_path)
>>> os.chdir(dir_name)
>>>
>>> asset_path('runcommands.util') == dir_name
True
>>> asset_path('runcommands.util:path.py') == file_path
True
>>> asset_path(
...     'runcommands.util:{name}.py',
...     format_kwargs={'name': 'path'}
... ) == file_path
True
>>> asset_path('runcommands.util:dir/') == (dir_name + '/dir')
True
>>> asset_path('runcommands.util:dir/', keep_slash=True) == (dir_name + '/dir/')
True
runcommands.util.find_project_root(start_dir='.')[source]

Find the project root.

See func:is_project_root for details on which directories are considered project roots.

This starts in the current directory and then goes up until the file system root is reached. If a project root isn’t found, a ValueError will be raised.

runcommands.util.is_project_root(path)[source]

Is the path a project root?

A project root is a directory that contains a source control subdirectory (git, hg, and svn).

todo:: Be more inclusive.

runcommands.util.module_from_path(name, path)[source]

Import a file system path as a Python module.

The module will be named name.

runcommands.util.paths_to_str(paths, format_kwargs={}, delimiter=':', asset_paths=False, check_paths=False)[source]

Convert paths to a single string.

Parameters:
  • paths (str|list) – A string like “/a/path:/another/path” or a list of paths; may include absolute paths and/or asset paths; paths that are relative will be left relative
  • format_kwargs (dict) – Will be injected into each path
  • delimiter (str) – The string used to separate paths
  • asset_paths (bool) – Whether paths that look like asset paths will be converted to absolute paths
  • check_paths (bool) – Whether paths should be checked to ensure they exist
runcommands.util.confirm(prompt='Really?', color='warning', yes_value='y', abort_on_unconfirmed=False, abort_options=None)[source]

Prompt for confirmation.

Confirmation can be aborted by typing in a no value instead of one of the yes values or with Ctrl-C.

Parameters:
  • prompt (str) – Prompt to present user [“Really?”]
  • color (string|Color|bool) – False or None to print without color [“yellow”]
  • yes_value (str) – Value user must type in to confirm; note that this will be case sensitive if it contains any upper case letters [“y”]
  • abort_on_unconfirmed (bool|int|str) –

    When user does not confirm:

    • If this is an integer, print “Aborted” to stdout if it’s 0 or to stderr if it’s not 0 and then exit with this code
    • If this is a string, print it to stdout and exit with code 0
    • If this is True (or any other truthy value), print “Aborted” to stdout and exit with code 0
  • abort_options (dict) – Options to pass to abort() when not confirmed (these options will override any options set via abort_on_unconfirmed)
runcommands.util.camel_to_underscore(name)[source]

Convert camel case name to underscore name.

Examples:

>>> camel_to_underscore('HttpRequest')
'http_request'
>>> camel_to_underscore('httpRequest')
'http_request'
>>> camel_to_underscore('HTTPRequest')
'http_request'
>>> camel_to_underscore('myHTTPRequest')
'my_http_request'
>>> camel_to_underscore('MyHTTPRequest')
'my_http_request'
>>> camel_to_underscore('my_http_request')
'my_http_request'
>>> camel_to_underscore('MyHTTPRequestXYZ')
'my_http_request_xyz'
>>> camel_to_underscore('_HTTPRequest')
'_http_request'
>>> camel_to_underscore('Request')
'request'
>>> camel_to_underscore('REQUEST')
'request'
>>> camel_to_underscore('_Request')
'_request'
>>> camel_to_underscore('__Request')
'__request'
>>> camel_to_underscore('_request')
'_request'
>>> camel_to_underscore('Request_')
'request_'
runcommands.util.invert_string(string)[source]

Invert the logical meaning of a string.

Examples:

>>> invert_string('Yes')
'No'
>>> invert_string('No')
'Yes'
>>> invert_string("don't")
'do'