universal-common
A library that extends the Python base class library with utility functions and types, inspired by the .NET base class library and language features - without needing full feature parity, just enough to make everyday Python a little saner.
Features
- Null-coalescing (
coalesce) and null/whitespace string checks (is_null_or_empty,is_null_or_white_space) - LINQ-style iteration helpers (
first,first_or_default,last,last_or_default), available both as free functions and as methods onList Dictionary: adictsubclass that also supports attribute accessevent/BoundEvent: a C#-style event pattern with+=/-=subscriptionStopwatch: a simple elapsed-time measurer, usable as a context managerMediaType: parsing and building MIME media type strings (e.g."application/json; charset=utf-8")SemanticVersion: dependency-free Semantic Versioning 2.0.0 parsing and comparisonSqlConnectionStringBuilder: a minimal SQL connection string builder/parserEnvironment/SpecialFolder: cross-platform special-folder lookup (app data, cache, desktop, documents, downloads, ...), with zero third-party dependencies
Installation
Install the package from PyPI using pip:
pip install universal-common
Usage
Null coalescing and string checks
from universal_common import coalesce, is_null_or_empty, is_null_or_white_space
coalesce(None, None, 3) # 3 - first non-None value
is_null_or_empty(None) # True
is_null_or_empty("") # True
is_null_or_white_space(" ") # True - unlike `if not s:`, this catches whitespace-only strings
LINQ-style iteration helpers
from universal_common import first, first_or_default, last, last_or_default, List
numbers = [1, 2, 5, 4]
first(numbers) # 1
first(numbers, lambda x: x > 3) # 5
last(numbers) # 4
last_or_default(numbers, lambda x: x > 10) # None, instead of raising
# The same methods are available directly on List:
items = List([1, 2, 5, 4])
items.first_or_default(lambda x: x > 3) # 5
items.last() # 4
first/last raise ValueError when nothing matches; first_or_default/last_or_default return None instead.
Attribute-accessible dictionaries
from universal_common import Dictionary
settings = Dictionary({"name": "Ada"})
settings.name # "Ada"
settings["name"] # "Ada"
settings.age = 30 # same as settings["age"] = 30
settings.missing # None, does not raise
C#-style events
from universal_common import event
class Button:
@event
def clicked(self):
"""Raised when the button is clicked."""
button = Button()
button.clicked += lambda: print("clicked!")
button.clicked() # invokes every subscribed handler
If more than one handler raises, every handler still runs; the first exception is raised, and any additional ones are attached to it as .other_exceptions rather than silently discarded.
Timing
from universal_common import Stopwatch
with Stopwatch() as stopwatch:
do_work()
print(stopwatch.elapsed, "seconds")
# Or standalone:
stopwatch = Stopwatch.start_new()
do_work()
stopwatch.stop()
print(stopwatch.elapsed_milliseconds, "ms")
Media types
from universal_common import MediaType
media_type = MediaType.parse("application/json; charset=utf-8")
media_type.full_type # "application/json"
media_type.charset # "utf-8"
str(media_type) # "application/json; charset=utf-8"
Semantic versioning
from universal_common import SemanticVersion
version = SemanticVersion.parse("1.2.3-beta.1+build.5")
version.major, version.minor, version.patch # (1, 2, 3)
SemanticVersion.parse("1.0.0-alpha") < SemanticVersion.parse("1.0.0") # True
sorted([SemanticVersion.parse(v) for v in ["2.0.0", "1.0.0", "1.5.0"]])
Comparison follows the semver 2.0.0 precedence rules exactly: numeric identifiers sort before alphanumeric ones, a version without a prerelease outranks one with a prerelease at the same major.minor.patch, and build metadata (+...) is ignored for comparison.
SQL connection strings
from universal_common import SqlConnectionStringBuilder
builder = SqlConnectionStringBuilder()
builder.server = "localhost"
builder.database = "app"
builder.user_id = "admin"
builder.password = "hunter2"
str(builder) # "Server=localhost;Database=app;Uid=admin;Pwd=hunter2"
parsed = SqlConnectionStringBuilder.parse("Server=localhost;Database=app")
parsed.server # "localhost"
Special folders
from universal_common import Environment, SpecialFolder
Environment.get_folder_path(SpecialFolder.APPLICATION_DATA) # %APPDATA%, ~/Library/Application Support, or $XDG_CONFIG_HOME
Environment.get_folder_path(SpecialFolder.LOCAL_APPLICATION_DATA)
Environment.get_folder_path(SpecialFolder.CACHE)
Environment.get_folder_path(SpecialFolder.DESKTOP)
Environment.get_folder_path(SpecialFolder.DOCUMENTS)
Environment.get_folder_path(SpecialFolder.DOWNLOADS)
This mirrors most (not all - CACHE and DOWNLOADS aren't real Environment.SpecialFolder members, added because they're commonly needed) of a useful subset of .NET's Environment.SpecialFolder - the ones that resolve sensibly on Windows, macOS, and Linux.
License
CC0 1.0 Universal (Public Domain Dedication).
Metadata
Release files for universal-common 1.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| universal_common-1.4.0.tar.gz | 15.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| universal_common-1.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.5 kB
Release files / universal_common-1.4.0.tar.gz
| Download URL | universal_common-1.4.0.tar.gz |
|---|---|
| Size | 15.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d123d0df4243ee8e67eba5ff24d1caa1404e237e8f3fb2994f55a365a2a88a42
|
|
BLAKE2b-256 checksum How to use checksums |
97b1d96b6d099768abd624ffb9a01eca8b6b4613522297f9b78e441666983f0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / universal_common-1.4.0-py3-none-any.whl
| Download URL | universal_common-1.4.0-py3-none-any.whl |
|---|---|
| Size | 13.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6a5a8828ed9c94987ebb15d1b97185fbe51ab9a1b35f220287f7efe6bb56929a
|
|
BLAKE2b-256 checksum How to use checksums |
d3d8aecda15750f9e756d67adb905dfb3b0a190a91f12fdab64cb524cf84cd8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Security for universal-common 1.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.