pybase64 1.5.0__cp313-cp313-android_24_arm64_v8a.whl
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.
- pybase64/__init__.py +128 -0
- pybase64/__main__.py +318 -0
- pybase64/_fallback.py +399 -0
- pybase64/_license.py +61 -0
- pybase64/_license.pyi +1 -0
- pybase64/_pybase64.cpython-313-aarch64-linux-android.so +0 -0
- pybase64/_pybase64.pyi +43 -0
- pybase64/_typing.py +44 -0
- pybase64/_unspecified.py +8 -0
- pybase64/_version.py +3 -0
- pybase64/py.typed +0 -0
- pybase64-1.5.0.dist-info/METADATA +353 -0
- pybase64-1.5.0.dist-info/RECORD +19 -0
- pybase64-1.5.0.dist-info/WHEEL +5 -0
- pybase64-1.5.0.dist-info/entry_points.txt +2 -0
- pybase64-1.5.0.dist-info/licenses/LICENSE +25 -0
- pybase64-1.5.0.dist-info/licenses/base64/LICENSE +28 -0
- pybase64-1.5.0.dist-info/sboms/pybase64.cdx.json +1 -0
- pybase64-1.5.0.dist-info/top_level.txt +1 -0
pybase64/__init__.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
__lazy_modules__ = ["pybase64._license"]
|
|
4
|
+
|
|
5
|
+
from pybase64._license import _license
|
|
6
|
+
from pybase64._version import _version
|
|
7
|
+
|
|
8
|
+
TYPE_CHECKING = False
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pybase64._typing import Buffer
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from pybase64._pybase64 import (
|
|
14
|
+
_get_simd_flags_compile, # noqa: F401
|
|
15
|
+
_get_simd_flags_runtime, # noqa: F401
|
|
16
|
+
_get_simd_name,
|
|
17
|
+
_get_simd_path,
|
|
18
|
+
_set_simd_path, # noqa: F401
|
|
19
|
+
b64decode,
|
|
20
|
+
b64decode_as_bytearray,
|
|
21
|
+
b64encode,
|
|
22
|
+
b64encode_as_string,
|
|
23
|
+
encodebytes,
|
|
24
|
+
)
|
|
25
|
+
except ImportError:
|
|
26
|
+
from pybase64._fallback import (
|
|
27
|
+
_get_simd_name,
|
|
28
|
+
_get_simd_path,
|
|
29
|
+
b64decode,
|
|
30
|
+
b64decode_as_bytearray,
|
|
31
|
+
b64encode,
|
|
32
|
+
b64encode_as_string,
|
|
33
|
+
encodebytes,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = (
|
|
38
|
+
"b64decode",
|
|
39
|
+
"b64decode_as_bytearray",
|
|
40
|
+
"b64encode",
|
|
41
|
+
"b64encode_as_string",
|
|
42
|
+
"encodebytes",
|
|
43
|
+
"standard_b64decode",
|
|
44
|
+
"standard_b64encode",
|
|
45
|
+
"urlsafe_b64decode",
|
|
46
|
+
"urlsafe_b64encode",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
__version__ = _version
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_license_text() -> str:
|
|
53
|
+
"""Return pybase64 license information as a :class:`str` object.
|
|
54
|
+
|
|
55
|
+
The result includes libbase64 license information as well.
|
|
56
|
+
"""
|
|
57
|
+
return _license
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_version() -> str:
|
|
61
|
+
"""Return pybase64 version as a :class:`str` object.
|
|
62
|
+
|
|
63
|
+
The result reports if the C extension is used or not.
|
|
64
|
+
e.g. `1.0.0 (C extension active - AVX2)`
|
|
65
|
+
"""
|
|
66
|
+
simd_name = _get_simd_name(_get_simd_path())
|
|
67
|
+
if simd_name != "fallback":
|
|
68
|
+
return f"{__version__} (C extension active - {simd_name})"
|
|
69
|
+
return f"{__version__} (C extension inactive)"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def standard_b64encode(s: Buffer) -> bytes:
|
|
73
|
+
"""Encode bytes using the standard Base64 alphabet.
|
|
74
|
+
|
|
75
|
+
Argument ``s`` is a :term:`bytes-like object` to encode.
|
|
76
|
+
|
|
77
|
+
The result is returned as a :class:`bytes` object.
|
|
78
|
+
"""
|
|
79
|
+
return b64encode(s)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def standard_b64decode(s: str | Buffer) -> bytes:
|
|
83
|
+
"""Decode bytes encoded with the standard Base64 alphabet.
|
|
84
|
+
|
|
85
|
+
Argument ``s`` is a :term:`bytes-like object` or ASCII string to
|
|
86
|
+
decode.
|
|
87
|
+
|
|
88
|
+
The result is returned as a :class:`bytes` object.
|
|
89
|
+
|
|
90
|
+
A :exc:`binascii.Error` is raised if the input is incorrectly padded.
|
|
91
|
+
|
|
92
|
+
Characters that are not in the standard alphabet are discarded prior
|
|
93
|
+
to the padding check.
|
|
94
|
+
"""
|
|
95
|
+
return b64decode(s)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def urlsafe_b64encode(s: Buffer, *, padded: bool = True) -> bytes:
|
|
99
|
+
"""Encode bytes using the URL- and filesystem-safe Base64 alphabet.
|
|
100
|
+
|
|
101
|
+
Argument ``s`` is a :term:`bytes-like object` to encode.
|
|
102
|
+
|
|
103
|
+
The result is returned as a :class:`bytes` object.
|
|
104
|
+
|
|
105
|
+
The alphabet uses '-' instead of '+' and '_' instead of '/'.
|
|
106
|
+
|
|
107
|
+
The result can still contain ``=`` if ``padded`` is true (default).
|
|
108
|
+
"""
|
|
109
|
+
return b64encode(s, b"-_", padded=padded)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def urlsafe_b64decode(s: str | Buffer, *, padded: bool = False) -> bytes:
|
|
113
|
+
"""Decode bytes using the URL- and filesystem-safe Base64 alphabet.
|
|
114
|
+
|
|
115
|
+
Argument ``s`` is a :term:`bytes-like object` or ASCII string to
|
|
116
|
+
decode.
|
|
117
|
+
|
|
118
|
+
The result is returned as a :class:`bytes` object.
|
|
119
|
+
|
|
120
|
+
If ``padded`` is ``False``, padding in the input is not required.
|
|
121
|
+
Otherwise, a :exc:`binascii.Error` is raised if the input is incorrectly padded.
|
|
122
|
+
|
|
123
|
+
Characters that are not in the URL-safe base-64 alphabet, and are not
|
|
124
|
+
a plus '+' or slash '/', are discarded prior to the padding check.
|
|
125
|
+
|
|
126
|
+
The alphabet uses '-' instead of '+' and '_' instead of '/'.
|
|
127
|
+
"""
|
|
128
|
+
return b64decode(s, b"-_", padded=padded)
|
pybase64/__main__.py
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
__lazy_modules__ = ["base64", "pathlib", "timeit"]
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import base64
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from timeit import default_timer as timer
|
|
10
|
+
|
|
11
|
+
import pybase64
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Sequence
|
|
16
|
+
from types import ModuleType
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def bench_one(
|
|
21
|
+
duration: float,
|
|
22
|
+
data: bytes,
|
|
23
|
+
module: ModuleType,
|
|
24
|
+
altchars: bytes | None,
|
|
25
|
+
kwargs: dict[str, bool | bytes],
|
|
26
|
+
) -> None:
|
|
27
|
+
duration = duration / 2.0
|
|
28
|
+
combination_unsupported = all(
|
|
29
|
+
[
|
|
30
|
+
module is base64,
|
|
31
|
+
"ignorechars" in kwargs or "padded" in kwargs,
|
|
32
|
+
sys.version_info < (3, 15),
|
|
33
|
+
],
|
|
34
|
+
)
|
|
35
|
+
validate = kwargs["validate"]
|
|
36
|
+
if validate and altchars is None and "ignorechars" not in kwargs and "padded" not in kwargs:
|
|
37
|
+
encbytes = module.encodebytes
|
|
38
|
+
number = 0
|
|
39
|
+
time = timer()
|
|
40
|
+
while True:
|
|
41
|
+
encodedcontent = encbytes(data)
|
|
42
|
+
number += 1
|
|
43
|
+
if timer() - time > duration:
|
|
44
|
+
break
|
|
45
|
+
iter_ = number
|
|
46
|
+
time = timer()
|
|
47
|
+
while iter_ > 0:
|
|
48
|
+
encodedcontent = encbytes(data)
|
|
49
|
+
iter_ -= 1
|
|
50
|
+
time = timer() - time
|
|
51
|
+
print(
|
|
52
|
+
"{:<24s} {:5.0f} MB/s ({:,d} bytes -> {:,d} bytes)".format(
|
|
53
|
+
module.__name__ + "." + encbytes.__name__ + ":",
|
|
54
|
+
((number * len(data)) / (1024.0 * 1024.0)) / time,
|
|
55
|
+
len(data),
|
|
56
|
+
len(encodedcontent),
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if validate and "ignorechars" not in kwargs:
|
|
61
|
+
enc = module.b64encode
|
|
62
|
+
if combination_unsupported:
|
|
63
|
+
print("{:<24s} N/A".format(module.__name__ + "." + enc.__name__ + ":"))
|
|
64
|
+
else:
|
|
65
|
+
number = 0
|
|
66
|
+
time = timer()
|
|
67
|
+
while True:
|
|
68
|
+
encodedcontent = enc(data, altchars=altchars)
|
|
69
|
+
number += 1
|
|
70
|
+
if timer() - time > duration:
|
|
71
|
+
break
|
|
72
|
+
iter_ = number
|
|
73
|
+
time = timer()
|
|
74
|
+
while iter_ > 0:
|
|
75
|
+
encodedcontent = enc(data, altchars=altchars)
|
|
76
|
+
iter_ -= 1
|
|
77
|
+
time = timer() - time
|
|
78
|
+
print(
|
|
79
|
+
"{:<24s} {:5.0f} MB/s ({:,d} bytes -> {:,d} bytes)".format(
|
|
80
|
+
module.__name__ + "." + enc.__name__ + ":",
|
|
81
|
+
((number * len(data)) / (1024.0 * 1024.0)) / time,
|
|
82
|
+
len(data),
|
|
83
|
+
len(encodedcontent),
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if kwargs.get("ignorechars") == b"\n" or not validate:
|
|
88
|
+
encodedcontent = pybase64.b64encode(data, altchars=altchars, wrapcol=76)
|
|
89
|
+
else:
|
|
90
|
+
encodedcontent = pybase64.b64encode(data, altchars=altchars)
|
|
91
|
+
dec = module.b64decode
|
|
92
|
+
if combination_unsupported:
|
|
93
|
+
print("{:<24s} N/A".format(module.__name__ + "." + dec.__name__ + ":"))
|
|
94
|
+
else:
|
|
95
|
+
number = 0
|
|
96
|
+
time = timer()
|
|
97
|
+
while True:
|
|
98
|
+
decodedcontent = dec(encodedcontent, altchars=altchars, **kwargs)
|
|
99
|
+
number += 1
|
|
100
|
+
if timer() - time > duration:
|
|
101
|
+
break
|
|
102
|
+
iter_ = number
|
|
103
|
+
time = timer()
|
|
104
|
+
while iter_ > 0:
|
|
105
|
+
decodedcontent = dec(encodedcontent, altchars=altchars, **kwargs)
|
|
106
|
+
iter_ -= 1
|
|
107
|
+
time = timer() - time
|
|
108
|
+
print(
|
|
109
|
+
"{:<24s} {:5.0f} MB/s ({:,d} bytes -> {:,d} bytes)".format(
|
|
110
|
+
module.__name__ + "." + dec.__name__ + ":",
|
|
111
|
+
((number * len(data)) / (1024.0 * 1024.0)) / time,
|
|
112
|
+
len(encodedcontent),
|
|
113
|
+
len(data),
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
assert decodedcontent == data # noqa: S101
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def readall(file: str) -> bytes:
|
|
120
|
+
if file == "-":
|
|
121
|
+
return sys.stdin.buffer.read()
|
|
122
|
+
return Path(file).read_bytes()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def writeall(file: str, data: bytes) -> None:
|
|
126
|
+
if file == "-":
|
|
127
|
+
sys.stdout.buffer.write(data)
|
|
128
|
+
else:
|
|
129
|
+
Path(file).write_bytes(data)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def benchmark(*, duration: float, input: str) -> None: # noqa: A002
|
|
133
|
+
print(__package__ + " " + pybase64.get_version())
|
|
134
|
+
data = readall(input)
|
|
135
|
+
for altchars in [None, b"-_"]:
|
|
136
|
+
for validate in [True, False]:
|
|
137
|
+
for ignorechars in [None, b"", b"\n"]:
|
|
138
|
+
for padded in [True, False]:
|
|
139
|
+
# skip redundant combinations
|
|
140
|
+
if altchars is None and validate and padded and ignorechars == b"":
|
|
141
|
+
# same as "altchars is None and validate and padded and ignorechars is None"
|
|
142
|
+
# when altchars is not None, the alphabet translation differs
|
|
143
|
+
continue
|
|
144
|
+
kwargs: dict[str, bool | bytes] = {"validate": validate}
|
|
145
|
+
if ignorechars is not None:
|
|
146
|
+
if not validate:
|
|
147
|
+
continue
|
|
148
|
+
kwargs["ignorechars"] = ignorechars
|
|
149
|
+
if not padded:
|
|
150
|
+
kwargs["padded"] = padded
|
|
151
|
+
title = f"bench: altchars={altchars!r:s}"
|
|
152
|
+
if ignorechars is None:
|
|
153
|
+
title = f"{title}, validate={validate!r:s}"
|
|
154
|
+
else:
|
|
155
|
+
title = f"{title}, ignorechars={ignorechars!r:s}"
|
|
156
|
+
print(f"{title}, padded={padded!r:s}")
|
|
157
|
+
for module in [pybase64, base64]:
|
|
158
|
+
bench_one(duration, data, module, altchars, kwargs)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def encode(*, input: str, altchars: bytes | None, output: str) -> None: # noqa: A002
|
|
162
|
+
data = readall(input)
|
|
163
|
+
data = pybase64.b64encode(data, altchars)
|
|
164
|
+
writeall(output, data)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def decode(*, input: str, altchars: bytes | None, validate: bool, output: str) -> None: # noqa: A002
|
|
168
|
+
data = readall(input)
|
|
169
|
+
data = pybase64.b64decode(data, altchars, validate)
|
|
170
|
+
writeall(output, data)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class LicenseAction(argparse.Action):
|
|
174
|
+
def __init__(
|
|
175
|
+
self,
|
|
176
|
+
option_strings: Sequence[str],
|
|
177
|
+
dest: str,
|
|
178
|
+
license: str | None = None, # noqa: A002
|
|
179
|
+
help: str | None = "show license information and exit", # noqa: A002
|
|
180
|
+
) -> None:
|
|
181
|
+
super().__init__(
|
|
182
|
+
option_strings=option_strings,
|
|
183
|
+
dest=dest,
|
|
184
|
+
default=argparse.SUPPRESS,
|
|
185
|
+
nargs=0,
|
|
186
|
+
help=help,
|
|
187
|
+
)
|
|
188
|
+
self.license = license
|
|
189
|
+
|
|
190
|
+
def __call__(
|
|
191
|
+
self,
|
|
192
|
+
parser: argparse.ArgumentParser,
|
|
193
|
+
namespace: argparse.Namespace, # noqa: ARG002
|
|
194
|
+
values: str | Sequence[Any] | None, # noqa: ARG002
|
|
195
|
+
option_string: str | None = None, # noqa: ARG002
|
|
196
|
+
) -> None:
|
|
197
|
+
print(self.license)
|
|
198
|
+
parser.exit()
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def check_file(value: str, *, is_input: bool) -> str:
|
|
202
|
+
if value == "-":
|
|
203
|
+
return value
|
|
204
|
+
path = Path(value)
|
|
205
|
+
if is_input:
|
|
206
|
+
return str(path.resolve(strict=True))
|
|
207
|
+
return str(path.parent.resolve(strict=True) / path.name)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def main(argv: Sequence[str] | None = None) -> None:
|
|
211
|
+
# main parser
|
|
212
|
+
parser = argparse.ArgumentParser(
|
|
213
|
+
prog=__package__,
|
|
214
|
+
description=__package__ + " command-line tool.",
|
|
215
|
+
)
|
|
216
|
+
parser.add_argument(
|
|
217
|
+
"-V",
|
|
218
|
+
"--version",
|
|
219
|
+
action="version",
|
|
220
|
+
version=__package__ + " " + pybase64.get_version(),
|
|
221
|
+
)
|
|
222
|
+
parser.add_argument("--license", action=LicenseAction, license=pybase64.get_license_text())
|
|
223
|
+
# create sub-parsers
|
|
224
|
+
subparsers = parser.add_subparsers(help="tool help")
|
|
225
|
+
# benchmark parser
|
|
226
|
+
benchmark_parser = subparsers.add_parser("benchmark", help="-h for usage")
|
|
227
|
+
benchmark_parser.add_argument(
|
|
228
|
+
"-d",
|
|
229
|
+
"--duration",
|
|
230
|
+
metavar="D",
|
|
231
|
+
dest="duration",
|
|
232
|
+
type=float,
|
|
233
|
+
default=1.0,
|
|
234
|
+
help="expected duration for a single encode or decode test",
|
|
235
|
+
)
|
|
236
|
+
benchmark_parser.register("type", "input file", lambda s: check_file(s, is_input=True))
|
|
237
|
+
benchmark_parser.add_argument(
|
|
238
|
+
"input",
|
|
239
|
+
type="input file",
|
|
240
|
+
help="input file used for the benchmark",
|
|
241
|
+
)
|
|
242
|
+
benchmark_parser.set_defaults(func=benchmark)
|
|
243
|
+
# encode parser
|
|
244
|
+
encode_parser = subparsers.add_parser("encode", help="-h for usage")
|
|
245
|
+
encode_parser.register("type", "input file", lambda s: check_file(s, is_input=True))
|
|
246
|
+
encode_parser.register("type", "output file", lambda s: check_file(s, is_input=False))
|
|
247
|
+
encode_parser.add_argument("input", type="input file", help="input file to be encoded")
|
|
248
|
+
group = encode_parser.add_mutually_exclusive_group()
|
|
249
|
+
group.add_argument(
|
|
250
|
+
"-u",
|
|
251
|
+
"--url",
|
|
252
|
+
action="store_const",
|
|
253
|
+
const=b"-_",
|
|
254
|
+
dest="altchars",
|
|
255
|
+
help="use URL encoding",
|
|
256
|
+
)
|
|
257
|
+
group.add_argument(
|
|
258
|
+
"-a",
|
|
259
|
+
"--altchars",
|
|
260
|
+
dest="altchars",
|
|
261
|
+
help="use alternative characters for encoding",
|
|
262
|
+
)
|
|
263
|
+
encode_parser.add_argument(
|
|
264
|
+
"-o",
|
|
265
|
+
"--output",
|
|
266
|
+
dest="output",
|
|
267
|
+
type="output file",
|
|
268
|
+
default="-",
|
|
269
|
+
help="encoded output file (default to stdout)",
|
|
270
|
+
)
|
|
271
|
+
encode_parser.set_defaults(func=encode)
|
|
272
|
+
# decode parser
|
|
273
|
+
decode_parser = subparsers.add_parser("decode", help="-h for usage")
|
|
274
|
+
decode_parser.register("type", "input file", lambda s: check_file(s, is_input=True))
|
|
275
|
+
decode_parser.register("type", "output file", lambda s: check_file(s, is_input=False))
|
|
276
|
+
decode_parser.add_argument("input", type="input file", help="input file to be decoded")
|
|
277
|
+
group = decode_parser.add_mutually_exclusive_group()
|
|
278
|
+
group.add_argument(
|
|
279
|
+
"-u",
|
|
280
|
+
"--url",
|
|
281
|
+
action="store_const",
|
|
282
|
+
const=b"-_",
|
|
283
|
+
dest="altchars",
|
|
284
|
+
help="use URL decoding",
|
|
285
|
+
)
|
|
286
|
+
group.add_argument(
|
|
287
|
+
"-a",
|
|
288
|
+
"--altchars",
|
|
289
|
+
dest="altchars",
|
|
290
|
+
help="use alternative characters for decoding",
|
|
291
|
+
)
|
|
292
|
+
decode_parser.add_argument(
|
|
293
|
+
"-o",
|
|
294
|
+
"--output",
|
|
295
|
+
dest="output",
|
|
296
|
+
type="output file",
|
|
297
|
+
default="-",
|
|
298
|
+
help="decoded output file (default to stdout)",
|
|
299
|
+
)
|
|
300
|
+
decode_parser.add_argument(
|
|
301
|
+
"--no-validation",
|
|
302
|
+
dest="validate",
|
|
303
|
+
action="store_false",
|
|
304
|
+
help="disable validation of the input data",
|
|
305
|
+
)
|
|
306
|
+
decode_parser.set_defaults(func=decode)
|
|
307
|
+
# ready, parse
|
|
308
|
+
if argv is None:
|
|
309
|
+
argv = sys.argv[1:]
|
|
310
|
+
if len(argv) == 0:
|
|
311
|
+
argv = ["-h"]
|
|
312
|
+
args = vars(parser.parse_args(args=argv))
|
|
313
|
+
func = args.pop("func")
|
|
314
|
+
func(**args)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
if __name__ == "__main__":
|
|
318
|
+
main()
|