All work

myBasis

Everyday Python utilities for text, iteration, and type coercion.

Source on GitLab Python · MPL-2.0 · v1.2.2
Isometric stack of the my-basis Python package, bottom to top: infra, utils, caches, typing, types, regex, and on top, side by side, apis and files. At runtime each layer imports only from layers below it, so infra imports nothing and apis and files do not import each other; an amber arrow beside the stack points down to show the direction. A slab is as thick as the layer has lines of code, on one linear scale: utils and typing are the thickest, infra and caches the thinnest. Beside the stack, on a dashed ground, data and scripts sit outside the import graph, drawn to the same thickness scale. apis2.0k regex5.1k types3.1k typing5.5k caches1.1k utils5.5k infra0.8k files1.8k thickness = lines imports data scripts outside graph

I made this module to streamline some patterns that seemed both A) frequently-relevant and feasible to streamline. It grew alongside my projects over the years, which means it was in daily use by me from day one.

It covers iteration helpers, regex composition, caching, file formats, and runtime type casting (including a Pydantic model that applies the same casting rules during validation). It has (IMHO) novel, deep approaches to runtime typing ("Vibe Typing"), text processing, and building unusually-huge regular expressions pipelines without losing readability or performance. The regex work was driven by Wikiparse, where I had to write extremely performant code in Python for the first time. Nearly every Python project on this page depends on it. It's on PyPI as my-basis.

$ cat demo.py
from my import ty, MyType, Span, ut

print(ty.cast('42', int))
print(ty.cast(['1', '2', '3'], list[int]))
print(ty.check('42', int))
print(ty.match('hello', str | int))

t = MyType(dict[str, int])
print(t.main)

s = Span(3, 9)
print(s)

odds, evens = ut.partition(range(10), lambda n: n % 2 == 0)
print(odds, evens)

print(ut.decimal_to_roman(2026))
print(ut.plural(3, 'fox', 'foxes'))

$ python demo.py
42
[1, 2, 3]
False
True
<class 'dict'>
3-8
[1, 3, 5, 7, 9] [0, 2, 4, 6, 8]
MMXXVI
foxes
The same string value 42 passes through cast to int and becomes the integer 42, and separately through check against int and only answers False, since the value is still a string; a list of digit strings passes through cast to list of int and becomes a list of integers. value operation result '42' cast → int 42 '42' check → int False ['1', '2', '3'] cast → list[int] [1, 2, 3]
Seven public areas of myBasis, each shown as one real call from its own README and the real result of re-running it: ut.partition splits a list by a predicate; Span checks whether two intervals intersect; AutocastModel coerces string input assigned to a Pydantic model; RegexStore searches a named pattern and prints the match; Cache stores and reads back a value by key; env reads an environment variable; Markdown parses a document into walkable section nodes. utilitiesutut.partition([1, 2, 3, 4], lambda x: x % 2 == 0)→ ([1, 3], [2, 4]) reusable typesSpanSpan(3, 9).intersects(Span(8, 12))→ True runtime typingty · AutocastModels = Settings(port='8080', debug='true')(s.port, s.debug)→ (8080, True) regular expressionsRegexStoreprint(store.search('greeting', 'hello world'))→ name: world cachesCachecache['answer'] = 42cache['answer']→ 42 interfacesenvenv.get('DEMO_FLAG')→ 'true' file formatsMarkdownroot = Markdown.parse(doc)[0][str(n).splitlines()[0] for n in root.walk()]→ ['# Title', '## Section A']