e8f3ec854c425cc36565a40adbf00d22a2febeec
Marco Ricci Change the author e-mail ad...

Marco Ricci authored 2 months ago

src/derivepassphrase/sequin.py            1) # SPDX-FileCopyrightText: 2024 Marco Ricci <software@the13thletter.info>
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                    2) #
src/sequin/__init__.py                    3) # SPDX-License-Identifier: MIT
src/sequin/__init__.py                    4) 
src/sequin/__init__.py                    5) """A Python reimplementation of James Coglan's "sequin" Node.js module.
src/sequin/__init__.py                    6) 
src/sequin/__init__.py                    7) James Coglan's "sequin" Node.js module provides a pseudorandom number
src/sequin/__init__.py                    8) generator (using rejection sampling on a stream of input numbers) that
src/sequin/__init__.py                    9) attempts to minimize the amount of information it throws away:
src/sequin/__init__.py                   10) (non-degenerate) rejected samples are fed into a stream of higher-order
src/sequin/__init__.py                   11) numbers from which the next random number generation request will be
src/sequin/__init__.py                   12) served.  The sequin module is used in Coglan's "vault" module (a
src/sequin/__init__.py                   13) deterministic, stateless password manager that recomputes passwords
src/sequin/__init__.py                   14) instead of storing them), and this reimplementation is used for
src/sequin/__init__.py                   15) a similar purpose.
src/sequin/__init__.py                   16) 
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 3 months ago

src/derivepassphrase/sequin/__init__.py  17) The main API is the [`Sequin`] [derivepassphrase.sequin.Sequin] class,
src/derivepassphrase/sequin/__init__.py  18) which is thoroughly documented.
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   19) 
src/sequin/__init__.py                   20) """
src/sequin/__init__.py                   21) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   22) # ruff: noqa: RUF002,RUF003
src/sequin/__init__.py                   23) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   24) from __future__ import annotations
src/sequin/__init__.py                   25) 
src/sequin/__init__.py                   26) import collections
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   27) from typing import TYPE_CHECKING
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   28) 
Marco Ricci Support Python 3.10 and PyP...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   29) from typing_extensions import assert_type
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   30) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   31) if TYPE_CHECKING:
src/sequin/__init__.py                   32)     from collections.abc import Iterator, Sequence
src/sequin/__init__.py                   33) 
Marco Ricci Rename SequinExhaustedExcep...

Marco Ricci authored 4 months ago

src/sequin/__init__.py                   34) __all__ = ('Sequin', 'SequinExhaustedError')
Marco Ricci Change the author e-mail ad...

Marco Ricci authored 2 months ago

