Metadata-Version: 2.1 Name: python-utils Version: 3.9.1 Summary: Python Utils is a module with some convenient utilities not included with the standard Python install Home-page: https://github.com/WoLpH/python-utils Author: Rick van Hattem Author-email: Wolph@wol.ph License: BSD Classifier: License :: OSI Approved :: BSD License Requires-Python: >=3.9.0 License-File: LICENSE Requires-Dist: typing_extensions>3.10.0.2 Provides-Extra: loguru Requires-Dist: loguru; extra == "loguru" Provides-Extra: docs Requires-Dist: mock; extra == "docs" Requires-Dist: sphinx; extra == "docs" Requires-Dist: python-utils; extra == "docs" Provides-Extra: tests Requires-Dist: ruff; extra == "tests" Requires-Dist: pyright; extra == "tests" Requires-Dist: pytest; extra == "tests" Requires-Dist: pytest-cov; extra == "tests" Requires-Dist: pytest-mypy; extra == "tests" Requires-Dist: pytest-asyncio; extra == "tests" Requires-Dist: sphinx; extra == "tests" Requires-Dist: types-setuptools; extra == "tests" Requires-Dist: loguru; extra == "tests" Requires-Dist: loguru-mypy; extra == "tests" Requires-Dist: mypy-ipython; extra == "tests" Requires-Dist: blessings; extra == "tests" Useful Python Utils ============================================================================== .. image:: https://github.com/WoLpH/python-utils/actions/workflows/main.yml/badge.svg?branch=master :target: https://github.com/WoLpH/python-utils/actions/workflows/main.yml .. image:: https://coveralls.io/repos/WoLpH/python-utils/badge.svg?branch=master :target: https://coveralls.io/r/WoLpH/python-utils?branch=master Python Utils is a collection of small Python functions and classes which make common patterns shorter and easier. It is by no means a complete collection but it has served me quite a bit in the past and I will keep extending it. One of the libraries using Python Utils is Django Utils. Documentation is available at: https://python-utils.readthedocs.org/en/latest/ Links ----- - The source: https://github.com/WoLpH/python-utils - Project page: https://pypi.python.org/pypi/python-utils - Reporting bugs: https://github.com/WoLpH/python-utils/issues - Documentation: https://python-utils.readthedocs.io/en/latest/ - My blog: https://wol.ph/ Security contact information ------------------------------------------------------------------------------ To report a security vulnerability, please use the `Tidelift security contact `_. Tidelift will coordinate the fix and disclosure. Requirements for installing: ------------------------------------------------------------------------------ For the Python 3+ release (i.e. v3.0.0 or higher) there are no requirements. For the Python 2 compatible version (v2.x.x) the `six` package is needed. Installation: ------------------------------------------------------------------------------ The package can be installed through `pip` (this is the recommended method): .. code-block:: bash pip install python-utils Or if `pip` is not available, `easy_install` should work as well: .. code-block:: bash easy_install python-utils Or download the latest release from Pypi (https://pypi.python.org/pypi/python-utils) or Github. Note that the releases on Pypi are signed with my GPG key (https://pgp.mit.edu/pks/lookup?op=vindex&search=0xE81444E9CE1F695D) and can be checked using GPG: .. code-block:: bash gpg --verify python-utils-.tar.gz.asc python-utils-.tar.gz Quickstart ------------------------------------------------------------------------------ This module makes it easy to execute common tasks in Python scripts such as converting text to numbers and making sure a string is in unicode or bytes format. Examples ------------------------------------------------------------------------------ Automatically converting a generator to a list, dict or other collections using a decorator: .. code-block:: pycon >>> @decorators.listify() ... def generate_list(): ... yield 1 ... yield 2 ... yield 3 ... >>> generate_list() [1, 2, 3] >>> @listify(collection=dict) ... def dict_generator(): ... yield 'a', 1 ... yield 'b', 2 >>> dict_generator() {'a': 1, 'b': 2} Retrying until timeout ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To easily retry a block of code with a configurable timeout, you can use the `time.timeout_generator`: .. code-block:: pycon >>> for i in time.timeout_generator(10): ... try: ... # Run your code here ... except Exception as e: ... # Handle the exception Formatting of timestamps, dates and times ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Easy formatting of timestamps and calculating the time since: .. code-block:: pycon >>> time.format_time('1') '0:00:01' >>> time.format_time(1.234) '0:00:01' >>> time.format_time(1) '0:00:01' >>> time.format_time(datetime.datetime(2000, 1, 2, 3, 4, 5, 6)) '2000-01-02 03:04:05' >>> time.format_time(datetime.date(2000, 1, 2)) '2000-01-02' >>> time.format_time(datetime.timedelta(seconds=3661)) '1:01:01' >>> time.format_time(None) '--:--:--' >>> formatters.timesince(now) 'just now' >>> formatters.timesince(now - datetime.timedelta(seconds=1)) '1 second ago' >>> formatters.timesince(now - datetime.timedelta(seconds=2)) '2 seconds ago' >>> formatters.timesince(now - datetime.timedelta(seconds=60)) '1 minute ago' Converting your test from camel-case to underscores: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: pycon >>> camel_to_underscore('SpamEggsAndBacon') 'spam_eggs_and_bacon' Attribute setting decorator. Very useful for the Django admin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A convenient decorator to set function attributes using a decorator: .. code-block:: pycon You can use: >>> @decorators.set_attributes(short_description='Name') ... def upper_case_name(self, obj): ... return ("%s %s" % (obj.first_name, obj.last_name)).upper() Instead of: >>> def upper_case_name(obj): ... return ("%s %s" % (obj.first_name, obj.last_name)).upper() >>> upper_case_name.short_description = 'Name' This can be very useful for the Django admin as it allows you to have all metadata in one place. Scaling numbers between ranges ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: pycon >>> converters.remap(500, old_min=0, old_max=1000, new_min=0, new_max=100) 50 # Or with decimals: >>> remap(decimal.Decimal('250.0'), 0.0, 1000.0, 0.0, 100.0) Decimal('25.0') Get the screen/window/terminal size in characters: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: pycon >>> terminal.get_terminal_size() (80, 24) That method supports IPython and Jupyter as well as regular shells, using `blessings` and other modules depending on what is available. Extracting numbers from nearly every string: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: pycon >>> converters.to_int('spam15eggs') 15 >>> converters.to_int('spam') 0 >>> number = converters.to_int('spam', default=1) 1 Doing a global import of all the modules in a package programmatically: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To do a global import programmatically you can use the `import_global` function. This effectively emulates a `from ... import *` .. code-block:: python from python_utils.import_ import import_global # The following is the equivalent of `from some_module import *` import_global('some_module') Automatically named logger for classes: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Or add a correclty named logger to your classes which can be easily accessed: .. code-block:: python class MyClass(Logged): def __init__(self): Logged.__init__(self) my_class = MyClass() # Accessing the logging method: my_class.error('error') # With formatting: my_class.error('The logger supports %(formatting)s', formatting='named parameters') # Or to access the actual log function (overwriting the log formatting can # be done n the log method) import logging my_class.log(logging.ERROR, 'log') Alternatively loguru is also supported. It is largely a drop-in replacement for the logging module which is a bit more convenient to configure: First install the extra loguru package: .. code-block:: bash pip install 'python-utils[loguru]' .. code-block:: python class MyClass(Logurud): ... Now you can use the `Logurud` class to make functions such as `self.info()` available. The benefit of this approach is that you can add extra context or options to you specific loguru instance (i.e. `self.logger`): Convenient type aliases and some commonly used types: .. code-block:: python # For type hinting scopes such as locals/globals/vars Scope = Dict[str, Any] OptionalScope = O[Scope] # Note that Number is only useful for extra clarity since float # will work for both int and float in practice. Number = U[int, float] DecimalNumber = U[Number, decimal.Decimal] # To accept an exception or list of exceptions ExceptionType = Type[Exception] ExceptionsType = U[Tuple[ExceptionType, ...], ExceptionType] # Matching string/bytes types: StringTypes = U[str, bytes]