py2http.util¶
This module contains various utilities including a lazyprop descriptor for lazy loading properties, a CreateProcess context manager for running functions in parallel processes, a ModuleFoundIgnore context manager for ignoring ModuleNotFoundErrors, and more.
The lazyprop descriptor is used to define properties that are computed once and then cached until the instance of the class is destroyed. It is useful for computing properties on-demand but only once.
The CreateProcess context manager is used to launch a parallel process and close it on exit. This is helpful when you need to execute tasks concurrently in a separate process.
The ModuleFoundIgnore context manager allows you to ignore ModuleNotFoundError exceptions in a block of code. This can be useful when importing optional modules that may or may not exist.
The TypeAsserter function generates a callable that asserts the expected type of a value based on a given kind. It can be used to validate the types of inputs based on predefined rules.
Overall, this module provides a collection of useful tools for handling lazy property loading, parallel processing, exception handling, type validation, and more.
Functions
|
Call |
|
|
|
Decorator to emit a DeprecationWarning when the decorated function is called. |
|
|
|
Make a generator of (k, v) items extracted from an input object, given an iterable of attributes to extract |
|
Quasi-inverse of obj_to_path: Get a root_obj and attr_path from an object. |
|
Get an object from a root object and "attribute path" specification. |
|
|
|
Get dict from a Parameter object |
Classes
|
A context manager to launch a parallel process and close it on exit. |
|
A class to use as a value to indicate that something was missing |
Context manager to ignore ModuleNotFoundErrors. |
|
|
Class to indicate if one should skip an item |
|
Makes a callable that asserts that a value |
|
A descriptor implementation of lazyprop (cached property). |
- class py2http.util.CreateProcess(proc_func, process_name=None, wait_before_entering=2, verbose=False, args=(), **kwargs)[source]¶
Bases:
objectA context manager to launch a parallel process and close it on exit.
- class py2http.util.Missing(val=None)[source]¶
Bases:
objectA class to use as a value to indicate that something was missing
- class py2http.util.ModuleNotFoundIgnore[source]¶
Bases:
objectContext manager to ignore ModuleNotFoundErrors.
When all goes well, code is executed normally:
>>> with ModuleNotFoundIgnore(): ... import os.path # test when the module exists ... # The following code is reached and executed ... print('hi there!') ... print(str(os.path.join)[:14] + '...') # code is reached hi there! <function join...But if you try to import a module that doesn’t exist on your system, the block will be skipped from that point onward, silently.
>>> with ModuleNotFoundIgnore(): ... import do.i.exist ... # The following code is NEVER reached or executed ... print(do.i.exist) ... t = 0 / 0But if there’s any other kind of error (other than ModuleNotFoundError that is, the error will be raised normally.
>>> with ModuleNotFoundIgnore(): ... t = 0/0 Traceback (most recent call last): ... ZeroDivisionError: division by zero
- class py2http.util.TypeAsserter(types_for_kind, if_kind_missing='ignore')[source]¶
Bases:
objectMakes a callable that asserts that a value
vhas the expected type(s) that it’s kindkshould be>>> assert_type = TypeAsserter({'foo': str, 'bar': (Callable, type(None))}) >>> assert_type('bar', lambda x: x) >>> assert_type('bar', None) >>> assert_type('foo', 'i am a string') >>> assert_type('foo', list('i am not a string')) Traceback (most recent call last): ... AssertionError: Invalid foo type, must be a <class 'str'>, but was a <class 'list'>If a kind wasn’t specified, the default is to ignore
>>> assert_type('not_a_kind', 'blah') >>> assert_type = TypeAsserter({'foo': str, 'bar': (Callable, type(None))}) # nothing happensBut you can choose to warn or raise an exception instead
>>> assert_type = TypeAsserter({'foo': str, 'bar': list}, if_kind_missing='raise') >>> assert_type('not_a_kind', 'blah') Traceback (most recent call last): ... ValueError: Unrecognized kind: not_a_kind. The ones I recognize: ['foo', 'bar']
- py2http.util.call_with_inputs(func, args=(), kwargs=None)[source]¶
Call
func(*args, **kwargs), passing the entries ofkwargsthat name positional-only parameters offuncpositionally, which JSON (a mapping) can only supply by name (i2mint/py2http#14).>>> call_with_inputs({"a": 1}.__getitem__, kwargs={"key": "a"}) 1 >>> d = {} >>> call_with_inputs(d.__setitem__, kwargs={"key": "k", "value": 2}), d (None, {'k': 2}) >>> call_with_inputs(lambda x, /, y=0: (x, y), kwargs={"x": 1, "y": 2}) (1, 2)A positional-only argument that is neither required to be given nor given takes its default; a missing required one is an
InputError(a client error), not aTypeError. A callable whose signature can’t be read gets**kwargsas is.Python lets a function with
**kwargsreceive a keyword that is also the name of a positional-only parameter (Counter.update(iterable=3)): such an optional parameter is left inkwargs; only required ones are bound by name.
- py2http.util.deprecate(func=None, *, msg=None)[source]¶
Decorator to emit a DeprecationWarning when the decorated function is called.
- class py2http.util.lazyprop(func)[source]¶
Bases:
objectA descriptor implementation of lazyprop (cached property). Made based on David Beazley’s “Python Cookbook” book and enhanced with boltons.cacheutils ideas.
>>> class Test: ... def __init__(self, a): ... self.a = a ... @lazyprop ... def len(self): ... print('generating "len"') ... return len(self.a) >>> t = Test([0, 1, 2, 3, 4]) >>> t.__dict__ {'a': [0, 1, 2, 3, 4]} >>> t.len generating "len" 5 >>> t.__dict__ {'a': [0, 1, 2, 3, 4], 'len': 5} >>> t.len 5 >>> # But careful when using lazyprop that no one will change the value of a without deleting the property first >>> t.a = [0, 1, 2] # if we change a... >>> t.len # ... we still get the old cached value of len 5 >>> del t.len # if we delete the len prop >>> t.len # ... then len being recomputed again generating "len" 3
- py2http.util.obj_to_items_gen(obj, attrs, on_missing_attr=<class 'py2http.util.Missing'>, kv_trans=<function <lambda>>)[source]¶
Make a generator of (k, v) items extracted from an input object, given an iterable of attributes to extract
- Parameters:
- Returns:
A generator
- py2http.util.obj_to_path(obj)[source]¶
Quasi-inverse of obj_to_path: Get a root_obj and attr_path from an object. Obviously, would only be able to work with some types (only by-ref types?).
>>> class A: ... def foo(self, x): ... ... foo.x = 3 ... class B: ... def bar(self, x): ... ... >>> for t in [(A, ('foo',)), (A, ('B',)), (A, ('B', 'bar'))]: ... print(obj_to_path(path_to_obj(*t))) ... print(t) ... print() (<class 'util.A'>, ('foo',)) (<class 'util.A'>, ('foo',)) <class 'util.A.B'> (<class 'util.A'>, ('B',)) (<class 'util.A'>, ('B', 'bar')) (<class 'util.A'>, ('B', 'bar'))# >>> for t in [(A, (‘foo’,)), (A, (‘B’,)), (A, (‘B’, ‘bar’))]: # … assert obj_to_path(path_to_obj(*t)) == t
- py2http.util.path_to_obj(root_obj, attr_path)[source]¶
Get an object from a root object and “attribute path” specification.
>>> class A: ... def foo(self, x): ... ... foo.x = 3 ... class B: ... def bar(self, x): ... ... >>> obj = path_to_obj(A, ('foo',)) >>> assert callable(obj) and obj.__name__ == 'foo' >>> path_to_obj(A, ('foo', 'x')) 3 >>> obj = path_to_obj(A, ('B', 'bar')) >>> assert callable(obj) and obj.__qualname__ == 'A.B.bar'
- py2http.util.pyparam_to_dict(param, kv_trans=<function _pyparam_kv_trans.skip_empties>)[source]¶
Get dict from a Parameter object
- Parameters:
param – A inspect.Parameter instance
kv_trans (
Callable) – A callable that will be called on the (k, v) attribute items of the Parameter instance
- Returns:
A dict extracted from this Parameter
>>> from inspect import Parameter, Signature, signature >>> from functools import partial >>> >>> def mult(x: float, /, y=1, *, z: int=1): ... >>> params_dicts = map(pyparam_to_dict, signature(mult).parameters.values()) >>> # see that we can recover the original signature from these dicts >>> assert Signature(map(lambda kw: Parameter(**kw), params_dicts)) == signature(mult)Now what about the kv_trans? It’s default is made to return None when a value is equal to
Parameter.empty(which is the way the inspect module distinguishes theNoneobject from “it’s just not there”.But we could provide our own kv_trans, which should be a function taking
(k, v)pair (those k and v arg names are imposed!) and returns… well, what ever you want to return really. But you if return None, the(k, v)item will be skipped.Look here how using
kv_trans=pyparam_to_dict.kv_trans.with_str_kinddoes the job of skippingParameter.emptyitems, but also cast thekindvalue to a string, so that it can be jsonizable.>>> params_to_jdict = partial(pyparam_to_dict, kv_trans=pyparam_to_dict.kv_trans.with_str_kind) >>> got = list(map(params_to_jdict, signature(mult).parameters.values())) >>> expected = [ ... {'name': 'x', 'kind': 'POSITIONAL_ONLY', 'annotation': float}, ... {'name': 'y', 'kind': 'POSITIONAL_OR_KEYWORD', 'default': 1}, ... {'name': 'z', 'kind': 'KEYWORD_ONLY', 'default': 1, 'annotation': int}] >>> assert got == expected, f"\n got={got}\n expected={expected}"