fastbencode 0.2__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastbencode-0.3.2/.github/dependabot.yaml +13 -0
- fastbencode-0.3.2/.github/workflows/auto-merge.yml +22 -0
- fastbencode-0.3.2/.github/workflows/disperse.yml +14 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/.github/workflows/pythonpackage.yml +14 -6
- fastbencode-0.3.2/.github/workflows/wheels.yaml +93 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/.gitignore +1 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/CODE_OF_CONDUCT.md +1 -1
- {fastbencode-0.2 → fastbencode-0.3.2}/PKG-INFO +19 -9
- {fastbencode-0.2 → fastbencode-0.3.2}/README.md +6 -0
- fastbencode-0.3.2/disperse.toml +8 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/__init__.py +9 -8
- fastbencode-0.3.2/fastbencode/_bencode_py.py +185 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/_bencode_pyx.pyi +1 -3
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/_bencode_pyx.pyx +67 -19
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/tests/__init__.py +3 -3
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/tests/test_bencode.py +201 -108
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/PKG-INFO +19 -9
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/SOURCES.txt +4 -3
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/requires.txt +3 -0
- fastbencode-0.3.2/pyproject.toml +74 -0
- fastbencode-0.3.2/setup.cfg +4 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/setup.py +38 -23
- fastbencode-0.2/.github/workflows/disperse.yml +0 -24
- fastbencode-0.2/.github/workflows/pythonpublish.yml +0 -58
- fastbencode-0.2/disperse.conf +0 -8
- fastbencode-0.2/fastbencode/_bencode_py.py +0 -162
- fastbencode-0.2/pyproject.toml +0 -3
- fastbencode-0.2/setup.cfg +0 -35
- {fastbencode-0.2 → fastbencode-0.3.2}/COPYING +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/MANIFEST.in +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/SECURITY.md +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/_bencode_pyx.h +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/py.typed +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/python-compat.h +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/dependency_links.txt +0 -0
- {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Keep GitHub Actions up to date with GitHub's Dependabot...
|
|
2
|
+
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
|
|
3
|
+
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
|
|
4
|
+
version: 2
|
|
5
|
+
updates:
|
|
6
|
+
- package-ecosystem: "github-actions"
|
|
7
|
+
directory: "/"
|
|
8
|
+
schedule:
|
|
9
|
+
interval: weekly
|
|
10
|
+
- package-ecosystem: "pip"
|
|
11
|
+
directory: "/"
|
|
12
|
+
schedule:
|
|
13
|
+
interval: weekly
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Dependabot auto-merge
|
|
2
|
+
on: pull_request_target
|
|
3
|
+
|
|
4
|
+
permissions:
|
|
5
|
+
pull-requests: write
|
|
6
|
+
contents: write
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
dependabot:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
if: ${{ github.actor == 'dependabot[bot]' }}
|
|
12
|
+
steps:
|
|
13
|
+
- name: Dependabot metadata
|
|
14
|
+
id: metadata
|
|
15
|
+
uses: dependabot/fetch-metadata@v2
|
|
16
|
+
with:
|
|
17
|
+
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
18
|
+
- name: Enable auto-merge for Dependabot PRs
|
|
19
|
+
run: gh pr merge --auto --squash "$PR_URL"
|
|
20
|
+
env:
|
|
21
|
+
PR_URL: ${{github.event.pull_request.html_url}}
|
|
22
|
+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
|
@@ -9,23 +9,31 @@ jobs:
|
|
|
9
9
|
strategy:
|
|
10
10
|
matrix:
|
|
11
11
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
12
|
-
python-version: [3.
|
|
12
|
+
python-version: ['3.10', '3.11', '3.12', '3.13', '3.9']
|
|
13
13
|
fail-fast: false
|
|
14
14
|
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
17
|
- name: Set up Python ${{ matrix.python-version }}
|
|
18
|
-
uses: actions/setup-python@
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
19
|
with:
|
|
20
20
|
python-version: ${{ matrix.python-version }}
|
|
21
21
|
- name: Install dependencies
|
|
22
22
|
run: |
|
|
23
23
|
python -m pip install --upgrade pip cython
|
|
24
|
-
pip install -U pip
|
|
24
|
+
pip install -U pip ".[dev]"
|
|
25
25
|
- name: Style checks
|
|
26
26
|
run: |
|
|
27
|
-
python -m
|
|
28
|
-
- name: Test suite run
|
|
27
|
+
python -m ruff check .
|
|
28
|
+
- name: Test suite run (pure Python)
|
|
29
|
+
run: |
|
|
30
|
+
python -m unittest fastbencode.tests.test_suite
|
|
31
|
+
env:
|
|
32
|
+
PYTHONHASHSEED: random
|
|
33
|
+
- name: Install in editable mode
|
|
34
|
+
run: |
|
|
35
|
+
pip install -e .
|
|
36
|
+
- name: Test suite run (with C extension)
|
|
29
37
|
run: |
|
|
30
38
|
python -m unittest fastbencode.tests.test_suite
|
|
31
39
|
env:
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
name: Build Python distributions
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: "0 6 * * *" # Daily 6AM UTC build
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build-wheels:
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
|
+
fail-fast: true
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install setuptools wheel cibuildwheel
|
|
24
|
+
- name: Set up QEMU
|
|
25
|
+
uses: docker/setup-qemu-action@v3
|
|
26
|
+
if: "matrix.os == 'ubuntu-latest'"
|
|
27
|
+
- name: Build wheels
|
|
28
|
+
run: python -m cibuildwheel --output-dir wheelhouse
|
|
29
|
+
- name: Upload wheels
|
|
30
|
+
uses: actions/upload-artifact@v4
|
|
31
|
+
with:
|
|
32
|
+
name: artifact-${{ matrix.os }}
|
|
33
|
+
path: ./wheelhouse/*.whl
|
|
34
|
+
|
|
35
|
+
build-sdist:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
- uses: actions/setup-python@v5
|
|
40
|
+
- name: Install dependencies
|
|
41
|
+
run: |
|
|
42
|
+
python -m pip install --upgrade pip
|
|
43
|
+
pip install build
|
|
44
|
+
- name: Build sdist
|
|
45
|
+
run: python -m build --sdist
|
|
46
|
+
- name: Upload sdist
|
|
47
|
+
uses: actions/upload-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: artifact-sdist
|
|
50
|
+
path: ./dist/*.tar.gz
|
|
51
|
+
|
|
52
|
+
test-sdist:
|
|
53
|
+
needs:
|
|
54
|
+
- build-sdist
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/setup-python@v5
|
|
58
|
+
- name: Install dependencies
|
|
59
|
+
run: |
|
|
60
|
+
python -m pip install --upgrade pip
|
|
61
|
+
# Upgrade packging to avoid a bug in twine.
|
|
62
|
+
# See https://github.com/pypa/twine/issues/1216
|
|
63
|
+
pip install "twine>=6.1.0" "packaging>=24.2"
|
|
64
|
+
- name: Download sdist
|
|
65
|
+
uses: actions/download-artifact@v4
|
|
66
|
+
with:
|
|
67
|
+
name: artifact-sdist
|
|
68
|
+
path: dist
|
|
69
|
+
- name: Test sdist
|
|
70
|
+
run: twine check dist/*
|
|
71
|
+
- name: Test installation from sdist
|
|
72
|
+
run: pip install dist/*.tar.gz
|
|
73
|
+
|
|
74
|
+
publish:
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
needs:
|
|
77
|
+
- build-wheels
|
|
78
|
+
- build-sdist
|
|
79
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
80
|
+
permissions:
|
|
81
|
+
id-token: write
|
|
82
|
+
environment:
|
|
83
|
+
name: pypi
|
|
84
|
+
url: https://pypi.org/p/fastbencode
|
|
85
|
+
steps:
|
|
86
|
+
- name: Download distributions
|
|
87
|
+
uses: actions/download-artifact@v4
|
|
88
|
+
with:
|
|
89
|
+
merge-multiple: true
|
|
90
|
+
pattern: artifact-*
|
|
91
|
+
path: dist
|
|
92
|
+
- name: Publish package distributions to PyPI
|
|
93
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -6,7 +6,7 @@ In the interest of fostering an open and welcoming environment, we as
|
|
|
6
6
|
contributors and maintainers pledge to making participation in our project and
|
|
7
7
|
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
8
|
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
|
9
|
-
level of experience, education,
|
|
9
|
+
level of experience, education, socioeconomic status, nationality, personal
|
|
10
10
|
appearance, race, religion, or sexual identity and orientation.
|
|
11
11
|
|
|
12
12
|
## Our Standards
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fastbencode
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Implementation of bencode with optional fast C extensions
|
|
5
|
-
|
|
6
|
-
Maintainer: Breezy Developers
|
|
7
|
-
Maintainer-email: breezy-core@googlegroups.com
|
|
5
|
+
Maintainer-email: Breezy Developers <breezy-core@googlegroups.com>
|
|
8
6
|
License: GPLv2 or later
|
|
7
|
+
Project-URL: Homepage, https://github.com/breezy-team/fastbencode
|
|
9
8
|
Project-URL: GitHub, https://github.com/breezy-team/fastbencode
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
12
9
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
14
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
16
15
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
17
16
|
Classifier: Operating System :: POSIX
|
|
18
17
|
Classifier: Operating System :: Microsoft :: Windows
|
|
19
|
-
Requires-Python: >=3.
|
|
20
|
-
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
21
20
|
License-File: COPYING
|
|
21
|
+
Provides-Extra: cext
|
|
22
|
+
Requires-Dist: cython>=0.29; extra == "cext"
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: ruff==0.11.9; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
22
26
|
|
|
23
27
|
fastbencode
|
|
24
28
|
===========
|
|
@@ -38,6 +42,12 @@ Example:
|
|
|
38
42
|
>>> bdecode(bencode([1, 2, b'a', {b'd': 3}]))
|
|
39
43
|
[1, 2, b'a', {b'd': 3}]
|
|
40
44
|
|
|
45
|
+
The default ``bencode``/``bdecode`` functions just operate on
|
|
46
|
+
bytestrings. Use ``bencode_utf8`` / ``bdecode_utf8`` to
|
|
47
|
+
serialize/deserialize all plain strings as UTF-8 bytestrings.
|
|
48
|
+
Note that for performance reasons, all dictionary keys still have to be
|
|
49
|
+
bytestrings.
|
|
50
|
+
|
|
41
51
|
License
|
|
42
52
|
=======
|
|
43
53
|
fastbencode is available under the GNU GPL, version 2 or later.
|
|
@@ -16,6 +16,12 @@ Example:
|
|
|
16
16
|
>>> bdecode(bencode([1, 2, b'a', {b'd': 3}]))
|
|
17
17
|
[1, 2, b'a', {b'd': 3}]
|
|
18
18
|
|
|
19
|
+
The default ``bencode``/``bdecode`` functions just operate on
|
|
20
|
+
bytestrings. Use ``bencode_utf8`` / ``bdecode_utf8`` to
|
|
21
|
+
serialize/deserialize all plain strings as UTF-8 bytestrings.
|
|
22
|
+
Note that for performance reasons, all dictionary keys still have to be
|
|
23
|
+
bytestrings.
|
|
24
|
+
|
|
19
25
|
License
|
|
20
26
|
=======
|
|
21
27
|
fastbencode is available under the GNU GPL, version 2 or later.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# Copyright (C) 2007, 2009 Canonical Ltd
|
|
2
|
+
# Copyright (C) 2021-2023 Jelmer Vernooij <jelmer@jelmer.uk>
|
|
2
3
|
#
|
|
3
4
|
# This program is free software; you can redistribute it and/or modify
|
|
4
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -14,12 +15,11 @@
|
|
|
14
15
|
# along with this program; if not, write to the Free Software
|
|
15
16
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16
17
|
|
|
17
|
-
"""Wrapper around the bencode cython and python implementation"""
|
|
18
|
+
"""Wrapper around the bencode cython and python implementation."""
|
|
18
19
|
|
|
19
20
|
from typing import Type
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
__version__ = (0, 2)
|
|
22
|
+
__version__ = (0, 3, 2)
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
_extension_load_failures = []
|
|
@@ -49,21 +49,22 @@ def failed_to_load_extension(exception):
|
|
|
49
49
|
exception_str = str(exception)
|
|
50
50
|
if exception_str not in _extension_load_failures:
|
|
51
51
|
import warnings
|
|
52
|
+
|
|
52
53
|
warnings.warn(
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
f"failed to load compiled extension: {exception_str}", UserWarning
|
|
55
|
+
)
|
|
55
56
|
_extension_load_failures.append(exception_str)
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
Bencached: Type
|
|
59
60
|
|
|
60
61
|
try:
|
|
61
|
-
from ._bencode_pyx import bdecode, bdecode_as_tuple, bencode
|
|
62
|
+
from ._bencode_pyx import Bencached, bdecode, bdecode_as_tuple, bencode
|
|
62
63
|
except ImportError as e:
|
|
63
64
|
failed_to_load_extension(e)
|
|
64
65
|
from ._bencode_py import ( # noqa: F401
|
|
66
|
+
Bencached,
|
|
65
67
|
bdecode,
|
|
66
68
|
bdecode_as_tuple,
|
|
67
69
|
bencode,
|
|
68
|
-
|
|
69
|
-
)
|
|
70
|
+
)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# bencode structured encoding
|
|
2
|
+
#
|
|
3
|
+
# Written by Petru Paler
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person
|
|
6
|
+
# obtaining a copy of this software and associated documentation files
|
|
7
|
+
# (the "Software"), to deal in the Software without restriction,
|
|
8
|
+
# including without limitation the rights to use, copy, modify, merge,
|
|
9
|
+
# publish, distribute, sublicense, and/or sell copies of the Software,
|
|
10
|
+
# and to permit persons to whom the Software is furnished to do so,
|
|
11
|
+
# subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be
|
|
14
|
+
# included in all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# Modifications copyright (C) 2008 Canonical Ltd
|
|
17
|
+
# Modifications copyright (C) 2021-2023 Jelmer Vernooij
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
from typing import Callable, Dict, List, Type
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BDecoder:
|
|
24
|
+
def __init__(self, yield_tuples=False, bytestring_encoding=None) -> None:
|
|
25
|
+
"""Constructor.
|
|
26
|
+
|
|
27
|
+
:param yield_tuples: if true, decode "l" elements as tuples rather than
|
|
28
|
+
lists.
|
|
29
|
+
"""
|
|
30
|
+
self.yield_tuples = yield_tuples
|
|
31
|
+
self.bytestring_encoding = bytestring_encoding
|
|
32
|
+
decode_func = {}
|
|
33
|
+
decode_func[b"l"] = self.decode_list
|
|
34
|
+
decode_func[b"d"] = self.decode_dict
|
|
35
|
+
decode_func[b"i"] = self.decode_int
|
|
36
|
+
decode_func[b"0"] = self.decode_bytes
|
|
37
|
+
decode_func[b"1"] = self.decode_bytes
|
|
38
|
+
decode_func[b"2"] = self.decode_bytes
|
|
39
|
+
decode_func[b"3"] = self.decode_bytes
|
|
40
|
+
decode_func[b"4"] = self.decode_bytes
|
|
41
|
+
decode_func[b"5"] = self.decode_bytes
|
|
42
|
+
decode_func[b"6"] = self.decode_bytes
|
|
43
|
+
decode_func[b"7"] = self.decode_bytes
|
|
44
|
+
decode_func[b"8"] = self.decode_bytes
|
|
45
|
+
decode_func[b"9"] = self.decode_bytes
|
|
46
|
+
self.decode_func = decode_func
|
|
47
|
+
|
|
48
|
+
def decode_int(self, x, f):
|
|
49
|
+
f += 1
|
|
50
|
+
newf = x.index(b"e", f)
|
|
51
|
+
n = int(x[f:newf])
|
|
52
|
+
if x[f : f + 2] == b"-0":
|
|
53
|
+
raise ValueError
|
|
54
|
+
elif x[f : f + 1] == b"0" and newf != f + 1:
|
|
55
|
+
raise ValueError
|
|
56
|
+
return (n, newf + 1)
|
|
57
|
+
|
|
58
|
+
def decode_bytes(self, x, f):
|
|
59
|
+
colon = x.index(b":", f)
|
|
60
|
+
n = int(x[f:colon])
|
|
61
|
+
if x[f : f + 1] == b"0" and colon != f + 1:
|
|
62
|
+
raise ValueError
|
|
63
|
+
colon += 1
|
|
64
|
+
d = x[colon : colon + n]
|
|
65
|
+
if self.bytestring_encoding:
|
|
66
|
+
d = d.decode(self.bytestring_encoding)
|
|
67
|
+
return (d, colon + n)
|
|
68
|
+
|
|
69
|
+
def decode_list(self, x, f):
|
|
70
|
+
r, f = [], f + 1
|
|
71
|
+
while x[f : f + 1] != b"e":
|
|
72
|
+
v, f = self.decode_func[x[f : f + 1]](x, f)
|
|
73
|
+
r.append(v)
|
|
74
|
+
if self.yield_tuples:
|
|
75
|
+
r = tuple(r)
|
|
76
|
+
return (r, f + 1)
|
|
77
|
+
|
|
78
|
+
def decode_dict(self, x, f):
|
|
79
|
+
r, f = {}, f + 1
|
|
80
|
+
lastkey = None
|
|
81
|
+
while x[f : f + 1] != b"e":
|
|
82
|
+
k, f = self.decode_bytes(x, f)
|
|
83
|
+
if lastkey is not None and lastkey >= k:
|
|
84
|
+
raise ValueError
|
|
85
|
+
lastkey = k
|
|
86
|
+
r[k], f = self.decode_func[x[f : f + 1]](x, f)
|
|
87
|
+
return (r, f + 1)
|
|
88
|
+
|
|
89
|
+
def bdecode(self, x):
|
|
90
|
+
if not isinstance(x, bytes):
|
|
91
|
+
raise TypeError
|
|
92
|
+
try:
|
|
93
|
+
r, l = self.decode_func[x[:1]](x, 0) # noqa: E741
|
|
94
|
+
except (IndexError, KeyError, OverflowError) as e:
|
|
95
|
+
raise ValueError(str(e))
|
|
96
|
+
if l != len(x): # noqa: E741
|
|
97
|
+
raise ValueError
|
|
98
|
+
return r
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
_decoder = BDecoder()
|
|
102
|
+
bdecode = _decoder.bdecode
|
|
103
|
+
|
|
104
|
+
_tuple_decoder = BDecoder(True)
|
|
105
|
+
bdecode_as_tuple = _tuple_decoder.bdecode
|
|
106
|
+
|
|
107
|
+
_utf8_decoder = BDecoder(bytestring_encoding="utf-8")
|
|
108
|
+
bdecode_utf8 = _utf8_decoder.bdecode
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class Bencached:
|
|
112
|
+
__slots__ = ["bencoded"]
|
|
113
|
+
|
|
114
|
+
def __init__(self, s) -> None:
|
|
115
|
+
self.bencoded = s
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class BEncoder:
|
|
119
|
+
def __init__(self, bytestring_encoding=None):
|
|
120
|
+
self.bytestring_encoding = bytestring_encoding
|
|
121
|
+
self.encode_func: Dict[Type, Callable[[object, List[bytes]], None]] = {
|
|
122
|
+
Bencached: self.encode_bencached,
|
|
123
|
+
int: self.encode_int,
|
|
124
|
+
bytes: self.encode_bytes,
|
|
125
|
+
list: self.encode_list,
|
|
126
|
+
tuple: self.encode_list,
|
|
127
|
+
dict: self.encode_dict,
|
|
128
|
+
bool: self.encode_bool,
|
|
129
|
+
str: self.encode_str,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
def encode_bencached(self, x, r):
|
|
133
|
+
r.append(x.bencoded)
|
|
134
|
+
|
|
135
|
+
def encode_bool(self, x, r):
|
|
136
|
+
self.encode_int(int(x), r)
|
|
137
|
+
|
|
138
|
+
def encode_int(self, x, r):
|
|
139
|
+
r.extend((b"i", int_to_bytes(x), b"e"))
|
|
140
|
+
|
|
141
|
+
def encode_bytes(self, x, r):
|
|
142
|
+
r.extend((int_to_bytes(len(x)), b":", x))
|
|
143
|
+
|
|
144
|
+
def encode_list(self, x, r):
|
|
145
|
+
r.append(b"l")
|
|
146
|
+
for i in x:
|
|
147
|
+
self.encode(i, r)
|
|
148
|
+
r.append(b"e")
|
|
149
|
+
|
|
150
|
+
def encode_dict(self, x, r):
|
|
151
|
+
r.append(b"d")
|
|
152
|
+
ilist = sorted(x.items())
|
|
153
|
+
for k, v in ilist:
|
|
154
|
+
r.extend((int_to_bytes(len(k)), b":", k))
|
|
155
|
+
self.encode(v, r)
|
|
156
|
+
r.append(b"e")
|
|
157
|
+
|
|
158
|
+
def encode_str(self, x, r):
|
|
159
|
+
if self.bytestring_encoding is None:
|
|
160
|
+
raise TypeError(
|
|
161
|
+
"string found but no encoding specified. "
|
|
162
|
+
"Use bencode_utf8 rather bencode?"
|
|
163
|
+
)
|
|
164
|
+
return self.encode_bytes(x.encode(self.bytestring_encoding), r)
|
|
165
|
+
|
|
166
|
+
def encode(self, x, r):
|
|
167
|
+
self.encode_func[type(x)](x, r)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def int_to_bytes(n):
|
|
171
|
+
return b"%d" % n
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def bencode(x):
|
|
175
|
+
r = []
|
|
176
|
+
encoder = BEncoder()
|
|
177
|
+
encoder.encode(x, r)
|
|
178
|
+
return b"".join(r)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def bencode_utf8(x):
|
|
182
|
+
r = []
|
|
183
|
+
encoder = BEncoder(bytestring_encoding="utf-8")
|
|
184
|
+
encoder.encode(x, r)
|
|
185
|
+
return b"".join(r)
|