Skip to main content

Frequenz Core Library

Build Status PyPI Package Docs

Introduction

Core utilities to complement Python's standard library. This library provides essential building blocks for Python applications, including mathematical utilities, datetime constants, typing helpers, strongly-typed identifiers, module introspection tools, and warning and deprecation helpers.

The frequenz-core library is designed to be lightweight, type-safe, and follow modern Python best practices. It fills common gaps in the standard library with utilities that are frequently needed across different projects.

Supported Platforms

The following platforms are officially supported (tested):

  • Python: 3.11, 3.12, 3.13, 3.14
  • Operating System: Ubuntu Linux 24.04
  • Architectures: amd64, arm64

Installation

You can install the library from PyPI using pip:

python -m pip install frequenz-core

Or add it to your project's dependencies in pyproject.toml:

[project]
dependencies = [
    "frequenz-core >= 1.0.2, < 2",
]

Quick Start

Here's a quick overview of the main functionality:

from frequenz.core.math import is_close_to_zero, Interval
from frequenz.core.datetime import UNIX_EPOCH
from frequenz.core.module import get_public_module_name

# Math utilities
print(is_close_to_zero(1e-10))  # True - check if float is close to zero
interval = Interval(1, 10)
print(5 in interval)  # True - check if value is in range

# Datetime utilities
print(UNIX_EPOCH)  # 1970-01-01 00:00:00+00:00

# Module utilities
public_name = get_public_module_name("my.package._private.module")
print(public_name)  # "my.package"

Code Examples

Math Utilities

The math module provides utilities for floating-point comparisons and interval checking:

from frequenz.core.math import is_close_to_zero, Interval

# Robust floating-point zero comparison
assert is_close_to_zero(1e-10)  # True
assert not is_close_to_zero(0.1)  # False

# Interval checking with inclusive bounds
numbers = Interval(0, 100)
assert 50 in numbers  # True
assert not (150 in numbers)  # False - 150 is outside the interval

# Unbounded intervals
positive = Interval(0, None)  # [0, ∞]
assert 1000 in positive  # True

Enum Utilities

Define enums with deprecated members that raise deprecation warnings when accessed:

from frequenz.core.enum import Enum, deprecated_member, unique

@unique
class TaskStatus(Enum):
   OPEN = 1
   IN_PROGRESS = 2
   # Duplicate values are fine with `@unique` as long as they are deprecated
   PENDING = deprecated_member(1, "PENDING is deprecated, use OPEN instead")
   DONE = deprecated_member(3, "DONE is deprecated, use FINISHED instead")
   FINISHED = 4

status1 = TaskStatus.PENDING  # Warns: "PENDING is deprecated, use OPEN instead"
assert status1 is TaskStatus.OPEN

Typing Utilities

Disable class constructors to enforce factory pattern usage:

from frequenz.core.typing import disable_init

@disable_init
class ApiClient:
    @classmethod
    def create(cls, api_key: str) -> "ApiClient":
        # Factory method with validation
        instance = cls.__new__(cls)
        # Custom initialization logic here
        return instance

# This will raise TypeError:
# client = ApiClient()  # ❌ TypeError

# Use factory method instead:
client = ApiClient.create("my-api-key")  # ✅ Works

Annotate floating point values honestly, as Python's numeric tower lets int values through any float annotation:

from typing import assert_never

from frequenz.core.typing import FloatInt

def describe(value: FloatInt | None) -> str:
    match value:
        case float() | int():
            return f"number {value}"
        case None:
            return "nothing"
        case unexpected:
            assert_never(unexpected)

assert describe(1) == "number 1"  # ✅ `case float():` alone would crash here
assert describe(1.5) == "number 1.5"
assert describe(None) == "nothing"

Warnings/Deprecations Utilities

