├── qq_chat_history ├── py.typed ├── __init__.py ├── message.py ├── cli.py └── body.py ├── .gitignore ├── .flake8 ├── tests ├── file.txt ├── test_empty.py ├── test_name.py ├── test_file.py ├── test_group.py ├── test_private.py └── test_save.py ├── pyproject.toml ├── LICENSE ├── .github └── workflows │ └── tests.yml ├── README.md └── poetry.lock /qq_chat_history/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .pytest_cache 3 | dist 4 | __pycache__ -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 127 3 | show-source = true 4 | count = true 5 | statistics = true 6 | -------------------------------------------------------------------------------- /tests/file.txt: -------------------------------------------------------------------------------- 1 | === 2 | 假装我是文件头 3 | === 4 | 5 | 1883-03-07 11:22:33 A(123123) 6 | A 7 | 8 | 1883-03-07 12:34:56 B(456456) 9 | B 10 | -------------------------------------------------------------------------------- /qq_chat_history/__init__.py: -------------------------------------------------------------------------------- 1 | from .body import Body as Body 2 | from .body import parse as parse 3 | from .message import Message as Message 4 | 5 | __all__ = [ 6 | 'parse', 7 | 'Message', 8 | 'Body', 9 | ] 10 | -------------------------------------------------------------------------------- /tests/test_empty.py: -------------------------------------------------------------------------------- 1 | from qq_chat_history import parse 2 | 3 | lines = ''' 4 | === 5 | 假装我是文件头 6 | === 7 | 8 | 其实只要不是时间开头,是什么都无所谓 9 | '''.strip().splitlines() 10 | 11 | 12 | def test_empty() -> None: 13 | assert len(parse(lines)) == 0 14 | -------------------------------------------------------------------------------- /tests/test_name.py: -------------------------------------------------------------------------------- 1 | from qq_chat_history import parse 2 | 3 | lines = """ 4 | 1883-03-07 11:22:34 (A)(123123) 5 | 加个括号 6 | 7 | 1883-03-07 11:22:35 (B(123123) 8 | 半括号 9 | """.strip().splitlines() 10 | 11 | 12 | def test_name() -> None: 13 | body = parse(lines) 14 | assert body.find_latest_name('123123') == '(B' 15 | assert body.find_names('123123') == [ 16 | '(A)', '(B', 17 | ] 18 | assert body.find_latest_name('does not exist') is None 19 | -------------------------------------------------------------------------------- /qq_chat_history/message.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass() 5 | class Message: 6 | """Messages in chat history files.""" 7 | 8 | date: str 9 | id: str 10 | name: str 11 | content: str 12 | 13 | 14 | @dataclass() 15 | class MessageBuilder: 16 | """The builder of messages for internal use.""" 17 | 18 | date: str 19 | id: str 20 | name: str 21 | 22 | def build_message(self, content: str) -> Message: 23 | return Message(**self.__dict__, content=content) 24 | -------------------------------------------------------------------------------- /tests/test_file.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from qq_chat_history import Message, parse 4 | 5 | file = Path(__file__).parent / 'file.txt' 6 | 7 | 8 | def test_file() -> None: 9 | body = parse(file) 10 | 11 | assert body.find_first_message_by_id('123123') == Message( 12 | id='123123', name='A', content='A', date='1883-03-07 11:22:33', 13 | ) 14 | 15 | assert body.find_first_message_by_name('B') == Message( 16 | id='456456', name='B', content='B', date='1883-03-07 12:34:56', 17 | ) 18 | -------------------------------------------------------------------------------- /tests/test_group.py: -------------------------------------------------------------------------------- 1 | from qq_chat_history import Message, parse 2 | 3 | lines = ''' 4 | 1883-03-07 11:22:33 A 5 | Text A1 6 | Text A2 7 | 8 | 1883-03-07 12:34:56 B(123123) 9 | Text B 10 | '''.strip().splitlines() 11 | 12 | 13 | def test_group() -> None: 14 | body = parse(lines) 15 | 16 | assert body.find_first_message_by_name('A') == Message( 17 | date='1883-03-07 11:22:33', id='someone@example.com', name='A', content='Text A1\nText A2', 18 | ) 19 | 20 | assert body.find_first_message_by_id('123123') == Message( 21 | date='1883-03-07 12:34:56', id='123123', name='B', content='Text B', 22 | ) 23 | -------------------------------------------------------------------------------- /tests/test_private.py: -------------------------------------------------------------------------------- 1 | from qq_chat_history import Message, parse 2 | 3 | lines = ''' 4 | 1883-03-07 12:34:56 B 5 | 你说得对 6 | 7 | 1883-03-07 22:00:51 A 8 | 2006-01-02 15:04:05 9 | 10 | 11 | 12 | 13 | 2006-01-02 15:04:05 14 | '''.strip().splitlines() 15 | 16 | 17 | def test_private() -> None: 18 | body = parse(lines) 19 | 20 | assert body.find_first_message_by_name('B') == Message( 21 | date='1883-03-07 12:34:56', id='B', name='B', content='你说得对', 22 | ) 23 | 24 | # Blank lines will be omitted. 25 | assert body.find_first_message_by_id('A') == Message( 26 | date='1883-03-07 22:00:51', id='A', name='A', content='2006-01-02 15:04:05\n2006-01-02 15:04:05', 27 | ) 28 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "qq-chat-history" 3 | version = "1.1.7" 4 | description = "A tool to extract QQ chat history." 5 | authors = ["hikariyo "] 6 | license = "MIT" 7 | readme = "README.md" 8 | packages = [{include = "qq_chat_history"}] 9 | repository = "https://github.com/hikariyo/qq-chat-history" 10 | 11 | 12 | [tool.poetry.dependencies] 13 | python = "^3.9" 14 | click = "^8.1.3" 15 | ujson = "^5.7.0" 16 | pyyaml = "^6.0" 17 | 18 | 19 | [tool.poetry.group.dev.dependencies] 20 | pytest = "^7.2.1" 21 | types-ujson = "^5.7.0.0" 22 | mypy = "^0.991" 23 | flake8 = "^6.0.0" 24 | types-pyyaml = "^6.0.12.8" 25 | 26 | 27 | [tool.poetry.scripts] 28 | qq-chat-history = "qq_chat_history.cli:run" 29 | 30 | 31 | [tool.mypy] 32 | strict = true 33 | 34 | 35 | [build-system] 36 | requires = ["poetry-core"] 37 | build-backend = "poetry.core.masonry.api" 38 | -------------------------------------------------------------------------------- /tests/test_save.py: -------------------------------------------------------------------------------- 1 | from io import StringIO 2 | 3 | import ujson 4 | import yaml 5 | 6 | from qq_chat_history import parse 7 | 8 | lines = ''' 9 | 1883-03-07 11:22:33 A 10 | Text A 11 | 12 | 1883-03-07 12:34:56 B(123123) 13 | Text B 14 | '''.strip().splitlines() 15 | 16 | expected_dicts = [ 17 | { 18 | 'date': '1883-03-07 11:22:33', 19 | 'id': 'someone@example.com', 20 | 'name': 'A', 21 | 'content': 'Text A', 22 | }, 23 | { 24 | 'date': '1883-03-07 12:34:56', 25 | 'id': '123123', 26 | 'name': 'B', 27 | 'content': 'Text B', 28 | }, 29 | ] 30 | 31 | 32 | def do_format(fmt: str) -> StringIO: 33 | fp = StringIO() 34 | parse(lines).save(fp, fmt, indent=2) 35 | fp.seek(0) 36 | return fp 37 | 38 | 39 | def test_formatters() -> None: 40 | with do_format('json') as f: 41 | assert ujson.load(f) == expected_dicts 42 | 43 | with do_format('yaml') as f: 44 | assert yaml.load(f, Loader=yaml.CLoader) == expected_dicts 45 | -------------------------------------------------------------------------------- /qq_chat_history/cli.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import click 4 | 5 | from . import parse 6 | 7 | 8 | @click.command() 9 | @click.argument('input-file', type=click.Path(exists=True, dir_okay=False, path_type=Path)) 10 | @click.option( 11 | '--output-file', '-o', help='Output file path, with extension name auto-corrected.', 12 | type=click.Path(dir_okay=False, path_type=Path), default='output.json', show_default=True, 13 | ) 14 | @click.option( 15 | '--output-format', '-f', help='Output file format.', 16 | type=click.Choice(['json', 'yaml']), default='json', show_default=True, 17 | ) 18 | @click.option('--indent', '-d', help='Output file indent.', type=int, default=2, show_default=True) 19 | def run(input_file: Path, output_file: Path, output_format: str, indent: int) -> None: 20 | """Parses a chat history file in the CLI.""" 21 | if output_file.suffix[1:] != output_format: 22 | output_file = output_file.with_suffix(f'.{output_format}') 23 | 24 | with output_file.open('w', encoding='utf8') as fp: 25 | parse(input_file).save(fp, output_format, indent=indent) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Hikariyo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | 10 | permissions: 11 | contents: read 12 | 13 | 14 | jobs: 15 | test: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | python-version: [ "3.9", "3.10" ] 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v4 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | 30 | - name: Install dependencies 31 | run: | 32 | python -m pip install poetry 33 | poetry install 34 | 35 | - name: Lint with flake8 36 | run: | 37 | # stop the build if there are Python syntax errors or undefined names 38 | poetry run flake8 . --select=E9,F63,F7,F82 39 | # exit-zero treats all errors as warnings. 40 | poetry run flake8 . --exit-zero --max-complexity=10 41 | 42 | - name: Check with mypy 43 | run: | 44 | poetry run mypy . 45 | 46 | - name: Test with pytest 47 | run: | 48 | poetry run pytest 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QQ 聊天记录提取器 2 | 3 | ## 简介 4 | 5 | 从 QQ 聊天记录文件中提取聊天信息,仅支持 `txt` 格式的聊天记录。 6 | 7 | **现在 NTQQ 不支持导出文件**,可以使用我写的一个小[脚本](https://gist.github.com/hikariyo/03d57130eb006c5b0feed86173bc843f)来通过 OneBot 协议获取消息,逻辑比较简单就不单独开仓库了。 8 | 9 | ## 安装 10 | 11 | 使用 `pip` 安装,要求 `Python 3.9` 或以上版本。 12 | 13 | ```bash 14 | > pip install -U qq-chat-history 15 | ``` 16 | 17 | ## 使用 18 | 19 | 最简单的启动方式如下,它会自动在当前目录下创建 `output.json` 进行输出(如果安装到虚拟环境请确保已激活)。 20 | 21 | ```bash 22 | > qq-chat-history /path/to/file.txt 23 | ``` 24 | 25 | 启动时输入 `--help` 参数查看更多配置项。 26 | 27 | ```bash 28 | > qq-chat-history --help 29 | ``` 30 | 31 | 或者,可以作为一个第三方库使用,如下: 32 | 33 | ```python 34 | import qq_chat_history 35 | 36 | lines = ''' 37 | ========= 38 | 假装我是 QQ 自动生成的文件头 39 | ========= 40 | 41 | 1883-03-07 11:22:33 A 42 | Text A1 43 | Text A2 44 | 45 | 1883-03-07 12:34:56 B(123123) 46 | Text B 47 | 48 | 1883-03-07 13:24:36 C(456456) 49 | Text C 50 | 51 | 1883-03-07 22:00:51 A 52 | Text D 53 | '''.strip().splitlines() 54 | 55 | # 这里的 lines 也可以是文件对象或者以字符串或者 Path 对象表示的文件路径。 56 | for msg in qq_chat_history.parse(lines): 57 | print(msg.date, msg.id, msg.name, msg.content) 58 | ``` 59 | 60 | 注意 `parse` 方法返回的是一个 `Body` 对象,一般以 `Iterable[Message]` 的形式使用。当然 `Body` 也提供了几个函数,~虽然一般也没什么用~。 61 | 62 | ## Tips 63 | 64 | + 如果当作一个第三方库来用,例如 `find_xxx` 方法,可以从数据中查找指定 `id` 或 `name` 的消息;`save` 方法可以将数据以 `yaml` 或 `json` 格式保存到文件中,虽然这个工作一般都直接以 `CLI` 模式启动来完成。 65 | 66 | + 函数 `parse` 可以处理多样的类型。 67 | 68 | + `Iterable[str]`:迭代每行的可迭代对象,如 `list` 或 `tuple` 等。 69 | + `TextIOBase`:文本文件对象,如用 `open` 打开的文本文件,或者 `io.StringIO` 都属于文本文件对象。 70 | + `str`, `Path`:文件路径,如 `./data.txt`。 71 | 72 | 这些参数都将以对应的方法来构造 `Body` 对象。 73 | -------------------------------------------------------------------------------- /qq_chat_history/body.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import deque 3 | from functools import lru_cache 4 | from io import TextIOBase 5 | from itertools import dropwhile 6 | from pathlib import Path 7 | from typing import Any, Iterable, Iterator, Optional, TextIO, Union, cast 8 | 9 | import ujson 10 | import yaml 11 | 12 | from .message import Message, MessageBuilder 13 | 14 | BRACKETS_REGEX = re.compile(r'[(<]([^()<>]*?)[>)]$') 15 | DATE_HEAD_REGEX = re.compile(r'^(\d{4}-\d{2}-\d{2}\s+\d\d?:\d{2}:\d{2})\s+') 16 | 17 | 18 | class Body: 19 | """Chat history file body containing messages.""" 20 | 21 | def __init__(self, messages: list[Message]) -> None: 22 | """Initializes the body with messages. 23 | 24 | Constructing a body directly by this method is not recommended. 25 | Instead, using class methods `from_xxx` is recommended. 26 | """ 27 | self._messages = messages 28 | 29 | @staticmethod 30 | def _make_builder_from_head(line: str) -> Optional[MessageBuilder]: 31 | """Parses a message head. Returns None if the given line is invalid.""" 32 | if (date_matcher := DATE_HEAD_REGEX.search(line)) is None: 33 | return None 34 | date = date_matcher.group().strip() 35 | 36 | if matcher := BRACKETS_REGEX.findall(line): 37 | group_user_id = cast(str, matcher[-1]) 38 | name = DATE_HEAD_REGEX.sub('', BRACKETS_REGEX.sub('', line)).strip() 39 | return MessageBuilder(date=date, id=group_user_id, name=name) 40 | 41 | if not (private_user_id := DATE_HEAD_REGEX.sub('', line)): 42 | return None 43 | return MessageBuilder(date=date, id=private_user_id, name=private_user_id) 44 | 45 | @staticmethod 46 | def _gen_from_builder(builder: Optional[MessageBuilder], content_lines: deque[str]) -> Iterable[Message]: 47 | """Generates a message from given builder, or nothing if the builder itself is None.""" 48 | if builder is None: 49 | return 50 | 51 | yield builder.build_message( 52 | '\n'.join( 53 | content_lines.popleft() for _ in range(len(content_lines)) 54 | ), 55 | ) 56 | 57 | @classmethod 58 | def from_lines(cls, lines: Iterable[str]) -> 'Body': 59 | """Builds a body from lines.""" 60 | messages: list[Message] = [] 61 | builder: Optional[MessageBuilder] = None 62 | content_lines: deque[str] = deque() 63 | 64 | for line in dropwhile(lambda li: cls._make_builder_from_head(li) is None, lines): 65 | if next_builder := cls._make_builder_from_head(line): 66 | messages.extend(cls._gen_from_builder(builder, content_lines)) 67 | builder = next_builder 68 | elif line: 69 | # Omit blank lines. 70 | content_lines.append(line) 71 | 72 | messages.extend(cls._gen_from_builder(builder, content_lines)) 73 | return cls(messages) 74 | 75 | @classmethod 76 | def from_path(cls, path: Union[str, Path]) -> 'Body': 77 | """Builds a body from the path to a certain file.""" 78 | if isinstance(path, str): 79 | path = Path(path) 80 | return cls.from_lines(path.read_text('utf8').splitlines()) 81 | 82 | def save(self, fp: TextIO, fmt: str, **kwargs: Any) -> None: 83 | """Saves to a file, supporting `yaml` and `json` formats.""" 84 | data = [m.__dict__ for m in self._messages] 85 | 86 | if fmt == 'json': 87 | kwargs.setdefault('ensure_ascii', False) 88 | ujson.dump(data, fp, **kwargs) 89 | return 90 | 91 | if fmt == 'yaml': 92 | kwargs.setdefault('allow_unicode', True) 93 | kwargs.setdefault('Dumper', yaml.CDumper) 94 | yaml.dump(data, fp, **kwargs) 95 | return 96 | 97 | raise NameError(f'unknown format name {fmt}') 98 | 99 | def __iter__(self) -> Iterator[Message]: 100 | """Iterates over the messages.""" 101 | yield from self._messages 102 | 103 | def __len__(self) -> int: 104 | """Counts the messages.""" 105 | return len(self._messages) 106 | 107 | def find_names(self, id_: str) -> list[str]: 108 | """Gets all names used by given id.""" 109 | return [msg.name for msg in self._messages if msg.id == id_] 110 | 111 | @lru_cache() 112 | def find_latest_name(self, id_: str) -> Optional[str]: 113 | """Gets the latest name used by given id. Returns None when not found.""" 114 | if names := self.find_names(id_): 115 | return names[-1] 116 | return None 117 | 118 | def find_messages_by_id(self, id_: str) -> list[Message]: 119 | """Finds all messages by given id.""" 120 | return [msg for msg in self._messages if msg.id == id_] 121 | 122 | def find_messages_by_name(self, name: str) -> list[Message]: 123 | """Finds all messages by given name.""" 124 | return [msg for msg in self._messages if msg.name == name] 125 | 126 | def find_first_message_by_id(self, id_: str) -> Optional[Message]: 127 | """Finds the first message by given id.""" 128 | for msg in self._messages: 129 | if msg.id == id_: 130 | return msg 131 | return None 132 | 133 | def find_first_message_by_name(self, name: str) -> Optional[Message]: 134 | """Finds the first message by given name.""" 135 | for msg in self._messages: 136 | if msg.name == name: 137 | return msg 138 | return None 139 | 140 | 141 | def parse(data: Union[Iterable[str], TextIOBase, str, Path]) -> Body: 142 | """Builds a message body by the data in an iterable or a file.""" 143 | if isinstance(data, (str, Path)): 144 | return Body.from_path(data) 145 | 146 | if isinstance(data, TextIOBase): 147 | data = data.read().splitlines() 148 | 149 | return Body.from_lines(data) 150 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "click" 5 | version = "8.1.3" 6 | description = "Composable command line interface toolkit" 7 | category = "main" 8 | optional = false 9 | python-versions = ">=3.7" 10 | files = [ 11 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 12 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 13 | ] 14 | 15 | [package.dependencies] 16 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 17 | 18 | [[package]] 19 | name = "colorama" 20 | version = "0.4.6" 21 | description = "Cross-platform colored terminal text." 22 | category = "main" 23 | optional = false 24 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 25 | files = [ 26 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 27 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 28 | ] 29 | 30 | [[package]] 31 | name = "exceptiongroup" 32 | version = "1.1.1" 33 | description = "Backport of PEP 654 (exception groups)" 34 | category = "dev" 35 | optional = false 36 | python-versions = ">=3.7" 37 | files = [ 38 | {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, 39 | {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, 40 | ] 41 | 42 | [package.extras] 43 | test = ["pytest (>=6)"] 44 | 45 | [[package]] 46 | name = "flake8" 47 | version = "6.0.0" 48 | description = "the modular source code checker: pep8 pyflakes and co" 49 | category = "dev" 50 | optional = false 51 | python-versions = ">=3.8.1" 52 | files = [ 53 | {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, 54 | {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, 55 | ] 56 | 57 | [package.dependencies] 58 | mccabe = ">=0.7.0,<0.8.0" 59 | pycodestyle = ">=2.10.0,<2.11.0" 60 | pyflakes = ">=3.0.0,<3.1.0" 61 | 62 | [[package]] 63 | name = "iniconfig" 64 | version = "2.0.0" 65 | description = "brain-dead simple config-ini parsing" 66 | category = "dev" 67 | optional = false 68 | python-versions = ">=3.7" 69 | files = [ 70 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 71 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 72 | ] 73 | 74 | [[package]] 75 | name = "mccabe" 76 | version = "0.7.0" 77 | description = "McCabe checker, plugin for flake8" 78 | category = "dev" 79 | optional = false 80 | python-versions = ">=3.6" 81 | files = [ 82 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, 83 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, 84 | ] 85 | 86 | [[package]] 87 | name = "mypy" 88 | version = "0.991" 89 | description = "Optional static typing for Python" 90 | category = "dev" 91 | optional = false 92 | python-versions = ">=3.7" 93 | files = [ 94 | {file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, 95 | {file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, 96 | {file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, 97 | {file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"}, 98 | {file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"}, 99 | {file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"}, 100 | {file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"}, 101 | {file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"}, 102 | {file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"}, 103 | {file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"}, 104 | {file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"}, 105 | {file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"}, 106 | {file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"}, 107 | {file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"}, 108 | {file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"}, 109 | {file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"}, 110 | {file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"}, 111 | {file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"}, 112 | {file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"}, 113 | {file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"}, 114 | {file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"}, 115 | {file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"}, 116 | {file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"}, 117 | {file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"}, 118 | {file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"}, 119 | {file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"}, 120 | {file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"}, 121 | {file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"}, 122 | {file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"}, 123 | {file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"}, 124 | ] 125 | 126 | [package.dependencies] 127 | mypy-extensions = ">=0.4.3" 128 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 129 | typing-extensions = ">=3.10" 130 | 131 | [package.extras] 132 | dmypy = ["psutil (>=4.0)"] 133 | install-types = ["pip"] 134 | python2 = ["typed-ast (>=1.4.0,<2)"] 135 | reports = ["lxml"] 136 | 137 | [[package]] 138 | name = "mypy-extensions" 139 | version = "1.0.0" 140 | description = "Type system extensions for programs checked with the mypy type checker." 141 | category = "dev" 142 | optional = false 143 | python-versions = ">=3.5" 144 | files = [ 145 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 146 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 147 | ] 148 | 149 | [[package]] 150 | name = "packaging" 151 | version = "23.0" 152 | description = "Core utilities for Python packages" 153 | category = "dev" 154 | optional = false 155 | python-versions = ">=3.7" 156 | files = [ 157 | {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, 158 | {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, 159 | ] 160 | 161 | [[package]] 162 | name = "pluggy" 163 | version = "1.0.0" 164 | description = "plugin and hook calling mechanisms for python" 165 | category = "dev" 166 | optional = false 167 | python-versions = ">=3.6" 168 | files = [ 169 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 170 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 171 | ] 172 | 173 | [package.extras] 174 | dev = ["pre-commit", "tox"] 175 | testing = ["pytest", "pytest-benchmark"] 176 | 177 | [[package]] 178 | name = "pycodestyle" 179 | version = "2.10.0" 180 | description = "Python style guide checker" 181 | category = "dev" 182 | optional = false 183 | python-versions = ">=3.6" 184 | files = [ 185 | {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, 186 | {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, 187 | ] 188 | 189 | [[package]] 190 | name = "pyflakes" 191 | version = "3.0.1" 192 | description = "passive checker of Python programs" 193 | category = "dev" 194 | optional = false 195 | python-versions = ">=3.6" 196 | files = [ 197 | {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, 198 | {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, 199 | ] 200 | 201 | [[package]] 202 | name = "pytest" 203 | version = "7.3.0" 204 | description = "pytest: simple powerful testing with Python" 205 | category = "dev" 206 | optional = false 207 | python-versions = ">=3.7" 208 | files = [ 209 | {file = "pytest-7.3.0-py3-none-any.whl", hash = "sha256:933051fa1bfbd38a21e73c3960cebdad4cf59483ddba7696c48509727e17f201"}, 210 | {file = "pytest-7.3.0.tar.gz", hash = "sha256:58ecc27ebf0ea643ebfdf7fb1249335da761a00c9f955bcd922349bcb68ee57d"}, 211 | ] 212 | 213 | [package.dependencies] 214 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 215 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 216 | iniconfig = "*" 217 | packaging = "*" 218 | pluggy = ">=0.12,<2.0" 219 | tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} 220 | 221 | [package.extras] 222 | testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 223 | 224 | [[package]] 225 | name = "pyyaml" 226 | version = "6.0" 227 | description = "YAML parser and emitter for Python" 228 | category = "main" 229 | optional = false 230 | python-versions = ">=3.6" 231 | files = [ 232 | {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, 233 | {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, 234 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, 235 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, 236 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, 237 | {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, 238 | {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, 239 | {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, 240 | {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, 241 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, 242 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, 243 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, 244 | {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, 245 | {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, 246 | {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, 247 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, 248 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, 249 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, 250 | {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, 251 | {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, 252 | {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, 253 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, 254 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, 255 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, 256 | {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, 257 | {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, 258 | {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, 259 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, 260 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, 261 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, 262 | {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, 263 | {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, 264 | {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, 265 | {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, 266 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, 267 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, 268 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, 269 | {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, 270 | {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, 271 | {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, 272 | ] 273 | 274 | [[package]] 275 | name = "tomli" 276 | version = "2.0.1" 277 | description = "A lil' TOML parser" 278 | category = "dev" 279 | optional = false 280 | python-versions = ">=3.7" 281 | files = [ 282 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 283 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 284 | ] 285 | 286 | [[package]] 287 | name = "types-pyyaml" 288 | version = "6.0.12.9" 289 | description = "Typing stubs for PyYAML" 290 | category = "dev" 291 | optional = false 292 | python-versions = "*" 293 | files = [ 294 | {file = "types-PyYAML-6.0.12.9.tar.gz", hash = "sha256:c51b1bd6d99ddf0aa2884a7a328810ebf70a4262c292195d3f4f9a0005f9eeb6"}, 295 | {file = "types_PyYAML-6.0.12.9-py3-none-any.whl", hash = "sha256:5aed5aa66bd2d2e158f75dda22b059570ede988559f030cf294871d3b647e3e8"}, 296 | ] 297 | 298 | [[package]] 299 | name = "types-ujson" 300 | version = "5.7.0.1" 301 | description = "Typing stubs for ujson" 302 | category = "dev" 303 | optional = false 304 | python-versions = "*" 305 | files = [ 306 | {file = "types-ujson-5.7.0.1.tar.gz", hash = "sha256:54351a62ec1b6550efb17af63ef7f0c00d0efa9c099de7da5c627e1efa280553"}, 307 | {file = "types_ujson-5.7.0.1-py3-none-any.whl", hash = "sha256:67cdedbab6ea905f21e236497e9e97d8f7f0845d72b47a7404974dcb88adeb22"}, 308 | ] 309 | 310 | [[package]] 311 | name = "typing-extensions" 312 | version = "4.5.0" 313 | description = "Backported and Experimental Type Hints for Python 3.7+" 314 | category = "dev" 315 | optional = false 316 | python-versions = ">=3.7" 317 | files = [ 318 | {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, 319 | {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, 320 | ] 321 | 322 | [[package]] 323 | name = "ujson" 324 | version = "5.7.0" 325 | description = "Ultra fast JSON encoder and decoder for Python" 326 | category = "main" 327 | optional = false 328 | python-versions = ">=3.7" 329 | files = [ 330 | {file = "ujson-5.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5eba5e69e4361ac3a311cf44fa71bc619361b6e0626768a494771aacd1c2f09b"}, 331 | {file = "ujson-5.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aae4d9e1b4c7b61780f0a006c897a4a1904f862fdab1abb3ea8f45bd11aa58f3"}, 332 | {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2e43ccdba1cb5c6d3448eadf6fc0dae7be6c77e357a3abc968d1b44e265866d"}, 333 | {file = "ujson-5.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54384ce4920a6d35fa9ea8e580bc6d359e3eb961fa7e43f46c78e3ed162d56ff"}, 334 | {file = "ujson-5.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24ad1aa7fc4e4caa41d3d343512ce68e41411fb92adf7f434a4d4b3749dc8f58"}, 335 | {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:afff311e9f065a8f03c3753db7011bae7beb73a66189c7ea5fcb0456b7041ea4"}, 336 | {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e80f0d03e7e8646fc3d79ed2d875cebd4c83846e129737fdc4c2532dbd43d9e"}, 337 | {file = "ujson-5.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:137831d8a0db302fb6828ee21c67ad63ac537bddc4376e1aab1c8573756ee21c"}, 338 | {file = "ujson-5.7.0-cp310-cp310-win32.whl", hash = "sha256:7df3fd35ebc14dafeea031038a99232b32f53fa4c3ecddb8bed132a43eefb8ad"}, 339 | {file = "ujson-5.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:af4639f684f425177d09ae409c07602c4096a6287027469157bfb6f83e01448b"}, 340 | {file = "ujson-5.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b0f2680ce8a70f77f5d70aaf3f013d53e6af6d7058727a35d8ceb4a71cdd4e9"}, 341 | {file = "ujson-5.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a19fd8e7d8cc58a169bea99fed5666023adf707a536d8f7b0a3c51dd498abf"}, 342 | {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6abb8e6d8f1ae72f0ed18287245f5b6d40094e2656d1eab6d99d666361514074"}, 343 | {file = "ujson-5.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8cd622c069368d5074bd93817b31bdb02f8d818e57c29e206f10a1f9c6337dd"}, 344 | {file = "ujson-5.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14f9082669f90e18e64792b3fd0bf19f2b15e7fe467534a35ea4b53f3bf4b755"}, 345 | {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7ff6ebb43bc81b057724e89550b13c9a30eda0f29c2f506f8b009895438f5a6"}, 346 | {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f7f241488879d91a136b299e0c4ce091996c684a53775e63bb442d1a8e9ae22a"}, 347 | {file = "ujson-5.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5593263a7fcfb934107444bcfba9dde8145b282de0ee9f61e285e59a916dda0f"}, 348 | {file = "ujson-5.7.0-cp311-cp311-win32.whl", hash = "sha256:26c2b32b489c393106e9cb68d0a02e1a7b9d05a07429d875c46b94ee8405bdb7"}, 349 | {file = "ujson-5.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed24406454bb5a31df18f0a423ae14beb27b28cdfa34f6268e7ebddf23da807e"}, 350 | {file = "ujson-5.7.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18679484e3bf9926342b1c43a3bd640f93a9eeeba19ef3d21993af7b0c44785d"}, 351 | {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee295761e1c6c30400641f0a20d381633d7622633cdf83a194f3c876a0e4b7e"}, 352 | {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b738282e12a05f400b291966630a98d622da0938caa4bc93cf65adb5f4281c60"}, 353 | {file = "ujson-5.7.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00343501dbaa5172e78ef0e37f9ebd08040110e11c12420ff7c1f9f0332d939e"}, 354 | {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c0d1f7c3908357ee100aa64c4d1cf91edf99c40ac0069422a4fd5fd23b263263"}, 355 | {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a5d2f44331cf04689eafac7a6596c71d6657967c07ac700b0ae1c921178645da"}, 356 | {file = "ujson-5.7.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:16b2254a77b310f118717715259a196662baa6b1f63b1a642d12ab1ff998c3d7"}, 357 | {file = "ujson-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:6faf46fa100b2b89e4db47206cf8a1ffb41542cdd34dde615b2fc2288954f194"}, 358 | {file = "ujson-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ff0004c3f5a9a6574689a553d1b7819d1a496b4f005a7451f339dc2d9f4cf98c"}, 359 | {file = "ujson-5.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:75204a1dd7ec6158c8db85a2f14a68d2143503f4bafb9a00b63fe09d35762a5e"}, 360 | {file = "ujson-5.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7312731c7826e6c99cdd3ac503cd9acd300598e7a80bcf41f604fee5f49f566c"}, 361 | {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b9dc5a90e2149643df7f23634fe202fed5ebc787a2a1be95cf23632b4d90651"}, 362 | {file = "ujson-5.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a6961fc48821d84b1198a09516e396d56551e910d489692126e90bf4887d29"}, 363 | {file = "ujson-5.7.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b01a9af52a0d5c46b2c68e3f258fdef2eacaa0ce6ae3e9eb97983f5b1166edb6"}, 364 | {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7316d3edeba8a403686cdcad4af737b8415493101e7462a70ff73dd0609eafc"}, 365 | {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ee997799a23227e2319a3f8817ce0b058923dbd31904761b788dc8f53bd3e30"}, 366 | {file = "ujson-5.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dda9aa4c33435147262cd2ea87c6b7a1ca83ba9b3933ff7df34e69fee9fced0c"}, 367 | {file = "ujson-5.7.0-cp38-cp38-win32.whl", hash = "sha256:bea8d30e362180aafecabbdcbe0e1f0b32c9fa9e39c38e4af037b9d3ca36f50c"}, 368 | {file = "ujson-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:c96e3b872bf883090ddf32cc41957edf819c5336ab0007d0cf3854e61841726d"}, 369 | {file = "ujson-5.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6411aea4c94a8e93c2baac096fbf697af35ba2b2ed410b8b360b3c0957a952d3"}, 370 | {file = "ujson-5.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d3b3499c55911f70d4e074c626acdb79a56f54262c3c83325ffb210fb03e44d"}, 371 | {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:341f891d45dd3814d31764626c55d7ab3fd21af61fbc99d070e9c10c1190680b"}, 372 | {file = "ujson-5.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f242eec917bafdc3f73a1021617db85f9958df80f267db69c76d766058f7b19"}, 373 | {file = "ujson-5.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3af9f9f22a67a8c9466a32115d9073c72a33ae627b11de6f592df0ee09b98b6"}, 374 | {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a3d794afbf134df3056a813e5c8a935208cddeae975bd4bc0ef7e89c52f0ce0"}, 375 | {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:800bf998e78dae655008dd10b22ca8dc93bdcfcc82f620d754a411592da4bbf2"}, 376 | {file = "ujson-5.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b5ac3d5c5825e30b438ea92845380e812a476d6c2a1872b76026f2e9d8060fc2"}, 377 | {file = "ujson-5.7.0-cp39-cp39-win32.whl", hash = "sha256:cd90027e6d93e8982f7d0d23acf88c896d18deff1903dd96140613389b25c0dd"}, 378 | {file = "ujson-5.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:523ee146cdb2122bbd827f4dcc2a8e66607b3f665186bce9e4f78c9710b6d8ab"}, 379 | {file = "ujson-5.7.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e87cec407ec004cf1b04c0ed7219a68c12860123dfb8902ef880d3d87a71c172"}, 380 | {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bab10165db6a7994e67001733f7f2caf3400b3e11538409d8756bc9b1c64f7e8"}, 381 | {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b522be14a28e6ac1cf818599aeff1004a28b42df4ed4d7bc819887b9dac915fc"}, 382 | {file = "ujson-5.7.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7592f40175c723c032cdbe9fe5165b3b5903604f774ab0849363386e99e1f253"}, 383 | {file = "ujson-5.7.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ed22f9665327a981f288a4f758a432824dc0314e4195a0eaeb0da56a477da94d"}, 384 | {file = "ujson-5.7.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:adf445a49d9a97a5a4c9bb1d652a1528de09dd1c48b29f79f3d66cea9f826bf6"}, 385 | {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64772a53f3c4b6122ed930ae145184ebaed38534c60f3d859d8c3f00911eb122"}, 386 | {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35209cb2c13fcb9d76d249286105b4897b75a5e7f0efb0c0f4b90f222ce48910"}, 387 | {file = "ujson-5.7.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90712dfc775b2c7a07d4d8e059dd58636bd6ff1776d79857776152e693bddea6"}, 388 | {file = "ujson-5.7.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0e4e8981c6e7e9e637e637ad8ffe948a09e5434bc5f52ecbb82b4b4cfc092bfb"}, 389 | {file = "ujson-5.7.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:581c945b811a3d67c27566539bfcb9705ea09cb27c4be0002f7a553c8886b817"}, 390 | {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d36a807a24c7d44f71686685ae6fbc8793d784bca1adf4c89f5f780b835b6243"}, 391 | {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4257307e3662aa65e2644a277ca68783c5d51190ed9c49efebdd3cbfd5fa44"}, 392 | {file = "ujson-5.7.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea7423d8a2f9e160c5e011119741682414c5b8dce4ae56590a966316a07a4618"}, 393 | {file = "ujson-5.7.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c592eb91a5968058a561d358d0fef59099ed152cfb3e1cd14eee51a7a93879e"}, 394 | {file = "ujson-5.7.0.tar.gz", hash = "sha256:e788e5d5dcae8f6118ac9b45d0b891a0d55f7ac480eddcb7f07263f2bcf37b23"}, 395 | ] 396 | 397 | [metadata] 398 | lock-version = "2.0" 399 | python-versions = "^3.9" 400 | content-hash = "140b7e27cdef9510c9cd104ed28d03c9317dbaa6ed4199be7c7b8486653f506d" 401 | --------------------------------------------------------------------------------