diff options
-rw-r--r-- | doc/conf.py | 4 | ||||
-rw-r--r-- | doc/index.rst | 2 | ||||
-rw-r--r-- | src/snakeoil/contexts.py | 25 | ||||
-rw-r--r-- | src/snakeoil/demandload.py | 26 | ||||
-rw-r--r-- | src/snakeoil/iterables.py | 10 | ||||
-rw-r--r-- | src/snakeoil/osutils/__init__.py | 9 | ||||
-rw-r--r-- | src/snakeoil/process/__init__.py | 19 | ||||
-rw-r--r-- | src/snakeoil/process/namespaces.py | 41 | ||||
-rw-r--r-- | src/snakeoil/sequences.py | 21 |
9 files changed, 69 insertions, 88 deletions
diff --git a/doc/conf.py b/doc/conf.py index dacd9ef..d2cbc09 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -11,12 +11,14 @@ # All configuration values have a default; values that are commented out # serve to show the default. +import os import subprocess +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('../src/')) +sys.path.insert(0, os.path.abspath('../src/')) # generate API docs subprocess.call([ diff --git a/doc/index.rst b/doc/index.rst index 22216a8..1ac772e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -43,7 +43,7 @@ Getting the source (downloading releases or trunk) Snakeoil vcs of choice is `git <http://git.scm.org/>`_, and our source can be checked out at https://github.com/pkgcore/snakeoil -All releases are available at |release_url|\., with release news available at :ref:`releases`\. +All releases are available at |release_url|, with release news available at :doc:`news`\. As for dependencies, snakeoil basically just requires python3.8 and up. diff --git a/src/snakeoil/contexts.py b/src/snakeoil/contexts.py index cafedb1..57092b4 100644 --- a/src/snakeoil/contexts.py +++ b/src/snakeoil/contexts.py @@ -336,8 +336,7 @@ def chdir(path): On exiting the context, the current working directory is switched back to its original value. - Args: - path: The directory path to change the working directory to. + :param path: The directory path to change the working directory to. """ orig_cwd = os.getcwd() os.chdir(path) @@ -348,15 +347,14 @@ def chdir(path): @contextmanager -def syspath(path, condition=True, position=0): - """Context manager that mangles sys.path and then reverts on exit. - - Args: - path: The directory path to add to sys.path. - condition: Optional boolean that decides whether sys.path is mangled or - not, defaults to being enabled. - position: Optional integer that is the place where the path is inserted - in sys.path, defaults to prepending. +def syspath(path: str, condition: bool=True, position: int=0): + """Context manager that mangles ``sys.path`` and then reverts on exit. + + :param path: The directory path to add to ``sys.path``. + :param condition: Optional boolean that decides whether ``sys.path`` is mangled + or not, defaults to being enabled. + :param position: Optional integer that is the place where the path is inserted + in ``sys.path``, defaults to prepending. """ syspath = sys.path[:] if condition: @@ -431,9 +429,8 @@ def os_environ(*remove, **update): def patch(target, new): """Simplified module monkey patching via context manager. - Args: - target: Target class or object. - new: Object or value to replace the target with. + :param target: Target class or object. + :param new: Object or value to replace the target with. """ def _import_module(target): diff --git a/src/snakeoil/demandload.py b/src/snakeoil/demandload.py index 00b83a3..0c84e8c 100644 --- a/src/snakeoil/demandload.py +++ b/src/snakeoil/demandload.py @@ -79,11 +79,11 @@ def parse_imports(imports): raise ValueError( "dotted imports are disallowed; see " "snakeoil.demandload docstring for " - "details; %r" % s) + f"details; {s!r}") split = s.split('@', 1) for s in split: if not s.translate(_allowed_chars).isspace(): - raise ValueError("bad target: %s" % s) + raise ValueError(f"bad target: {s}") if len(split) == 2: yield tuple(split) else: @@ -93,12 +93,12 @@ def parse_imports(imports): # "from" import. base, targets = fromlist if not base.translate(_allowed_chars).isspace(): - raise ValueError("bad target: %s" % base) + raise ValueError(f"bad target: {base}") for target in targets.split(','): split = target.split('@', 1) for s in split: if not s.translate(_allowed_chars).isspace(): - raise ValueError("bad target: %s" % s) + raise ValueError(f"bad target: {s}") yield base + '.' + split[0], split[-1] def _protection_enabled_disabled(): @@ -138,7 +138,7 @@ class Placeholder: :py:func:`demandload`. """ if not isinstance(target, str): - raise TypeError("Asked to load non string namespace: %r" % (target,)) + raise TypeError(f"Asked to load non string namespace: {target!r}") return cls(scope, name, functools.partial(load_any, target)) @classmethod @@ -163,7 +163,7 @@ class Placeholder: object we're demandloading. """ if not callable(load_func): - raise TypeError("load_func must be callable; got %r" % (load_func,)) + raise TypeError(f"load_func must be callable; got {load_func!r}") object.__setattr__(self, '_scope', scope) object.__setattr__(self, '_name', name) object.__setattr__(self, '_replacing_tids', []) @@ -191,7 +191,7 @@ class Placeholder: tids_to_complain_about = object.__getattribute__(self, '_replacing_tids') if threading.current_thread().ident in tids_to_complain_about: if _protection_enabled(): - raise ValueError('Placeholder for %r was triggered twice' % (name,)) + raise ValueError(f'Placeholder for {name!r} was triggered twice') elif _noisy_protection(): logging.warning('Placeholder for %r was triggered multiple times ' 'in file %r', name, scope.get("__file__", "unknown")) @@ -258,12 +258,12 @@ def demandload(*imports, **kwargs): Other args are strings listing module names. names are handled like this:: - foo import foo - foo@bar import foo as bar - foo:bar from foo import bar - foo:bar,quux from foo import bar, quux - foo.bar:quux from foo.bar import quux - foo:baz@quux from foo import baz as quux + foo import foo + foo@bar import foo as bar + foo:bar from foo import bar + foo:bar,quux from foo import bar, quux + foo.bar:quux from foo.bar import quux + foo:baz@quux from foo import baz as quux """ # pull the caller's global namespace if undefined diff --git a/src/snakeoil/iterables.py b/src/snakeoil/iterables.py index 8ed92f4..787af67 100644 --- a/src/snakeoil/iterables.py +++ b/src/snakeoil/iterables.py @@ -13,11 +13,9 @@ def partition(iterable, predicate=bool): Taking care that the predicate is called only once for each element. - Args: - iterable: target iterable to split into two - predicate: filtering function used to split the iterable - Returns: - A tuple of iterators, the first containing items that don't match the + :param iterable: target iterable to split into two + :param predicate: filtering function used to split the iterable + :return: A tuple of iterators, the first containing items that don't match the filter and the second the matched items. """ a, b = itertools.tee((predicate(x), x) for x in iterable) @@ -28,7 +26,7 @@ def partition(iterable, predicate=bool): class expandable_chain: """ chained iterables, with the ability to add new iterables to the chain - as long as the instance hasn't raised StopIteration already. This is + as long as the instance hasn't raised ``StopIteration`` already. This is fairly useful for implementing queues of things that must be processed. >>> from snakeoil.iterables import expandable_chain diff --git a/src/snakeoil/osutils/__init__.py b/src/snakeoil/osutils/__init__.py index 1dc7561..f0ea498 100644 --- a/src/snakeoil/osutils/__init__.py +++ b/src/snakeoil/osutils/__init__.py @@ -63,7 +63,7 @@ def supported_systems(*systems): Supported platforms are passed as string arguments. When run on any other system (determined using sys.platform), the function fails immediately with - NotImplementedError. + ``NotImplementedError``. Example usage: @@ -75,7 +75,8 @@ def supported_systems(*systems): >>> if sys.platform.startswith(('linux', 'darwin')): >>> assert func() == True - NotImplementedError is raised on platforms that aren't supported. + ``NotImplementedError`` is raised on platforms that aren't supported. + >>> @supported_systems('nonexistent') >>> def func2(param): ... return False @@ -202,7 +203,7 @@ def abssymlink(path): :param path: filepath to resolve :return: resolved path - :raise: EnvironmentError, errno=ENINVAL if the requested path isn't + :raises EnvironmentError: with errno=ENINVAL if the requested path isn't a symlink """ mylink = os.readlink(path) @@ -235,7 +236,7 @@ def abspath(path): return the target. :param path: filepath to resolve. - :raise: EnvironmentError some errno other than an ENOENT or EINVAL + :raises EnvironmentError: some errno other than an ENOENT or EINVAL is encountered :return: the absolute path calculated against the filesystem """ diff --git a/src/snakeoil/process/__init__.py b/src/snakeoil/process/__init__.py index 00db14c..f242269 100644 --- a/src/snakeoil/process/__init__.py +++ b/src/snakeoil/process/__init__.py @@ -11,7 +11,7 @@ import time from ..osutils import access -def find_binary(binary, paths=None, fallback=None): +def find_binary(binary: str, paths=None, fallback=None) -> str: """look through the PATH environment, finding the binary to execute""" if os.path.isabs(binary): @@ -33,14 +33,12 @@ def find_binary(binary, paths=None, fallback=None): raise CommandNotFound(binary) -def get_exit_status(status): - """Get the exit status of a child from an os.waitpid call. +def get_exit_status(status: int): + """Get the exit status of a child from an :py:func:`os.waitpid` call. - Args: - status: The return value of os.waitpid(pid, 0)[1] + :param status: The return value of ``os.waitpid(pid, 0)[1]`` - Returns: - The exit status of the process. If the process exited with a signal, + :return: The exit status of the process. If the process exited with a signal, the return value will be 128 plus the signal number. """ if os.WIFSIGNALED(status): @@ -50,16 +48,15 @@ def get_exit_status(status): return os.WEXITSTATUS(status) -def exit_as_status(status): - """Exit the same way as |status|. +def exit_as_status(status: int): + """Exit the same way as `status`. If the status field says it was killed by a signal, then we'll do that to ourselves. Otherwise we'll exit with the exit code. See http://www.cons.org/cracauer/sigint.html for more details. - Args: - status: A status as returned by os.wait type funcs. + :param status: A status as returned by :py:func:`os.wait` type funcs. """ exit_status = os.WEXITSTATUS(status) diff --git a/src/snakeoil/process/namespaces.py b/src/snakeoil/process/namespaces.py index 8bc9242..fd6bd74 100644 --- a/src/snakeoil/process/namespaces.py +++ b/src/snakeoil/process/namespaces.py @@ -29,12 +29,9 @@ CLONE_NEWNET = 0x40000000 def setns(fd, nstype): """Binding to the Linux setns system call. See setns(2) for details. - Args: - fd: An open file descriptor or path to one. - nstype: Namespace to enter; one of CLONE_*. - - Raises: - OSError: if setns failed. + :param fd: An open file descriptor or path to one. + :param nstype: Namespace to enter; one of CLONE_*. + :raises OSError: if setns failed. """ try: fp = None @@ -54,11 +51,8 @@ def setns(fd, nstype): def unshare(flags): """Binding to the Linux unshare system call. See unshare(2) for details. - Args: - flags: Namespaces to unshare; bitwise OR of CLONE_* flags. - - Raises: - OSError: if unshare failed. + :param flags: Namespaces to unshare; bitwise OR of CLONE_* flags. + :raises OSError: if unshare failed. """ libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) if libc.unshare(ctypes.c_int(flags)) != 0: @@ -69,11 +63,8 @@ def unshare(flags): def _reap_children(pid): """Reap all children that get reparented to us until we see |pid| exit. - Args: - pid: The main child to watch for. - - Returns: - The wait status of the |pid| child. + :param pid: The main child to watch for. + :return: The wait status of the |pid| child. """ pid_status = 0 @@ -116,8 +107,7 @@ def create_pidns(): If functionality is not available, then it will return w/out doing anything. - Returns: - The last pid outside of the namespace. + :return: The last pid outside of the namespace. """ first_pid = os.getpid() @@ -267,14 +257,13 @@ def simple_unshare(mount=True, uts=True, ipc=True, net=False, pid=False, If support for any namespace type is not available, we'll silently skip it. - Args: - mount: Create a mount namespace. - uts: Create a UTS namespace. - ipc: Create an IPC namespace. - net: Create a net namespace. - pid: Create a pid namespace. - user: Create a user namespace. - hostname: hostname to use for the UTS namespace + :param mount: Create a mount namespace. + :param uts: Create a UTS namespace. + :param ipc: Create an IPC namespace. + :param net: Create a net namespace. + :param pid: Create a pid namespace. + :param user: Create a user namespace. + :param hostname: hostname to use for the UTS namespace """ # user namespace must be first if user: diff --git a/src/snakeoil/sequences.py b/src/snakeoil/sequences.py index 1a156da..c041136 100644 --- a/src/snakeoil/sequences.py +++ b/src/snakeoil/sequences.py @@ -6,7 +6,6 @@ __all__ = ( 'split_negations', ) -from operator import itemgetter from typing import Any, Callable, Iterable, Type from .iterables import expandable_chain @@ -138,7 +137,8 @@ def iflatten_func(l: Iterable, skip_func: Callable[[Any], bool]) -> Iterable: class ChainedLists: - """Given a set of sequences, this will act as a proxy to them without collapsing them into a single list. + """Given a set of sequences, this will act as a proxy to them without + collapsing them into a single list. This is primarily useful when you're dealing in large sets (or custom sequence objects), and do not want to collapse them into one sequence- but @@ -161,6 +161,7 @@ class ChainedLists: 7 >>> cl[0] = 9 Traceback (most recent call last): + ... TypeError: not mutable """ __slots__ = ("_lists", "__weakref__") @@ -259,12 +260,10 @@ def predicate_split(func, stream, key=None): def split_negations(iterable, func=str): """"Split an iterable into negative and positive elements. - Args: - iterable: iterable targeted for splitting - func: wrapper method to modify tokens + :param iterable: iterable targeted for splitting + :param func: wrapper method to modify tokens - Returns: - Tuple containing negative and positive element tuples, respectively. + :return: Tuple containing negative and positive element tuples, respectively. """ neg, pos = [], [] for token in iterable: @@ -284,12 +283,10 @@ def split_negations(iterable, func=str): def split_elements(iterable, func=str): """"Split an iterable into negative, neutral, and positive elements. - Args: - iterable: iterable targeted for splitting - func: wrapper method to modify tokens + :param iterable: iterable targeted for splitting + :param func: wrapper method to modify tokens - Returns: - Tuple containing negative, neutral, and positive element tuples, respectively. + :return: Tuple containing negative, neutral, and positive element tuples, respectively. """ neg, neu, pos = [], [], [] token_map = {'-': neg, '+': pos} |