hio.help.helping

hio.help.helping module

Module Contents

hio.help.helping.isign(i)

Integer sign function :returns: 1 if i > 0, -1 if i < 0, 0 otherwise :rtype: (int)

hio.help.helping.sceil(r)

Symmetric ceiling function Returns the symmetric ceiling of r away from zero.

Because int() provides a symmetric floor towards zero, increment int(r) by 1 when r - int(r) > 0 (r positive), -1 when r - int(r) < 0 (r negative), and 0 when r - int(r) == 0 (r integral already).

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

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

functools.update_wrapper assigns and updates attributes in WRAPPER_ASSIGNMENTS (__module__, __name__, __qualname__, __doc__, __annotations__) and 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)

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)

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)

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

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

class hio.help.helping.NonStringSequence

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

hio.help.helping.isNonStringIterable(obj)

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.isNonStringSequence(obj)

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

hio.help.helping.isIterator(obj)

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)

Atomically open or create file from filepath.

If file already exists, open with mode. Otherwise create a new file using write/update mode (binary if “b” in mode). Returns file object. perm uses mode bits like stat.S_IRUSR | stat.S_IWUSR (0o600).

hio.help.helping.dump(data, path)

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)

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

hio.help.helping.intToB64(i, l=1)

Converts int i to at least l Base64 chars as str.

Returns Base64 conversion of i of minimum length l. If more than l chars are needed to represent i in Base64 then the string is lengthened appropriately. When fewer than l chars are needed, the string is left padded with “A”. l is the minimum number of Base64 digits, where Base64 0 is “A”.

hio.help.helping.intToB64b(i, l=1)

Converts int i to at least l Base64 chars as bytes.

Returns:

Base64 conversion of i of length minimum l. If more than

l bytes are needed to represent i in Base64 then returned bytes is extended appropriately. When less then l bytes is needed then returned bytes is prepadded with b’A’ bytes.

Return type:

b64 (bytes)

Parameters:
  • i (int) – to be converted

  • l (int) – min number of b64 digits. When empty these are left padded with Base64 0 == b’A’ digits. The length of return bytes is extended to accommodate full Base64 encoding of i regardless of l.

hio.help.helping.b64ToInt(s)

Converts Base64 to int :returns: conversion s (str | bytes) to int :rtype: i (int)

Parameters:

s (str | bytes) – to be converted

hio.help.helping.codeB64ToB2(s)

Convert Base64 chars in s to B2 bytes

Returns:

conversion (decode) of s Base64 chars to Base2 bytes. Where the number of total bytes returned is equal to the minimun number of chars (octet) sufficient to hold the total converted concatenated chars from s, with one sextet per each Base64 char of s. Assumes no pad chars in s.

Return type:

bs (bytes)

Sextets are left aligned with pad bits in last (rightmost) byte to support mid padding of code portion with respect to rest of primitive. This is useful for decoding as bytes, code characters from the front of a Base64 encoded string of characters.

Parameters:

s (str | bytes) – Base64 str or bytes to convert

hio.help.helping.codeB2ToB64(b, l)

Converts first l sextets of base2 b bytes to base64 str and returns

Returns::
code (str): conversion (encode) of l Base2 sextets from front of b

to Base64 chars.

One char for each of l sextets from front (left) of b. This is useful for encoding as code characters, sextets from the front of a Base2 bytes (byte string). Must provide l because of ambiguity between l=3 and l=4. Both require 3 bytes in b. Trailing pad bits are removed so returned sextets as characters are right aligned .

Parameters::

b (bytes | str): target from which to nab sextets l (int): number of sextets to convert from front of b

hio.help.helping.nabSextets(b, l)

Nab l sextets from front of b.

Returns bytes with the first l sextets from the left of b. Length is the minimum needed to hold all l sextets. The last byte is right padded with zeros to be compatible with mid-padded codes on front of primitives. b is bytes or str, and l is the number of sextets to nab.