Skip to content

v3.0.0

Choose a tag to compare

@EtorixDev EtorixDev released this 18 Feb 22:43
· 15 commits to main since this release

Breaking

  • Python 3.8 is no longer supported.
  • TimeLength().strict is deprecated. Its functionality has been replaced with timelength.FailureFlags and timelength.ParserSettings. Find a full list of options for each in the README.
    • The default for FailureFlags is FailureFlags.NONE which means as long as a single value is parsed, it will be considered a success.
    • The spiritual successor to strict = True is FailureFlags.ALL, which means if any failure flag is met, the parsing will be considered a failure.
  • decimal_separators and thousand_separators in the config were renamed to decimal_delimiters and thousand_delimiters.
    • This will only affect you if you utilized a CustomLocale.
  • CustomLocale was removed in favor of just using Locale.
  • BufferType and buffer_type() renamed to StringType and string_type() respectively.
  • TimeLength().result.invalid and TimeLength().result.valid are now tuples of tuples instead of lists of tuples.
    • The invalid tuple is of type tuple[tuple[float | str, FailureFlags], ...].
    • The valid tuple is of type tuple[tuple[float, Scale], ...].

Features

  • timelength.FailureFlags is an IntFlag enum which holds all the currently possible reasons for a parse to fail. It is not guaranteed that every flag will be used by every parser, but every flag from all parsers will be present. See the README for a full list.
    • Set specific failure flags by passing them to your locale.
    • Example: locale = English(flags=(FailureFlags.LONELY_VALUE | FailureFlags.UNKNOWN_TERM)).
    • In this scenario, parsing will only fail if LONELY_VALUE or UNKNOWN_TERM appear in the result.invalid tuple, or if no valid results were parsed.
  • Modify parsing behavior by passing a timelength.ParserSettings() to locale.settings. It is not guaranteed that every setting will be used by every parser, but every setting from all parsers will be present.
    • Example: locale = English(settings=ParserSettings(allow_duplicate_scales=False))
    • assume_seconds (Literal["LAST", "SINGLE", "NEVER"]): Defaults to SINGLE. How to handle no scale being provided. If seconds are disabled, the first loaded scale will take its place.
      • LAST: Assume seconds only for the last value if no scale is provided for it.
      • SINGLE: Only assume seconds when a single number is provided.
      • NEVER: Never assume seconds when no scale is provided.
    • limit_allowed_terms (bool): Defaults to True. Prevent terms from the allowed_terms list in the config from being used in the middle of a segment/sentence, thus interrupting a value/scale pair. The affected segment will become abandoned and added to the invalid tuple. The terms may still be used at the beginning or end of a segment/sentence. If False, The terms will be ignored (within other limitations) and not affect parsing.
    • allow_duplicate_scales (bool): Defaults to True. Allow scales to be parsed multiple times. The values will stack. If False, the first scale will be used and subsequent duplicates will be added to the invalid tuple.
    • prevent_thousands_extra_digits (bool): Defaults to True. Prevent thousands from being parsed if it has more than three digits following the thousand delimiter. Ex: 1,2345. The number will be added to the invalid tuple. If False, the number will be interpreted as 12,345. This does not allow for thousands to be parsed with less than three digits following the thousand delimiter.
    • allow_thousands_lacking_digits (bool): Defaults to False. If True, allow thousands to be parsed with less than three digits following the thousand delimiter. Ex: 1,23 will be interpreted as 123, or 2,455 5 as 24,555 (depending on terms in config).
  • HH:MM:SS notation (roughly).
    • It is not strictly adherent to typical HH:MM:SS standards. Any parsable numbers work in each slot, whether they are single digits, multiple digits, or include decimals.
      • For example, 2.56:27/3:270:19.2231 is a valid input in place of 2.56 days, 9 hours, 270 minutes, and 19.2231 seconds.
      • It also accepts a single connector, such as a space, between deliminators. Example: 2: 6: 3.
    • Supports up to as many segments as there are scales defined, including custom scales (10 default, Millisecond to Century).
      • The segments are parsed in reverse order, so smallest to largest (the order defined in the config and therefore the order loaded into the Locale, may differ for custom defined Scales) to ensure the correct scales are applied.
        • EXCEPTION: The default base from which HH:MM:SS starts at is Second. Any scales (typically of lesser value) listed prior in the config, or appended to the scales list before Second in the case of custom scales, will not be utilized unless Second is disabled or as many HH:MM:SS segments are parsed as there are scales defined.
        • 12:30:15 is 12 hours, 30 minutes, and 15 seconds, NOT 12 minutes, 30 seconds, and 15 milliseconds.
        • 1:10:100:12:52:30:24:60:60:1000 will make use of Century to Millisecond.
    • Delimiters are modifiable in the config under the hhmmss_delimiters key. Values must be unique from decimal_delimiters and thousand_delimiters.
  • Quickly access the parsed TimeLength as a timedelta with TimeLength().result.delta.
  • Find the relative datetime of your input in the past or future with TimeLength().ago() and TimeLength().hence().
    • Both take an optional base argument which is a datetime. It defaults to the present in UTC.
  • Have TimeLength guess the Locale by passing Guess() for the locale.
    • It will attempt to parse with all locales currently available and return the best result. The best result is the one with the least invalid results.
    • Add custom Locales by appending to Guess().locales.
    • TimeLength().locale will be set to the guessed locale.
    • Guess subsequent parses by using TimeLength().parse(guess_locale=True) or TimeLength().parse(guess_locale=Guess()).
  • Perform arithmetic operations on TimeLength objects.
    • Check the README for a full list of supported operations and types.
    • All operations not involving a datetime are absolute. For example, TimeLength("1 minute") - TimeLength("5 minutes") will return TimeLength("4 minutes").
    • Any resultant TimeLengths will inherit the locale from the first encountered TimeLength in the arithmetic.
  • Perform comparison operations on TimeLength objects.
    • Comparison based on their parsed seconds for all but bool and len comparisons.
    • bool returns if parsing succeeded based on the result.success attribute.
    • len returns the length of the passed content attribute.
  • Other things I've likely forgotten.

Improvements

  • Seconds will now only be assumed as the input if the Second scale is enabled (and assuming is enabled). If Second is disabled, the first loaded scale (typically the smallest value wise unless you have defined custom scales out of order) will be used instead.
  • Overhauled various __str__ and _repr__ functions.
  • Added full type hinting.
  • Commented areas where the reasoning for doing things is unclear (many places).
  • A lot of things are now properties to discourage modifying them.
  • Various errors added for incorrect usage.
  • Tests expanded to 100% coverage.
  • The ruff formatter now uses a line-length of 120 instead of the default 88.
  • Other things I've likely forgotten.