aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/conf.py4
-rw-r--r--doc/index.rst2
-rw-r--r--src/snakeoil/contexts.py25
-rw-r--r--src/snakeoil/demandload.py26
-rw-r--r--src/snakeoil/iterables.py10
-rw-r--r--src/snakeoil/osutils/__init__.py9
-rw-r--r--src/snakeoil/process/__init__.py19
-rw-r--r--src/snakeoil/process/namespaces.py41
-rw-r--r--src/snakeoil/sequences.py21
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}