Roskarl
Is a tiny module for environment variables
Requires
Python 3.11.0+
How to install
uv pip install roskarl
Example usage
from roskarl import (
env_var,
env_var_bool,
env_var_cron,
env_var_custom,
env_var_duration,
env_var_enum,
env_var_interval_expression,
env_var_interval_expression_extended,
env_var_float,
env_var_int,
env_var_iso8601_datetime,
env_var_list,
env_var_log_level,
env_var_path,
env_var_rfc3339_datetime,
env_var_secret,
env_var_tz,
env_var_url,
env_var_dsn,
DSN,
Secret,
)
All functions return None if the variable is not set. An optional default parameter can be provided to return a fallback value instead.
Pass required=True to raise instead of returning None — type checkers will narrow the return type accordingly (e.g. str instead of str | None), so no assert is needed at callsites
str (returns str)
value = env_var(name="STR_VAR", default="fallback")
bool (returns bool — accepts true or false (case insensitive))
value = env_var_bool(name="BOOL_VAR")
tz (returns str if value is a valid IANA timezone (e.g. Europe/Stockholm))
value = env_var_tz(name="TZ_VAR")
list (returns list[str] if value is splittable by separator)
value = env_var_list(name="LIST_VAR", separator="|")
int (returns int if value is numeric)
value = env_var_int(name="INT_VAR")
float (returns float if value is a float)
value = env_var_float(name="FLOAT_VAR")
cron (returns str if value is a valid cron expression)
value = env_var_cron(name="CRON_VAR")
interval expression (returns str if value is a valid offset-free 5-field cron expression)
value = env_var_interval_expression(name="INTERVAL_VAR")
interval expression extended (returns str if value is a valid offset-free 6-field cron expression)
value = env_var_interval_expression_extended(name="INTERVAL_EXTENDED_VAR")
datetime (ISO8601) (returns datetime if value is a valid ISO8601 datetime string — timezone is optional)
value = env_var_iso8601_datetime(name="DATETIME_VAR")
datetime (RFC3339) (returns datetime if value is a valid RFC3339 datetime string — timezone is required)
value = env_var_rfc3339_datetime(name="DATETIME_VAR")
url (returns str if value has a scheme + netloc, e.g. https://example.com)
value = env_var_url(name="API_URL")
secret (returns Secret — wraps the value so it can't accidentally be logged)
repr() and str() return ***. Call .reveal() at the point of use.
key = env_var_secret(name="API_KEY", required=True)
print(key) # ***
stripe.api_key = key.reveal()
path (returns pathlib.Path)
Pass must_exist=True to fail fast if the path is not present on disk
value = env_var_path(name="CONFIG_PATH", must_exist=True)
enum (returns an instance of your Enum subclass)
Matches against each member's .value. Raises ValueError if no match
from enum import Enum
class Mode(Enum):
LIVE = "live"
DRY_RUN = "dry-run"
value = env_var_enum(name="MODE", enum_class=Mode, required=True)
duration (returns timedelta)
Parses compound duration strings using suffixes ms, s, m, h, d. Spaces between parts are tolerated.
value = env_var_duration(name="REQUEST_TIMEOUT", default=timedelta(seconds=30))
# accepts: "30s", "5m", "1h30m", "500ms", "7d", "1h 30m"
log level (returns int matching Python's logging levels)
Accepts DEBUG, INFO, WARNING/WARN, ERROR, CRITICAL/FATAL (case-insensitive).
import logging
level = env_var_log_level(name="LOG_LEVEL", default=logging.INFO)
logging.basicConfig(level=level)
custom (returns whatever your parser returns)
Escape hatch for types without a dedicated helper — pass any Callable[[str], T].
from uuid import UUID
value = env_var_custom(name="UUID_VAR", parser=UUID, required=True) # type: UUID
DSN
Note: Special characters in passwords must be URL-encoded.
from urllib.parse import quote
password = 'My$ecret!Pass@2024'
encoded = quote(password, safe='')
print(encoded) # My%24ecret%21Pass%402024 <--- use this
value = env_var_dsn(name="DSN_VAR")
returns DSN object if value is a valid DSN string, formatted as:
postgresql://username:password@hostname:5432/database_name
The DSN object exposes the following attributes:
| Attribute | Type | Example |
|---|---|---|
scheme |
str |
postgresql |
host |
str |
hostname |
port |
int |
5432 |
username |
str |
username |
password |
str |
password |
database |
str |
database_name |
Testing
Tests use pytest. Run the full suite:
pytest tests/
Release
See RELEASE.md for instructions on how to publish a new version.
Metadata
Release files for roskarl 3.1.31
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 | Actions |
|---|---|---|---|---|
| roskarl-3.1.31.tar.gz | 18.3 kB | Without provenance | Details for roskarl-3.1.31.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| roskarl-3.1.31-py3-none-any.whl | Python 3 | none | any | Details for roskarl-3.1.31-py3-none-any.whl |
Total release size: 30.0 kB
Release files / roskarl-3.1.31.tar.gz
| Download URL | roskarl-3.1.31.tar.gz |
|---|---|
| Size | 18.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
66bb50cc2ada56e6646d980aab0564fba41ac8eec1786be7131e6622d63821aa
|
|
BLAKE2b-256 checksum How to use checksums |
260b7659a8650265559f6207a5650a9eaee20fd6941f7f18cc1ab2584feb4e59
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / roskarl-3.1.31-py3-none-any.whl
| Download URL | roskarl-3.1.31-py3-none-any.whl |
|---|---|
| Size | 11.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3338b99a48fef2ec9a3f50a2082b197d0a16c99e001ed29cd157d9087acf96b1
|
|
BLAKE2b-256 checksum How to use checksums |
56627a670472d690fb530dc0c42b2a52f042db52b278cefb511b04119a9bf369
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Security for roskarl 3.1.31
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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.