src/derivepassphrase/sequin.py           35) __author__ = 'Marco Ricci <software@the13thletter.info>'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   36) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   37) 
src/sequin/__init__.py                   38) class Sequin:
src/sequin/__init__.py                   39)     """Generate pseudorandom non-negative numbers in different ranges.
src/sequin/__init__.py                   40) 
src/sequin/__init__.py                   41)     Given a (presumed high-quality) uniformly random sequence of input
src/sequin/__init__.py                   42)     bits, generate pseudorandom non-negative integers in a certain range
src/sequin/__init__.py                   43)     on each call of the `generate` method.  (It is permissible to
src/sequin/__init__.py                   44)     specify a different range per call to `generate`; this is the main
src/sequin/__init__.py                   45)     use case.)  We use a modified version of rejection sampling, where
src/sequin/__init__.py                   46)     rejected values are stored in "rejection queues" if possible, and
src/sequin/__init__.py                   47)     these rejection queues re-seed the next round of rejection sampling.
src/sequin/__init__.py                   48) 
src/sequin/__init__.py                   49)     This is a Python reimplementation of James Coglan's [Node.js sequin
src/sequin/__init__.py                   50)     module][JS_SEQUIN], as introduced in [his blog post][BLOG_POST].  It
src/sequin/__init__.py                   51)     uses a [technique by Christian Lawson-Perfect][SEQUIN_TECHNIQUE].
src/sequin/__init__.py                   52)     I do not know why the original module is called "sequin"; I presume
src/sequin/__init__.py                   53)     it to be a pun on "sequence".
src/sequin/__init__.py                   54) 
src/sequin/__init__.py                   55)     [JS_SEQUIN]: https://www.npmjs.com/package/sequin
src/sequin/__init__.py                   56)     [BLOG_POST]: https://blog.jcoglan.com/2012/07/16/designing-vaults-generator-algorithm/
src/sequin/__init__.py                   57)     [SEQUIN_TECHNIQUE]: https://checkmyworking.com/2012/06/converting-a-stream-of-binary-digits-to-a-stream-of-base-n-digits/
src/sequin/__init__.py                   58) 
src/sequin/__init__.py                   59)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   60) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   61)     def __init__(
src/sequin/__init__.py                   62)         self,
src/sequin/__init__.py                   63)         sequence: str | bytes | bytearray | Sequence[int],
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   64)         /,
src/sequin/__init__.py                   65)         *,
src/sequin/__init__.py                   66)         is_bitstring: bool = False,
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 months ago

src/derivepassphrase/sequin.py           67)     ) -> None:
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   68)         """Initialize the Sequin.
src/sequin/__init__.py                   69) 
src/sequin/__init__.py                   70)         Args:
src/sequin/__init__.py                   71)             sequence:
src/sequin/__init__.py                   72)                 A sequence of bits, or things convertible to bits, to
src/sequin/__init__.py                   73)                 seed the pseudorandom number generator.  Byte and text
src/sequin/__init__.py                   74)                 strings are converted to 8-bit integer sequences.
src/sequin/__init__.py                   75)                 (Conversion will fail if the text string contains
src/sequin/__init__.py                   76)                 non-ISO-8859-1 characters.)  The numbers are then
src/sequin/__init__.py                   77)                 converted to bits.
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   78)             is_bitstring:
src/sequin/__init__.py                   79)                 If true, treat the input as a bitstring.  By default,
src/sequin/__init__.py                   80)                 the input is treated as a string of 8-bit integers, from
src/sequin/__init__.py                   81)                 which the individual bits must still be extracted.
src/sequin/__init__.py                   82) 
src/sequin/__init__.py                   83)         Raises:
src/sequin/__init__.py                   84)             ValueError:
src/sequin/__init__.py                   85)                 The sequence contains values outside the permissible
src/sequin/__init__.py                   86)                 range.
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   87) 
src/sequin/__init__.py                   88)         """
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   89)         msg = 'sequence item out of range'
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   90) 
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   91)         def uint8_to_bits(value: int) -> Iterator[int]:
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   92)             """Yield individual bits of an 8-bit number, MSB first."""
src/sequin/__init__.py                   93)             for i in (0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01):
src/sequin/__init__.py                   94)                 yield 1 if value | i == value else 0
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                   95) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   96)         if isinstance(sequence, str):
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                   97)             try:
src/sequin/__init__.py                   98)                 sequence = tuple(sequence.encode('iso-8859-1'))
src/sequin/__init__.py                   99)             except UnicodeError as e:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  100)                 raise ValueError(msg) from e
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  101)         else:
src/sequin/__init__.py                  102)             sequence = tuple(sequence)
src/sequin/__init__.py                  103)         assert_type(sequence, tuple[int, ...])
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  104)         self.bases: dict[int, collections.deque[int]] = {}
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  105) 
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  106)         def gen() -> Iterator[int]:
src/sequin/__init__.py                  107)             for num in sequence:
src/sequin/__init__.py                  108)                 if num not in range(2 if is_bitstring else 256):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  109)                     raise ValueError(msg)
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  110)                 if is_bitstring:
src/sequin/__init__.py                  111)                     yield num
src/sequin/__init__.py                  112)                 else:
src/sequin/__init__.py                  113)                     yield from uint8_to_bits(num)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  114) 
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  115)         self.bases[2] = collections.deque(gen())
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  116) 
src/sequin/__init__.py                  117)     def _all_or_nothing_shift(
src/sequin/__init__.py                  118)         self, count: int, /, *, base: int = 2
src/sequin/__init__.py                  119)     ) -> Sequence[int]:
src/sequin/__init__.py                  120)         """Shift and return items if and only if there are enough.
src/sequin/__init__.py                  121) 
src/sequin/__init__.py                  122)         Args:
src/sequin/__init__.py                  123)             count: Number of items to shift/consume.
src/sequin/__init__.py                  124)             base: Use the base `base` sequence.
src/sequin/__init__.py                  125) 
src/sequin/__init__.py                  126)         Returns:
src/sequin/__init__.py                  127)             If there are sufficient items in the sequence left, then
src/sequin/__init__.py                  128)             consume them from the sequence and return them.  Otherwise,
src/sequin/__init__.py                  129)             consume nothing, and return nothing.
src/sequin/__init__.py                  130) 
src/sequin/__init__.py                  131)         Notes:
src/sequin/__init__.py                  132)             We currently remove now-empty sequences from the registry of
src/sequin/__init__.py                  133)             sequences.
src/sequin/__init__.py                  134) 
src/sequin/__init__.py                  135)         Examples:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  136)             >>> seq = Sequin([1, 0, 1, 0, 0, 1, 0, 0, 0, 1], is_bitstring=True)
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  137)             >>> seq.bases
src/sequin/__init__.py                  138)             {2: deque([1, 0, 1, 0, 0, 1, 0, 0, 0, 1])}
src/sequin/__init__.py                  139)             >>> seq._all_or_nothing_shift(3)
src/sequin/__init__.py                  140)             (1, 0, 1)
src/sequin/__init__.py                  141)             >>> seq._all_or_nothing_shift(3)
src/sequin/__init__.py                  142)             (0, 0, 1)
src/sequin/__init__.py                  143)             >>> seq.bases[2]
src/sequin/__init__.py                  144)             deque([0, 0, 0, 1])
src/sequin/__init__.py                  145)             >>> seq._all_or_nothing_shift(5)
src/sequin/__init__.py                  146)             ()
src/sequin/__init__.py                  147)             >>> seq.bases[2]
src/sequin/__init__.py                  148)             deque([0, 0, 0, 1])
src/sequin/__init__.py                  149)             >>> seq._all_or_nothing_shift(4)
src/sequin/__init__.py                  150)             (0, 0, 0, 1)
src/sequin/__init__.py                  151)             >>> 2 in seq.bases  # now-empty sequences are removed
src/sequin/__init__.py                  152)             False
src/sequin/__init__.py                  153) 
src/sequin/__init__.py                  154)         """
src/sequin/__init__.py                  155)         try:
src/sequin/__init__.py                  156)             seq = self.bases[base]
src/sequin/__init__.py                  157)         except KeyError:
src/sequin/__init__.py                  158)             return ()
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  159)         stash: collections.deque[int] = collections.deque()
src/sequin/__init__.py                  160)         try:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  161)             for _ in range(count):
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  162)                 stash.append(seq.popleft())
src/sequin/__init__.py                  163)         except IndexError:
src/sequin/__init__.py                  164)             seq.extendleft(reversed(stash))
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  165)             return ()
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  166)         # Clean up queues.
src/sequin/__init__.py                  167)         if not seq:
src/sequin/__init__.py                  168)             del self.bases[base]
src/sequin/__init__.py                  169)         return tuple(stash)
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  170) 
src/sequin/__init__.py                  171)     @staticmethod
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  172)     def _big_endian_number(digits: Sequence[int], /, *, base: int = 2) -> int:
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  173)         """Evaluate the given integer sequence as a big endian number.
src/sequin/__init__.py                  174) 
src/sequin/__init__.py                  175)         Args:
src/sequin/__init__.py                  176)             digits: A sequence of integers to evaluate.
src/sequin/__init__.py                  177)             base: The number base to evaluate those integers in.
src/sequin/__init__.py                  178) 
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 months ago

