Utility classes and functions¶
Arguments¶
- class momotor.bundles.utils.arguments.BundleFactoryArguments(xml_name=None, use_lxml=None, validate_xml=None, location_base=None, validate_signature=True, legacy=False)¶
-
-
use_lxml:
bool
|None
= None¶ force (
True
) or prevent (False
) use of lxml library. IfNone
, uses lxml when installed.
-
use_lxml:
- class momotor.bundles.utils.arguments.DirectoryConstructionArguments(use_lxml=None, pretty_xml=False, encoding='utf-8', xml_name=None, sign_files=True, hashers=<factory>, legacy=False, optimize=True, generator_name=True, dir_mode=448)¶
-
dir_mode:
int
= 448¶ the mode bits (defaults to 0o700, making the directory only accessible to the current user)
-
generator_name:
bool
|str
= True¶ add a generator meta node. If
True
, uses this package’s name and version number. IfFalse
does not add a generator node. If a string is provided, uses that as the generator name, and adds the package name. DefaultTrue
-
hashers:
Sequence
[str
]¶ hashing algorithms to use when
sign_files
is set toTrue
. Default['sha1']
-
sign_files:
bool
= True¶ sign the <file> nodes. This calculates a hash of the attachments and adds it as an attribute in the XML
-
dir_mode:
- class momotor.bundles.utils.arguments.FileConstructionArguments(use_lxml=None, pretty_xml=False, encoding='utf-8', xml_name=None, sign_files=True, hashers=<factory>, legacy=False, optimize=True, generator_name=True, zip=False, compression=8, compresslevel=None)¶
-
compression:
int
= 8¶ compression mode, see
zipfile.ZipFile
for possible values. (Defaults toZIP_DEFLATED
, only used when generating a zipped bundle)
-
compresslevel:
int
|None
= None¶ compression level, see
zipfile.ZipFile
for possible values. (Only used when generating a zipped bundle)
-
generator_name:
bool
|str
= True¶ add a generator meta node. If
True
, uses this package’s name and version number. IfFalse
does not add a generator node. If a string is provided, uses that as the generator name, and adds the package name. DefaultTrue
-
hashers:
Sequence
[str
]¶ hashing algorithms to use when
sign_files
is set toTrue
. Default['sha1']
-
sign_files:
bool
= True¶ sign the <file> nodes. This calculates a hash of the attachments and adds it as an attribute in the XML
-
use_lxml:
bool
|None
= None¶ force (
True
) or prevent (False
) use of lxml library. IfNone
, auto-detects lxml availability
-
compression:
Assertions¶
- momotor.bundles.utils.assertion.assert_element_mapping_instanceof(mapping, expected_key_type, expected_value_type, bundle)¶
Combines
assert_elements_bundle()
andassert_mapping_instanceof()
- Parameters:
mapping (
TypeVar
(ElementMappingType
, bound=Optional
[Mapping
[Hashable
, momotor.bundles.elements.base.Element]])) – A mapping containing items to testexpected_key_type (
type
[Hashable
]) – Expected type for the keysexpected_value_type (
type
[Element
]) – Expected type for the valuesbundle (
Bundle
) – expected bundle instance for each element
- Return type:
TypeVar
(ElementMappingType
, bound=Optional
[Mapping
[Hashable
, momotor.bundles.elements.base.Element]])
- momotor.bundles.utils.assertion.assert_elements_bundle(elements, bundle)¶
Assert that all elements are linked the correct bundle. Returns elements
- momotor.bundles.utils.assertion.assert_elements_instanceof(elements, expected_type, bundle)¶
Combines
assert_elements_bundle()
andassert_sequence_instanceof()
- momotor.bundles.utils.assertion.assert_mapping_instanceof(mapping, expected_key_type, expected_value_type)¶
Assert that all items in the mapping have the expected key and value types. Returns mapping
- momotor.bundles.utils.assertion.assert_sequence_instanceof(items, expected_type)¶
Assert that all items are of the expected type. Returns items
Boolean¶
- momotor.bundles.utils.boolean.to_bool(val)¶
Convert a representation of truth to True or False.
True values are ‘y’, ‘yes’, ‘t’, ‘true’, ‘on’, and ‘1’; false values are ‘n’, ‘no’, ‘f’, ‘false’, ‘off’, and ‘0’. Raises ValueError if ‘val’ is anything else.
- Return type:
>>> to_bool(True) True
>>> to_bool('y') True
>>> to_bool('yes') True
>>> to_bool('t') True
>>> to_bool('true') True
>>> to_bool('on') True
>>> to_bool('1') True
>>> to_bool(1) True
>>> to_bool(False) False
>>> to_bool('n') False
>>> to_bool('no') False
>>> to_bool('f') False
>>> to_bool('false') False
>>> to_bool('off') False
>>> to_bool('0') False
>>> to_bool(0) False
>>> to_bool(None) False
>>> to_bool('other') Traceback (most recent call last): ... ValueError: invalid truth value 'other'
Domains¶
- momotor.bundles.utils.domain.merge_domains(*domains)¶
Merge domains of format <domain>#<subdomain>.
For all domains, the first provided part is returned as part of the merged domain:
abc#def | uvw#xyz = abc#def abc#def | uvw = abc#def abc#def | #xyz = abc#def abc | uvw#xyz = abc#xyz abc | uvw = abc abc | #xyz = abc#xyz #def | uvw#xyz = uwv#def #def | uvw = uwv#def #def | #xyz = #def
>>> merge_domains() is None True
>>> merge_domains(None) is None True
>>> merge_domains('abc#def', 'uvw') 'abc#def'
>>> merge_domains('abc#def', '#xyz') 'abc#def'
>>> merge_domains('abc#def', 'uvw#xyz') 'abc#def'
>>> merge_domains('abc', 'uvw#xyz') 'abc#xyz'
>>> merge_domains('abc', 'uvw') 'abc'
>>> merge_domains('abc', '#xyz') 'abc#xyz'
>>> merge_domains('#def', 'uvw#xyz') 'uvw#def'
>>> merge_domains('#def', 'uvw') 'uvw#def'
>>> merge_domains('#def', '#xyz') '#def'
- momotor.bundles.utils.domain.split_domain(domain)¶
Split a domain name <domain>[#<subdomain>] into its parts.
>>> split_domain(None) (None, None)
>>> split_domain('') (None, None)
>>> split_domain('#') (None, None)
>>> split_domain('domain') ('domain', None)
>>> split_domain('domain#') ('domain', None)
>>> split_domain('#subdomain') (None, 'subdomain')
>>> split_domain('domain#subdomain') ('domain', 'subdomain')
- momotor.bundles.utils.domain.unsplit_domain(domain, subdomain)¶
Merge <domain> and <subdomain> parts into a <domain>#<subdomain> string, handling
None
valuesThe reverse operation of
split_domain()
.>>> unsplit_domain(None, None) is None True
>>> unsplit_domain('domain', None) 'domain'
>>> unsplit_domain('domain', '') 'domain'
>>> unsplit_domain(None, 'subdomain') '#subdomain'
>>> unsplit_domain('domain', 'subdomain') 'domain#subdomain'
Encoding¶
Data encoding and decoding
- momotor.bundles.utils.encoding.ENCODINGS¶
List of all supported encodings
- momotor.bundles.utils.encoding.decode_data(data, encoding)¶
Decode encoded data.
- Parameters:
- Return type:
- Returns:
The decoded data
- Raises:
ValueError – For unsupported encodings
- momotor.bundles.utils.encoding.encode_data(data)¶
Encode provided data.
Printable data is encoded using Quoted-printable encoding, any other data is encoded using Base64 encoding.
- momotor.bundles.utils.encoding.encode_posix_path(path)¶
Encode a path using idna encoding to ensure it will only contain ascii characters
- Return type:
- momotor.bundles.utils.encoding.is_printable(s, low=32, allowed=None)¶
Detect if string is printable; it should not contain any control characters, except those in allowed, and less than 5% of the characters are allowed to be high-ascii
- momotor.bundles.utils.encoding.quopri_decode(data)¶
Decode quoted printable data
- momotor.bundles.utils.encoding.quopri_encode(data)¶
Encode data using quoted printable method Uses a different algorithm than
quopri.encodestring()
:Encodes first space character on a line, but not the rest
Encodes newline, return characters and high-ascii
Grouping¶
- momotor.bundles.utils.grouping.group_by_attr(items, *attrs)¶
Group a list of elements by the value of one or more attributes
Immutable¶
- class momotor.bundles.utils.immutable.ImmutableDict(*args, **kwargs)¶
An immutable
dict
- pop(key)¶
If the key is not found, return the default if given; otherwise, raise a KeyError.
- Return type:
- popitem(last=True)¶
Remove and return a (key, value) pair as a 2-tuple.
Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.
- Return type:
- setdefault(key, default=None)¶
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
- Return type:
- class momotor.bundles.utils.immutable.ImmutableOrderedDict(*args, **kwargs)¶
An immutable
OrderedDict
- pop(key)¶
If the key is not found, return the default if given; otherwise, raise a KeyError.
- Return type:
- popitem(last=True)¶
Remove and return a (key, value) pair from the dictionary.
Pairs are returned in LIFO order if last is true or FIFO order if false.
- Return type:
- setdefault(key, default=None)¶
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
- Return type:
KeyedTuple¶
- class momotor.bundles.utils.keyedtuple.KeyedTuple(items=None, *, key_attr=None)¶
A tuple of objects with an indexable attribute that acts as both an immutable sequence and a mapping. Elements can be accessed by their numeric index or the key attribute.
- Parameters:
If items is another
KeyedTuple
, key_attr must either be the same as the key_attr of items, or not provided.- copy()¶
Create a shallow copy
- Return type:
Self
- count(value)¶
Return number of occurrences of value
- get(key_or_index, default=None)¶
Get an item from the sequence by index, key or item
- index(value, start=0, stop=None)¶
Return first index of value
- values()¶
A set-like object providing a view on the values
- Return type:
ValuesView
[TypeVar
(IT
)]
lxml¶
Nodes¶
- momotor.bundles.utils.nodes.get_nested_complex_nodes(node, node_name, *sub_node_names)¶
Get all the nodes in a nested complex node structure.
For example, with the following XML:
<root> <level1> <level2> <level2> <level2> </level1> <level1> <level2> </level1> </root>
a call
get_nested_complex_list(root_node, 'level1', 'level2')
yields a sequence of[('level1', level1-node), ('level2', level2-node), ('level2', level2-node), ('level2', level2-node), ('level1', level1-node), ('level2', level2-node) ]
Text¶
Useful functions for string processing, borrowed from Django (with a few small modifications)
- momotor.bundles.utils.text.smart_split(text)¶
Generator that splits a string by spaces, leaving quoted phrases together. Supports both single and double quotes, and supports escaping quotes with backslashes. In the output, strings will keep their initial and trailing quote marks and escaped quotes will remain escaped (the results can then be further processed with unescape_string_literal()).
>>> list(smart_split(r'This is "a person\'s" test.')) ['This', 'is', '"a person\\\'s"', 'test.'] >>> list(smart_split(r"Another 'person\'s' test.")) ['Another', "'person\\'s'", 'test.'] >>> list(smart_split(r'A "\"funky\" style" test.')) ['A', '"\\"funky\\" style"', 'test.']
- momotor.bundles.utils.text.unescape_string_literal(s)¶
Convert quoted string literals to unquoted strings with escaped quotes and backslashes unquoted:
>>> unescape_string_literal('"abc"') 'abc' >>> unescape_string_literal("'abc'") 'abc' >>> unescape_string_literal('"a \"bc\""') 'a "bc"' >>> unescape_string_literal("'\'ab\' c'") "'ab' c"
- Return type:
Zip¶
- class momotor.bundles.utils.zipwrapper.ZipWrapper(*, path=None, content=None)¶
A wrapper around a
ZipFile
. The zip file can be either located in the filesystem or in memory.Example usage:
zip_wrapper = ZipWrapper('test.zip') with zip_wrapper as zip_file, zip_file.open() as f: # f is now an open zipfile.ZipFile object
- Parameters:
content (
bytes
|memoryview
|None
) – Abytes
ormemoryview
containing the data of the zip file
- close()¶
Close the wrapped zip file
-
content:
bytes
|memoryview
|None
¶