pycommons package

pycommons is a package with utility functionality for Python projects.

Subpackages

Submodules

pycommons.types module

Some basic type handling routines.

pycommons.types.check_int_range(val, name=None, min_value=0, max_value=1000000000)[source]

Check whether a value val is an integer in a given range.

Via type annotation, this method actually accepts a value val of any type as input. However, if val is not an instance of int, it will throw an error. Also, if val is not in the prescribed range, it will throw an error, too. By default, the range is 0…1_000_000_000.

I noticed that often, we think that only want to check a lower limit for val, e.g., that a number of threads or a population size should be val > 0. However, in such cases, there also always a reasonable upper limits. We never actually want an EA to have a population larger than, say, 1_000_000_000. That would make no sense. So indeed, whenever we have a lower limit for a parameter, we also should have an upper limit resulting from physical constraints. 1_000_000_000 is a reasonably sane upper limit in many situations. If we need smaller or larger limits, we can of course specify them.

Notice that there is one strange border case: In Python, bool is a subtype of int, where True has value 1 and False has value 0. See <https://docs.python.org/3/library/functions.html#bool>. We therefore treat bool values indeed as instances of int.

Parameters:
  • val (Any) – the value to check

  • name (str | None, default: None) – the name of the value, or None

  • min_value (int | float, default: 0) – the minimum permitted value

  • max_value (int | float, default: 1000000000) – the maximum permitted value

Return type:

int

Returns:

val if everything is OK

Raises:
  • TypeError – if val is not an int

  • ValueError – if val is an int but outside the prescribed range

>>> try:
...   print(check_int_range(12, min_value=7, max_value=13))
... except (ValueError, TypeError) as err:
...   print(err)
12
>>> try:
...   print(check_int_range(123, min_value=7, max_value=13))
... except (ValueError, TypeError) as err:
...   print(err)
...   print(err.__class__)
Value=123 is invalid, must be in 7..13.
<class 'ValueError'>
>>> try:
...   print(check_int_range(5.0, name="ThisIsFloat"))
... except (ValueError, TypeError) as err:
...   print(err)
...   print(err.__class__)
ThisIsFloat should be an instance of int but is float, namely 5.0.
<class 'TypeError'>

The behavior in the border case of bool instances actually also being instances of int:

>>> check_int_range(True, "true", 0, 2)
True
>>> check_int_range(False, "false", 0, 2)
False
>>> try:
...   print(check_int_range(True, min_value=7, max_value=13))
... except (ValueError, TypeError) as err:
...   print(err)
...   print(err.__class__)
Value=True is invalid, must be in 7..13.
<class 'ValueError'>
pycommons.types.check_to_int_range(val, name=None, min_value=0, max_value=1000000000)[source]

Check whether a value val can be converted an integer in a given range.

Parameters:
  • val (Any) – the value to convert via int(…) and then to check

  • name (str | None, default: None) – the name of the value, or None

  • min_value (int | float, default: 0) – the minimum permitted value

  • max_value (int | float, default: 1000000000) – the maximum permitted value

Return type:

int

Returns:

val if everything is OK

Raises:
  • TypeError – if val is None

  • ValueError – if val is not None but can either not be converted to an int or to an int outside the prescribed range

>>> try:
...   print(check_to_int_range(12))
... except (ValueError, TypeError) as err:
...   print(err)
12
>>> try:
...   print(check_to_int_range(12.0))
... except (ValueError, TypeError) as err:
...   print(err)
12
>>> try:
...   print(check_to_int_range("12"))
... except (ValueError, TypeError) as err:
...   print(err)
12
>>> try:
...   print(check_to_int_range("A"))
... except (ValueError, TypeError) as err:
...   print(err)
...   print(err.__class__)
Cannot convert value='A' to int, let alone in range 0..1000000000.
<class 'ValueError'>
>>> try:
...   print(check_to_int_range(None))
... except (ValueError, TypeError) as err:
...   print(err)
...   print(err.__class__)
Cannot convert value=None to int, let alone in range 0..1000000000.
<class 'TypeError'>
pycommons.types.type_error(obj, name, expected=None, call=False)[source]

Create an error to raise if a type did not fit.

This eror contains information about the object name, the expected type, the actual type, and, in some cases, the actual value of the object. This should help tracing down what went wrong.

We sometimes include the actual value of the object. This happens if the object is an int, float, or bool. If the object is a str, then we include at most the first 32 characters. If the ojbect is a list, tuple, set, dict, or frozenset, then we include its length.