src/derivepassphrase/sequin.py          179)         Returns:
src/derivepassphrase/sequin.py          180)             The number value of the integer sequence.
src/derivepassphrase/sequin.py          181) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  182)         Raises:
src/sequin/__init__.py                  183)             ValueError: `base` is an invalid base.
src/sequin/__init__.py                  184)             ValueError: Not all integers are valid base `base` digits.
src/sequin/__init__.py                  185) 
src/sequin/__init__.py                  186)         Examples:
src/sequin/__init__.py                  187)             >>> Sequin._big_endian_number([1, 2, 3, 4, 5, 6, 7, 8], base=10)
src/sequin/__init__.py                  188)             12345678
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  189)             >>> Sequin._big_endian_number([1, 2, 3, 4, 5, 6, 7, 8], base=100)
src/sequin/__init__.py                  190)             102030405060708
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  191)             >>> Sequin._big_endian_number([0, 0, 0, 0, 1, 4, 9, 7], base=10)
src/sequin/__init__.py                  192)             1497
src/sequin/__init__.py                  193)             >>> Sequin._big_endian_number([1, 0, 0, 1, 0, 0, 0, 0], base=2)
src/sequin/__init__.py                  194)             144
src/sequin/__init__.py                  195)             >>> Sequin._big_endian_number([1, 7, 5, 5], base=8) == 0o1755
src/sequin/__init__.py                  196)             True
src/sequin/__init__.py                  197) 
src/sequin/__init__.py                  198)         """
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  199)         if base < 2:  # noqa: PLR2004
src/sequin/__init__.py                  200)             msg = f'invalid base: {base!r}'
src/sequin/__init__.py                  201)             raise ValueError(msg)
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  202)         ret = 0
src/sequin/__init__.py                  203)         allowed_range = range(base)
src/sequin/__init__.py                  204)         n = len(digits)
src/sequin/__init__.py                  205)         for i in range(n):
src/sequin/__init__.py                  206)             i2 = (n - 1) - i
src/sequin/__init__.py                  207)             x = digits[i]
src/sequin/__init__.py                  208)             if not isinstance(x, int):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  209)                 msg = f'not an integer: {x!r}'
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 months ago

src/derivepassphrase/sequin.py          210)                 raise TypeError(msg)  # noqa: DOC501
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  211)             if x not in allowed_range:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  212)                 msg = f'invalid base {base!r} digit: {x!r}'
src/sequin/__init__.py                  213)                 raise ValueError(msg)
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  214)             ret += (base**i2) * x
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  215)         return ret
src/sequin/__init__.py                  216) 
src/sequin/__init__.py                  217)     def generate(self, n: int, /) -> int:
src/sequin/__init__.py                  218)         """Generate a base `n` non-negative integer.
src/sequin/__init__.py                  219) 
src/sequin/__init__.py                  220)         We attempt to generate a value using rejection sampling.  If the
src/sequin/__init__.py                  221)         generated sample is outside the desired range (i.e., is
src/sequin/__init__.py                  222)         rejected), then attempt to reuse the sample by seeding
src/sequin/__init__.py                  223)         a "higher-order" input sequence of uniformly random numbers (for
src/sequin/__init__.py                  224)         a different base).
src/sequin/__init__.py                  225) 
src/sequin/__init__.py                  226)         Args:
src/sequin/__init__.py                  227)             n:
src/sequin/__init__.py                  228)                 Generate numbers in the range 0, ..., `n` - 1.
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  229)                 (Inclusive.)  Must be larger than 0.
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  230) 
src/sequin/__init__.py                  231)         Returns:
src/sequin/__init__.py                  232)             A pseudorandom number in the range 0, ..., `n` - 1.
src/sequin/__init__.py                  233) 
src/sequin/__init__.py                  234)         Raises:
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  235)             ValueError:
src/sequin/__init__.py                  236)                 The range is empty.
Marco Ricci Rename SequinExhaustedExcep...

