hio.help.helping

hio.help.helping module

Module Contents

Classes

NonStringIterable

Allows isinstance check for iterable that is not a string

NonStringSequence

Allows isinstance check for sequence that is not a string

Functions

copyfunc(f, name=None)

Copy a function in detail.

attributize(genie)

Decorator function:

repack(n, seq, default=None)

Repacks seq into a generator of len n and returns the generator.

just(n, seq, default=None)

Returns a generator of just the first n elements of seq and substitutes

nonStringIterable(obj)

Returns: (bool) True if obj is non-string iterable, False otherwise

nonStringSequence(obj)

Returns: (bool) True if obj is non-string sequence, False otherwise

isIterator(obj)

Returns True if obj is an iterator object, that is,

ocfn(path, mode='r+', perm=stat.S_IRUSR | stat.S_IWUSR)

Atomically open or create file from filepath.

dump(data, path)

Serialize data dict and write to file given by path where serialization is

load(path)

Return data read from file path as dict

hio.help.helping.copyfunc(f, name=None)[source]

Copy a function in detail. To change name of func provide name parameter

functools to update_wrapper assigns and updates following attributes WRAPPER_ASSIGNMENTS = (‘__module__’, ‘__name__’, ‘__qualname__’, ‘__doc__’,

‘__annotations__’)

WRAPPER_UPDATES = (‘__dict__’,) Based on https://stackoverflow.com/questions/6527633/how-can-i-make-a-deepcopy-of-a-function-in-python https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function

hio.help.helping.attributize(genie)[source]

Decorator function:

Python generators do not support adding attributes. Adding support for attributes provides a way to pass information from a WSGI App that returns a generator to a WSGI server via the generator after the WSGI app has already started returning its body. The hio.http.Server WSGI server looks for the attributes ._status and ._headers and substitutes these if present. This allows a streaming WSGI App body iterator to later modify the headers and status taht will be returned before the body iterator began iterating. This is useful for web hooks or backend requests that are serviced by an async coroutine based WSGI app so that they may leverage the streaming support of standard WSGI but use a the coroutine based hio.http.Server as an async WSGI server.

This decorator takes a Duck Typing approach to decorating a generator function or method that returns a new function type instance that when called will return a generator like object that supports attributes. the new wrapped object acts like a generator but with attributes.

Parameters

genie (generator function, generator method) – is either a generator function that returns a generator object a generator method that returns a generator object

If genie is a generator function then a reference to its wrapper

is injected as the first positional argument to the orginal generator function. The convention is to use the parameter ‘me’ to refer to the injected reference to the wrapper.

If genie is a generator method, that is, its first parameter is ‘self’

then a reference to its wrapper is injected as the second positional argument to the original generator method. the convention is to use the parameter ‘me’ to refer to the injected reference to the wrapper so as not to collide with the ‘self’ instance reference.

When wrapped the new type is AttributiveGenerator

Usage: # decorated generator function @attributize def bar(me, req=None, rep=None):

me._status = 400 # or copy from rep.status me._headers = odict(example=”Hi”) # or copy from rep.headers yield b”” yield b”” yield b”Hello There” return b”Goodbye”

gen = bar() msg = next(gen) # attributes set after first next gen._status gen._headers

# decorated generator method class R:

@attributize def bar(self, me, req=None, rep=None):

self.name = “Peter” me._status = 400 # or copy from rep.status me._headers = odict(example=”Hi”) # or copy from rep.headers yield b”” yield b”” yield b”Hello There ” + self.name.encode() return b”Goodbye”

r = R() gen = r.bar() msg = next(gen) # attributes set after first next gen._status gen._headers

# use as function wrapper directly instead of as decorator def gf(me, x): # convention injected reference to attributed wrapper is ‘me’

me.x = 5 me.y = ‘a’ cnt = 0 while cnt < x:

yield cnt cnt += 1

agf = attributize(gf) ag = agf(3) # body of gf is not run until first next call assert isIterator(ag) assert not hasattr(ag, ‘x’) assert not hasattr(ag, ‘y’) n = next(ag) # first run here which sets up attributes assert n == 0 assert hasattr(ag, ‘x’) assert hasattr(ag, ‘y’) assert ag.x == 5 assert ag.y ==’a’ n = next(ag) assert n == 1

