From d0f55054a45b31ed55acf70c19ac2f8e57c40d59 Mon Sep 17 00:00:00 2001 From: Josh Karpel Date: Sun, 19 Feb 2023 13:12:19 -0600 Subject: [PATCH] Slide Transitions (#207) --- .coveragerc | 3 - .github/workflows/quality-check.yml | 3 + docs/api.md | 8 + docs/assets/quickstart_code.svg | 68 +- docs/assets/triggers_animation_1.svg | 12 +- docs/assets/triggers_animation_2.svg | 12 +- docs/assets/triggers_animation_3.svg | 12 +- docs/assets/triggers_animation_4.svg | 12 +- docs/changelog.md | 4 + docs/contributing.md | 5 +- docs/examples/triggers_animation.py | 1 + docs/generate_screenshots.py | 47 +- docs/transitions.md | 101 +++ mkdocs.yml | 1 + poetry.lock | 702 +++++++++++------- pyproject.toml | 15 +- spiel/__init__.py | 14 +- spiel/app.py | 76 +- spiel/cli.py | 73 +- spiel/constants.py | 2 + spiel/deck.py | 22 +- spiel/screens/transition.py | 85 +++ spiel/slide.py | 20 +- spiel/transitions/__init__.py | 0 spiel/transitions/protocol.py | 72 ++ spiel/transitions/swipe.py | 36 + spiel/widgets/fixed_slide.py | 50 ++ spiel/widgets/slide.py | 7 +- spiel/widgets/widget.py | 11 +- synthfile | 14 + tests/cli/__init__.py | 0 tests/{test_cli.py => cli/test_demo.py} | 44 -- tests/cli/test_help.py | 20 + tests/cli/test_present.py | 20 + tests/cli/test_version.py | 18 + tests/conftest.py | 2 +- tests/renderables/__init__.py | 0 tests/{ => renderables}/test_image.py | 0 tests/test_app.py | 41 +- tests/test_init.py | 34 - tests/transitions/__init__.py | 0 tests/transitions/conftest.py | 12 + tests/transitions/test_swipe.py | 121 +++ tests/utils/__init__.py | 0 tests/{ => utils}/test_chunks.py | 0 tests/{ => utils}/test_clamp.py | 0 .../test_filter_join.py} | 0 tests/widgets/__init__.py | 0 tests/{ => widgets}/test_slide_widget.py | 0 49 files changed, 1219 insertions(+), 581 deletions(-) create mode 100644 docs/transitions.md create mode 100644 spiel/screens/transition.py create mode 100644 spiel/transitions/__init__.py create mode 100644 spiel/transitions/protocol.py create mode 100644 spiel/transitions/swipe.py create mode 100644 spiel/widgets/fixed_slide.py create mode 100644 synthfile create mode 100644 tests/cli/__init__.py rename tests/{test_cli.py => cli/test_demo.py} (56%) create mode 100644 tests/cli/test_help.py create mode 100644 tests/cli/test_present.py create mode 100644 tests/cli/test_version.py create mode 100644 tests/renderables/__init__.py rename tests/{ => renderables}/test_image.py (100%) delete mode 100644 tests/test_init.py create mode 100644 tests/transitions/__init__.py create mode 100644 tests/transitions/conftest.py create mode 100644 tests/transitions/test_swipe.py create mode 100644 tests/utils/__init__.py rename tests/{ => utils}/test_chunks.py (100%) rename tests/{ => utils}/test_clamp.py (100%) rename tests/{test_joinify.py => utils/test_filter_join.py} (100%) create mode 100644 tests/widgets/__init__.py rename tests/{ => widgets}/test_slide_widget.py (100%) diff --git a/.coveragerc b/.coveragerc index 2cb3d43..7b841fa 100644 --- a/.coveragerc +++ b/.coveragerc @@ -6,9 +6,6 @@ source = spiel/ tests/ -omit = - spiel/demo/* - [report] skip_empty = True diff --git a/.github/workflows/quality-check.yml b/.github/workflows/quality-check.yml index 92791f0..362d4af 100644 --- a/.github/workflows/quality-check.yml +++ b/.github/workflows/quality-check.yml @@ -17,6 +17,7 @@ jobs: run: shell: bash runs-on: ${{ matrix.platform }} + timeout-minutes: 15 env: PLATFORM: ${{ matrix.platform }} PYTHON_VERSION: ${{ matrix.python-version }} @@ -38,6 +39,8 @@ jobs: run: poetry run pre-commit run --all-files --show-diff-on-failure --color=always - name: Make sure we can build the package run: poetry build -vvv + - name: Test types + run: poetry run mypy - name: Test code run: poetry run pytest -v --cov --cov-report=xml --durations=20 - name: Test docs diff --git a/docs/api.md b/docs/api.md index 2969002..07fbdd9 100644 --- a/docs/api.md +++ b/docs/api.md @@ -10,6 +10,14 @@ ::: spiel.Triggers +## Transitions + +::: spiel.Direction + +::: spiel.Transition + +::: spiel.Swipe + ## Presenting Decks ::: spiel.present diff --git a/docs/assets/quickstart_code.svg b/docs/assets/quickstart_code.svg index 8878c4c..00c0d7d 100644 --- a/docs/assets/quickstart_code.svg +++ b/docs/assets/quickstart_code.svg @@ -194,7 +194,7 @@ - + Decks are made of Slides @@ -206,39 +206,39 @@ (Rich supports syntax highlighting, so Spiel does too!) ┌────────────────────────────────────────────────────────────────────┐┌────────────────────────────────────────────────────────────────────┐ -10 @dataclass17 @dataclass -11 classDeck(Sequence[Slide]):18 classSlide: -12 """19 """ -13     Represents a "deck" of "slides": a presentation.20     Represents a single slide in the presentation. -14     """21     """ -15 22  -16 name:str23 title:str="" -17 """The name of the `Deck`/presentation, which will be dis24 """The title of the `Slide`, which will be displayed in t -18 25  -19 _slides:list[Slide]=field(default_factory=list)26 content:Content=lambda:Text() -20 27 """ -21 defslide(28     A callable that is invoked by Spiel to display the slide' -22 self,29  -23 title:str="",30     The function may optionally take arguments with these nam -24 bindings:Mapping[str,Callable[...,None]]|None=31  -25 )->Callable[[Content],Content]:32     - `trigger`: The current [`Trigger`][spiel.Triggers] stat -26 """33     """ -27         A decorator that creates a new slide in the deck,34  -28         with the decorated function as the `Slide`'s `content35 bindings:Mapping[str,Callable[...,None]]=field(defau -29 36  -30         Args:37 defrender(self,triggers:Triggers)->RenderableType: -31             title: The title to display for the slide.38 signature=inspect.signature(self.content) -32             bindings: A mapping of39  -33                 [keys](https://textual.textualize.io/guide/in40 kwargs:dict[str,object]={} -34                 to callables to be executed when those keys a41 ifTRIGGERSinsignature.parameters: -35                 when on this slide.42 kwargs[TRIGGERS]=triggers -36         """43  -37 44 returnself.content(**kwargs) -38 defslideify(content:Content)->Content:└────────────────────────────────────────────────────────────────────┘ -39 self.add_slides( -40 Slide( -41 title=title, -42 content=content, +12 @dataclass19 @dataclass +13 classDeck(Sequence[Slide]):20 classSlide: +14 """21 """ +15     Represents a "deck" of "slides": a presentation.22     Represents a single slide in the presentation. +16     """23     """ +17 24  +18 name:str25 title:str="" +19 """The name of the [`Deck`][spiel.Deck], which will be di26 """The title of the `Slide`, which will be displayed in t +20 27  +21 default_transition:Type[Transition]|None=Swipe28 content:Content=lambda:Text() +22 """\29 """\ +23     The default slide transition animation;30     A callable that is invoked by Spiel to display the slide' +24     used if the slide being moved to does not specify its own31  +25     Defaults to the [`Swipe`][spiel.Swipe] transition.32     The function may optionally take arguments with these nam +26     Set to `None` for no transition animation.33  +27     """34     - `trigger`: The current [`Trigger`][spiel.Triggers] stat +28 35     """ +29 _slides:list[Slide]=field(default_factory=list)36  +30 37 bindings:Mapping[str,Callable[...,None]]=field(defau +31 defslide(38 """\ +32 self,39     A mapping of +33 title:str="",40     [keys](https://textual.textualize.io/guide/input/#key) +34 bindings:Mapping[str,Callable[...,None]]|None=41     to callables to be executed when those keys are pressed, +35 transition:Type[Transition]|None=None,42     when on this slide. +36 )->Callable[[Content],Content]:43     """ +37 """44  +38         A decorator that creates a new slide in the deck,45 transition:Type[Transition]|None=Swipe +39         with the decorated function as the [`Slide.content`][46 """\ +40 47     The transition animation to use when moving to this slide +41         Args:48     Set to `None` to use the +42             title: The title to display for the slide.49     [`Deck.default_transition`][spiel.Deck.default_transition +43             bindings: A mapping of50     of the deck this slide is in. +44                 [keys](https://textual.textualize.io/guide/in51     """ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Spiel Demo Deck | Decks and Slides                                                                       2022-12-17 03:31 PM   [02 / 11] diff --git a/docs/assets/triggers_animation_1.svg b/docs/assets/triggers_animation_1.svg index 7b0d60c..5093be4 100644 --- a/docs/assets/triggers_animation_1.svg +++ b/docs/assets/triggers_animation_1.svg @@ -94,17 +94,17 @@ - + -spaces_before_bang=0 | spaces_after_bang=5 -╭────────╮ -!      -╰────────╯ - +triggers=Triggers(now=0, _times=(0,)) +spaces_before_bang=0 | spaces_after_bang=5 +╭────────╮ +!      +╰────────╯ diff --git a/docs/assets/triggers_animation_2.svg b/docs/assets/triggers_animation_2.svg index 792f8a7..f647562 100644 --- a/docs/assets/triggers_animation_2.svg +++ b/docs/assets/triggers_animation_2.svg @@ -94,17 +94,17 @@ - + -spaces_before_bang=1 | spaces_after_bang=4 -╭────────╮ - !     -╰────────╯ - +triggers=Triggers(now=1.5, _times=(0,)) +spaces_before_bang=1 | spaces_after_bang=4 +╭────────╮ + !     +╰────────╯ diff --git a/docs/assets/triggers_animation_3.svg b/docs/assets/triggers_animation_3.svg index 1e39cd7..59ef3bc 100644 --- a/docs/assets/triggers_animation_3.svg +++ b/docs/assets/triggers_animation_3.svg @@ -94,17 +94,17 @@ - + -spaces_before_bang=3 | spaces_after_bang=2 -╭────────╮ -   !   -╰────────╯ - +triggers=Triggers(now=2.5, _times=(0,)) +spaces_before_bang=2 | spaces_after_bang=3 +╭────────╮ +  !    +╰────────╯ diff --git a/docs/assets/triggers_animation_4.svg b/docs/assets/triggers_animation_4.svg index 176a730..b4c8fdf 100644 --- a/docs/assets/triggers_animation_4.svg +++ b/docs/assets/triggers_animation_4.svg @@ -94,17 +94,17 @@ - + -spaces_before_bang=5 | spaces_after_bang=0 -╭────────╮ -     ! -╰────────╯ - +triggers=Triggers(now=5.5, _times=(0,)) +spaces_before_bang=5 | spaces_after_bang=0 +╭────────╮ +     ! +╰────────╯ diff --git a/docs/changelog.md b/docs/changelog.md index e3cc6f5..3e50fa3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,10 @@ *Unreleased* +### Added + +- [#207](https://github.com/JoshKarpel/spiel/pull/207) Add a default "swipe" transition between slides and support for user-defined transitions. + ## `0.4.6` Released `2023-01-19` diff --git a/docs/contributing.md b/docs/contributing.md index 817ba12..cccb71f 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -28,10 +28,9 @@ To set up a local development environment after cloning the repository: ### Running Tests and Type-Checking -Use `pytest` to run tests. +Run `pytest` to run tests. -Types will automatically be checked as part of the test suite run; -`mypy` can also be run standalone. +Run `mypy` to check types. ### Building the Docs Locally diff --git a/docs/examples/triggers_animation.py b/docs/examples/triggers_animation.py index 7fa7fd0..95dea80 100644 --- a/docs/examples/triggers_animation.py +++ b/docs/examples/triggers_animation.py @@ -23,6 +23,7 @@ def animate(triggers: Triggers) -> RenderableType: return Align( Group( + Align.center(Text(f"{triggers=}")), Align.center(Text(f"{spaces_before_bang=} | {spaces_after_bang=}")), Align.center(Panel(Text(bar), expand=False, height=3)), ), diff --git a/docs/generate_screenshots.py b/docs/generate_screenshots.py index 96a40c2..80e0312 100755 --- a/docs/generate_screenshots.py +++ b/docs/generate_screenshots.py @@ -14,8 +14,9 @@ from rich.console import Console from textual.app import App from textual.pilot import Pilot -import spiel.constants from spiel.app import SpielApp +from spiel.constants import DEMO_FILE +from spiel.triggers import Triggers ROOT_DIR = Path(__file__).resolve().parent.parent ASSETS_DIR = ROOT_DIR / "docs" / "assets" @@ -52,14 +53,22 @@ async def auto_pilot(pilot: Pilot[object], name: str, keys: Iterable[str]) -> No await pilot.app.action_quit() -def take_screenshot(name: str, deck_file: Path, size: tuple[int, int], keys: Iterable[str]) -> str: +def take_screenshot( + name: str, + deck_file: Path, + size: tuple[int, int], + keys: Iterable[str], + triggers: Triggers, +) -> str: print(f"Generating {name}") SpielApp( deck_path=deck_file, watch_path=deck_file.parent, - show_messages=False, - fixed_time=datetime(year=2022, month=12, day=17, hour=15, minute=31, second=42), + _show_messages=False, + _fixed_time=datetime(year=2022, month=12, day=17, hour=15, minute=31, second=42), + _fixed_triggers=triggers, + _enable_transitions=False, ).run( headless=True, auto_pilot=partial(auto_pilot, name=name, keys=keys), @@ -72,13 +81,15 @@ def take_screenshot(name: str, deck_file: Path, size: tuple[int, int], keys: Ite if __name__ == "__main__": start_time = monotonic() - demo_deck = spiel.constants.DEMO_FILE + demo_deck = DEMO_FILE quickstart_deck = ROOT_DIR / "docs" / "examples" / "quickstart.py" slide_via_decorator = ROOT_DIR / "docs" / "examples" / "slide_via_decorator.py" slide_loop = ROOT_DIR / "docs" / "examples" / "slide_loop.py" triggers_reveal = ROOT_DIR / "docs" / "examples" / "triggers_reveal.py" triggers_animation = ROOT_DIR / "docs" / "examples" / "triggers_animation.py" + triggers = Triggers(now=0, _times=(0,)) + with ProcessPoolExecutor() as pool: futures = [ pool.submit( @@ -87,27 +98,31 @@ if __name__ == "__main__": deck_file=triggers_animation, size=(70, 15), keys=(), + triggers=Triggers(now=0, _times=(0,)), ), pool.submit( take_screenshot, name="triggers_animation_2", deck_file=triggers_animation, size=(70, 15), - keys=("wait:1450",), + keys=(), + triggers=Triggers(now=1.5, _times=(0,)), ), pool.submit( take_screenshot, name="triggers_animation_3", deck_file=triggers_animation, size=(70, 15), - keys=("wait:2950",), + keys=(), + triggers=Triggers(now=2.5, _times=(0,)), ), pool.submit( take_screenshot, name="triggers_animation_4", deck_file=triggers_animation, size=(70, 15), - keys=("wait:5450",), + keys=(), + triggers=Triggers(now=5.5, _times=(0,)), ), pool.submit( take_screenshot, @@ -115,6 +130,7 @@ if __name__ == "__main__": deck_file=demo_deck, size=(130, 35), keys=(), + triggers=triggers, ), pool.submit( take_screenshot, @@ -122,6 +138,7 @@ if __name__ == "__main__": deck_file=demo_deck, size=(135, 40), keys=("d", "right", "down"), + triggers=triggers, ), pool.submit( take_screenshot, @@ -129,6 +146,7 @@ if __name__ == "__main__": deck_file=demo_deck, size=(110, 35), keys=("?",), + triggers=triggers, ), pool.submit( take_screenshot, @@ -136,6 +154,7 @@ if __name__ == "__main__": deck_file=quickstart_deck, size=(70, 20), keys=(), + triggers=triggers, ), pool.submit( take_screenshot, @@ -143,6 +162,7 @@ if __name__ == "__main__": deck_file=demo_deck, size=(140, 45), keys=("right",), + triggers=triggers, ), pool.submit( take_screenshot, @@ -150,6 +170,7 @@ if __name__ == "__main__": deck_file=slide_via_decorator, size=(60, 15), keys=(), + triggers=triggers, ), pool.submit( take_screenshot, @@ -157,6 +178,7 @@ if __name__ == "__main__": deck_file=slide_loop, size=(60, 15), keys=(), + triggers=triggers, ), pool.submit( take_screenshot, @@ -164,6 +186,7 @@ if __name__ == "__main__": deck_file=slide_loop, size=(60, 15), keys=("right",), + triggers=triggers, ), pool.submit( take_screenshot, @@ -171,6 +194,7 @@ if __name__ == "__main__": deck_file=slide_loop, size=(60, 15), keys=("right", "right"), + triggers=triggers, ), pool.submit( take_screenshot, @@ -178,20 +202,23 @@ if __name__ == "__main__": deck_file=triggers_reveal, size=(70, 15), keys=(), + triggers=Triggers(now=0, _times=(0,)), ), pool.submit( take_screenshot, name="triggers_reveal_2", deck_file=triggers_reveal, size=(70, 15), - keys=("t",), + keys=(), + triggers=Triggers(now=1, _times=(0, 1)), ), pool.submit( take_screenshot, name="triggers_reveal_3", deck_file=triggers_reveal, size=(70, 15), - keys=("t", "t"), + keys=(), + triggers=Triggers(now=2, _times=(0, 1, 2)), ), ] diff --git a/docs/transitions.md b/docs/transitions.md new file mode 100644 index 0000000..0d81f01 --- /dev/null +++ b/docs/transitions.md @@ -0,0 +1,101 @@ +# Slide Transitions + +!!! warning "Under construction!" + + Transitions are a new and experiment feature in Spiel + and the interface might change dramatically from version to version. + If you plan on using transitions, we recommend pinning the + exact version of Spiel your presentation was developed in to ensure stability. + +## Setting Transitions + +To set the default transition for the entire deck, +which will be used if a slide does not override it, +set [`Deck.default_transition`][spiel.Deck.default_transition] to +a **type** that implements the [`Transition`][spiel.Transition] +protocol. + +For example, the default transition is [`Swipe`][spiel.Swipe], +so not passing `default_transition` at all is equivalent to + +```python +from spiel import Deck, Swipe + +deck = Deck(name=f"Spiel Demo Deck", default_transition=Swipe) +``` + +To override the deck-wide default for an individual slide, +specify the transition type in the [`@slide`][spiel.Deck.slide] decorator: + +```python +from spiel import Deck, Swipe + +deck = Deck(name=f"Spiel Demo Deck") + +@deck.slide(title="My Title", transition=Swipe) +def slide(): + ... +``` + +Or, in the arguments to [`Slide`][spiel.Slide]: + +```python +from spiel import Slide, Swipe + +slide = Slide(title="My Title", transition=Swipe) +``` + +In either case, the specified transition will be used when +transitioning **to** that slide. +It does not matter whether the slide is the "next" or "previous" +slide: the slide being moved to determines which transition +effect will be used. + +## Disabling Transitions + +In any of the above examples, you can also set `default_transition`/`transition` to `None`. +In that case, there will be no transition effect when moving to the slide; +it will just be displayed on the next render, already in-place. + +## Writing Custom Transitions + +To implement your own custom transition, you must write a class which implements +the [`Transition`][spiel.Transition] [protocol](https://docs.python.org/3/library/typing.html#typing.Protocol). + +The protocol is: + +```python title="Transition Protocol" +--8<-- "../spiel/transitions/protocol.py" +``` + +As an example, consider the [`Swipe`][spiel.Swipe] transition included in Spiel: + +```python title="Swipe Transition" +--8<-- "../spiel/transitions/swipe.py" +``` + +The transition effect is implemented using +[Textual CSS styles](https://textual.textualize.io/styles/) +on the [widgets](https://textual.textualize.io/guide/widgets/) +that represent the "from" and "to" widgets. + +Because the slide widgets are on [different layers](https://textual.textualize.io/styles/layers/), +they would normally both try to render in the "upper left corner" of the screen, +and since the `from` slide is on the upper layer, it would be the one that actually gets rendered. + +In `Swipe.initialize`, the `to` widget is moved to either the left or the right +(depending on the transition direction) by `100%`, i.e., it's own width. +This puts the slides side-by-side, with the `to` slide fully off-screen. + +As the transition progresses, the horizontal offsets of the two widgets are adjusted in lockstep +so that they appear to move across the screen. +Again, the direction of offset adjustment depends on the transition direction. +The absolute value of the horizontal offsets always sums to `100%`, which keeps the slides glued together +as they move across the screen. + +When `progress=100` in the final state, the `to` widget will be at zero horizontal offset, +and the `from` widget will be at plus or minus `100%`, fully moved off-screen. + +!!! tip "Contribute your transitions!" + + If you have developed a cool transition, consider [contributing it to Spiel](./contributing.md)! diff --git a/mkdocs.yml b/mkdocs.yml index 89cc45f..59d44cb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,6 +84,7 @@ nav: - quickstart.md - presenting.md - slides.md + - transitions.md - api.md - gallery.md - contributing.md diff --git a/poetry.lock b/poetry.lock index 7ecc0ab..3c4707a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,106 +2,106 @@ [[package]] name = "aiohttp" -version = "3.8.3" +version = "3.8.4" description = "Async http client/server framework (asyncio)" category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"}, - {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e"}, - {file = "aiohttp-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97decbb3372d4b69e4d4c8117f44632551c692bb1361b356a02b97b69e18a62"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309aa21c1d54b8ef0723181d430347d7452daaff93e8e2363db8e75c72c2fb2d"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad5383a67514e8e76906a06741febd9126fc7c7ff0f599d6fcce3e82b80d026f"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20acae4f268317bb975671e375493dbdbc67cddb5f6c71eebdb85b34444ac46b"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05a3c31c6d7cd08c149e50dc7aa2568317f5844acd745621983380597f027a18"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6f76310355e9fae637c3162936e9504b4767d5c52ca268331e2756e54fd4ca5"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:256deb4b29fe5e47893fa32e1de2d73c3afe7407738bd3c63829874661d4822d"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5c59fcd80b9049b49acd29bd3598cada4afc8d8d69bd4160cd613246912535d7"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:059a91e88f2c00fe40aed9031b3606c3f311414f86a90d696dd982e7aec48142"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2feebbb6074cdbd1ac276dbd737b40e890a1361b3cc30b74ac2f5e24aab41f7b"}, - {file = "aiohttp-3.8.3-cp310-cp310-win32.whl", hash = "sha256:5bf651afd22d5f0c4be16cf39d0482ea494f5c88f03e75e5fef3a85177fecdeb"}, - {file = "aiohttp-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:653acc3880459f82a65e27bd6526e47ddf19e643457d36a2250b85b41a564715"}, - {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:86fc24e58ecb32aee09f864cb11bb91bc4c1086615001647dbfc4dc8c32f4008"}, - {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75e14eac916f024305db517e00a9252714fce0abcb10ad327fb6dcdc0d060f1d"}, - {file = "aiohttp-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1fde0f44029e02d02d3993ad55ce93ead9bb9b15c6b7ccd580f90bd7e3de476"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab94426ddb1ecc6a0b601d832d5d9d421820989b8caa929114811369673235c"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89d2e02167fa95172c017732ed7725bc8523c598757f08d13c5acca308e1a061"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9a2c72fc95d59b881cf38a4b2be9381b9527f9d328771e90f72ac76f31ad8"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7149272fb5834fc186328e2c1fa01dda3e1fa940ce18fded6d412e8f2cf76d"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7018ecc5fe97027214556afbc7c502fbd718d0740e87eb1217b17efd05b3d276"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88c70ed9da9963d5496d38320160e8eb7e5f1886f9290475a881db12f351ab5d"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:da22885266bbfb3f78218dc40205fed2671909fbd0720aedba39b4515c038091"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:e65bc19919c910127c06759a63747ebe14f386cda573d95bcc62b427ca1afc73"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:08c78317e950e0762c2983f4dd58dc5e6c9ff75c8a0efeae299d363d439c8e34"}, - {file = "aiohttp-3.8.3-cp311-cp311-win32.whl", hash = "sha256:45d88b016c849d74ebc6f2b6e8bc17cabf26e7e40c0661ddd8fae4c00f015697"}, - {file = "aiohttp-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:96372fc29471646b9b106ee918c8eeb4cca423fcbf9a34daa1b93767a88a2290"}, - {file = "aiohttp-3.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c971bf3786b5fad82ce5ad570dc6ee420f5b12527157929e830f51c55dc8af77"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff25f48fc8e623d95eca0670b8cc1469a83783c924a602e0fbd47363bb54aaca"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e381581b37db1db7597b62a2e6b8b57c3deec95d93b6d6407c5b61ddc98aca6d"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db19d60d846283ee275d0416e2a23493f4e6b6028825b51290ac05afc87a6f97"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25892c92bee6d9449ffac82c2fe257f3a6f297792cdb18ad784737d61e7a9a85"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398701865e7a9565d49189f6c90868efaca21be65c725fc87fc305906be915da"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4a4fbc769ea9b6bd97f4ad0b430a6807f92f0e5eb020f1e42ece59f3ecfc4585"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b29bfd650ed8e148f9c515474a6ef0ba1090b7a8faeee26b74a8ff3b33617502"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e56b9cafcd6531bab5d9b2e890bb4937f4165109fe98e2b98ef0dcfcb06ee9d"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ec40170327d4a404b0d91855d41bfe1fe4b699222b2b93e3d833a27330a87a6d"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2df5f139233060578d8c2c975128fb231a89ca0a462b35d4b5fcf7c501ebdbe1"}, - {file = "aiohttp-3.8.3-cp36-cp36m-win32.whl", hash = "sha256:f973157ffeab5459eefe7b97a804987876dd0a55570b8fa56b4e1954bf11329b"}, - {file = "aiohttp-3.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:437399385f2abcd634865705bdc180c8314124b98299d54fe1d4c8990f2f9494"}, - {file = "aiohttp-3.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:09e28f572b21642128ef31f4e8372adb6888846f32fecb288c8b0457597ba61a"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f3553510abdbec67c043ca85727396ceed1272eef029b050677046d3387be8d"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e168a7560b7c61342ae0412997b069753f27ac4862ec7867eff74f0fe4ea2ad9"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db4c979b0b3e0fa7e9e69ecd11b2b3174c6963cebadeecfb7ad24532ffcdd11a"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e164e0a98e92d06da343d17d4e9c4da4654f4a4588a20d6c73548a29f176abe2"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8a78079d9a39ca9ca99a8b0ac2fdc0c4d25fc80c8a8a82e5c8211509c523363"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:21b30885a63c3f4ff5b77a5d6caf008b037cb521a5f33eab445dc566f6d092cc"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4b0f30372cef3fdc262f33d06e7b411cd59058ce9174ef159ad938c4a34a89da"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8135fa153a20d82ffb64f70a1b5c2738684afa197839b34cc3e3c72fa88d302c"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ad61a9639792fd790523ba072c0555cd6be5a0baf03a49a5dd8cfcf20d56df48"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978b046ca728073070e9abc074b6299ebf3501e8dee5e26efacb13cec2b2dea0"}, - {file = "aiohttp-3.8.3-cp37-cp37m-win32.whl", hash = "sha256:0d2c6d8c6872df4a6ec37d2ede71eff62395b9e337b4e18efd2177de883a5033"}, - {file = "aiohttp-3.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:21d69797eb951f155026651f7e9362877334508d39c2fc37bd04ff55b2007091"}, - {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ca9af5f8f5812d475c5259393f52d712f6d5f0d7fdad9acdb1107dd9e3cb7eb"}, - {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d90043c1882067f1bd26196d5d2db9aa6d268def3293ed5fb317e13c9413ea4"}, - {file = "aiohttp-3.8.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d737fc67b9a970f3234754974531dc9afeea11c70791dcb7db53b0cf81b79784"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf909ea0a3fc9596e40d55d8000702a85e27fd578ff41a5500f68f20fd32e6c"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5835f258ca9f7c455493a57ee707b76d2d9634d84d5d7f62e77be984ea80b849"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da37dcfbf4b7f45d80ee386a5f81122501ec75672f475da34784196690762f4b"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f44875f2804bc0511a69ce44a9595d5944837a62caecc8490bbdb0e18b1342"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:527b3b87b24844ea7865284aabfab08eb0faf599b385b03c2aa91fc6edd6e4b6"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5ba88df9aa5e2f806650fcbeedbe4f6e8736e92fc0e73b0400538fd25a4dd96"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e7b8813be97cab8cb52b1375f41f8e6804f6507fe4660152e8ca5c48f0436017"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2dea10edfa1a54098703cb7acaa665c07b4e7568472a47f4e64e6319d3821ccf"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:713d22cd9643ba9025d33c4af43943c7a1eb8547729228de18d3e02e278472b6"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2d252771fc85e0cf8da0b823157962d70639e63cb9b578b1dec9868dd1f4f937"}, - {file = "aiohttp-3.8.3-cp38-cp38-win32.whl", hash = "sha256:66bd5f950344fb2b3dbdd421aaa4e84f4411a1a13fca3aeb2bcbe667f80c9f76"}, - {file = "aiohttp-3.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:84b14f36e85295fe69c6b9789b51a0903b774046d5f7df538176516c3e422446"}, - {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16c121ba0b1ec2b44b73e3a8a171c4f999b33929cd2397124a8c7fcfc8cd9e06"}, - {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d6aaa4e7155afaf994d7924eb290abbe81a6905b303d8cb61310a2aba1c68ba"}, - {file = "aiohttp-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43046a319664a04b146f81b40e1545d4c8ac7b7dd04c47e40bf09f65f2437346"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599418aaaf88a6d02a8c515e656f6faf3d10618d3dd95866eb4436520096c84b"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a2964319d359f494f16011e23434f6f8ef0434acd3cf154a6b7bec511e2fb7"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73a4131962e6d91109bca6536416aa067cf6c4efb871975df734f8d2fd821b37"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598adde339d2cf7d67beaccda3f2ce7c57b3b412702f29c946708f69cf8222aa"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75880ed07be39beff1881d81e4a907cafb802f306efd6d2d15f2b3c69935f6fb"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0239da9fbafd9ff82fd67c16704a7d1bccf0d107a300e790587ad05547681c8"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4e3a23ec214e95c9fe85a58470b660efe6534b83e6cbe38b3ed52b053d7cb6ad"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:47841407cc89a4b80b0c52276f3cc8138bbbfba4b179ee3acbd7d77ae33f7ac4"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:54d107c89a3ebcd13228278d68f1436d3f33f2dd2af5415e3feaeb1156e1a62c"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c37c5cce780349d4d51739ae682dec63573847a2a8dcb44381b174c3d9c8d403"}, - {file = "aiohttp-3.8.3-cp39-cp39-win32.whl", hash = "sha256:f178d2aadf0166be4df834c4953da2d7eef24719e8aec9a65289483eeea9d618"}, - {file = "aiohttp-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7"}, - {file = "aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"}, + {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ce45967538fb747370308d3145aa68a074bdecb4f3a300869590f725ced69c1"}, + {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b744c33b6f14ca26b7544e8d8aadff6b765a80ad6164fb1a430bbadd593dfb1a"}, + {file = "aiohttp-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a45865451439eb320784918617ba54b7a377e3501fb70402ab84d38c2cd891b"}, + {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86d42d7cba1cec432d47ab13b6637bee393a10f664c425ea7b305d1301ca1a3"}, + {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee3c36df21b5714d49fc4580247947aa64bcbe2939d1b77b4c8dcb8f6c9faecc"}, + {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:176a64b24c0935869d5bbc4c96e82f89f643bcdf08ec947701b9dbb3c956b7dd"}, + {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c844fd628851c0bc309f3c801b3a3d58ce430b2ce5b359cd918a5a76d0b20cb5"}, + {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5393fb786a9e23e4799fec788e7e735de18052f83682ce2dfcabaf1c00c2c08e"}, + {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e4b09863aae0dc965c3ef36500d891a3ff495a2ea9ae9171e4519963c12ceefd"}, + {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:adfbc22e87365a6e564c804c58fc44ff7727deea782d175c33602737b7feadb6"}, + {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:147ae376f14b55f4f3c2b118b95be50a369b89b38a971e80a17c3fd623f280c9"}, + {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:eafb3e874816ebe2a92f5e155f17260034c8c341dad1df25672fb710627c6949"}, + {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6cc15d58053c76eacac5fa9152d7d84b8d67b3fde92709195cb984cfb3475ea"}, + {file = "aiohttp-3.8.4-cp310-cp310-win32.whl", hash = "sha256:59f029a5f6e2d679296db7bee982bb3d20c088e52a2977e3175faf31d6fb75d1"}, + {file = "aiohttp-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:fe7ba4a51f33ab275515f66b0a236bcde4fb5561498fe8f898d4e549b2e4509f"}, + {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d8ef1a630519a26d6760bc695842579cb09e373c5f227a21b67dc3eb16cfea4"}, + {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b3f2e06a512e94722886c0827bee9807c86a9f698fac6b3aee841fab49bbfb4"}, + {file = "aiohttp-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a80464982d41b1fbfe3154e440ba4904b71c1a53e9cd584098cd41efdb188ef"}, + {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b631e26df63e52f7cce0cce6507b7a7f1bc9b0c501fcde69742130b32e8782f"}, + {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f43255086fe25e36fd5ed8f2ee47477408a73ef00e804cb2b5cba4bf2ac7f5e"}, + {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d347a172f866cd1d93126d9b239fcbe682acb39b48ee0873c73c933dd23bd0f"}, + {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3fec6a4cb5551721cdd70473eb009d90935b4063acc5f40905d40ecfea23e05"}, + {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80a37fe8f7c1e6ce8f2d9c411676e4bc633a8462844e38f46156d07a7d401654"}, + {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d1e6a862b76f34395a985b3cd39a0d949ca80a70b6ebdea37d3ab39ceea6698a"}, + {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd468460eefef601ece4428d3cf4562459157c0f6523db89365202c31b6daebb"}, + {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:618c901dd3aad4ace71dfa0f5e82e88b46ef57e3239fc7027773cb6d4ed53531"}, + {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:652b1bff4f15f6287550b4670546a2947f2a4575b6c6dff7760eafb22eacbf0b"}, + {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80575ba9377c5171407a06d0196b2310b679dc752d02a1fcaa2bc20b235dbf24"}, + {file = "aiohttp-3.8.4-cp311-cp311-win32.whl", hash = "sha256:bbcf1a76cf6f6dacf2c7f4d2ebd411438c275faa1dc0c68e46eb84eebd05dd7d"}, + {file = "aiohttp-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:6e74dd54f7239fcffe07913ff8b964e28b712f09846e20de78676ce2a3dc0bfc"}, + {file = "aiohttp-3.8.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:880e15bb6dad90549b43f796b391cfffd7af373f4646784795e20d92606b7a51"}, + {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb96fa6b56bb536c42d6a4a87dfca570ff8e52de2d63cabebfd6fb67049c34b6"}, + {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a6cadebe132e90cefa77e45f2d2f1a4b2ce5c6b1bfc1656c1ddafcfe4ba8131"}, + {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f352b62b45dff37b55ddd7b9c0c8672c4dd2eb9c0f9c11d395075a84e2c40f75"}, + {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ab43061a0c81198d88f39aaf90dae9a7744620978f7ef3e3708339b8ed2ef01"}, + {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9cb1565a7ad52e096a6988e2ee0397f72fe056dadf75d17fa6b5aebaea05622"}, + {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:1b3ea7edd2d24538959c1c1abf97c744d879d4e541d38305f9bd7d9b10c9ec41"}, + {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7c7837fe8037e96b6dd5cfcf47263c1620a9d332a87ec06a6ca4564e56bd0f36"}, + {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3b90467ebc3d9fa5b0f9b6489dfb2c304a1db7b9946fa92aa76a831b9d587e99"}, + {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:cab9401de3ea52b4b4c6971db5fb5c999bd4260898af972bf23de1c6b5dd9d71"}, + {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d1f9282c5f2b5e241034a009779e7b2a1aa045f667ff521e7948ea9b56e0c5ff"}, + {file = "aiohttp-3.8.4-cp36-cp36m-win32.whl", hash = "sha256:5e14f25765a578a0a634d5f0cd1e2c3f53964553a00347998dfdf96b8137f777"}, + {file = "aiohttp-3.8.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4c745b109057e7e5f1848c689ee4fb3a016c8d4d92da52b312f8a509f83aa05e"}, + {file = "aiohttp-3.8.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:aede4df4eeb926c8fa70de46c340a1bc2c6079e1c40ccf7b0eae1313ffd33519"}, + {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ddaae3f3d32fc2cb4c53fab020b69a05c8ab1f02e0e59665c6f7a0d3a5be54f"}, + {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4eb3b82ca349cf6fadcdc7abcc8b3a50ab74a62e9113ab7a8ebc268aad35bb9"}, + {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bcb89336efa095ea21b30f9e686763f2be4478f1b0a616969551982c4ee4c3b"}, + {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c08e8ed6fa3d477e501ec9db169bfac8140e830aa372d77e4a43084d8dd91ab"}, + {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6cd05ea06daca6ad6a4ca3ba7fe7dc5b5de063ff4daec6170ec0f9979f6c332"}, + {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7a00a9ed8d6e725b55ef98b1b35c88013245f35f68b1b12c5cd4100dddac333"}, + {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:de04b491d0e5007ee1b63a309956eaed959a49f5bb4e84b26c8f5d49de140fa9"}, + {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:40653609b3bf50611356e6b6554e3a331f6879fa7116f3959b20e3528783e699"}, + {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dbf3a08a06b3f433013c143ebd72c15cac33d2914b8ea4bea7ac2c23578815d6"}, + {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854f422ac44af92bfe172d8e73229c270dc09b96535e8a548f99c84f82dde241"}, + {file = "aiohttp-3.8.4-cp37-cp37m-win32.whl", hash = "sha256:aeb29c84bb53a84b1a81c6c09d24cf33bb8432cc5c39979021cc0f98c1292a1a"}, + {file = "aiohttp-3.8.4-cp37-cp37m-win_amd64.whl", hash = "sha256:db3fc6120bce9f446d13b1b834ea5b15341ca9ff3f335e4a951a6ead31105480"}, + {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fabb87dd8850ef0f7fe2b366d44b77d7e6fa2ea87861ab3844da99291e81e60f"}, + {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91f6d540163f90bbaef9387e65f18f73ffd7c79f5225ac3d3f61df7b0d01ad15"}, + {file = "aiohttp-3.8.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d265f09a75a79a788237d7f9054f929ced2e69eb0bb79de3798c468d8a90f945"}, + {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d89efa095ca7d442a6d0cbc755f9e08190ba40069b235c9886a8763b03785da"}, + {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dac314662f4e2aa5009977b652d9b8db7121b46c38f2073bfeed9f4049732cd"}, + {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe11310ae1e4cd560035598c3f29d86cef39a83d244c7466f95c27ae04850f10"}, + {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ddb2a2026c3f6a68c3998a6c47ab6795e4127315d2e35a09997da21865757f8"}, + {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e75b89ac3bd27d2d043b234aa7b734c38ba1b0e43f07787130a0ecac1e12228a"}, + {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6e601588f2b502c93c30cd5a45bfc665faaf37bbe835b7cfd461753068232074"}, + {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a5d794d1ae64e7753e405ba58e08fcfa73e3fad93ef9b7e31112ef3c9a0efb52"}, + {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a1f4689c9a1462f3df0a1f7e797791cd6b124ddbee2b570d34e7f38ade0e2c71"}, + {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3032dcb1c35bc330134a5b8a5d4f68c1a87252dfc6e1262c65a7e30e62298275"}, + {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8189c56eb0ddbb95bfadb8f60ea1b22fcfa659396ea36f6adcc521213cd7b44d"}, + {file = "aiohttp-3.8.4-cp38-cp38-win32.whl", hash = "sha256:33587f26dcee66efb2fff3c177547bd0449ab7edf1b73a7f5dea1e38609a0c54"}, + {file = "aiohttp-3.8.4-cp38-cp38-win_amd64.whl", hash = "sha256:e595432ac259af2d4630008bf638873d69346372d38255774c0e286951e8b79f"}, + {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a7bdf9e57126dc345b683c3632e8ba317c31d2a41acd5800c10640387d193ed"}, + {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:22f6eab15b6db242499a16de87939a342f5a950ad0abaf1532038e2ce7d31567"}, + {file = "aiohttp-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7235604476a76ef249bd64cb8274ed24ccf6995c4a8b51a237005ee7a57e8643"}, + {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea9eb976ffdd79d0e893869cfe179a8f60f152d42cb64622fca418cd9b18dc2a"}, + {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92c0cea74a2a81c4c76b62ea1cac163ecb20fb3ba3a75c909b9fa71b4ad493cf"}, + {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493f5bc2f8307286b7799c6d899d388bbaa7dfa6c4caf4f97ef7521b9cb13719"}, + {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a63f03189a6fa7c900226e3ef5ba4d3bd047e18f445e69adbd65af433add5a2"}, + {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10c8cefcff98fd9168cdd86c4da8b84baaa90bf2da2269c6161984e6737bf23e"}, + {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bca5f24726e2919de94f047739d0a4fc01372801a3672708260546aa2601bf57"}, + {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03baa76b730e4e15a45f81dfe29a8d910314143414e528737f8589ec60cf7391"}, + {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8c29c77cc57e40f84acef9bfb904373a4e89a4e8b74e71aa8075c021ec9078c2"}, + {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:03543dcf98a6619254b409be2d22b51f21ec66272be4ebda7b04e6412e4b2e14"}, + {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17b79c2963db82086229012cff93ea55196ed31f6493bb1ccd2c62f1724324e4"}, + {file = "aiohttp-3.8.4-cp39-cp39-win32.whl", hash = "sha256:34ce9f93a4a68d1272d26030655dd1b58ff727b3ed2a33d80ec433561b03d67a"}, + {file = "aiohttp-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:41a86a69bb63bb2fc3dc9ad5ea9f10f1c9c8e282b471931be0268ddd09430b04"}, + {file = "aiohttp-3.8.4.tar.gz", hash = "sha256:bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"}, ] [package.dependencies] aiosignal = ">=1.1.2" async-timeout = ">=4.0.0a3,<5.0" attrs = ">=17.3.0" -charset-normalizer = ">=2.0,<3.0" +charset-normalizer = ">=2.0,<4.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" yarl = ">=1.0,<2.0" @@ -202,19 +202,102 @@ files = [ [[package]] name = "charset-normalizer" -version = "2.1.1" +version = "3.0.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "dev" optional = false -python-versions = ">=3.6.0" +python-versions = "*" files = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, + {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, + {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, ] -[package.extras] -unicode-backport = ["unicodedata2"] - [[package]] name = "click" version = "8.1.3" @@ -244,63 +327,63 @@ files = [ [[package]] name = "coverage" -version = "7.0.5" +version = "7.1.0" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a7f23bbaeb2a87f90f607730b45564076d870f1fb07b9318d0c21f36871932b"}, - {file = "coverage-7.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c18d47f314b950dbf24a41787ced1474e01ca816011925976d90a88b27c22b89"}, - {file = "coverage-7.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef14d75d86f104f03dea66c13188487151760ef25dd6b2dbd541885185f05f40"}, - {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66e50680e888840c0995f2ad766e726ce71ca682e3c5f4eee82272c7671d38a2"}, - {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289"}, - {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d8d04e755934195bdc1db45ba9e040b8d20d046d04d6d77e71b3b34a8cc002d0"}, - {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e109f1c9a3ece676597831874126555997c48f62bddbcace6ed17be3e372de8"}, - {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a1890fca2962c4f1ad16551d660b46ea77291fba2cc21c024cd527b9d9c8809"}, - {file = "coverage-7.0.5-cp310-cp310-win32.whl", hash = "sha256:be9fcf32c010da0ba40bf4ee01889d6c737658f4ddff160bd7eb9cac8f094b21"}, - {file = "coverage-7.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:cbfcba14a3225b055a28b3199c3d81cd0ab37d2353ffd7f6fd64844cebab31ad"}, - {file = "coverage-7.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30b5fec1d34cc932c1bc04017b538ce16bf84e239378b8f75220478645d11fca"}, - {file = "coverage-7.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1caed2367b32cc80a2b7f58a9f46658218a19c6cfe5bc234021966dc3daa01f0"}, - {file = "coverage-7.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d254666d29540a72d17cc0175746cfb03d5123db33e67d1020e42dae611dc196"}, - {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19245c249aa711d954623d94f23cc94c0fd65865661f20b7781210cb97c471c0"}, - {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b05ed4b35bf6ee790832f68932baf1f00caa32283d66cc4d455c9e9d115aafc"}, - {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:29de916ba1099ba2aab76aca101580006adfac5646de9b7c010a0f13867cba45"}, - {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e057e74e53db78122a3979f908973e171909a58ac20df05c33998d52e6d35757"}, - {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"}, - {file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"}, - {file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"}, - {file = "coverage-7.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b69522b168a6b64edf0c33ba53eac491c0a8f5cc94fa4337f9c6f4c8f2f5296c"}, - {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436e103950d05b7d7f55e39beeb4d5be298ca3e119e0589c0227e6d0b01ee8c7"}, - {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c56bec53d6e3154eaff6ea941226e7bd7cc0d99f9b3756c2520fc7a94e6d96"}, - {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a38362528a9115a4e276e65eeabf67dcfaf57698e17ae388599568a78dcb029"}, - {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f67472c09a0c7486e27f3275f617c964d25e35727af952869dd496b9b5b7f6a3"}, - {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:220e3fa77d14c8a507b2d951e463b57a1f7810a6443a26f9b7591ef39047b1b2"}, - {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecb0f73954892f98611e183f50acdc9e21a4653f294dfbe079da73c6378a6f47"}, - {file = "coverage-7.0.5-cp37-cp37m-win32.whl", hash = "sha256:d8f3e2e0a1d6777e58e834fd5a04657f66affa615dae61dd67c35d1568c38882"}, - {file = "coverage-7.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9e662e6fc4f513b79da5d10a23edd2b87685815b337b1a30cd11307a6679148d"}, - {file = "coverage-7.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:790e4433962c9f454e213b21b0fd4b42310ade9c077e8edcb5113db0818450cb"}, - {file = "coverage-7.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49640bda9bda35b057b0e65b7c43ba706fa2335c9a9896652aebe0fa399e80e6"}, - {file = "coverage-7.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d66187792bfe56f8c18ba986a0e4ae44856b1c645336bd2c776e3386da91e1dd"}, - {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:276f4cd0001cd83b00817c8db76730938b1ee40f4993b6a905f40a7278103b3a"}, - {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95304068686545aa368b35dfda1cdfbbdbe2f6fe43de4a2e9baa8ebd71be46e2"}, - {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:17e01dd8666c445025c29684d4aabf5a90dc6ef1ab25328aa52bedaa95b65ad7"}, - {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea76dbcad0b7b0deb265d8c36e0801abcddf6cc1395940a24e3595288b405ca0"}, - {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:50a6adc2be8edd7ee67d1abc3cd20678987c7b9d79cd265de55941e3d0d56499"}, - {file = "coverage-7.0.5-cp38-cp38-win32.whl", hash = "sha256:e4ce984133b888cc3a46867c8b4372c7dee9cee300335e2925e197bcd45b9e16"}, - {file = "coverage-7.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4a950f83fd3f9bca23b77442f3a2b2ea4ac900944d8af9993743774c4fdc57af"}, - {file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"}, - {file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"}, - {file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"}, - {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b78729038abea6a5df0d2708dce21e82073463b2d79d10884d7d591e0f385ded"}, - {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b"}, - {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c407b1950b2d2ffa091f4e225ca19a66a9bd81222f27c56bd12658fc5ca1209"}, - {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c76a3075e96b9c9ff00df8b5f7f560f5634dffd1658bafb79eb2682867e94f78"}, - {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f26648e1b3b03b6022b48a9b910d0ae209e2d51f50441db5dce5b530fad6d9b1"}, - {file = "coverage-7.0.5-cp39-cp39-win32.whl", hash = "sha256:ba3027deb7abf02859aca49c865ece538aee56dcb4871b4cced23ba4d5088904"}, - {file = "coverage-7.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:949844af60ee96a376aac1ded2a27e134b8c8d35cc006a52903fc06c24a3296f"}, - {file = "coverage-7.0.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:b9727ac4f5cf2cbf87880a63870b5b9730a8ae3a4a360241a0fdaa2f71240ff0"}, - {file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"}, + {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"}, + {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"}, + {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"}, + {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"}, + {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"}, + {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"}, + {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"}, + {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"}, + {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"}, + {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"}, + {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"}, + {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"}, + {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"}, + {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"}, + {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"}, + {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"}, + {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"}, + {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"}, + {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"}, + {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"}, + {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"}, + {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"}, + {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"}, + {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"}, + {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"}, + {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"}, + {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"}, + {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"}, + {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"}, + {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"}, + {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"}, ] [package.dependencies] @@ -455,7 +538,7 @@ files = [ name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." -category = "dev" +category = "main" optional = false python-versions = "*" files = [ @@ -471,14 +554,14 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "griffe" -version = "0.25.4" +version = "0.25.5" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "griffe-0.25.4-py3-none-any.whl", hash = "sha256:919f935a358b31074d16e324e26b041883c60a8cf10504655e394afc3a7caad8"}, - {file = "griffe-0.25.4.tar.gz", hash = "sha256:f190edf8ef58d43c856d2d6761ec324a043ff60deb8c14359263571e8b91fe68"}, + {file = "griffe-0.25.5-py3-none-any.whl", hash = "sha256:1fb9edff48e66d4873014a2ebf21aca5f271d0006a4c937826e3cf592ffb3706"}, + {file = "griffe-0.25.5.tar.gz", hash = "sha256:11ea3403ef0560a1cbcf7f302eb5d21cf4c1d8ed3f8a16a75aa9f6f458caf3f1"}, ] [package.dependencies] @@ -489,14 +572,14 @@ async = ["aiofiles (>=0.7,<1.0)"] [[package]] name = "hypothesis" -version = "6.62.1" +version = "6.68.2" description = "A library for property-based testing" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "hypothesis-6.62.1-py3-none-any.whl", hash = "sha256:d00a4a9c54b0b8b4570fe1abe42395807a973b4a507e6718309800e6f84e160d"}, - {file = "hypothesis-6.62.1.tar.gz", hash = "sha256:7d1e2f9871e6509662da317adf9b4aabd6b38280fb6c7930aa4f574d2ed25150"}, + {file = "hypothesis-6.68.2-py3-none-any.whl", hash = "sha256:2a41cc766cde52705895e54547374af89c617e8ec7bc4186cb7f03884a667d4e"}, + {file = "hypothesis-6.68.2.tar.gz", hash = "sha256:a7eb2b0c9a18560d8197fe35047ceb58e7e8ab7623a3e5a82613f6a2cd71cffa"}, ] [package.dependencies] @@ -522,14 +605,14 @@ zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2022.7)"] [[package]] name = "identify" -version = "2.5.13" +version = "2.5.18" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.13-py2.py3-none-any.whl", hash = "sha256:8aa48ce56e38c28b6faa9f261075dea0a942dfbb42b341b4e711896cbb40f3f7"}, - {file = "identify-2.5.13.tar.gz", hash = "sha256:abb546bca6f470228785338a01b539de8a85bbf46491250ae03363956d8ebb10"}, + {file = "identify-2.5.18-py2.py3-none-any.whl", hash = "sha256:93aac7ecf2f6abf879b8f29a8002d3c6de7086b8c28d88e1ad15045a15ab63f9"}, + {file = "identify-2.5.18.tar.gz", hash = "sha256:89e144fa560cc4cffb6ef2ab5e9fb18ed9f9b3cb054384bab4b95c12f6c309fe"}, ] [package.extras] @@ -583,7 +666,7 @@ files = [ name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -597,11 +680,32 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "linkify-it-py" +version = "1.0.3" +description = "Links recognition library with FULL unicode support." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "linkify-it-py-1.0.3.tar.gz", hash = "sha256:2b3f168d5ce75e3a425e34b341a6b73e116b5d9ed8dbbbf5dc7456843b7ce2ee"}, + {file = "linkify_it_py-1.0.3-py3-none-any.whl", hash = "sha256:11e29f00150cddaa8f434153f103c14716e7e097a8fd372d9eb1ed06ed91524d"}, +] + +[package.dependencies] +uc-micro-py = "*" + +[package.extras] +benchmark = ["pytest", "pytest-benchmark"] +dev = ["black", "flake8", "isort", "pre-commit"] +doc = ["myst-parser", "sphinx", "sphinx-book-theme"] +test = ["coverage", "pytest", "pytest-cov"] + [[package]] name = "markdown" version = "3.3.7" description = "Python implementation of Markdown." -category = "dev" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -625,6 +729,8 @@ files = [ ] [package.dependencies] +linkify-it-py = {version = ">=1.0,<2.0", optional = true, markers = "extra == \"linkify\""} +mdit-py-plugins = {version = "*", optional = true, markers = "extra == \"plugins\""} mdurl = ">=0.1,<1.0" [package.extras] @@ -641,7 +747,7 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -697,6 +803,26 @@ files = [ {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, ] +[[package]] +name = "mdit-py-plugins" +version = "0.3.4" +description = "Collection of plugins for markdown-it-py" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdit-py-plugins-0.3.4.tar.gz", hash = "sha256:3278aab2e2b692539082f05e1243f24742194ffd92481f48844f057b51971283"}, + {file = "mdit_py_plugins-0.3.4-py3-none-any.whl", hash = "sha256:4f1441264ac5cb39fa40a5901921c2acf314ea098d75629750c138f80d552cdf"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<3.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["attrs", "myst-parser (>=0.16.1,<0.17.0)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "mdurl" version = "0.1.2" @@ -713,7 +839,7 @@ files = [ name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." -category = "dev" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -725,7 +851,7 @@ files = [ name = "mkdocs" version = "1.4.2" description = "Project documentation with Markdown." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -765,16 +891,30 @@ files = [ Markdown = ">=3.3" mkdocs = ">=1.1" +[[package]] +name = "mkdocs-exclude" +version = "1.0.2" +description = "A mkdocs plugin that lets you exclude files or trees." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "mkdocs-exclude-1.0.2.tar.gz", hash = "sha256:ba6fab3c80ddbe3fd31d3e579861fd3124513708271180a5f81846da8c7e2a51"}, +] + +[package.dependencies] +mkdocs = "*" + [[package]] name = "mkdocs-material" -version = "9.0.6" +version = "9.0.13" description = "Documentation that simply works" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_material-9.0.6-py3-none-any.whl", hash = "sha256:4a71195ddc100dddf07d4b23b53373f36c5f0f1010fa4ea301ca7a8e949dd9e7"}, - {file = "mkdocs_material-9.0.6.tar.gz", hash = "sha256:6065b573e38746dc267d7fc84252be31b73da955b2ce553687806b6030e51ee0"}, + {file = "mkdocs_material-9.0.13-py3-none-any.whl", hash = "sha256:06e51eba6a090de070a3489890cf1e491d52c04c6ff2b06dd4586c6cdd974a3f"}, + {file = "mkdocs_material-9.0.13.tar.gz", hash = "sha256:a62696610899d01df091b4d5ad23f9811f878a1f34307d7cea677baf4854c84f"}, ] [package.dependencies] @@ -1002,42 +1142,38 @@ files = [ [[package]] name = "mypy" -version = "0.991" +version = "1.0.1" description = "Optional static typing for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, - {file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, - {file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, - {file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"}, - {file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"}, - {file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"}, - {file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"}, - {file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"}, - {file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"}, - {file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"}, - {file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"}, - {file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"}, - {file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"}, - {file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"}, - {file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"}, - {file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"}, - {file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"}, - {file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"}, - {file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"}, - {file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"}, - {file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"}, - {file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"}, - {file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"}, - {file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"}, - {file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"}, - {file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"}, - {file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"}, - {file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"}, - {file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"}, - {file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"}, + {file = "mypy-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:71a808334d3f41ef011faa5a5cd8153606df5fc0b56de5b2e89566c8093a0c9a"}, + {file = "mypy-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:920169f0184215eef19294fa86ea49ffd4635dedfdea2b57e45cb4ee85d5ccaf"}, + {file = "mypy-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a0f74a298769d9fdc8498fcb4f2beb86f0564bcdb1a37b58cbbe78e55cf8c0"}, + {file = "mypy-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:65b122a993d9c81ea0bfde7689b3365318a88bde952e4dfa1b3a8b4ac05d168b"}, + {file = "mypy-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:5deb252fd42a77add936b463033a59b8e48eb2eaec2976d76b6878d031933fe4"}, + {file = "mypy-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2013226d17f20468f34feddd6aae4635a55f79626549099354ce641bc7d40262"}, + {file = "mypy-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:48525aec92b47baed9b3380371ab8ab6e63a5aab317347dfe9e55e02aaad22e8"}, + {file = "mypy-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c96b8a0c019fe29040d520d9257d8c8f122a7343a8307bf8d6d4a43f5c5bfcc8"}, + {file = "mypy-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:448de661536d270ce04f2d7dddaa49b2fdba6e3bd8a83212164d4174ff43aa65"}, + {file = "mypy-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d42a98e76070a365a1d1c220fcac8aa4ada12ae0db679cb4d910fabefc88b994"}, + {file = "mypy-1.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e64f48c6176e243ad015e995de05af7f22bbe370dbb5b32bd6988438ec873919"}, + {file = "mypy-1.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fdd63e4f50e3538617887e9aee91855368d9fc1dea30da743837b0df7373bc4"}, + {file = "mypy-1.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dbeb24514c4acbc78d205f85dd0e800f34062efcc1f4a4857c57e4b4b8712bff"}, + {file = "mypy-1.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a2948c40a7dd46c1c33765718936669dc1f628f134013b02ff5ac6c7ef6942bf"}, + {file = "mypy-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bc8d6bd3b274dd3846597855d96d38d947aedba18776aa998a8d46fabdaed76"}, + {file = "mypy-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:17455cda53eeee0a4adb6371a21dd3dbf465897de82843751cf822605d152c8c"}, + {file = "mypy-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e831662208055b006eef68392a768ff83596035ffd6d846786578ba1714ba8f6"}, + {file = "mypy-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e60d0b09f62ae97a94605c3f73fd952395286cf3e3b9e7b97f60b01ddfbbda88"}, + {file = "mypy-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:0af4f0e20706aadf4e6f8f8dc5ab739089146b83fd53cb4a7e0e850ef3de0bb6"}, + {file = "mypy-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:24189f23dc66f83b839bd1cce2dfc356020dfc9a8bae03978477b15be61b062e"}, + {file = "mypy-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93a85495fb13dc484251b4c1fd7a5ac370cd0d812bbfc3b39c1bafefe95275d5"}, + {file = "mypy-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f546ac34093c6ce33f6278f7c88f0f147a4849386d3bf3ae193702f4fe31407"}, + {file = "mypy-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c6c2ccb7af7154673c591189c3687b013122c5a891bb5651eca3db8e6c6c55bd"}, + {file = "mypy-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:15b5a824b58c7c822c51bc66308e759243c32631896743f030daf449fe3677f3"}, + {file = "mypy-1.0.1-py3-none-any.whl", hash = "sha256:eda5c8b9949ed411ff752b9a01adda31afe7eae1e53e946dbdf9db23865e66c4"}, + {file = "mypy-1.0.1.tar.gz", hash = "sha256:28cea5a6392bb43d266782983b5a4216c25544cd7d80be681a155ddcdafd152d"}, ] [package.dependencies] @@ -1053,26 +1189,14 @@ reports = ["lxml"] [[package]] name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." category = "dev" optional = false -python-versions = "*" -files = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] - -[[package]] -name = "nanoid" -version = "2.0.0" -description = "A tiny, secure, URL-friendly, unique string ID generator for Python" -category = "main" -optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "nanoid-2.0.0-py3-none-any.whl", hash = "sha256:90aefa650e328cffb0893bbd4c236cfd44c48bc1f2d0b525ecc53c3187b653bb"}, - {file = "nanoid-2.0.0.tar.gz", hash = "sha256:5a80cad5e9c6e9ae3a41fa2fb34ae189f7cb420b2a5d8f82bd9d23466e4efa68"}, + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] @@ -1094,7 +1218,7 @@ setuptools = "*" name = "packaging" version = "23.0" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1110,6 +1234,20 @@ category = "main" optional = false python-versions = ">=3.7" files = [ + {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, + {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, + {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, + {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, + {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, + {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, + {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, + {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, + {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, + {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, + {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, + {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, + {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, + {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, @@ -1181,19 +1319,19 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "2.6.2" +version = "3.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, - {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, + {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, + {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -1213,14 +1351,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.21.0" +version = "3.0.4" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, - {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, + {file = "pre_commit-3.0.4-py2.py3-none-any.whl", hash = "sha256:9e3255edb0c9e7fe9b4f328cb3dc86069f8fdc38026f1bf521018a05eaf4d67b"}, + {file = "pre_commit-3.0.4.tar.gz", hash = "sha256:bc4687478d55578c4ac37272fe96df66f73d9b5cf81be6f28627d4e712e752d5"}, ] [package.dependencies] @@ -1247,14 +1385,14 @@ plugins = ["importlib-metadata"] [[package]] name = "pymdown-extensions" -version = "9.9.1" +version = "9.9.2" description = "Extension pack for Python Markdown." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pymdown_extensions-9.9.1-py3-none-any.whl", hash = "sha256:8a8973933ab45b6fe8f5f8da1de25766356b1f91dee107bf4a34efd158dc340b"}, - {file = "pymdown_extensions-9.9.1.tar.gz", hash = "sha256:abed29926960bbb3b40f5ed5fa6375e29724d4e3cb86ced7c2bbd37ead1afeea"}, + {file = "pymdown_extensions-9.9.2-py3-none-any.whl", hash = "sha256:c3d804eb4a42b85bafb5f36436342a5ad38df03878bb24db8855a4aa8b08b765"}, + {file = "pymdown_extensions-9.9.2.tar.gz", hash = "sha256:ebb33069bafcb64d5f5988043331d4ea4929325dc678a6bcf247ddfcf96499f8"}, ] [package.dependencies] @@ -1340,37 +1478,16 @@ pytest = ">=5.0" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] -[[package]] -name = "pytest-mypy" -version = "0.10.3" -description = "Mypy static type checker plugin for Pytest" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pytest-mypy-0.10.3.tar.gz", hash = "sha256:f8458f642323f13a2ca3e2e61509f7767966b527b4d8adccd5032c3e7b4fd3db"}, - {file = "pytest_mypy-0.10.3-py3-none-any.whl", hash = "sha256:7638d0d3906848fc1810cb2f5cc7fceb4cc5c98524aafcac58f28620e3102053"}, -] - -[package.dependencies] -attrs = ">=19.0" -filelock = ">=3.0" -mypy = [ - {version = ">=0.900", markers = "python_version >= \"3.11\""}, - {version = ">=0.780", markers = "python_version >= \"3.9\" and python_version < \"3.11\""}, -] -pytest = {version = ">=6.2", markers = "python_version >= \"3.10\""} - [[package]] name = "pytest-xdist" -version = "3.1.0" +version = "3.2.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.1.0.tar.gz", hash = "sha256:40fdb8f3544921c5dfcd486ac080ce22870e71d82ced6d2e78fa97c2addd480c"}, - {file = "pytest_xdist-3.1.0-py3-none-any.whl", hash = "sha256:70a76f191d8a1d2d6be69fc440cdf85f3e4c03c08b520fd5dc5d338d6cf07d89"}, + {file = "pytest-xdist-3.2.0.tar.gz", hash = "sha256:fa10f95a2564cd91652f2d132725183c3b590d9fdcdec09d3677386ecf4c1ce9"}, + {file = "pytest_xdist-3.2.0-py3-none-any.whl", hash = "sha256:336098e3bbd8193276867cc87db8b22903c3927665dff9d1ac8684c02f597b68"}, ] [package.dependencies] @@ -1386,7 +1503,7 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "dev" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1401,7 +1518,7 @@ six = ">=1.5" name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1451,7 +1568,7 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " -category = "dev" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1584,33 +1701,33 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.2.0" +version = "13.3.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "main" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.2.0-py3-none-any.whl", hash = "sha256:7c963f0d03819221e9ac561e1bc866e3f95a02248c1234daa48954e6d381c003"}, - {file = "rich-13.2.0.tar.gz", hash = "sha256:f1a00cdd3eebf999a15d85ec498bfe0b1a77efe9b34f645768a54132ef444ac5"}, + {file = "rich-13.3.1-py3-none-any.whl", hash = "sha256:8aa57747f3fc3e977684f0176a88e789be314a99f99b43b75d1e9cb5dc6db9e9"}, + {file = "rich-13.3.1.tar.gz", hash = "sha256:125d96d20c92b946b983d0d392b84ff945461e5a06d3867e9f9e575f8697b67f"}, ] [package.dependencies] markdown-it-py = ">=2.1.0,<3.0.0" -pygments = ">=2.6.0,<3.0.0" +pygments = ">=2.14.0,<3.0.0" [package.extras] -jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] +jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "66.0.0" +version = "67.3.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-66.0.0-py3-none-any.whl", hash = "sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab"}, - {file = "setuptools-66.0.0.tar.gz", hash = "sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6"}, + {file = "setuptools-67.3.2-py3-none-any.whl", hash = "sha256:bb6d8e508de562768f2027902929f8523932fcd1fb784e6d573d2cafac995a48"}, + {file = "setuptools-67.3.2.tar.gz", hash = "sha256:95f00380ef2ffa41d9bba85d95b27689d923c93dfbafed4aecd7cf988a25e012"}, ] [package.extras] @@ -1622,7 +1739,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1656,23 +1773,25 @@ files = [ [[package]] name = "textual" -version = "0.10.0" +version = "0.11.1" description = "Modern Text User Interface framework" category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "textual-0.10.0-py3-none-any.whl", hash = "sha256:d4c9215595d348bb35f27e9865572cd64c3d15448ff4578a33038c94e3fe6761"}, - {file = "textual-0.10.0.tar.gz", hash = "sha256:7b4e7fdc67e9101b6c9799be3f400d6812ebffc2fa760fe50b08450fbcc75bfe"}, + {file = "textual-0.11.1-py3-none-any.whl", hash = "sha256:77afbb64caa136fdc568ee43601fd5a1a94f13bb7e057c95dc8ee5dfa3f3083b"}, + {file = "textual-0.11.1.tar.gz", hash = "sha256:9b027853b686ac9561a3dc6f2b637a25089f2ee67a9e37bbf39d0da7567694b0"}, ] [package.dependencies] aiohttp = {version = ">=3.8.1", optional = true, markers = "extra == \"dev\""} click = {version = ">=8.1.2", optional = true, markers = "extra == \"dev\""} importlib-metadata = ">=4.11.3,<5.0.0" +markdown-it-py = {version = ">=2.1.0,<3.0.0", extras = ["linkify", "plugins"]} +mkdocs-exclude = ">=1.0.2,<2.0.0" msgpack = {version = ">=1.0.3", optional = true, markers = "extra == \"dev\""} -nanoid = ">=2.0.0" rich = ">12.6.0" +typing-extensions = ">=4.0.0,<5.0.0" [package.extras] dev = ["aiohttp (>=3.8.1)", "click (>=8.1.2)", "msgpack (>=1.0.3)"] @@ -1712,16 +1831,31 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.4.0" +version = "4.5.0" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, ] +[[package]] +name = "uc-micro-py" +version = "1.0.1" +description = "Micro subset of unicode data files for linkify-it-py projects." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "uc-micro-py-1.0.1.tar.gz", hash = "sha256:b7cdf4ea79433043ddfe2c82210208f26f7962c0cfbe3bacb05ee879a7fdb596"}, + {file = "uc_micro_py-1.0.1-py3-none-any.whl", hash = "sha256:316cfb8b6862a0f1d03540f0ae6e7b033ff1fa0ddbe60c12cbe0d4cec846a69f"}, +] + +[package.extras] +test = ["coverage", "pytest", "pytest-cov"] + [[package]] name = "urllib3" version = "1.26.14" @@ -1741,30 +1875,30 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.17.1" +version = "20.19.0" description = "Virtual Python Environment builder" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "virtualenv-20.17.1-py3-none-any.whl", hash = "sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4"}, - {file = "virtualenv-20.17.1.tar.gz", hash = "sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058"}, + {file = "virtualenv-20.19.0-py3-none-any.whl", hash = "sha256:54eb59e7352b573aa04d53f80fc9736ed0ad5143af445a1e539aada6eb947dd1"}, + {file = "virtualenv-20.19.0.tar.gz", hash = "sha256:37a640ba82ed40b226599c522d411e4be5edb339a0c0de030c0dc7b646d61590"}, ] [package.dependencies] distlib = ">=0.3.6,<1" filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<3" +platformdirs = ">=2.4,<4" [package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] -testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] [[package]] name = "watchdog" version = "2.2.1" description = "Filesystem events monitoring" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1922,21 +2056,21 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.11.0" +version = "3.14.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, - {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, + {file = "zipp-3.14.0-py3-none-any.whl", hash = "sha256:188834565033387710d046e3fe96acfc9b5e86cbca7f39ff69cf21a4128198b7"}, + {file = "zipp-3.14.0.tar.gz", hash = "sha256:9e5421e176ef5ab4c0ad896624e87a7b2f07aca746c9b2aa305952800cb8eecb"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<4" -content-hash = "4042da5d4785d3b5d52ce5e870731325d0c8e0ddebe43fad297c37cfdeb196d6" +content-hash = "d17227f8a6c2efa363f5814605b734c58a626231bdcb7514f3024192e1dbc479" diff --git a/pyproject.toml b/pyproject.toml index c3f72a2..4b6761f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "spiel" -version = "0.4.6" +version = "0.5.0" description = "A framework for building and presenting richly-styled presentations in your terminal using Python." readme="README.md" homepage="https://github.com/JoshKarpel/spiel" @@ -42,24 +42,23 @@ python = ">=3.10,<4" rich = ">=13.2" typer = ">=0.6" pillow = ">=8" -textual = ">=0.10.0" +textual = ">=0.11.0" watchfiles = ">=0.18" more-itertools = ">=9" [tool.poetry.group.dev.dependencies] -pre-commit = ">=2.20.0" +pre-commit = ">=3" pytest = ">=7" pytest-cov = ">=3" pytest-xdist = ">=3" -mypy = ">=0.991" -pytest-mypy = ">=0.10" +pytest-asyncio = ">=0.20" pytest-mock = ">=3" hypothesis = ">=6" -textual = {extras = ["dev"], version = ">=0.10.0"} +mypy = ">=1" mkdocs = ">=1.4" mkdocs-material = ">=9" mkdocstrings = {extras = ["python"], version = ">=0.19.0"} -pytest-asyncio = ">=0.20" +textual = {extras = ["dev"], version = ">=0.11.0"} [tool.poetry.scripts] spiel = 'spiel.cli:cli' @@ -76,7 +75,7 @@ line_length = 100 all = true [tool.pytest.ini_options] -addopts = ["--strict-markers", "--mypy", "-n", "auto"] +addopts = ["--strict-markers"] testpaths = ["tests", "spiel", "docs"] markers = ["slow"] diff --git a/spiel/__init__.py b/spiel/__init__.py index c60a617..0728466 100644 --- a/spiel/__init__.py +++ b/spiel/__init__.py @@ -2,6 +2,18 @@ from spiel.app import SuspendType, present from spiel.constants import __version__ from spiel.deck import Deck from spiel.slide import Slide +from spiel.transitions.protocol import Direction, Transition +from spiel.transitions.swipe import Swipe from spiel.triggers import Triggers -__all__ = ["present", "SuspendType", "__version__", "Deck", "Slide", "Triggers"] +__all__ = [ + "Deck", + "Direction", + "Slide", + "SuspendType", + "Swipe", + "Transition", + "Triggers", + "__version__", + "present", +] diff --git a/spiel/app.py b/spiel/app.py index c0d08ed..de62fe8 100644 --- a/spiel/app.py +++ b/spiel/app.py @@ -28,6 +28,8 @@ from spiel.exceptions import NoDeckFound from spiel.screens.deck import DeckScreen from spiel.screens.help import HelpScreen from spiel.screens.slide import SlideScreen +from spiel.screens.transition import SlideTransitionScreen +from spiel.transitions.protocol import Direction from spiel.triggers import Triggers from spiel.utils import clamp from spiel.widgets.slide import SlideWidget @@ -80,24 +82,30 @@ class SpielApp(App[None]): self, deck_path: Path, watch_path: Path | None = None, - show_messages: bool = True, - fixed_time: datetime.datetime | None = None, + _show_messages: bool = True, + _fixed_time: datetime.datetime | None = None, + _fixed_triggers: Triggers | None = None, + _enable_transitions: bool = True, + _slide_refresh_rate: float = 1 / 60, ): super().__init__() self.deck_path = deck_path self.watch_path = watch_path - self.show_messages = show_messages - self.fixed_time = fixed_time + self.show_messages = _show_messages + self.fixed_time = _fixed_time + self.fixed_triggers = _fixed_triggers + self.enable_transitions = _enable_transitions + self.slide_refresh_rate = _slide_refresh_rate async def on_mount(self) -> None: self.deck = load_deck(self.deck_path) self.reloader = asyncio.create_task(self.reload()) - await self.install_screen(SlideScreen(), name="slide") - await self.install_screen(DeckScreen(), name="deck") - await self.install_screen(HelpScreen(), name="help") + self.install_screen(SlideScreen(), name="slide") + self.install_screen(DeckScreen(), name="deck") + self.install_screen(HelpScreen(), name="help") await self.push_screen("slide") async def reload(self) -> None: @@ -144,11 +152,49 @@ class SpielApp(App[None]): self.set_timer(delay, clear) - def action_next_slide(self) -> None: - self.current_slide_idx = clamp(self.current_slide_idx + 1, 0, len(self.deck) - 1) + async def action_next_slide(self) -> None: + await self.handle_new_slide(self.current_slide_idx + 1, Direction.Next) - def action_prev_slide(self) -> None: - self.current_slide_idx = clamp(self.current_slide_idx - 1, 0, len(self.deck) - 1) + async def action_prev_slide(self) -> None: + await self.handle_new_slide(self.current_slide_idx - 1, Direction.Previous) + + async def handle_new_slide(self, new_slide_idx: int, direction: Direction) -> None: + new_slide_idx = clamp(new_slide_idx, 0, len(self.deck) - 1) + + current_slide = self.deck[self.current_slide_idx] + new_slide = self.deck[new_slide_idx] + + transition = new_slide.transition or self.deck.default_transition + + if ( + self.current_slide_idx == new_slide_idx + or not isinstance(self.screen, SlideScreen) + or transition is None + or not self.enable_transitions + ): + self.current_slide_idx = new_slide_idx + return + + transition_screen = SlideTransitionScreen( + from_slide=current_slide, + from_triggers=self.query_one(SlideWidget).triggers, + to_slide=new_slide, + direction=direction, + transition=transition, + ) + await self.switch_screen(transition_screen) + transition_screen.animate( + "progress", + value=100, + delay=0, + duration=0.75, + on_complete=lambda: self.finalize_transition(new_slide_idx), + ) + + async def finalize_transition(self, new_slide_idx: int) -> None: + await self.switch_screen("slide") + + self.current_slide_idx = new_slide_idx def action_next_row(self) -> None: self.current_slide_idx = clamp( @@ -164,7 +210,7 @@ class SpielApp(App[None]): self.title = new_deck.name def watch_current_slide_idx(self, new_current_slide_idx: int) -> None: - self.query_one(SlideWidget).triggers = Triggers.new() + self.query_one(SlideWidget).triggers = self.fixed_triggers or Triggers.new() self.sub_title = self.deck[new_current_slide_idx].title def action_trigger(self) -> None: @@ -179,7 +225,10 @@ class SpielApp(App[None]): @cached_property def repl(self) -> Callable[[], None]: # Lazily enable readline support - import readline # nopycln: import + try: + import readline # nopycln: import + except ImportError: + pass self.console.clear() # clear the console the first time we go into the repl sys.stdout.flush() @@ -203,7 +252,6 @@ class SpielApp(App[None]): if driver is not None: driver.stop_application_mode() - driver.exit_event.clear() # type: ignore[attr-defined] with redirect_stdout(sys.__stdout__), redirect_stderr(sys.__stderr__): yield driver.start_application_mode() diff --git a/spiel/cli.py b/spiel/cli.py index 964a071..d06a094 100644 --- a/spiel/cli.py +++ b/spiel/cli.py @@ -59,77 +59,6 @@ def _present( present(deck_path=path, watch_path=watch) -@cli.command() -def init( - path: Path = Argument( - ..., - writable=True, - resolve_path=True, - help="The path to create a new deck script at.", - ) -) -> None: - """ - Create a new deck script at the given path from a basic template. - - This is a good starting point if you already know what you want to do. - If you're not so sure, consider taking a look at the demo deck to see what's possible: - $ spiel demo --help - """ - console = Console() - - if path.exists(): - console.print( - Text(f"Error: {path} already exists, refusing to overwrite.", style=Style(color="red")) - ) - raise Exit(code=1) - - name = path.stem.replace("_", " ").title() - - try: - path.parent.mkdir(parents=True, exist_ok=True) - except Exception as e: - console.print( - Text( - f"Error: was not able to ensure that the parent directory {path.parent} exists due to: {e}.", - style=Style(color="red"), - ) - ) - raise Exit(code=1) - - try: - path.write_text( - dedent( - f"""\ - from textwrap import dedent - from spiel import Deck - - - deck = Deck(name="{name}") - - @deck.slide(title="Title") - def title(): - markup = dedent( - \"""\\ - # {name} - This is your title slide! - \""" - ) - return Markdown(markup, justify="center") - """ - ) - ) - except Exception as e: - console.print( - Text( - f"Error: was not able to write template to {path} due to: {e}", - style=Style(color="red"), - ) - ) - raise Exit(code=1) - - console.print(Text(f"Wrote deck template to {path}", style=Style(color="green"))) - - demo = Typer( name="demo", no_args_is_help=True, @@ -206,6 +135,6 @@ def version( """ if plain: - console.print(__version__, style=Style()) + console.print(Text(__version__)) else: console.print(DebugTable()) diff --git a/spiel/constants.py b/spiel/constants.py index 715c319..92708be 100644 --- a/spiel/constants.py +++ b/spiel/constants.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from importlib import metadata from pathlib import Path diff --git a/spiel/deck.py b/spiel/deck.py index 13f977c..5154551 100644 --- a/spiel/deck.py +++ b/spiel/deck.py @@ -2,9 +2,11 @@ from __future__ import annotations from collections.abc import Callable, Iterator, Mapping, Sequence from dataclasses import dataclass, field -from typing import overload +from typing import Type, overload from spiel.slide import Content, Slide +from spiel.transitions.protocol import Transition +from spiel.transitions.swipe import Swipe @dataclass @@ -14,7 +16,15 @@ class Deck(Sequence[Slide]): """ name: str - """The name of the `Deck`/presentation, which will be displayed in the footer.""" + """The name of the [`Deck`][spiel.Deck], which will be displayed in the footer.""" + + default_transition: Type[Transition] | None = Swipe + """\ + The default slide transition animation; + used if the slide being moved to does not specify its own transition. + Defaults to the [`Swipe`][spiel.Swipe] transition. + Set to `None` for no transition animation. + """ _slides: list[Slide] = field(default_factory=list) @@ -22,10 +32,11 @@ class Deck(Sequence[Slide]): self, title: str = "", bindings: Mapping[str, Callable[..., None]] | None = None, + transition: Type[Transition] | None = None, ) -> Callable[[Content], Content]: """ A decorator that creates a new slide in the deck, - with the decorated function as the `Slide`'s `content`. + with the decorated function as the [`Slide.content`][spiel.Slide.content]. Args: title: The title to display for the slide. @@ -33,6 +44,10 @@ class Deck(Sequence[Slide]): [keys](https://textual.textualize.io/guide/input/#key) to callables to be executed when those keys are pressed, when on this slide. + transition: The transition animation to use when moving to this slide. + Set to `None` to use the + [`Deck.default_transition`][spiel.Deck.default_transition] + of the deck this slide is in. """ def slideify(content: Content) -> Content: @@ -41,6 +56,7 @@ class Deck(Sequence[Slide]): title=title, content=content, bindings=bindings or {}, + transition=transition, ) ) return content diff --git a/spiel/screens/transition.py b/spiel/screens/transition.py new file mode 100644 index 0000000..43fd6c9 --- /dev/null +++ b/spiel/screens/transition.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from typing import Type + +from textual.app import ComposeResult +from textual.reactive import reactive + +from spiel.screens.screen import SpielScreen +from spiel.slide import Slide +from spiel.transitions.protocol import Direction, Transition +from spiel.triggers import Triggers +from spiel.widgets.fixed_slide import FixedSlideWidget +from spiel.widgets.footer import Footer + + +class SlideTransitionScreen(SpielScreen): + DEFAULT_CSS = """\ + SlideTransitionScreen { + layout: vertical; + overflow: hidden hidden; + layers: below above; + } + + FixedSlideWidget#from { + layer: above; + } + + FixedSlideWidget#to { + layer: below; + } + + Footer { + layer: above; + } + + Footer#dummy { + layer: below; + } + """ + progress = reactive(0, init=False, layout=True) + + def __init__( + self, + from_slide: Slide, + from_triggers: Triggers, + to_slide: Slide, + transition: Type[Transition], + direction: Direction, + ): + super().__init__() + + self.from_slide = from_slide + self.from_triggers = from_triggers + self.to_slide = to_slide + self.transition = transition() + self.direction = direction + + def compose(self) -> ComposeResult: + from_widget = FixedSlideWidget(self.from_slide, triggers=self.from_triggers, id="from") + to_widget = FixedSlideWidget(self.to_slide, id="to") + + self.transition.initialize( + from_widget=from_widget, + to_widget=to_widget, + direction=self.direction, + ) + + yield from_widget + yield to_widget + + yield Footer() + yield Footer( + id="dummy" + ) # a dummy footer to hold space on the "below" layer, won't be displayed + + def watch_progress(self, new_progress: float) -> None: + from_widget = self.query_one("#from") + to_widget = self.query_one("#to") + + self.transition.progress( + from_widget=from_widget, + to_widget=to_widget, + direction=self.direction, + progress=new_progress, + ) diff --git a/spiel/slide.py b/spiel/slide.py index ebc4008..9cf6e98 100644 --- a/spiel/slide.py +++ b/spiel/slide.py @@ -2,11 +2,13 @@ from __future__ import annotations import inspect from dataclasses import dataclass, field -from typing import Callable, Mapping +from typing import Callable, Mapping, Type from rich.console import RenderableType from rich.text import Text +from spiel.transitions.protocol import Transition +from spiel.transitions.swipe import Swipe from spiel.triggers import Triggers TRIGGERS = "triggers" @@ -24,7 +26,7 @@ class Slide: """The title of the `Slide`, which will be displayed in the footer.""" content: Content = lambda: Text() - """ + """\ A callable that is invoked by Spiel to display the slide's content. The function may optionally take arguments with these names: @@ -33,6 +35,20 @@ class Slide: """ bindings: Mapping[str, Callable[..., None]] = field(default_factory=dict) + """\ + A mapping of + [keys](https://textual.textualize.io/guide/input/#key) + to callables to be executed when those keys are pressed, + when on this slide. + """ + + transition: Type[Transition] | None = Swipe + """\ + The transition animation to use when moving to this slide. + Set to `None` to use the + [`Deck.default_transition`][spiel.Deck.default_transition] + of the deck this slide is in. + """ def render(self, triggers: Triggers) -> RenderableType: signature = inspect.signature(self.content) diff --git a/spiel/transitions/__init__.py b/spiel/transitions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/spiel/transitions/protocol.py b/spiel/transitions/protocol.py new file mode 100644 index 0000000..5d0a64d --- /dev/null +++ b/spiel/transitions/protocol.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from enum import Enum +from typing import Protocol, runtime_checkable + +from textual.widget import Widget + + +class Direction(Enum): + """ + An enumeration that describes which direction a slide transition + animation should move in: whether we're going to the next slide, + or to the previous slide. + """ + + Next = "next" + """Indicates that the transition should handle going to the next slide.""" + + Previous = "previous" + """Indicates that the transition should handle going to the previous slide.""" + + +@runtime_checkable +class Transition(Protocol): + """ + A protocol that describes how to implement a transition animation. + + See [Writing Custom Transitions](./transitions.md#writing-custom-transitions) + for more details on how to implement the protocol. + """ + + def initialize( + self, + from_widget: Widget, + to_widget: Widget, + direction: Direction, + ) -> None: + """ + A hook function to set up any CSS that should be present at the start of the transition. + + Args: + from_widget: The widget showing the slide that we are leaving. + to_widget: The widget showing the slide that we are entering. + direction: The desired direction of the transition animation. + """ + ... + + def progress( + self, + from_widget: Widget, + to_widget: Widget, + direction: Direction, + progress: float, + ) -> None: + """ + A hook function that is called each time the `progress` + of the transition animation updates. + + Args: + from_widget: The widget showing the slide that we are leaving. + to_widget: The widget showing the slide that we are entering. + direction: The desired direction of the transition animation. + progress: The progress of the animation, as a percentage + (e.g., initial state is `0`, final state is `100`). + Note that this is **not necessarily** bounded between `0` and `100`, + nor is it necessarily [monotonically increasing](https://en.wikipedia.org/wiki/Monotonic_function), + depending on the underlying Textual animation easing function, + which may overshoot or bounce. + However, it will always start at `0` and end at `100`, + no matter which `direction` the transition should move in. + """ + ... diff --git a/spiel/transitions/swipe.py b/spiel/transitions/swipe.py new file mode 100644 index 0000000..2b52c24 --- /dev/null +++ b/spiel/transitions/swipe.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +from textual.widget import Widget + +from spiel.transitions.protocol import Direction, Transition + + +class Swipe(Transition): + """ + A transition where the current and incoming slide are placed side-by-side + and gradually slide across the screen, + with the current slide leaving and the incoming slide entering. + """ + + def initialize( + self, + from_widget: Widget, + to_widget: Widget, + direction: Direction, + ) -> None: + to_widget.styles.offset = ("100%" if direction is Direction.Next else "-100%", 0) + + def progress( + self, + from_widget: Widget, + to_widget: Widget, + direction: Direction, + progress: float, + ) -> None: + match direction: + case Direction.Next: + from_widget.styles.offset = (f"-{progress:.2f}%", 0) + to_widget.styles.offset = (f"{100 - progress:.2f}%", 0) + case Direction.Previous: + from_widget.styles.offset = (f"{progress:.2f}%", 0) + to_widget.styles.offset = (f"-{100 - progress:.2f}%", 0) diff --git a/spiel/widgets/fixed_slide.py b/spiel/widgets/fixed_slide.py new file mode 100644 index 0000000..240e61d --- /dev/null +++ b/spiel/widgets/fixed_slide.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import sys + +from rich.box import HEAVY +from rich.console import RenderableType +from rich.errors import NotRenderableError +from rich.panel import Panel +from rich.protocol import is_renderable +from rich.style import Style +from rich.traceback import Traceback + +import spiel +from spiel.exceptions import SpielException +from spiel.slide import Slide +from spiel.triggers import Triggers +from spiel.widgets.widget import SpielWidget + + +class FixedSlideWidget(SpielWidget): + def __init__(self, slide: Slide, triggers: Triggers | None = None, id: str | None = None): + super().__init__(id=id) + + self.slide = slide + self.triggers = triggers or Triggers.new() + + def render(self) -> RenderableType: + try: + self.remove_class("error") + r = self.slide.render(triggers=self.triggers) + if is_renderable(r): + return r + else: + raise NotRenderableError(f"object {r!r} is not renderable") + except Exception: + self.add_class("error") + et, ev, tr = sys.exc_info() + if et is None or ev is None or tr is None: + raise SpielException("Expected to be handling an exception, but wasn't.") + return Panel( + Traceback.from_exception( + exc_type=et, + exc_value=ev, + traceback=tr, + suppress=(spiel,), + ), + title="Slide content failed to render", + border_style=Style(bold=True, color="red1"), + box=HEAVY, + ) diff --git a/spiel/widgets/slide.py b/spiel/widgets/slide.py index 09cdc65..ffaaceb 100644 --- a/spiel/widgets/slide.py +++ b/spiel/widgets/slide.py @@ -24,7 +24,10 @@ class SlideWidget(SpielWidget): def on_mount(self) -> None: super().on_mount() - self.set_interval(1 / 60, self.update_triggers) + if not self.app.fixed_triggers: + self.set_interval(self.app.slide_refresh_rate, self.update_triggers) + else: + self.triggers = self.app.fixed_triggers def update_triggers(self) -> None: self.triggers = Triggers(now=monotonic(), _times=self.triggers._times) @@ -40,7 +43,7 @@ class SlideWidget(SpielWidget): except Exception: self.add_class("error") et, ev, tr = sys.exc_info() - if et is None or ev is None or tr is None: + if et is None or ev is None or tr is None: # pragma: unreachable raise SpielException("Expected to be handling an exception, but wasn't.") return Panel( Traceback.from_exception( diff --git a/spiel/widgets/widget.py b/spiel/widgets/widget.py index d8256cb..e47bba8 100644 --- a/spiel/widgets/widget.py +++ b/spiel/widgets/widget.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING -from textual.reactive import watch +from textual.reactive import _watch from textual.widget import Widget from spiel.slide import Slide @@ -15,12 +15,9 @@ class SpielWidget(Widget): app: "SpielApp" def on_mount(self) -> None: - watch(self.app, "deck", self.r) - watch(self.app, "current_slide_idx", self.r) - watch(self.app, "message", self.r) - - def r(self, _: object) -> None: - self.refresh() + _watch(self, self.app, "deck", self.refresh) + _watch(self, self.app, "current_slide_idx", self.refresh) + _watch(self, self.app, "message", self.refresh) @property def current_slide(self) -> Slide: diff --git a/synthfile b/synthfile new file mode 100644 index 0000000..46c7f0f --- /dev/null +++ b/synthfile @@ -0,0 +1,14 @@ +tests: + @watch spiel/ tests/ docs/ + + pytest + +types: + @watch spiel/ tests/ docs/ + + mypy + +docs: + @restart + + mkdocs serve --strict diff --git a/tests/cli/__init__.py b/tests/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cli.py b/tests/cli/test_demo.py similarity index 56% rename from tests/test_cli.py rename to tests/cli/test_demo.py index b4758b3..66fbd56 100644 --- a/tests/test_cli.py +++ b/tests/cli/test_demo.py @@ -1,54 +1,10 @@ -import subprocess -import sys from pathlib import Path from unittest.mock import MagicMock -import pytest from pytest_mock import MockFixture from typer.testing import CliRunner from spiel.cli import cli -from spiel.constants import DEMO_FILE, PACKAGE_NAME, __version__ - - -def test_help(runner: CliRunner) -> None: - result = runner.invoke(cli, ["--help"]) - - assert result.exit_code == 0 - - -def test_help_via_main() -> None: - result = subprocess.run([sys.executable, "-m", PACKAGE_NAME, "--help"]) - - print(result.stdout) - assert result.returncode == 0 - - -def test_version(runner: CliRunner) -> None: - result = runner.invoke(cli, ["version"]) - - assert result.exit_code == 0 - assert __version__ in result.stdout - - -def test_plain_version(runner: CliRunner) -> None: - result = runner.invoke(cli, ["version", "--plain"]) - - assert result.exit_code == 0 - assert __version__ in result.stdout - - -def test_present_deck_on_missing_file(runner: CliRunner, tmp_path: Path) -> None: - result = runner.invoke(cli, ["present", str(tmp_path / "missing.py")]) - - assert result.exit_code == 2 - - -@pytest.mark.parametrize("stdin", [""]) -def test_display_demo_deck(runner: CliRunner, stdin: str) -> None: - result = runner.invoke(cli, ["present", str(DEMO_FILE)], input=stdin) - - assert result.exit_code == 0 def test_demo_display(runner: CliRunner) -> None: diff --git a/tests/cli/test_help.py b/tests/cli/test_help.py new file mode 100644 index 0000000..d40d689 --- /dev/null +++ b/tests/cli/test_help.py @@ -0,0 +1,20 @@ +import subprocess +import sys + +from typer.testing import CliRunner + +from spiel.cli import cli +from spiel.constants import PACKAGE_NAME + + +def test_help(runner: CliRunner) -> None: + result = runner.invoke(cli, ["--help"]) + + assert result.exit_code == 0 + + +def test_help_via_main() -> None: + result = subprocess.run([sys.executable, "-m", PACKAGE_NAME, "--help"]) + + print(result.stdout) + assert result.returncode == 0 diff --git a/tests/cli/test_present.py b/tests/cli/test_present.py new file mode 100644 index 0000000..d57f2d4 --- /dev/null +++ b/tests/cli/test_present.py @@ -0,0 +1,20 @@ +from pathlib import Path + +import pytest +from typer.testing import CliRunner + +from spiel.cli import cli +from spiel.constants import DEMO_FILE + + +def test_present_on_missing_file(runner: CliRunner, tmp_path: Path) -> None: + result = runner.invoke(cli, ["present", str(tmp_path / "missing.py")]) + + assert result.exit_code == 2 + + +@pytest.mark.parametrize("stdin", [""]) +def test_display_demo(runner: CliRunner, stdin: str) -> None: + result = runner.invoke(cli, ["present", str(DEMO_FILE)], input=stdin) + + assert result.exit_code == 0 diff --git a/tests/cli/test_version.py b/tests/cli/test_version.py new file mode 100644 index 0000000..f5365c8 --- /dev/null +++ b/tests/cli/test_version.py @@ -0,0 +1,18 @@ +from typer.testing import CliRunner + +from spiel import __version__ +from spiel.cli import cli + + +def test_version(runner: CliRunner) -> None: + result = runner.invoke(cli, ["version"]) + + assert result.exit_code == 0 + assert __version__ in result.stdout + + +def test_plain_version(runner: CliRunner) -> None: + result = runner.invoke(cli, ["version", "--plain"]) + + assert result.exit_code == 0 + assert __version__ in result.stdout diff --git a/tests/conftest.py b/tests/conftest.py index 48dd147..0e56afa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,7 +22,7 @@ def runner() -> CliRunner: @pytest.fixture def three_slide_deck() -> Deck: - deck = Deck(name="three-slides") + deck = Deck(name="three-slides", default_transition=None) deck.add_slides(Slide(), Slide(), Slide()) return deck diff --git a/tests/renderables/__init__.py b/tests/renderables/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_image.py b/tests/renderables/test_image.py similarity index 100% rename from tests/test_image.py rename to tests/renderables/test_image.py diff --git a/tests/test_app.py b/tests/test_app.py index 853edab..b7fbf45 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1,45 +1,16 @@ -from collections.abc import Iterable -from itertools import combinations_with_replacement - import pytest -from hypothesis import given -from hypothesis.strategies import lists, sampled_from -import spiel.constants from spiel.app import SpielApp +from spiel.constants import DEMO_FILE @pytest.fixture def app() -> SpielApp: - return SpielApp(deck_path=spiel.constants.DEMO_FILE) - - -KEYS = [ - "right", - "left", - "d", - "t", - "enter", - "up", - "down", - "escape", - "question_mark", -] - - -@pytest.mark.slow -@given(keys=lists(elements=sampled_from(KEYS), max_size=100)) -async def test_hammer_on_the_keyboard_long_random(keys: Iterable[str]) -> None: - app = SpielApp(deck_path=spiel.constants.DEMO_FILE) - async with app.run_test() as pilot: - await pilot.press(*keys) - - -@pytest.mark.slow -@pytest.mark.parametrize("keys", combinations_with_replacement(KEYS, 3)) -async def test_hammer_on_the_keyboard_short_exhaustive(app: SpielApp, keys: Iterable[str]) -> None: - async with app.run_test() as pilot: - await pilot.press(*keys) + return SpielApp( + deck_path=DEMO_FILE, + _enable_transitions=False, + _slide_refresh_rate=1 / 10, + ) async def test_advance_through_demo_slides(app: SpielApp) -> None: diff --git a/tests/test_init.py b/tests/test_init.py deleted file mode 100644 index 9516957..0000000 --- a/tests/test_init.py +++ /dev/null @@ -1,34 +0,0 @@ -from pathlib import Path - -import pytest -from typer.testing import CliRunner - -from spiel.app import load_deck -from spiel.cli import cli - - -def test_init_cli_command_fails_if_file_exists(runner: CliRunner, tmp_path: Path) -> None: - target = tmp_path / "foo_bar.py" - target.touch() - - result = runner.invoke(cli, ["init", str(target)]) - - assert result.exit_code == 1 - - -@pytest.fixture -def init_file(runner: CliRunner, tmp_path: Path) -> Path: - target = tmp_path / "foo_bar.py" - runner.invoke(cli, ["init", str(target)]) - - return target - - -def test_title_slide_header_injection(init_file: Path) -> None: - assert "# Foo Bar" in init_file.read_text() - - -def test_can_load_init_file(init_file: Path) -> None: - deck = load_deck(init_file) - - assert deck.name == "Foo Bar" diff --git a/tests/transitions/__init__.py b/tests/transitions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/transitions/conftest.py b/tests/transitions/conftest.py new file mode 100644 index 0000000..8c78836 --- /dev/null +++ b/tests/transitions/conftest.py @@ -0,0 +1,12 @@ +import pytest +from textual.widget import Widget + + +@pytest.fixture +def from_widget() -> Widget: + return Widget() + + +@pytest.fixture +def to_widget() -> Widget: + return Widget() diff --git a/tests/transitions/test_swipe.py b/tests/transitions/test_swipe.py new file mode 100644 index 0000000..b717a53 --- /dev/null +++ b/tests/transitions/test_swipe.py @@ -0,0 +1,121 @@ +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis.strategies import floats +from textual.css.scalar import Scalar, ScalarOffset, Unit +from textual.widget import Widget + +from spiel import Direction, Swipe, Transition + + +@pytest.fixture +def transition() -> Swipe: + return Swipe() + + +Y = Scalar.parse("0", percent_unit=Unit.HEIGHT) + + +@pytest.mark.parametrize( + "direction, to_offset", + [ + (Direction.Next, ScalarOffset(Scalar.parse("100%"), Y)), + ], +) +def test_swipe_initialize( + from_widget: Widget, + to_widget: Widget, + direction: Direction, + to_offset: tuple[object, object], +) -> None: + Swipe().initialize(from_widget=from_widget, to_widget=to_widget, direction=direction) + + assert to_widget.styles.offset == to_offset + + +@pytest.mark.parametrize( + "progress, direction, from_offset, to_offset", + [ + ( + 0, + Direction.Next, + ScalarOffset(Scalar.parse("-0%"), Y), + ScalarOffset(Scalar.parse("100%"), Y), + ), + ( + 25, + Direction.Next, + ScalarOffset(Scalar.parse("-25%"), Y), + ScalarOffset(Scalar.parse("75%"), Y), + ), + ( + 50, + Direction.Next, + ScalarOffset(Scalar.parse("-50%"), Y), + ScalarOffset(Scalar.parse("50%"), Y), + ), + ( + 75, + Direction.Next, + ScalarOffset(Scalar.parse("-75%"), Y), + ScalarOffset(Scalar.parse("25%"), Y), + ), + ( + 75.123, + Direction.Next, + ScalarOffset(Scalar.parse("-75.12%"), Y), + ScalarOffset(Scalar.parse("24.88%"), Y), + ), + ( + 75.126, + Direction.Next, + ScalarOffset(Scalar.parse("-75.13%"), Y), + ScalarOffset(Scalar.parse("24.87%"), Y), + ), + ( + 100, + Direction.Next, + ScalarOffset(Scalar.parse("-100%"), Y), + ScalarOffset(Scalar.parse("0%"), Y), + ), + ], +) +def test_swipe_progress( + transition: Transition, + from_widget: Widget, + to_widget: Widget, + progress: float, + direction: Direction, + from_offset: tuple[object, object], + to_offset: tuple[object, object], +) -> None: + transition.initialize(from_widget=from_widget, to_widget=to_widget, direction=direction) + + transition.progress( + from_widget=from_widget, + to_widget=to_widget, + direction=direction, + progress=progress, + ) + + assert from_widget.styles.offset == from_offset + assert to_widget.styles.offset == to_offset + + +@given(progress=floats(min_value=0, max_value=100)) +@settings(suppress_health_check=[HealthCheck.function_scoped_fixture]) +def test_swipe_progress_always_balances_for_right( + transition: Transition, + from_widget: Widget, + to_widget: Widget, + progress: float, +) -> None: + transition.initialize(from_widget=from_widget, to_widget=to_widget, direction=Direction.Next) + + transition.progress( + from_widget=from_widget, + to_widget=to_widget, + direction=Direction.Next, + progress=progress, + ) + + assert abs(from_widget.styles.offset.x.value) + to_widget.styles.offset.x.value == 100 diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_chunks.py b/tests/utils/test_chunks.py similarity index 100% rename from tests/test_chunks.py rename to tests/utils/test_chunks.py diff --git a/tests/test_clamp.py b/tests/utils/test_clamp.py similarity index 100% rename from tests/test_clamp.py rename to tests/utils/test_clamp.py diff --git a/tests/test_joinify.py b/tests/utils/test_filter_join.py similarity index 100% rename from tests/test_joinify.py rename to tests/utils/test_filter_join.py diff --git a/tests/widgets/__init__.py b/tests/widgets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_slide_widget.py b/tests/widgets/test_slide_widget.py similarity index 100% rename from tests/test_slide_widget.py rename to tests/widgets/test_slide_widget.py