The myBasis utility package — imported as my — is a broad extension of the Python standard library centered on text processing, functional programming, and runtime type coercion.
The use cases are diverse enough to not enumerate them all here, but they all share a strong sense of discipline: all code is thoroughly typed, tested, and documented following my best pass at best practices (it does get easier!).
I made this module to streamline some patterns that seemed both A) frequently-relevant and feasible to streamline. The repo thus grew alongside my projects over time, a genesis which gives it the advantage of being in daily use by the original author in multiple examples right off the bat.
Left-rule blocks mark artificial prose; quotations retain their own attribution.
Documentation: basis.docs.doering.ai
Installation
In an activated Python 3.13+ environment:
uv pip install my-basis
# or:
python -m pip install my-basis
A first example
Start with
ty: cast a value into a target type, check whether it already fits, or inspect the type itself. Casting and checking are deliberately different operations.
from my import ty, MyType
ty.cast('42', int) # -> 42
ty.cast(['1', '2', '3'], list[int]) # -> [1, 2, 3]
ty.cast({'a': '1', 'b': '2'}, dict[str, int]) # -> {'a': 1, 'b': 2}
ty.check(42, int) # -> True
ty.check('42', int) # -> False
ty.match('hello', str | int) # -> True
t = MyType(dict[str, int])
t.main # -> <class 'dict'>
t.args # child MyType nodes for str and int
t.root # -> dict[str, int]
tyis the sharedTypistinstance, combiningcast,check, andmatch. Use the typing guide when the coercion rules themselves matter.
Find your corner
Seven public subpackages cover the main jobs. The root re-exports their public names, so
from my import ut, ty, Span, Markdownis enough for the examples here. The heavierapisandfilesbranches load lazily.
| Area | Start here | Useful for | API reference |
|---|---|---|---|
| Utilities | ut |
Partitioning iterables, transforming text, working with syntax and system resources | Hosted |
| Runtime typing | ty, MyType, AutocastModel |
Coercion, conformance checks, and inspecting annotations | Hosted |
| Reusable types | Span, Buffer, Command |
Intervals, mutable text, and reusable shell invocations | Hosted |
| Regular expressions | RegexStore, MatchData |
Composing named patterns and inspecting matches | Hosted |
| Caches | Cache, NestedCache, FileCache, PickleCache |
In-memory, hierarchical, disk-backed, and expiring storage | Hosted |
| Interfaces | env, fs, GoogleSheet |
Typed environment access, named paths, and optional spreadsheet integration | Hosted |
| File formats | Markdown |
Parsing, walking, and editing a document tree | Hosted |
A short tour
Utilities
utcollects the utility families into one namespace. You can also import a family directly—IterUtilsanditer_utils, for example, name the same class. One detail worth noticing below:findreturns an index, not the matching value.
from my import ut
ut.partition([1, 2, 3, 4], lambda x: x % 2 == 0) # -> ([1, 3], [2, 4])
ut.condense(['a', None, '', 'b', 0]) # -> ['a', 'b']
ut.find([3, 8, 2], lambda x: x > 5) # -> 1
Runtime typing
AutocastModelapplies the casting rules during Pydantic validation. It's useful when incoming values are close to the shape you need, including a scalar where your model expects a list. Use it where that permissiveness is intended.
from my import AutocastModel
class Settings(AutocastModel):
port: int = 0
debug: bool = False
tags: list[str] = []
s = Settings(port='8080', debug='true', tags='solo')
(s.port, s.debug, s.tags) # -> (8080, True, ['solo'])
Reusable types
The types branch gives recurring concepts their own objects.
Span, for instance, represents a half-open interval and handles its length and overlap checks. The shared type vocabulary also pairs annotation aliases such asAtomwith runtime tuples such asAtoms.
from my import Span
a, b = Span(3, 9), Span(8, 12)
a.delta # -> 6
a.intersects(b) # -> True
Regular expressions
RegexStoregives patterns names you can compose and reuse.MatchDatakeeps repeated groups accessible, andCOMMON_RGXSsupplies a collection of ready-made patterns. The meta layer is there when you need to inspect the expression itself.
from my import RegexStore, COMMON_RGXS
COMMON_RGXS.findall('url', 'visit https://example.com or www.foo.dev')
# -> [MatchData("https://example.com" -> {'url': ['example.com']}),
# MatchData("www.foo.dev" -> {'url': ['foo.dev']})]
store = RegexStore()
store.define('greeting', r'hello (?P<name>\w+)')
print(store.search('greeting', 'hello world')) # -> name: world
Caches
Choose a cache by its storage pattern: bounded memory, nested levels, memory over disk, or pickle-backed persistence with expiry. The simplest case is a
Cache. If you usePickleCache, load only data you trust—unpickling can execute code.
from my import Cache
cache = Cache(maxsize=256)
cache['answer'] = 42
cache['answer'] # -> 42
Interfaces
envsnapshots environment variables when it first loads;fsprovides a named path registry. Set demonstration variables before importingenv(or use a fresh process if you've already loaded it).GoogleSheetadds spreadsheet access through the optional
import os
os.environ['DEMO_FLAG'] = 'true'
from my import env
env.get('DEMO_FLAG') # -> 'true'
env.flag('DEMO_FLAG') # -> 1 (0 when unset)
File formats
Markdownparses a document into a hierarchy of sections while respecting fenced code. You can walk the nodes, edit them, and render the result.
from my import Markdown
root = Markdown.parse('# Title\n\nIntro prose\n\n## Section A\n\nBody\n')[0]
[str(node).splitlines()[0] for node in root.walk()] # -> ['# Title', '## Section A']
Optional integrations
Install extras only for the integrations you use:
uv pip install "my-basis[metrics]"orpython -m pip install "my-basis[metrics]", for example. In a uv-managed project, the equivalent dependency declaration isuv add "my-basis[metrics]".
| Extra | Adds |
|---|---|
metrics |
Logfire/OpenTelemetry logging, counters, and instrumentation helpers through MetricUtils |
google |
GoogleSheet access, OAuth support, and pandas DataFrame conversion |
myst |
MyST syntax support in Markdown.render()'s formatting pass |
terminal |
The pyratatui-backed examples under my/scripts/tuitorii/ |
aiohttp |
An HTTP-client convenience dependency; it does not unlock a separate API by itself |
Why this library
Its breadth is somewhat unusual: any given application will probably use a small subset of the contents, so it shines where dependency purity isn't paramount — personal projects, local dev scripts, offline data processing, prototypes, and the project you're working on right now are the ideal usecases.
As a rough sense of scale: a bare pip install my-basis pulls a couple dozen distributions (on the order of ~80 MB unpacked), and turning on every optional extra can push a full environment past ~290 MB because of heavy common dependencies like pandas, numpy, and various pieces of rubble amongst the ruins Google's Python SDK ecosystem.
I do still kinda recommend that for personal scripts/admin/env/dev projects, where having the ability to easily work with google sheets, cast types, or performantly write all kinds of filetypes is worth more than some disk space.
The 1.0 release has been cut, beyond which I intend to enforce strict semver; don't expect breaking changes any time in the foreseeable future. If you're like me (i.e. have ADHD?), this library will spark the most joy when you are vaguely aware of its contents and know it's at your fingertips at any time while coding; not only can it save you a bunch of time writing functions, but the prospect of attempting functions with it in hand is so much more approachable that a lot more ends up getting done.
If that makes sense? I guess I'm really trying to sell you the promise of bolder, quicker software engineering.
Refactor an existing repository
The package includes a read-only source scanner and the
adopt-my-basisagent skill. From a Python repository you want to assess:
uvx --from my-basis my-basis-adopt skill path
uvx --from my-basis my-basis-adopt skill export .agents/skills/adopt-my-basis
uvx --from my-basis my-basis-adopt prepare .
Give the resulting
intake.jsonpath to your agent. The scanner inventories files, dependencies, Python compatibility, candidate checks, and regex structure without importing the target package or editing its source;preparewrites its intake artifacts. The agent can then assess a proposal and produce a MyST, HTML, or Typst/PDF report. A justified decline or no-op is a valid result.
skill pathlocates the packaged instructions;skill exportcopies them when your agent needs a local catalogue entry. See the full workflow and RegexStore adoption guide.
Documentation and development
The hosted documentation covers the package API; its sources are in
docs/. From a checkout, install the development dependencies and build it with:
task sync
task docs
Use the test guide for the suite and its conventions. Python 3.13 is the current minimum; the source uses modern typing syntax throughout. Pydantic is a core dependency even when your own code does not use Pydantic models. The separate Typst package has its own installation path and is not part of the Python wheel.
GitLab is the development forge; the GitHub repository is a read-only source mirror. Report issues and propose changes at the GitLab project.
Contributing
The project was built over the course of 2025 for its author's own use, so it's definitely opinionated — influenced by a weathered respect for polymorphism, an addiction to ergonomic code in the Don-Norman sense, and a reliance on symbolic, deterministic devtools (heavy typing, even at runtime). If any of that resonates: get in touch, or open an issue or merge request on GitLab.
Licensed under MPL-2.0.
Metadata
Release files for my-basis 1.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| my_basis-1.2.2.tar.gz | 331.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| my_basis-1.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 703.7 kB
Release files / my_basis-1.2.2.tar.gz
| Download URL | my_basis-1.2.2.tar.gz |
|---|---|
| Size | 331.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
31da990b4e90e90a30308c7d3274f133ae664812c4b7e2bcfcd619e0d3b411d5
|
|
BLAKE2b-256 checksum How to use checksums |
ad34bcb57f683792e58e4d1288789bc511935eb0a2cd6f3770c273b011c6aaf3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / my_basis-1.2.2-py3-none-any.whl
| Download URL | my_basis-1.2.2-py3-none-any.whl |
|---|---|
| Size | 372.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
114293d4c63e119436095c7119edd370fc45bc23ca88b16140537160af2a3158
|
|
BLAKE2b-256 checksum How to use checksums |
3fc15a0fac3272c50ed056a85bbd4de23dfc2367d0cf1e08c728a0852274b36c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|