Marco Ricci authored 4 months ago

src/sequin/__init__.py                  237)             SequinExhaustedError:
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  238)                 The sequin is exhausted.
src/sequin/__init__.py                  239) 
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  240)         Examples:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  241)             >>> seq = Sequin(
src/sequin/__init__.py                  242)             ...     [1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1],
src/sequin/__init__.py                  243)             ...     is_bitstring=True,
src/sequin/__init__.py                  244)             ... )
src/sequin/__init__.py                  245)             >>> seq2 = Sequin(
src/sequin/__init__.py                  246)             ...     [1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1],
src/sequin/__init__.py                  247)             ...     is_bitstring=True,
src/sequin/__init__.py                  248)             ... )
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  249)             >>> seq.generate(5)
src/sequin/__init__.py                  250)             3
src/sequin/__init__.py                  251)             >>> seq.generate(5)
src/sequin/__init__.py                  252)             3
src/sequin/__init__.py                  253)             >>> seq.generate(5)
src/sequin/__init__.py                  254)             1
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  255)             >>> seq.generate(5)  # doctest: +IGNORE_EXCEPTION_DETAIL
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  256)             Traceback (most recent call last):
src/sequin/__init__.py                  257)                 ...
Marco Ricci Rename SequinExhaustedExcep...

Marco Ricci authored 4 months ago