In previous versions of this function, we always included the full representation of the object. However, this might lead to very lengthy output and could even cause an out-of-memory exception. So we now focus on the above classes only.

Since one might still try to cause some mischief by overriding the __str__ or __len__ methods of these objects, we force that the methods of the base classes are used, which looks a bit odd in the code but should at least somewhat help preventing issues.

Parameters:
  • obj (Any) – the object that is of the wrong type

  • name (str) – the name of the object

  • expected (Union[None, type, Iterable[type]], default: None) – the expected types (or None)

  • call (bool, default: False) – the object should have been callable?

Return type:

ValueError | TypeError

Returns:

a TypeError with a descriptive information

>>> type_error(1.3, "var", int)
TypeError('var should be an instance of int but is float, namely 1.3.')
>>> type_error("x", "z", (int, float)).args[0]
"z should be an instance of any in {float, int} but is str, namely 'x'."
>>> type_error("x", "z", (int, float, None)).args[0]
"z should be an instance of any in {None, float, int} but is str, namely 'x'."
>>> type_error("x", "z", (int, float, type(None))).args[0]
"z should be an instance of any in {None, float, int} but is str, namely 'x'."
>>> type_error("f", "q", call=True).args[0]
"q should be a callable but is str, namely 'f'."
>>> type_error("1", "2", bool, call=True).args[0]
"2 should be an instance of bool or a callable but is str, namely '1'."
>>> type_error(None, "x", str)
TypeError('x should be an instance of str but is None.')
>>> type_error("123456789012345678901234567890123456789", "var", int)
TypeError("var should be an instance of int but is str, namely '123456789012345678901234567890...'.")
>>> type_error("12345678901234567890123456789012", "var", int)
TypeError("var should be an instance of int but is str, namely '12345678901234567890123456789012'.")
>>> type_error("123456789012345678901234567890123", "var", int)
TypeError("var should be an instance of int but is str, namely '12345678901234567890123456789...'.")
>>> type_error([1], "var", int)
TypeError('var should be an instance of int but is list of length 1.')
>>> type_error({2, 3}, "var", int)
TypeError('var should be an instance of int but is set of length 2.')
>>> type_error((1, 2, 3), "var", int)
TypeError('var should be an instance of int but is tuple of length 3.')
>>> type_error({}, "var", int)
TypeError('var should be an instance of int but is dict of length 0.')
>>> type_error(frozenset((23, )), "var", int)
TypeError('var should be an instance of int but is frozenset of length 1.')
>>> type_error(1, "var", list)
TypeError('var should be an instance of list but is int, namely 1.')
>>> type_error(1.3, "var", list)
TypeError('var should be an instance of list but is float, namely 1.3.')
>>> type_error(True, "var", list)
TypeError('var should be an instance of list but is bool, namely True.')
>>> type_error(ValueError("x"), "var", list)
TypeError('var should be an instance of list but is ValueError.')
>>> type_error(None, "var", list)
TypeError('var should be an instance of list but is None.')
pycommons.types.type_name(tpe)[source]

Convert a type to a string which represents its name.

Parameters:

tpe (type | None) – the type

Return type:

str

Returns:

the string

>>> type_name(None)
'None'
>>> type_name(type(None))
'None'
>>> type_name(int)
'int'
>>> from pycommons.io.path import file_path, Path
>>> type_name(Path)
'pycommons.io.path.Path'
>>> from typing import Callable
>>> type_name(Callable)
'typing.Callable'
>>> from typing import Callable as Ca
>>> type_name(Ca)
'typing.Callable'
>>> from typing import Callable as Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
>>> type_name(Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
'typing.Callable'
>>> import typing as ttttttttttttttttttttttttttttttttttttttttttt
>>> type_name(ttttttttttttttttttttttttttttttttttttttttttt.Callable)
'typing.Callable'
pycommons.types.type_name_of(obj)[source]

Get the fully-qualified class name of an object.

Parameters:

obj (Any) – the object

Return type:

str

Returns:

the fully-qualified class name of the object

>>> from pycommons.io.path import Path, file_path
>>> type_name_of(Path)
'type'
>>> type_name_of(file_path(__file__))
'pycommons.io.path.Path'
>>> type_name_of(None)
'None'
>>> type_name_of(int)
'type'
>>> type_name_of(print)
'builtin_function_or_method'
>>> from typing import Callable
>>> type_name_of(Callable)
'typing._CallableType'
>>> from math import sin
>>> type_name_of(sin)
'builtin_function_or_method'
>>> import pycommons.io as iox
>>> type_name_of(iox)
'module'

pycommons.version module

An internal file with the version of the pycommons package.