Skip to content

MetrologyNamespace (initial PR) #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ python_version = "3.13"
warn_unused_configs = true
strict = true
enable_error_code = ["ignore-without-code", "truthy-bool"]
disable_error_code = ["explicit-any", "decorated-any"]


[tool.basedpyright]
Expand Down
170 changes: 137 additions & 33 deletions src/metrology_apis/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,67 @@
"""Metrology APIs."""

from typing import Final, Protocol, Self, override, runtime_checkable
from typing import (
Final,
Protocol,
Self,
TypeVar,
override,
runtime_checkable,
)

import optype as op

__version__: Final = "0.0.1.dev0"
__all__ = ["__version__", "Dimension", "Quantity", "Unit"]


VT = TypeVar("VT")
DT = TypeVar("DT", bound="Dimension")
UT = TypeVar("UT", bound="Unit[DT]")


@runtime_checkable
class MetrologyNamespace[Q: Quantity[VT, UT, DT], V, U: Unit[DT], D: Dimension](
Protocol
):
@staticmethod
def asdimension(obj: str | D) -> D: ...

@staticmethod
def asunit(obj: str | U) -> U: ...

@staticmethod
def asquantity(obj: Q | V, *, unit: U) -> Q: ...


@runtime_checkable
class Dimension(Protocol):
def __metrology_namespace__[Q: Quantity[VT, UT, DT], V, U: Unit[DT]](
self, /, *, api_version: str | None = None
) -> MetrologyNamespace[Q, V, U, Self]:
"""
Return an object that has all the metrology API functions on it.

Parameters
----------
api_version : str or None
String representing the version of the metrology API
specification to be returned. If it is `None`, it should
return the namespace corresponding to latest version of the
metrology API specification. If the given version is invalid
or not implemented for the given module, an error should be
raised. Default: `None`.

Returns
-------
Any
An object representing the metrology API namespace. It
should have every top-level function defined in the
specification as an attribute. It may contain other public
names as well, but it is recommended to only include those
names that are part of the specification.
"""

def __mul__(self, other: Self, /) -> Self: ...
def __truediv__(self, other: Self, /) -> Self: ...
def __pow__(self, other: int, /) -> Self: ...
Expand All @@ -19,9 +71,35 @@ def __rtruediv__(self, other: Self, /) -> Self: ...


@runtime_checkable
class Unit(Protocol):
class Unit[D: Dimension](Protocol):
def __metrology_namespace__[Q: Quantity[VT, UT, DT], V](
self, /, *, api_version: str | None = None
) -> MetrologyNamespace[Q, V, Self, D]:
"""
Return an object that has all the metrology API functions on it.

Parameters
----------
api_version : str or None
String representing the version of the metrology API
specification to be returned. If it is `None`, it should
return the namespace corresponding to latest version of the
metrology API specification. If the given version is invalid
or not implemented for the given module, an error should be
raised. Default: `None`.

Returns
-------
Any
An object representing the metrology API namespace. It should
have every top-level function defined in the specification as
an attribute. It may contain other public names as well, but
it is recommended to only include those names that are part
of the specification.
"""

@property
def dimension(self) -> Dimension: ...
def dimension(self) -> D: ...

def __mul__(self, other: Self, /) -> Self: ...
def __truediv__(self, other: Self, /) -> Self: ...
Expand All @@ -32,7 +110,33 @@ def __rtruediv__(self, other: Self, /) -> Self: ...


@runtime_checkable
class Quantity[V, U: Unit](Protocol):
class Quantity[V, U: Unit[DT], D: Dimension](Protocol):
def __metrology_namespace__(
self, /, *, api_version: str | None = None
) -> MetrologyNamespace[Self, V, U, D]:
"""
Return an object that has all the metrology API functions on it.

Parameters
----------
api_version : str or None
String representing the version of the metrology API
specification to be returned. If it is `None`, it should
return the namespace corresponding to the latest version of
the metrology API specification. If the given version is
invalid or not implemented for the given module, an error
should be raised. Default: `None`.

Returns
-------
Any
An object representing the metrology API namespace. It should
have every top-level function defined in the specification as
an attribute. It may contain other public names as well, but it
is recommended to only include those names that are part of the
specification.
"""

