diff --git a/doc/source/api/fileutils.rst b/doc/source/api/fileutils.rst new file mode 100644 index 00000000..575bedf7 --- /dev/null +++ b/doc/source/api/fileutils.rst @@ -0,0 +1,7 @@ +============= + fileutils +============= + +.. automodule:: oslo_utils.fileutils + :members: + diff --git a/doc/source/index.rst b/doc/source/index.rst index 4a9e6db0..9f00c105 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -21,6 +21,7 @@ API Documentation api/encodeutils api/eventletutils api/excutils + api/fileutils api/fixture api/importutils api/netutils diff --git a/oslo_utils/encodeutils.py b/oslo_utils/encodeutils.py index 52da98aa..82ce6af7 100644 --- a/oslo_utils/encodeutils.py +++ b/oslo_utils/encodeutils.py @@ -104,6 +104,8 @@ def exception_to_unicode(exc): If the exception message is a bytes strings, try to decode it from UTF-8 (superset of ASCII), from the locale encoding, or fallback to decoding it from ISO-8859-1 (which never fails). + + .. versionadded:: 1.6 """ msg = None if six.PY2: diff --git a/oslo_utils/eventletutils.py b/oslo_utils/eventletutils.py index 1d6a6b8e..2d2a299f 100644 --- a/oslo_utils/eventletutils.py +++ b/oslo_utils/eventletutils.py @@ -14,6 +14,12 @@ # License for the specific language governing permissions and limitations # under the License. +""" +Eventlet utils helper module. + +.. versionadded:: 1.3 +""" + import threading import warnings @@ -35,6 +41,13 @@ _ALL_PATCH = frozenset(['__builtin__', 'MySQLdb', 'os', def fetch_current_thread_functor(): + """Get the current thread. + + If eventlet is used to monkey-patch the threading module, return the + current eventlet greenthread. Otherwise, return the current Python thread. + + .. versionadded:: 1.5 + """ # Until https://github.com/eventlet/eventlet/issues/172 is resolved # or addressed we have to use complicated workaround to get a object # that will not be recycled; the usage of threading.current_thread() diff --git a/oslo_utils/excutils.py b/oslo_utils/excutils.py index 52073aa5..66e0171f 100644 --- a/oslo_utils/excutils.py +++ b/oslo_utils/excutils.py @@ -45,6 +45,8 @@ class CausedByException(Exception): should itself be an exception instance, this is useful for creating a chain of exceptions for versions of python where this is not yet implemented/supported natively. + + .. versionadded:: 2.4 """ def __init__(self, message, cause=None): super(CausedByException, self).__init__(message) @@ -126,6 +128,8 @@ def raise_with_cause(exc_cls, message, *args, **kwargs): exceptions constructor. :param kwargs: any additional keyword arguments to pass to the exceptions constructor. + + .. versionadded:: 1.6 """ if 'cause' not in kwargs: exc_type, exc, exc_tb = sys.exc_info() @@ -174,6 +178,9 @@ class save_and_reraise_exception(object): [if statements to determine whether to raise a new exception] # Not raising a new exception, so reraise ctxt.reraise = True + + .. versionchanged:: 1.4 + Added *logger* optional parameter. """ def __init__(self, reraise=True, logger=None): self.reraise = reraise diff --git a/oslo_utils/fileutils.py b/oslo_utils/fileutils.py index b2c9a7ef..788d338d 100644 --- a/oslo_utils/fileutils.py +++ b/oslo_utils/fileutils.py @@ -13,6 +13,12 @@ # License for the specific language governing permissions and limitations # under the License. +""" +File utilities. + +.. versionadded:: 1.8 +""" + import contextlib import errno import logging @@ -87,6 +93,8 @@ def write_to_tempfile(content, path=None, suffix='', prefix='tmp'): For example: it can be used in database tests for creating configuration files. + + .. versionadded:: 1.9 """ if path: ensure_tree(path) diff --git a/oslo_utils/fixture.py b/oslo_utils/fixture.py index 9d91695a..9526154e 100644 --- a/oslo_utils/fixture.py +++ b/oslo_utils/fixture.py @@ -14,6 +14,12 @@ # License for the specific language governing permissions and limitations # under the License. +""" +Test fixtures. + +.. versionadded:: 1.3 +""" + import fixtures from oslo_utils import timeutils diff --git a/oslo_utils/importutils.py b/oslo_utils/importutils.py index 15fd9bf6..3ddcfdea 100644 --- a/oslo_utils/importutils.py +++ b/oslo_utils/importutils.py @@ -22,7 +22,10 @@ import traceback def import_class(import_str): - """Returns a class from a string including module and class.""" + """Returns a class from a string including module and class. + + .. versionadded:: 0.3 + """ mod_str, _sep, class_str = import_str.rpartition('.') __import__(mod_str) try: @@ -34,7 +37,10 @@ def import_class(import_str): def import_object(import_str, *args, **kwargs): - """Import a class and return an instance of it.""" + """Import a class and return an instance of it. + + .. versionadded:: 0.3 + """ return import_class(import_str)(*args, **kwargs) @@ -44,6 +50,12 @@ def import_object_ns(name_space, import_str, *args, **kwargs): Imports a class and return an instance of it, first by trying to find the class in a default namespace, then failing back to a full path if not found in the default namespace. + + .. versionadded:: 0.3 + + .. versionchanged:: 2.6 + Don't capture :exc:`ImportError` when instanciating the object, only + when importing the object class. """ import_value = "%s.%s" % (name_space, import_str) try: @@ -54,12 +66,19 @@ def import_object_ns(name_space, import_str, *args, **kwargs): def import_module(import_str): - """Import a module.""" + """Import a module. + + .. versionadded:: 0.3 + """ __import__(import_str) return sys.modules[import_str] def import_versioned_module(version, submodule=None): + """Import a versioned module. + + .. versionadded:: 0.3 + """ module = 'oslo.v%s' % version if submodule: module = '.'.join((module, submodule)) diff --git a/oslo_utils/netutils.py b/oslo_utils/netutils.py index bdb46320..43c99239 100644 --- a/oslo_utils/netutils.py +++ b/oslo_utils/netutils.py @@ -87,6 +87,8 @@ def is_valid_ipv4(address): :param address: Value to verify :type address: string :returns: bool + + .. versionadded:: 1.1 """ try: return netaddr.valid_ipv4(address) @@ -100,6 +102,8 @@ def is_valid_ipv6(address): :param address: Value to verify :type address: string :returns: bool + + .. versionadded:: 1.1 """ try: return netaddr.valid_ipv6(address) @@ -117,6 +121,8 @@ def get_ipv6_addr_by_EUI64(prefix, mac): :param mac: IEEE 802 48-bit MAC address. :returns: IPv6 address on success. :raises ValueError, TypeError: For any invalid input. + + .. versionadded:: 1.4 """ # Check if the prefix is an IPv4 address if netaddr.valid_ipv4(prefix): @@ -143,6 +149,7 @@ def is_ipv6_enabled(): :returns: True if the platform has IPv6 support, False otherwise. + .. versionadded:: 1.4 """ global _IS_IPV6_ENABLED @@ -164,12 +171,17 @@ def is_valid_ip(address): :param address: Value to verify :type address: string :returns: bool + + .. versionadded:: 1.1 """ return is_valid_ipv4(address) or is_valid_ipv6(address) def is_valid_port(port): - """Verify that port represents a valid port number.""" + """Verify that port represents a valid port number. + + .. versionadded:: 1.1.1 + """ try: val = int(port) except (ValueError, TypeError): @@ -185,6 +197,11 @@ def get_my_ipv4(): were to be sent out to some well known address on the Internet. In this case, IP from RFC5737 is used, but the specific address does not matter much. No traffic is actually sent. + + .. versionadded:: 1.1 + + .. versionchanged:: 1.2.1 + Return ``'127.0.0.1'`` if there is no default interface. """ try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) diff --git a/oslo_utils/reflection.py b/oslo_utils/reflection.py index 34714fc0..f8ef3b1d 100644 --- a/oslo_utils/reflection.py +++ b/oslo_utils/reflection.py @@ -14,6 +14,12 @@ # License for the specific language governing permissions and limitations # under the License. +""" +Reflection module. + +.. versionadded:: 1.1 +""" + import inspect import types @@ -31,7 +37,10 @@ _BUILTIN_MODULES = ('builtins', '__builtin__', '__builtins__', 'exceptions') def get_members(obj, exclude_hidden=True): - """Yields the members of an object, filtering by hidden/not hidden.""" + """Yields the members of an object, filtering by hidden/not hidden. + + .. versionadded:: 2.3 + """ for (name, value) in inspect.getmembers(obj): if name.startswith("_") and exclude_hidden: continue diff --git a/oslo_utils/strutils.py b/oslo_utils/strutils.py index 62912e24..2c643dca 100644 --- a/oslo_utils/strutils.py +++ b/oslo_utils/strutils.py @@ -213,7 +213,7 @@ def to_slug(value, incoming=None, errors="strict"): def mask_password(message, secret="***"): - """Replace password with 'secret' in message. + """Replace password with *secret* in message. :param message: The string which includes security information. :param secret: value with which to replace passwords. @@ -231,6 +231,24 @@ def mask_password(message, secret="***"): "'original_password' : '***'" >>> mask_password("u'original_password' : u'aaaaa'") "u'original_password' : u'***'" + + .. versionadded:: 0.2 + + .. versionchanged:: 1.1 + Replace also ``'auth_token'``, ``'new_pass'`` and ``'auth_password'`` + keys. + + .. versionchanged:: 1.1.1 + Replace also ``'secret_uuid'`` key. + + .. versionchanged:: 1.5 + Replace also ``'sys_pswd'`` key. + + .. versionchanged:: 2.6 + Replace also ``'token'`` key. + + .. versionchanged:: 2.7 + Replace also ``'secret'`` key. """ try: @@ -262,6 +280,8 @@ def is_int_like(val): :param val: Value to verify :type val: string :returns: bool + + .. versionadded:: 1.1 """ try: return six.text_type(int(val)) == six.text_type(val) diff --git a/oslo_utils/timeutils.py b/oslo_utils/timeutils.py index 2f032599..47ceb5e9 100644 --- a/oslo_utils/timeutils.py +++ b/oslo_utils/timeutils.py @@ -105,7 +105,12 @@ def normalize_time(timestamp): def is_older_than(before, seconds): - """Return True if before is older than seconds.""" + """Return True if before is older than seconds. + + .. versionchanged:: 1.7 + Accept datetime string with timezone information. + Fix comparison with timezone aware datetime. + """ if isinstance(before, six.string_types): before = parse_isotime(before) @@ -115,7 +120,12 @@ def is_older_than(before, seconds): def is_newer_than(after, seconds): - """Return True if after is newer than seconds.""" + """Return True if after is newer than seconds. + + .. versionchanged:: 1.7 + Accept datetime string with timezone information. + Fix comparison with timezone aware datetime. + """ if isinstance(after, six.string_types): after = parse_isotime(after) @@ -129,6 +139,8 @@ def utcnow_ts(microsecond=False): See :py:class:`oslo_utils.fixture.TimeFixture`. + .. versionchanged:: 1.3 + Added optional *microsecond* parameter. """ if utcnow.override_time is None: # NOTE(kgriffs): This is several times faster @@ -152,6 +164,8 @@ def utcnow(with_timezone=False): See :py:class:`oslo_utils.fixture.TimeFixture`. + .. versionchanged:: 1.6 + Added *with_timezone* parameter. """ if utcnow.override_time: try: @@ -171,6 +185,9 @@ def utcnow(with_timezone=False): def iso8601_from_timestamp(timestamp, microsecond=False): """Returns an iso8601 formatted date from timestamp. + .. versionchanged:: 1.3 + Added optional *microsecond* parameter. + .. deprecated:: 1.5.0 Use :func:`datetime.datetime.utcfromtimestamp` and :func:`datetime.datetime.isoformat` instead. @@ -227,7 +244,11 @@ def clear_time_override(): def marshall_now(now=None): - """Make an rpc-safe datetime with microseconds.""" + """Make an rpc-safe datetime with microseconds. + + .. versionchanged:: 1.6 + Timezone information is now serialized instead of being stripped. + """ if not now: now = utcnow() d = dict(day=now.day, month=now.month, year=now.year, hour=now.hour, @@ -239,7 +260,14 @@ def marshall_now(now=None): def unmarshall_time(tyme): - """Unmarshall a datetime dict.""" + """Unmarshall a datetime dict. + + .. versionchanged:: 1.5 + Drop leap second. + + .. versionchanged:: 1.6 + Added support for timezone information. + """ # NOTE(ihrachys): datetime does not support leap seconds, # so the best thing we can do for now is dropping them @@ -298,6 +326,8 @@ class Split(object): """A *immutable* stopwatch split. See: http://en.wikipedia.org/wiki/Stopwatch for what this is/represents. + + .. versionadded:: 1.4 """ __slots__ = ['_elapsed', '_length'] @@ -337,6 +367,8 @@ class StopWatch(object): depending on operating system and python version). .. _monotonic: https://pypi.python.org/pypi/monotonic/ + + .. versionadded:: 1.4 """ _STARTED = 'STARTED' _STOPPED = 'STOPPED' diff --git a/oslo_utils/uuidutils.py b/oslo_utils/uuidutils.py index c7cc5870..5a48ae68 100644 --- a/oslo_utils/uuidutils.py +++ b/oslo_utils/uuidutils.py @@ -15,6 +15,8 @@ """ UUID related utilities and helper functions. + +.. versionadded:: 1.1 """ import uuid @@ -42,6 +44,9 @@ def is_uuid_like(val): :param val: Value to verify :type val: string :returns: bool + + .. versionchanged:: 1.1.1 + Support non-lowercase UUIDs. """ try: return str(uuid.UUID(val)).replace('-', '') == _format_uuid_string(val) diff --git a/oslo_utils/versionutils.py b/oslo_utils/versionutils.py index eb1e5549..09f867ac 100644 --- a/oslo_utils/versionutils.py +++ b/oslo_utils/versionutils.py @@ -15,6 +15,8 @@ """ Helpers for comparing version strings. + +.. versionadded:: 1.6 """ import logging @@ -51,6 +53,12 @@ def is_compatible(requested_version, current_version, same_major=True): def convert_version_to_int(version): + """Convert a version to an integer. + + *version* must be a string with dots or a tuple of integers. + + .. versionadded:: 2.0 + """ try: if isinstance(version, six.string_types): version = convert_version_to_tuple(version) @@ -62,6 +70,10 @@ def convert_version_to_int(version): def convert_version_to_str(version_int): + """Convert a version integer to a string with dots. + + .. versionadded:: 2.0 + """ version_numbers = [] factor = 1000 while version_int != 0: @@ -73,4 +85,8 @@ def convert_version_to_str(version_int): def convert_version_to_tuple(version_str): + """Convert a version string with dots to a tuple. + + .. versionadded:: 2.0 + """ return tuple(int(part) for part in version_str.split('.'))