Miscellaneous utilities

Time durations with units

Time is measured in seconds, but edzed classes accept also durations and time periods represented as strings with larger time units day, hour and minute.

The traditional format:

DURATION = [n D] [n H] [n M] [n S]

Examples:

'2m' = 2 minutes = 120.0 seconds
'20h15m10' = 20 hours + 15 minutes + 10 seconds = 72_910.0
'2d 12h' = 2 days + 12 hours = 21_6000.0
'1.25h' = 1 and a quarter of and houre = 4_500.0

Changed in version 24.3.4:

  • An empty string is now rejected.

  • A decimal comma may be used.

  • Previously, fractional numbers were allowed only for seconds.

The ISO 8601 format:

DURATION = P [0Y] [0M] [nD] T [nH] [nM] [nS]

Description with examples: Wikipedia

New in version 24.3.4.

Notes:

Both formats:

  • At least one part of the duration string must be present.

  • Only the smallest unit may have a fractional part. Both decimal point and decimal comma are supported.

  • Numbers do not have to be normalized, e.g. '72H' is fine.

Traditional format only:

  • Unit symbols D, H, M, S may be entered also in lower case.

  • Whitespace around numbers and units is allowed.

ISO format only:

  • the largest usable unit is a day. Calendar years and months are not supported and must be set to 0 if present.


Conversions routines:

edzed.utils.timestr(seconds: int | float, sep: str = '', prec: int = 3) str

Convert seconds, return a string with time units.

The individual parts are separated with the sep string.

Minutes (m) and seconds (s) are always present in the result. Days (d) and hours (h) are prepended only when needed.

If the input value is a float, fractional seconds are formatted to prec decimal places.

This is an inverse function to convert() below provided the separator is empty or whitespace only.

Changed in version 22.11.2: Added the prec parameter.

edzed.utils.timestr_approx(seconds: int | float, sep: str = '') str

Convert seconds to a string using d, h, m, and s units with limited precision.

The individual parts are separated with the sep string.

This is an alternative to timestr(). It rounds off the least significant part of the value to make the result shorter and better human readable. Depending on the value magnitude, the seconds’ decimal places are gradually reduced from three down to zero and for large values the seconds or even the minutes are omitted entirely.

Compare:

timestr

timestr_approx

0m20.053s

20.1s

1d2h11m7.029s

1d2h11m

10d3h5m4.120s

10d3h

edzed.utils.convert(timestring: str) float

Convert a timestring to number of seconds. See also the next function.

edzed.utils.time_period(period: int | float | str) float
edzed.utils.time_period(period: None) None

This is a convenience function accepting all time period formats used in edzed:

  • time_period(None) returns None.

  • time_period(number) returns the number as float. Negative values are converted to 0.0.

  • time_period(string) converts the string with convert().

Improved asyncio.shield

Use shield_cancel() to protect small critical task sections from immediate cancellation.

async edzed.utils.shield_cancel(aw: Awaitable) Any

Shield from cancellation while aw is awaited.

Any pending asyncio.CancelledError is raised when aw is finished.

Make the shielded code and its execution time as short as possible.

Warning

Never suppress task cancellation completely!

Name to block resolver

When referencing a circuit block, edzed generally allows to use either a block name or a block object.

At some point the names need to be resolved, because the software works only with objects internally. The resolver is a service provided by the circuit simulator.

Circuit.resolve_name(obj, attr: str, block_type: type[Block] = edzed.Block)

Register an object with the resolver.

The object obj should be storing a reference to a circuit block in its attribute named attr.

  • If the reference is a name (i.e. a string), register the object to be processed by the resolver. The resolver will then replace the name by the corresponding block object and check its type before the simulation starts.

  • If the reference is a block object already, name resolving is not needed. Just check the type and return.

The block_type is the required type of the referenced block. A TypeError is raised if the block is not an instance of this type.

Inverted output

The name to block resolver supports the '_not_NAME' notation, where the name is derived from another block’s NAME by prepending a '_not_' prefix. The original NAME must not begin with an underscore.

This is a shortcut for connecting a logically inverted output. A new Not block will be created automatically if it does not exist already:

edzed.Not('_not_NAME').connect(NAME)