src/sequin/__init__.py                  258)             SequinExhaustedError: Sequin is exhausted
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  259) 
src/sequin/__init__.py                  260)             Using `n = 1` does not actually consume input bits:
src/sequin/__init__.py                  261) 
src/sequin/__init__.py                  262)             >>> seq2.generate(1)
src/sequin/__init__.py                  263)             0
src/sequin/__init__.py                  264) 
src/sequin/__init__.py                  265)             But it still won't work on exhausted sequins:
src/sequin/__init__.py                  266) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  267)             >>> seq.generate(1)  # doctest: +IGNORE_EXCEPTION_DETAIL
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  268)             Traceback (most recent call last):
src/sequin/__init__.py                  269)                 ...
Marco Ricci Rename SequinExhaustedExcep...

Marco Ricci authored 4 months ago

src/sequin/__init__.py                  270)             SequinExhaustedError: Sequin is exhausted
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  271) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  272)         """
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  273)         if 2 not in self.bases:  # noqa: PLR2004
src/sequin/__init__.py                  274)             raise SequinExhaustedError
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  275)         value = self._generate_inner(n, base=2)
src/sequin/__init__.py                  276)         if value == n:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  277)             raise SequinExhaustedError
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  278)         return value
src/sequin/__init__.py                  279) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  280)     def _generate_inner(self, n: int, /, *, base: int = 2) -> int:
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  281)         """Recursive call to generate a base `n` non-negative integer.
src/sequin/__init__.py                  282) 
src/sequin/__init__.py                  283)         We first determine the correct exponent `k` to generate base `n`
src/sequin/__init__.py                  284)         numbers from a stream of base `base` numbers, then attempt to
src/sequin/__init__.py                  285)         take `k` numbers from the base `base` sequence (or bail if not
src/sequin/__init__.py                  286)         possible).  If the resulting number `v` is out of range for
src/sequin/__init__.py                  287)         base `n`, then push `v - n` onto the rejection queue for
src/sequin/__init__.py                  288)         base `r` = `base` ** `k` - `n`, and attempt to generate the
src/sequin/__init__.py                  289)         requested base `n` integer from the sequence of base `r` numbers
src/sequin/__init__.py                  290)         next.  (This recursion is not attempted if `r` = 1.)  Otherwise,
src/sequin/__init__.py                  291)         return the number.
src/sequin/__init__.py                  292) 
src/sequin/__init__.py                  293)         Args:
src/sequin/__init__.py                  294)             n:
src/sequin/__init__.py                  295)                 Generate numbers in the range 0, ..., `n` - 1.
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  296)                 (Inclusive.)  Must be larger than 0.
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  297)             base:
src/sequin/__init__.py                  298)                 Use the base `base` sequence as a source for
src/sequin/__init__.py                  299)                 pseudorandom numbers.
src/sequin/__init__.py                  300) 
src/sequin/__init__.py                  301)         Returns:
src/sequin/__init__.py                  302)             A pseudorandom number in the range 0, ..., `n` - 1 if
src/sequin/__init__.py                  303)             possible, or `n` if the stream is exhausted.
src/sequin/__init__.py                  304) 
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  305)         Raises:
src/sequin/__init__.py                  306)             ValueError:
src/sequin/__init__.py                  307)                 The range is empty.
src/sequin/__init__.py                  308) 
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  309)         Examples:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  310)             >>> seq = Sequin(
src/sequin/__init__.py                  311)             ...     [1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1],
src/sequin/__init__.py                  312)             ...     is_bitstring=True,
src/sequin/__init__.py                  313)             ... )
src/sequin/__init__.py                  314)             >>> seq2 = Sequin(
src/sequin/__init__.py                  315)             ...     [1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1],
src/sequin/__init__.py                  316)             ...     is_bitstring=True,
src/sequin/__init__.py                  317)             ... )
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  318)             >>> seq._generate_inner(5)
src/sequin/__init__.py                  319)             3
src/sequin/__init__.py                  320)             >>> seq._generate_inner(5)
src/sequin/__init__.py                  321)             3
src/sequin/__init__.py                  322)             >>> seq._generate_inner(5)
src/sequin/__init__.py                  323)             1
src/sequin/__init__.py                  324)             >>> seq._generate_inner(5)  # error condition: sequin exhausted
src/sequin/__init__.py                  325)             5
src/sequin/__init__.py                  326) 
src/sequin/__init__.py                  327)             Using `n = 1` does not actually consume input bits, and
src/sequin/__init__.py                  328)             always works, regardless of sequin exhaustion:
src/sequin/__init__.py                  329) 
src/sequin/__init__.py                  330)             >>> seq2._generate_inner(1)
src/sequin/__init__.py                  331)             0
src/sequin/__init__.py                  332)             >>> seq._generate_inner(1)
src/sequin/__init__.py                  333)             0
src/sequin/__init__.py                  334) 
src/sequin/__init__.py                  335)             Using an unsuitable range will raise:
src/sequin/__init__.py                  336) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  337)             >>> seq2._generate_inner(0)  # doctest: +IGNORE_EXCEPTION_DETAIL
Marco Ricci Add unit tests, both new an...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  338)             Traceback (most recent call last):
src/sequin/__init__.py                  339)                 ...
src/sequin/__init__.py                  340)             ValueError: invalid target range
src/sequin/__init__.py                  341) 
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  342)         """
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  343)         if n < 1:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  344)             msg = 'invalid target range'
src/sequin/__init__.py                  345)             raise ValueError(msg)
src/sequin/__init__.py                  346)         if base < 2:  # noqa: PLR2004
src/sequin/__init__.py                  347)             msg = f'invalid base: {base!r}'
src/sequin/__init__.py                  348)             raise ValueError(msg)
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  349)         # p = base ** k, where k is the smallest integer such that
src/sequin/__init__.py                  350)         # p >= n.  We determine p and k inductively.
src/sequin/__init__.py                  351)         p = 1
src/sequin/__init__.py                  352)         k = 0
src/sequin/__init__.py                  353)         while p < n:
src/sequin/__init__.py                  354)             p *= base
src/sequin/__init__.py                  355)             k += 1
src/sequin/__init__.py                  356)         # The remainder r of p and n is used as the base for rejection
src/sequin/__init__.py                  357)         # queue.
src/sequin/__init__.py                  358)         r = p - n
src/sequin/__init__.py                  359)         # The generated number v is initialized to n because of the
src/sequin/__init__.py                  360)         # while loop below.
src/sequin/__init__.py                  361)         v = n
src/sequin/__init__.py                  362)         while v > n - 1:
src/sequin/__init__.py                  363)             list_slice = self._all_or_nothing_shift(k, base=base)
src/sequin/__init__.py                  364)             if not list_slice:
Marco Ricci Fix numerous argument type...

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  365)                 if n != 1:
src/sequin/__init__.py                  366)                     return n
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  367)                 v = 0
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  368)             v = self._big_endian_number(list_slice, base=base)
src/sequin/__init__.py                  369)             if v > n - 1:
src/sequin/__init__.py                  370)                 # If r is 0, then p == n, so v < n, or rather
src/sequin/__init__.py                  371)                 # v <= n - 1.
src/sequin/__init__.py                  372)                 assert r > 0
src/sequin/__init__.py                  373)                 if r == 1:
src/sequin/__init__.py                  374)                     continue
src/sequin/__init__.py                  375)                 self._stash(v - n, base=r)
src/sequin/__init__.py                  376)                 v = self._generate_inner(n, base=r)
src/sequin/__init__.py                  377)         return v
src/sequin/__init__.py                  378) 
src/sequin/__init__.py                  379)     def _stash(self, value: int, /, *, base: int = 2) -> None:
src/sequin/__init__.py                  380)         """Stash `value` on the base `base` sequence."""
src/sequin/__init__.py                  381)         if base not in self.bases:
src/sequin/__init__.py                  382)             self.bases[base] = collections.deque()
src/sequin/__init__.py                  383)         self.bases[base].append(value)
src/sequin/__init__.py                  384) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  385) 
Marco Ricci Rename SequinExhaustedExcep...

Marco Ricci authored 4 months ago

src/sequin/__init__.py                  386) class SequinExhaustedError(Exception):
Marco Ricci Add prototype implementation

Marco Ricci authored 5 months ago

src/sequin/__init__.py                  387)     """The sequin is exhausted.
src/sequin/__init__.py                  388) 
src/sequin/__init__.py                  389)     No more values can be generated from this sequin.
src/sequin/__init__.py                  390) 
src/sequin/__init__.py                  391)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 3 months ago

src/sequin/__init__.py                  392) 
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 2 months ago

src/derivepassphrase/sequin.py          393)     def __init__(self) -> None:  # noqa: D107