ry = rust + python (quick-maths!)
DOCS: https://ryo3.dev (WIP)
python bindings for rust crates I wish existed in python
THIS IS A WORK IN PROGRESS
pip install ry
uv add ry
Check install: python -m ry
This is a collection of pyo3-wrappers for rust crates I wish existed in python.
It all started with me wanting a fast python xxhash
and fnv-64
- jessekrubin [email protected]
- possibly you!?
(aka: questions that I have been asking myself)
- Q: Why?
- A: I (jesse) needed several hashing functions for python and then kept adding things as I needed them
- Q: Does this have anything to do with the (excellent) package manager
rye
?- A: short answer: no. long answer: no, it does not.
- Q: Why is the repo split into
ry
andryo3
?- A:
ry
is the python package,ryo3
is a rust crate setup to let you "register" functions you may want if you were writing your own pyo3-python bindings library; maybe someday theryo3::libs
module will be split up into separate packages
- A:
shlex
jiter
which
sqlformat
- compression:
brotli
bzip2
flat2
zstd
- hashing:
fnv
xxhash
- burnt-sushi:
walkdir
globset
(formerly globsters)jiff
subprocess.redo
(subprocesses that are lessy finicky and support tee-ing)regex
tokio
(fs + process)tracing
(could be nicer than python's awful logging lib -- currently a part of ry/ryo3 for my dev purposes - currently has impl thingy in utiles)reqwest
(async http client / waiting on pyo3 asyncio to stabilize and for me to have more time)
"""ry api ~ type annotations"""
import datetime as pydt
import typing as t
from os import PathLike
from ry._types.jiff import (
JIFF_ROUND_MODE_STRING,
JIFF_UNIT_STRING,
DateTimeTypedDict,
DateTypedDict,
TimeSpanTypedDict,
TimeTypedDict,
)
__version__: str
__authors__: str
__build_profile__: str
__build_timestamp__: str
__pkg_name__: str
__description__: str
# ==============================================================================
# TYPE ALIASES
# ==============================================================================
JsonPrimitive = None | bool | int | float | str
JsonValue = (
JsonPrimitive | dict[str, JsonPrimitive | JsonValue] | list[JsonPrimitive | JsonValue]
)
# ==============================================================================
# STD
# ==============================================================================
class Duration:
def __init__(self, seconds: int, nanoseconds: int) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __lt__(self, other: object) -> bool: ...
def __le__(self, other: object) -> bool: ...
def __gt__(self, other: object) -> bool: ...
def __ge__(self, other: object) -> bool: ...
def __richcmp__(self, other: Duration | pydt.timedelta, op: int) -> bool: ...
def __str__(self) -> str: ...
@classmethod
def from_pytimedelta(cls: type[Duration], td: pydt.timedelta) -> Duration: ...
def to_pytimedelta(self) -> pydt.timedelta: ...
@property
def days(self) -> int: ...
@property
def seconds(self) -> int: ...
@property
def microseconds(self) -> int: ...
# ==============================================================================
# RY03-CORE
# ==============================================================================
class FsPath:
def __init__(self, path: PathLike[str] | str | None = None) -> None: ...
def __fspath__(self) -> str: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __lt__(self, other: PathLike[str] | str) -> bool: ...
def __le__(self, other: PathLike[str] | str) -> bool: ...
def __gt__(self, other: PathLike[str] | str) -> bool: ...
def __ge__(self, other: PathLike[str] | str) -> bool: ...
def __truediv__(self, other: PathLike[str] | str) -> FsPath: ...
def __rtruediv__(self, other: PathLike[str] | str) -> FsPath: ...
def read_text(self) -> str: ...
def read_bytes(self) -> bytes: ...
def absolute(self) -> FsPath: ...
@property
def parent(self) -> FsPath: ...
def write_text(self, data: str) -> None: ...
def write_bytes(self, data: bytes) -> None: ...
def joinpath(self, *paths: str) -> FsPath: ...
def is_dir(self) -> bool: ...
def is_file(self) -> bool: ...
def exists(self) -> bool: ...
def with_name(self, name: str) -> FsPath: ...
def with_suffix(self, suffix: str) -> FsPath: ...
@property
def suffix(self) -> str: ...
@property
def suffixes(self) -> list[str]: ...
def iterdir(self) -> t.Iterator[FsPath]: ...
def relative_to(self, other: PathLike[str] | str | FsPath) -> FsPath: ...
def as_posix(self) -> str: ...
# TODO
@property
def parents(self) -> t.Sequence[t.Self]: ...
@property
def root(self) -> str: ...
def __bytes__(self) -> bytes: ...
def as_uri(self) -> str: ...
@property
def parts(self) -> tuple[str, ...]: ...
@property
def drive(self) -> str: ...
@property
def anchor(self) -> str: ...
@property
def name(self) -> str: ...
@property
def stem(self) -> str: ...
FsPathLike = str | FsPath | PathLike[str]
def pwd() -> str: ...
def home() -> str: ...
def cd(path: FsPathLike) -> None: ...
def ls(path: FsPathLike | None = None) -> list[FsPath]: ...
def quick_maths() -> t.Literal[3]:
"""Performs quick-maths
Implements the algorithm for performing "quick-maths" as described by
Big Shaq in his PHD thesis, 2017, in which he states:
> "2 plus 2 is 4, minus one that's 3, quick maths." (Big Shaq et al., 2017)
Reference:
https://youtu.be/3M_5oYU-IsU?t=60
Example:
>>> result = quick_maths()
>>> assert result == 3
NOTE: THIS IS FROM MY TEMPLATE RY03-MODULE
"""
# ==============================================================================
# SLEEP
# ==============================================================================
def sleep(seconds: float) -> float: ...
async def sleep_async(seconds: float) -> float: ...
# ==============================================================================
# FILESYSTEM
# ==============================================================================
def read_text(path: FsPathLike) -> str: ...
def read_bytes(path: FsPathLike) -> bytes: ...
def write_text(path: FsPathLike, data: str) -> None: ...
def write_bytes(path: FsPathLike, data: bytes) -> None: ...
# ==============================================================================
# SUBPROCESS (VERY MUCH WIP)
# ==============================================================================
def run(
*args: str | list[str],
capture_output: bool = True,
input: bytes | None = None,
) -> t.Any: ...
# ==============================================================================
# DEV
# ==============================================================================
def string_noop(s: str) -> str: ...
def bytes_noop(s: bytes) -> bytes: ...
# ------------------------------------------------------------------------------
# \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
# ------------------------------------------------------------------------------
# ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~ LIBS ~
# ------------------------------------------------------------------------------
# \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
# ------------------------------------------------------------------------------
# ==============================================================================
# WHICH
# ==============================================================================
def which(cmd: str, path: None | str = None) -> str | None: ...
def which_all(cmd: str, path: None | str = None) -> list[str]: ...
def whicha(cmd: str, path: None | str = None) -> list[str]:
"""Alias for which_all (may go away in the future)"""
# ==============================================================================
# HECK
# ==============================================================================
def camel_case(string: str) -> str: ...
def kebab_case(string: str) -> str: ...
def pascal_case(string: str) -> str: ...
def shouty_kebab_case(string: str) -> str: ...
def shouty_snake_case(string: str) -> str: ...
def snake_case(string: str) -> str: ...
def snek_case(string: str) -> str: ...
def title_case(string: str) -> str: ...
def train_case(string: str) -> str: ...
# ==============================================================================
# GLOBSET
# ==============================================================================
class Glob:
"""globset::Glob wrapper"""
def __init__(
self,
pattern: str,
/,
*,
case_insensitive: bool | None = None,
literal_separator: bool | None = None,
backslash_escape: bool | None = None,
) -> None: ...
def regex(self) -> str: ...
def is_match(self, path: str) -> bool: ...
def __call__(self, path: str) -> bool: ...
def __invert__(self) -> Glob: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
class GlobSet:
"""globset::GlobSet wrapper"""
def __init__(
self,
patterns: list[str],
/,
*,
case_insensitive: bool | None = None,
literal_separator: bool | None = None,
backslash_escape: bool | None = None,
) -> None: ...
def is_empty(self) -> bool: ...
def is_match(self, path: str) -> bool: ...
def matches(self, path: str) -> list[int]: ...
def __call__(self, path: str) -> bool: ...
def __invert__(self) -> GlobSet: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
class Globster:
"""Globster is a matcher with claws!
Note: The north american `Globster` is similar to the european `Globset`
but allows for negative patterns (prefixed with '!')
"""
def __init__(
self,
patterns: list[str],
/,
*,
case_insensitive: bool | None = None,
literal_separator: bool | None = None,
backslash_escape: bool | None = None,
) -> None: ...
def is_empty(self) -> bool: ...
def is_match(self, path: str) -> bool: ...
def __call__(self, path: str) -> bool: ...
def __invert__(self) -> GlobSet: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def glob(
pattern: str,
/,
*,
case_insensitive: bool | None = None,
literal_separator: bool | None = None,
backslash_escape: bool | None = None,
) -> Glob: ...
def globs(
patterns: list[str],
/,
*,
case_insensitive: bool | None = None,
literal_separator: bool | None = None,
backslash_escape: bool | None = None,
) -> Globster: ...
# ==============================================================================
# WALKDIR
# ==============================================================================
class WalkdirGen:
"""walkdir::Walkdir iterable wrapper"""
files: bool
dirs: bool
def __next__(self) -> str: ...
def __iter__(self) -> t.Iterator[str]: ...
class FspathsGen:
"""walkdir iterable that yields FsPath objects"""
files: bool
dirs: bool
def __next__(self) -> FsPath: ...
def __iter__(self) -> t.Iterator[FsPath]: ...
def walkdir(
path: FsPathLike | None = None,
files: bool = True,
dirs: bool = True,
contents_first: bool = False,
min_depth: int = 0,
max_depth: int | None = None,
follow_links: bool = False,
same_file_system: bool = False,
) -> WalkdirGen: ...
def fspaths(
path: FsPathLike | None = None,
files: bool = True,
dirs: bool = True,
contents_first: bool = False,
min_depth: int = 0,
max_depth: int | None = None,
follow_links: bool = False,
same_file_system: bool = False,
) -> WalkdirGen: ...
# ==============================================================================
# SHLEX
# ==============================================================================
def shplit(s: str) -> list[str]:
"""shlex::split wrapper much like python's stdlib shlex.split but faster"""
...
# ==============================================================================
# JSON
# ==============================================================================
def parse_json(
data: bytes | str,
/,
*,
allow_inf_nan: bool = True,
cache_mode: t.Literal[True, False, "all", "keys", "none"] = "all",
partial_mode: t.Literal[True, False, "off", "on", "trailing-strings"] = False,
catch_duplicate_keys: bool = False,
float_mode: t.Literal["float", "decimal", "lossless-float"] = "float",
) -> JsonValue: ...
def parse_json_bytes(
data: bytes,
/,
*,
allow_inf_nan: bool = True,
cache_mode: t.Literal[True, False, "all", "keys", "none"] = "all",
partial_mode: t.Literal[True, False, "off", "on", "trailing-strings"] = False,
catch_duplicate_keys: bool = False,
float_mode: t.Literal["float", "decimal", "lossless-float"] = "float",
) -> JsonValue: ...
def parse_json_str(
data: str,
/,
*,
allow_inf_nan: bool = True,
cache_mode: t.Literal[True, False, "all", "keys", "none"] = "all",
partial_mode: t.Literal[True, False, "off", "on", "trailing-strings"] = False,
catch_duplicate_keys: bool = False,
float_mode: t.Literal["float", "decimal", "lossless-float"] = "float",
) -> JsonValue: ...
def jiter_cache_clear() -> None: ...
def jiter_cache_usage() -> int: ...
# ==============================================================================
# FORMATTING
# ==============================================================================
def fmt_nbytes(nbytes: int) -> str: ...
# ==============================================================================
# FNV
# ==============================================================================
class FnvHasher:
name: t.Literal["fnv1a"]
def __init__(self, input: bytes | None = None) -> None: ...
def update(self, input: bytes) -> None: ...
def digest(self) -> int: ...
def hexdigest(self) -> str: ...
def copy(self) -> FnvHasher: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def fnv1a(input: bytes) -> FnvHasher: ...
# ==============================================================================
# DEV
# ==============================================================================
def anystr_noop(s: t.AnyStr) -> t.AnyStr: ...
# ==============================================================================
# BROTLI
# ==============================================================================
def brotli_encode(
input: bytes, quality: int = 11, magic_number: bool = False
) -> bytes: ...
def brotli_decode(input: bytes) -> bytes: ...
def brotli(input: bytes, quality: int = 11, magic_number: bool = False) -> bytes:
"""Alias for brotli_encode"""
# ==============================================================================
# BZIP2
# ==============================================================================
def bzip2_encode(input: bytes, quality: int = 9) -> bytes: ...
def bzip2_decode(input: bytes) -> bytes: ...
def bzip2(input: bytes, quality: int = 9) -> bytes:
"""Alias for bzip2_encode"""
# ==============================================================================
# GZIP
# ==============================================================================
def gzip_encode(input: bytes, quality: int = 9) -> bytes: ...
def gzip_decode(input: bytes) -> bytes: ...
def gzip(input: bytes, quality: int = 9) -> bytes:
"""Alias for gzip_encode"""
def gunzip(input: bytes) -> bytes:
"""Alias for gzip_decode"""
# ==============================================================================
# ZSTD
# ==============================================================================
def zstd_encode(input: bytes, level: int = 3) -> bytes: ...
def zstd(input: bytes, level: int = 3) -> bytes:
"""Alias for zstd_encode"""
def zstd_decode(input: bytes) -> bytes: ...
# ==============================================================================
# XXHASH
# ==============================================================================
@t.final
class Xxh32:
name: t.Literal["xxh32"]
def __init__(self, input: bytes = ..., seed: int | None = ...) -> None: ...
def update(self, input: bytes) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def intdigest(self) -> int: ...
def copy(self) -> Xxh32: ...
def reset(self, seed: int | None = ...) -> None: ...
@property
def seed(self) -> int: ...
@t.final
class Xxh64:
name: t.Literal["xxh64"]
def __init__(self, input: bytes = ..., seed: int | None = ...) -> None: ...
def update(self, input: bytes) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def intdigest(self) -> int: ...
def copy(self) -> Xxh32: ...
def reset(self, seed: int | None = ...) -> None: ...
@property
def seed(self) -> int: ...
@t.final
class Xxh3:
name: t.Literal["xxh3"]
def __init__(
self, input: bytes = ..., seed: int | None = ..., secret: bytes | None = ...
) -> None: ...
def update(self, input: bytes) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def intdigest(self) -> int: ...
@property
def seed(self) -> int: ...
def digest128(self) -> bytes: ...
def hexdigest128(self) -> str: ...
def intdigest128(self) -> int: ...
def copy(self) -> Xxh3: ...
def reset(self) -> None: ...
def xxh32(input: bytes | None = None, seed: int | None = None) -> Xxh32: ...
def xxh64(input: bytes | None = None, seed: int | None = None) -> Xxh64: ...
def xxh3(
input: bytes | None = None, seed: int | None = None, secret: bytes | None = None
) -> Xxh3: ...
# xxh32
def xxh32_digest(input: bytes, seed: int | None = None) -> bytes: ...
def xxh32_hexdigest(input: bytes, seed: int | None = None) -> str: ...
def xxh32_intdigest(input: bytes, seed: int | None = None) -> int: ...
# xxh64
def xxh64_digest(input: bytes, seed: int | None = None) -> bytes: ...
def xxh64_hexdigest(input: bytes, seed: int | None = None) -> str: ...
def xxh64_intdigest(input: bytes, seed: int | None = None) -> int: ...
# xxh128
def xxh128_digest(input: bytes, seed: int | None = None) -> bytes: ...
def xxh128_hexdigest(input: bytes, seed: int | None = None) -> str: ...
def xxh128_intdigest(input: bytes, seed: int | None = None) -> int: ...
# xxh3
def xxh3_64_digest(input: bytes, seed: int | None = None) -> bytes: ...
def xxh3_64_intdigest(input: bytes, seed: int | None = None) -> int: ...
def xxh3_64_hexdigest(input: bytes, seed: int | None = None) -> str: ...
def xxh3_digest(input: bytes, seed: int | None = None) -> bytes: ...
def xxh3_intdigest(input: bytes, seed: int | None = None) -> int: ...
def xxh3_hexdigest(input: bytes, seed: int | None = None) -> str: ...
# xxh128
def xxh3_128_digest(input: bytes, seed: int | None = None) -> bytes: ...
def xxh3_128_intdigest(input: bytes, seed: int | None = None) -> int: ...
def xxh3_128_hexdigest(input: bytes, seed: int | None = None) -> str: ...
# ==============================================================================
# SQLFORMAT
# ==============================================================================
SqlfmtParamValue = str | int | float | bool
TSqlfmtParamValue_co = t.TypeVar(
"TSqlfmtParamValue_co", bound=SqlfmtParamValue, covariant=True
)
SqlfmtParamsLike = (
dict[str, TSqlfmtParamValue_co]
| t.Sequence[tuple[str, TSqlfmtParamValue_co]]
| t.Sequence[TSqlfmtParamValue_co]
)
class SqlfmtQueryParams:
def __init__(self, params: SqlfmtParamsLike[TSqlfmtParamValue_co]) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def sqlfmt_params(
params: SqlfmtParamsLike[TSqlfmtParamValue_co] | SqlfmtQueryParams,
) -> SqlfmtQueryParams: ...
def sqlfmt(
sql: str,
params: SqlfmtParamsLike[TSqlfmtParamValue_co] | SqlfmtQueryParams | None = None,
*,
indent: int = 2, # -1 or any negative value will use tabs
uppercase: bool | None = True,
lines_between_statements: int = 1,
) -> str: ...
# ==============================================================================
# URL
# ==============================================================================
class Url:
def __init__(self, url: str) -> None: ...
@classmethod
def parse(cls, url: str) -> Url: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __hash__(self) -> int: ...
def join(self, *parts: str) -> Url: ...
def __truediv__(self, relative: str) -> Url: ...
def __rtruediv__(self, relative: str) -> Url: ...
def __eq__(self, other: object) -> bool: ...
def __lt__(self, other: object) -> bool: ...
def __le__(self, other: object) -> bool: ...
def __gt__(self, other: object) -> bool: ...
def __ge__(self, other: object) -> bool: ...
@property
def scheme(self) -> str: ...
@property
def host(self) -> str | None: ...
@property
def host_str(self) -> str | None: ...
@property
def port(self) -> int | None: ...
@property
def path(self) -> str: ...
@property
def path_segments(self) -> tuple[str, ...]: ...
@property
def query(self) -> str | None: ...
@property
def query_pairs(self) -> list[tuple[str, str]]: ...
@property
def fragment(self) -> str | None: ...
@property
def username(self) -> str: ...
@property
def password(self) -> str | None: ...
@property
def port_or_known_default(self) -> int | None: ...
@property
def authority(self) -> str: ...
def has_authority(self) -> bool: ...
def has_host(self) -> bool: ...
def is_special(self) -> bool: ...
@classmethod
def from_directory_path(cls, path: str) -> Url: ...
def to_filepath(self) -> str: ...
def set_fragment(self, fragment: str) -> None: ...
def set_host(self, host: str) -> None: ...
def set_ip_host(self, host: str) -> None: ...
def set_password(self, password: str) -> None: ...
def set_path(self, path: str) -> None: ...
def set_port(self, port: int) -> None: ...
def set_query(self, query: str) -> None: ...
def set_scheme(self, scheme: str) -> None: ...
def set_username(self, username: str) -> None: ...
def socket_addrs(self) -> None: ...
# ==============================================================================
# JIFF
# ==============================================================================
class Date:
MIN: Date
MAX: Date
ZERO: Date
def __init__(self, year: int, month: int, day: int) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def at(self, hour: int, minute: int, second: int, nanosecond: int) -> DateTime: ...
@property
def year(self) -> int: ...
@property
def month(self) -> int: ...
@property
def day(self) -> int: ...
def to_pydate(self) -> pydt.date: ...
@classmethod
def from_pydate(cls: type[Date], date: pydt.date) -> Date: ...
def astuple(self) -> tuple[int, int, int]: ...
def asdict(self) -> DateTypedDict: ...
def intz(self, tz: str) -> ZonedDateTime: ...
def __add__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
def __iadd__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
@t.overload
def __sub__(self, other: Date) -> TimeSpan: ...
@t.overload
def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
@t.overload
def __isub__(self, other: Date) -> TimeSpan: ...
@t.overload
def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
class Time:
MIN: Time
MAX: Time
def __init__(
self, hour: int = 0, minute: int = 0, second: int = 0, nanosecond: int = 0
) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __add__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
def __iadd__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
@t.overload
def __sub__(self, other: Time) -> TimeSpan: ...
@t.overload
def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
@t.overload
def __isub__(self, other: Time) -> TimeSpan: ...
@t.overload
def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
@classmethod
def strptime(cls: type[Time], format: str, string: str) -> Time: ...
def strftime(self, format: str) -> str: ...
@property
def hour(self) -> int: ...
@property
def minute(self) -> int: ...
@property
def second(self) -> int: ...
@property
def millisecond(self) -> int: ...
@property
def microsecond(self) -> int: ...
@property
def nanosecond(self) -> int: ...
def to_pytime(self) -> pydt.time: ...
@classmethod
def from_pytime(cls: type[Time], time: pydt.time) -> Time: ...
def astuple(self) -> tuple[int, int, int, int]: ...
def asdict(self) -> TimeTypedDict: ...
def series(self, span: TimeSpan) -> TimeSeries: ...
def until(self, other: Time) -> TimeSpan: ...
class TimeSeries:
def __iter__(self) -> t.Iterator[Time]: ...
def __next__(self) -> Time: ...
class DateTime:
MIN: DateTime
MAX: DateTime
ZERO: DateTime
def __init__(
self,
year: int,
month: int,
day: int,
hour: int = 0,
minute: int = 0,
second: int = 0,
nanosecond: int = 0,
) -> None: ...
def __str__(self) -> str: ...
def string(self) -> str: ...
@classmethod
def parse(cls: type[t.Self], s: str) -> t.Self: ...
def __repr__(self) -> str: ...
def __add__(self, other: TimeSpan | SignedDuration | Duration) -> DateTime: ...
def __iadd__(self, other: TimeSpan | SignedDuration | Duration) -> DateTime: ...
@t.overload
def __sub__(self, other: DateTime) -> TimeSpan: ...
@t.overload
def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> DateTime: ...
@t.overload
def __isub__(self, other: DateTime) -> TimeSpan: ...
@t.overload
def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> DateTime: ...
def intz(self, tz: str) -> ZonedDateTime: ...
def date(self) -> Date: ...
def time(self) -> Time: ...
@property
def year(self) -> int: ...
@property
def month(self) -> int: ...
@property
def day(self) -> int: ...
@property
def hour(self) -> int: ...
@property
def minute(self) -> int: ...
@property
def second(self) -> int: ...
@property
def nanosecond(self) -> int: ...
@property
def subsec_nanosecond(self) -> int: ...
@classmethod
def from_pydatetime(cls: type[DateTime], dt: pydt.datetime) -> DateTime: ...
def to_pydatetime(self) -> pydt.datetime: ...
def series(self, span: TimeSpan) -> DateTimeSeries: ...
def asdict(self) -> DateTimeTypedDict: ...
def round(self, options: JIFF_UNIT_STRING | DateTimeRound) -> t.Self: ...
class DateTimeSeries:
def __iter__(self) -> t.Iterator[DateTime]: ...
def __next__(self) -> DateTime: ...
class TimeZone:
def __init__(self, name: str) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __eq__(self, other: object) -> bool: ...
def to_pytzinfo(self) -> pydt.tzinfo: ...
@classmethod
def from_pytzinfo(cls: type[TimeZone], tz: pydt.tzinfo) -> TimeZone: ...
@classmethod
def utc(cls: type[TimeZone]) -> TimeZone: ...
class SignedDuration:
MIN: SignedDuration
MAX: SignedDuration
ZERO: SignedDuration
def __init__(self, secs: int, nanos: int) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __lt__(self, other: object) -> bool: ...
def __le__(self, other: object) -> bool: ...
def __gt__(self, other: object) -> bool: ...
def __ge__(self, other: object) -> bool: ...
def __neg__(self) -> t.Self: ...
def __add__(self, other: t.Self) -> t.Self: ...
def __richcmp__(self, other: SignedDuration | pydt.timedelta, op: int) -> bool: ...
def __str__(self) -> str: ...
def string(self) -> str: ...
def is_negative(self) -> bool: ...
def is_zero(self) -> bool: ...
@classmethod
def from_pytimedelta(
cls: type[SignedDuration], td: pydt.timedelta
) -> SignedDuration: ...
def to_pytimedelta(self) -> pydt.timedelta: ...
@property
def secs(self) -> int: ...
@property
def nanos(self) -> int: ...
@property
def days(self) -> int: ...
@property
def seconds(self) -> int: ...
@property
def microseconds(self) -> int: ...
class TimeSpan:
def __init__(
self,
) -> None: ...
def __str__(self) -> str: ...
def string(self) -> str: ...
def __repr__(self) -> str: ...
def __neg__(self) -> t.Self: ...
def negate(self) -> t.Self: ...
def __abs__(self) -> t.Self: ...
def __invert__(self) -> t.Self: ...
@classmethod
def from_pytimedelta(cls: type[t.Self], td: pydt.timedelta) -> t.Self: ...
def to_pytimedelta(self) -> pydt.timedelta: ...
@classmethod
def parse(cls: type[t.Self], s: str) -> t.Self: ...
def years(self, years: int) -> t.Self: ...
def months(self, months: int) -> t.Self: ...
def weeks(self, weeks: int) -> t.Self: ...
def days(self, days: int) -> t.Self: ...
def hours(self, hours: int) -> t.Self: ...
def minutes(self, minutes: int) -> t.Self: ...
def seconds(self, seconds: int) -> t.Self: ...
def to_jiff_duration(
self, relative: ZonedDateTime | Date | DateTime
) -> SignedDuration: ...
def repr_full(self) -> str: ...
def asdict(self) -> TimeSpanTypedDict: ...
class Timestamp:
"""
A representation of a timestamp with second and nanosecond precision.
"""
def __init__(
self, second: int | None = None, nanosecond: int | None = None
) -> None: ...
@classmethod
def now(cls: type[t.Self]) -> t.Self: ...
@classmethod
def parse(cls: type[t.Self], s: str) -> t.Self: ...
@classmethod
def from_millisecond(cls: type[t.Self], millisecond: int) -> t.Self: ...
def to_zoned(self, time_zone: TimeZone) -> ZonedDateTime: ...
def string(self) -> str: ...
def as_second(self) -> int: ...
def as_microsecond(self) -> int: ...
def as_millisecond(self) -> int: ...
def as_nanosecond(self) -> int: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __lt__(self, other: object) -> bool: ...
def __le__(self, other: object) -> bool: ...
def __gt__(self, other: object) -> bool: ...
def __ge__(self, other: object) -> bool: ...
def __richcmp__(self, other: Timestamp, op: int) -> bool: ...
def series(self, span: TimeSpan) -> TimestampSeries: ...
def __add__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
def __iadd__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
@t.overload
def __sub__(self, other: Timestamp) -> TimeSpan: ...
@t.overload
def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
@t.overload
def __isub__(self, other: Timestamp) -> TimeSpan: ...
@t.overload
def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
class TimestampSeries:
def __iter__(self) -> t.Iterator[Timestamp]: ...
def __next__(self) -> Timestamp: ...
class ZonedDateTime:
def __init__(self, timestamp: Timestamp, time_zone: TimeZone) -> None: ...
@classmethod
def now(cls: type[ZonedDateTime]) -> ZonedDateTime: ...
@classmethod
def parse(cls: type[ZonedDateTime], s: str) -> ZonedDateTime: ...
def __str__(self) -> str: ...
def string(self) -> str: ...
@classmethod
def from_pydatetime(cls: type[ZonedDateTime], dt: pydt.datetime) -> ZonedDateTime: ...
def to_pydatetime(self) -> pydt.datetime: ...
@classmethod
def strptime(cls: type[ZonedDateTime], format: str, input: str) -> ZonedDateTime: ...
def strftime(self, format: str) -> str: ...
def __richcmp__(self, other: ZonedDateTime, op: int) -> bool: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __lt__(self, other: object) -> bool: ...
def __le__(self, other: object) -> bool: ...
def __gt__(self, other: object) -> bool: ...
def __ge__(self, other: object) -> bool: ...
def __hash__(self) -> int: ...
def __add__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
def __iadd__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
@t.overload
def __sub__(self, other: ZonedDateTime) -> TimeSpan: ...
@t.overload
def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
@t.overload
def __isub__(self, other: ZonedDateTime) -> TimeSpan: ...
@t.overload
def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> t.Self: ...
def intz(self, tz: str) -> t.Self: ...
def checked_add(self, span: TimeSpan) -> t.Self: ...
def round(self, options: JIFF_UNIT_STRING | DateTimeRound) -> t.Self: ...
@property
def year(self) -> int: ...
@property
def month(self) -> int: ...
@property
def day(self) -> int: ...
@property
def hour(self) -> int: ...
@property
def minute(self) -> int: ...
@property
def second(self) -> int: ...
@property
def nanosecond(self) -> int: ...
@property
def subsec_nanosecond(self) -> int: ...
def timezone(self) -> TimeZone: ...
def timestamp(self) -> Timestamp: ...
def time(self) -> Time: ...
def datetime(self) -> DateTime: ...
class DateTimeRound:
def __init__(
self,
smallest: JIFF_UNIT_STRING | None = None,
mode: JIFF_ROUND_MODE_STRING | None = None,
increment: int = 1,
) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __eq__(self, other: object) -> bool: ...
def mode(self, mode: JIFF_ROUND_MODE_STRING) -> DateTimeRound: ...
def smallest(self, smallest: JIFF_UNIT_STRING) -> DateTimeRound: ...
def increment(self, increment: int) -> DateTimeRound: ...
def _smallest(self) -> JIFF_UNIT_STRING: ...
def _mode(self) -> JIFF_ROUND_MODE_STRING: ...
def _increment(self) -> int: ...
def replace(
self,
smallest: JIFF_UNIT_STRING | None,
mode: JIFF_ROUND_MODE_STRING | None,
increment: int | None,
) -> DateTimeRound: ...
class Offset:
def __init__(self, hours: int) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def date(year: int, month: int, day: int) -> Date: ...
def time(
hour: int = 0, minute: int = 0, second: int = 0, nanosecond: int = 0
) -> Time: ...
def datetime(
year: int,
month: int,
day: int,
hour: int = 0,
minute: int = 0,
second: int = 0,
nanosecond: int = 0,
) -> DateTime: ...
def timespan(
*,
years: int = 0,
months: int = 0,
weeks: int = 0,
days: int = 0,
hours: int = 0,
minutes: int = 0,
seconds: int = 0,
milliseconds: int = 0,
microseconds: int = 0,
nanoseconds: int = 0,
) -> TimeSpan: ...
def timespan_unchecked(
*,
years: int = 0,
months: int = 0,
weeks: int = 0,
days: int = 0,
hours: int = 0,
minutes: int = 0,
seconds: int = 0,
milliseconds: int = 0,
microseconds: int = 0,
nanoseconds: int = 0,
) -> TimeSpan: ...
def offset(hours: int) -> Offset: ...
just
is used to run tasks- Do not use the phrase
blazing fast
or any emojis in any PRs or issues or docs - type annotations are required
ruff
used for formatting and linting
- utiles (web-map tile utils): https://github.com/jessekrubin/utiles
- jsonc2json (jsonc to json converter): https://github.com/jessekrubin/jsonc2json