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.
Files changed (36) hide show
  1. fastbencode-0.3.2/.github/dependabot.yaml +13 -0
  2. fastbencode-0.3.2/.github/workflows/auto-merge.yml +22 -0
  3. fastbencode-0.3.2/.github/workflows/disperse.yml +14 -0
  4. {fastbencode-0.2 → fastbencode-0.3.2}/.github/workflows/pythonpackage.yml +14 -6
  5. fastbencode-0.3.2/.github/workflows/wheels.yaml +93 -0
  6. {fastbencode-0.2 → fastbencode-0.3.2}/.gitignore +1 -0
  7. {fastbencode-0.2 → fastbencode-0.3.2}/CODE_OF_CONDUCT.md +1 -1
  8. {fastbencode-0.2 → fastbencode-0.3.2}/PKG-INFO +19 -9
  9. {fastbencode-0.2 → fastbencode-0.3.2}/README.md +6 -0
  10. fastbencode-0.3.2/disperse.toml +8 -0
  11. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/__init__.py +9 -8
  12. fastbencode-0.3.2/fastbencode/_bencode_py.py +185 -0
  13. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/_bencode_pyx.pyi +1 -3
  14. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/_bencode_pyx.pyx +67 -19
  15. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/tests/__init__.py +3 -3
  16. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/tests/test_bencode.py +201 -108
  17. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/PKG-INFO +19 -9
  18. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/SOURCES.txt +4 -3
  19. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/requires.txt +3 -0
  20. fastbencode-0.3.2/pyproject.toml +74 -0
  21. fastbencode-0.3.2/setup.cfg +4 -0
  22. {fastbencode-0.2 → fastbencode-0.3.2}/setup.py +38 -23
  23. fastbencode-0.2/.github/workflows/disperse.yml +0 -24
  24. fastbencode-0.2/.github/workflows/pythonpublish.yml +0 -58
  25. fastbencode-0.2/disperse.conf +0 -8
  26. fastbencode-0.2/fastbencode/_bencode_py.py +0 -162
  27. fastbencode-0.2/pyproject.toml +0 -3
  28. fastbencode-0.2/setup.cfg +0 -35
  29. {fastbencode-0.2 → fastbencode-0.3.2}/COPYING +0 -0
  30. {fastbencode-0.2 → fastbencode-0.3.2}/MANIFEST.in +0 -0
  31. {fastbencode-0.2 → fastbencode-0.3.2}/SECURITY.md +0 -0
  32. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/_bencode_pyx.h +0 -0
  33. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/py.typed +0 -0
  34. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode/python-compat.h +0 -0
  35. {fastbencode-0.2 → fastbencode-0.3.2}/fastbencode.egg-info/dependency_links.txt +0 -0
  36. {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}}
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: Disperse configuration
3
+
4
+ "on":
5
+ - push
6
+
7
+ jobs:
8
+ build:
9
+
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: jelmer/action-disperse-validate@v2
@@ -9,23 +9,31 @@ jobs:
9
9
  strategy:
10
10
  matrix:
11
11
  os: [ubuntu-latest, macos-latest, windows-latest]
12
- python-version: [3.7, 3.8, 3.9, '3.10', '3.11']
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@v2
16
+ - uses: actions/checkout@v4
17
17
  - name: Set up Python ${{ matrix.python-version }}
18
- uses: actions/setup-python@v2
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 flake8
24
+ pip install -U pip ".[dev]"
25
25
  - name: Style checks
26
26
  run: |
27
- python -m flake8
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,3 +6,4 @@ __pycache__
6
6
  fastbencode.egg-info
7
7
  *.pyc
8
8
  dist
9
+ *~
@@ -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, socio-economic status, nationality, personal
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
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
- Home-page: https://github.com/breezy-team/fastbencode
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.7
20
- Provides-Extra: cext
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.
@@ -0,0 +1,8 @@
1
+ tag-name = "v$VERSION"
2
+ verify-command = "python3 -m unittest fastbencode.tests.test_suite"
3
+ tarball-location = []
4
+ release-timeout = 5
5
+
6
+ [[update_version]]
7
+ path = "fastbencode/__init__.py"
8
+ new-line = "__version__ = $TUPLED_VERSION"
@@ -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
- 'failed to load compiled extension: %s' % exception_str,
54
- UserWarning)
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, Bencached
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
- Bencached,
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)
@@ -1,7 +1,5 @@
1
-
2
1
  def bdecode(bytes) -> object: ...
3
2
  def bdecode_as_tuple(bytes) -> object: ...
4
3
  def bencode(object) -> bytes: ...
5
4
 
6
-
7
- class Bencached(object): ...
5
+ class Bencached: ...