Adding attributes to this injected reference makes them available as attributes of the resultant wrapper.

The HTTP WSGI server at hio.core.http.serving.Server uses an instance of hio.core.http.serving.Responder to generate the response for each WSGI request. The Responder instance checks its WSGI app generator for existence of the attributes ._status and ._headers. If so then it overrides its default response status with ._status and updates its default response headers with the headers in ._header. This allows a backend (webhook) to conveniently influence the response status and headers. The response body is returned by the generator itself.

Background: Unlike Python functions, Python generators do not support custom attributes and the generator locals dict at .gi_frame.f_locals dissappears once the generator is complete so its inconvenient.

Fixed attributes of generator objects. [‘.__next__’, ‘__iter__’, ‘close’, ‘gi_code’, ‘gi_frame’, ‘gi_running’, ‘gi_yieldfrom’, ‘send’, ‘throw’]

hio.help.helping.repack(n, seq, default=None)[source]

Repacks seq into a generator of len n and returns the generator. The purpose is to enable unpacking into n variables. The first n-1 elements of seq are returned as the first n-1 elements of the generator and any remaining elements are returned in a tuple as the last element of the generator default (None) is substituted for missing elements when len(seq) < n

Example:

x = (1, 2, 3, 4) tuple(repack(3, x)) (1, 2, (3, 4))

x = (1, 2, 3) tuple(repack(3, x)) (1, 2, (3,))

x = (1, 2) tuple(repack(3, x)) (1, 2, ())

x = (1, ) tuple(repack(3, x)) (1, None, ())

x = () tuple(repack(3, x)) (None, None, ())

hio.help.helping.just(n, seq, default=None)[source]

Returns a generator of just the first n elements of seq and substitutes default (None) for any missing elements. This guarantees that a generator of exactly n elements is returned. This is to enable unpacking into n varaibles

Example:

x = (1, 2, 3, 4) tuple(just(3, x)) (1, 2, 3) x = (1, 2, 3) tuple(just(3, x)) (1, 2, 3) x = (1, 2) tuple(just(3, x)) (1, 2, None) x = (1, ) tuple(just(3, x)) (1, None, None) x = () tuple(just(3, x)) (None, None, None)

class hio.help.helping.NonStringIterable[source]

Allows isinstance check for iterable that is not a string if isinstance(x, NonStringIterable):

classmethod __subclasshook__(cls, C)[source]

Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).

class hio.help.helping.NonStringSequence[source]

Allows isinstance check for sequence that is not a string if isinstance(x, NonStringSequence):

classmethod __subclasshook__(cls, C)[source]

Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).

hio.help.helping.nonStringIterable(obj)[source]

Returns: (bool) True if obj is non-string iterable, False otherwise

Another way that is less future proof return (hasattr(x, ‘__iter__’) and not isinstance(x, (str, bytes)))

hio.help.helping.nonStringSequence(obj)[source]

Returns: (bool) True if obj is non-string sequence, False otherwise

hio.help.helping.isIterator(obj)[source]

Returns True if obj is an iterator object, that is,

has an __iter__ method has a __next__ method .__iter__ is callable and returns obj

Otherwise returns False

hio.help.helping.ocfn(path, mode='r+', perm=stat.S_IRUSR | stat.S_IWUSR)[source]

Atomically open or create file from filepath.

If file already exists, Then open file using openMode Else create file using write update mode If not binary Else

write update binary mode

Returns file object

If binary Then If new file open with write update binary mode

x = stat.S_IRUSR | stat.S_IWUSR 384 == 0o600 436 == octal 0664

hio.help.helping.dump(data, path)[source]

Serialize data dict and write to file given by path where serialization is given by path’s extension of either JSON, MsgPack, or CBOR for extension .json, .mgpk, or .cbor respectively

hio.help.helping.load(path)[source]

Return data read from file path as dict file may be either json, msgpack, or cbor given by extension .json, .mgpk, or .cbor respectively Otherwise raise IOError