@property
def value(self) -> V: ...
@property
Expand All @@ -42,64 +146,64 @@ def unit(self) -> U: ...

@override
def __eq__[B]( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
self: "Quantity[V, U]", other: "Quantity[op.CanEq[V, B], U]", /
self: "Quantity[V, U, D]", other: "Quantity[op.CanEq[V, B], U, D]", /
) -> B: ...

@override
def __ne__[B]( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
self: "Quantity[V, U]", other: "Quantity[op.CanEq[V, B], U]", /
self: "Quantity[V, U, D]", other: "Quantity[op.CanEq[V, B], U, D]", /
) -> B: ...

def __lt__[B](
self: "Quantity[V, U]", other: "Quantity[op.CanLt[V, B], U]", /
self: "Quantity[V, U, D]", other: "Quantity[op.CanLt[V, B], U, D]", /
) -> B: ...
def __le__[B](
self: "Quantity[V, U]", other: "Quantity[op.CanLe[V, B], U]", /
self: "Quantity[V, U, D]", other: "Quantity[op.CanLe[V, B], U, D]", /
) -> B: ...
def __gt__[B](
self: "Quantity[V, U]", other: "Quantity[op.CanGt[V, B], U]", /
self: "Quantity[V, U, D]", other: "Quantity[op.CanGt[V, B], U, D]", /
) -> B: ...
def __ge__[B](
self: "Quantity[V, U]", other: "Quantity[op.CanGe[V, B], U]", /
self: "Quantity[V, U, D]", other: "Quantity[op.CanGe[V, B], U, D]", /
) -> B: ...

def __pos__[R](self: "Quantity[op.CanPos[R], U]") -> "Quantity[R, U]": ...
def __neg__[R](self: "Quantity[op.CanNeg[R], U]") -> "Quantity[R, U]": ...
def __abs__[R](self: "Quantity[op.CanAbs[R], U]") -> "Quantity[R, U]": ...
def __pos__[R](self: "Quantity[op.CanPos[R], U, D]") -> "Quantity[R, U, D]": ...
def __neg__[R](self: "Quantity[op.CanNeg[R], U, D]") -> "Quantity[R, U, D]": ...
def __abs__[R](self: "Quantity[op.CanAbs[R], U, D]") -> "Quantity[R, U, D]": ...

def __add__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanRAdd[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanRAdd[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...
def __radd__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanAdd[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanAdd[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...
def __sub__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanRSub[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanRSub[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...
def __rsub__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanSub[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanSub[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...

def __mul__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanRMul[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanRMul[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...
def __rmul__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanMul[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanMul[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...
def __truediv__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanRTruediv[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanRTruediv[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...
def __rtruediv__[R](
self: "Quantity[V, U]", other: "Quantity[op.CanTruediv[V, R], U]", /
) -> "Quantity[R, U]": ...
self: "Quantity[V, U, D]", other: "Quantity[op.CanTruediv[V, R], U, D]", /
) -> "Quantity[R, U, D]": ...

def __pow__[R](
self: "Quantity[op.CanPow2[op.JustInt | op.JustFloat, R], U]",
self: "Quantity[op.CanPow2[op.JustInt | op.JustFloat, R], U, D]",
other: op.JustInt | op.JustFloat,
/,
) -> "Quantity[R, U]": ...
) -> "Quantity[R, U, D]": ...
def __rpow__[R](
self: "Quantity[op.CanRPow[op.JustInt | op.JustFloat, R], U]",
self: "Quantity[op.CanRPow[op.JustInt | op.JustFloat, R], U, D]",
other: op.JustInt | op.JustFloat,
/,
) -> "Quantity[R, U]": ...
) -> "Quantity[R, U, D]": ...
Loading