Silence a warning around a call without the side effect warnings.catch_warnings has, which is to reset the deduplication history of the whole program, so every warning already shown is shown again (python/cpython#73858):

import warnings

from frequenz.core.warnings import ignoring_deprecations

def legacy_parse(raw: str) -> int:
    warnings.warn("legacy_parse() is deprecated", DeprecationWarning, stacklevel=2)
    return int(raw)

def parse(raw: str) -> int:
    # Only around the call that reaches the deprecated symbol.
    with ignoring_deprecations():
        return legacy_parse(raw)

with warnings.catch_warnings(record=True, action="default") as shown:
    for _ in range(10):
        warnings.warn("said once", UserWarning)
        parse("1")

assert len(shown) == 1  # ✅ `catch_warnings()` in `parse()` would show it 10 times

Keep the old import path of a symbol that moved working, serving the very same object so isinstance keeps working through both paths:

from typing import TYPE_CHECKING, TypeAlias

from frequenz.core.warnings import DeprecatedAlias, deprecated_aliases

if TYPE_CHECKING:
    # Type checkers can't see the runtime `__getattr__` in the `else` branch.
    from decimal import Decimal as _Decimal
    from fractions import Fraction as _Fraction

    Decimal: TypeAlias = _Decimal
    Rational: TypeAlias = _Fraction
else:
    # In the `else`, never at module level: a `__getattr__` mypy can see makes
    # every name it doesn't know in this module `Any`, typos in downstream
    # imports included.
    __getattr__ = deprecated_aliases(
        __name__,
        # Warns "<module>.Decimal is deprecated since v1.2.0. Use
        # decimal.Decimal instead."
        DeprecatedAlias("Decimal", new_module="decimal", since="v1.2.0"),
        # Renamed on the way out
        DeprecatedAlias(
            "Rational", new_module="fractions", new_name="Fraction", since="v1.3.0"
        ),
    )

And check in a test that a piece of code doesn't warn, without the "error" filter that would make warnings.warn() raise inside the code under test:

from frequenz.core.warnings import asserting_no_deprecations

def parse(raw: str) -> int:
    return int(raw)

with asserting_no_deprecations():
    assert parse("1") == 1

Strongly-Typed IDs

Create type-safe identifiers for different entities:

from frequenz.core.id import BaseId

class UserId(BaseId, str_prefix="USR"):
    pass

class OrderId(BaseId, str_prefix="ORD"):
    pass

user_id = UserId(123)
order_id = OrderId(456)

print(f"User: {user_id}")  # User: USR123
print(f"Order: {order_id}")  # Order: ORD456

# Type safety prevents mixing different ID types
def process_user(user_id: UserId) -> None:
    print(f"Processing user: {user_id}")

process_user(user_id)  # ✅ Works
# process_user(order_id)  # ❌ Type error

Documentation

For information on how to use this library, please refer to the documentation.

Contributing

If you want to know how to build this project and contribute to it, please check out the Contributing Guide.

Metadata

Release files for frequenz-core 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for frequenz-core 1.5.0
File Size Uploaded
frequenz_core-1.5.0.tar.gz 37.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for frequenz-core 1.5.0
File Interpreter ABI Platform
frequenz_core-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 72.8 kB

Release files / frequenz_core-1.5.0.tar.gz

Download URL frequenz_core-1.5.0.tar.gz
Size 37.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c3b02f21affb0424c9dc4ae5a2630a2fb4a2c2f127872edca01aca9852b0bfd8
BLAKE2b-256 checksum
How to use checksums
2e1874eb82106a991c68645944042c8d3108770300e8e3baa80f01933f179fa7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / frequenz_core-1.5.0-py3-none-any.whl

Download URL frequenz_core-1.5.0-py3-none-any.whl
Size 35.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a96502cd2469fca0fd51422d7f476fe0af1d3774e6d85fc8fb980027f563226f
BLAKE2b-256 checksum
How to use checksums
e80ec765371dd440dd889e5151981e7cae283156370e3e57a6008989f03286a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.5.0 This release

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page