summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Shadura <andrew.shadura@collabora.co.uk>2022-05-17 11:43:37 +0200
committerAndrej Shadura <andrew.shadura@collabora.co.uk>2022-05-17 11:43:37 +0200
commit5f97349d6a81a0e59e837093290cb43aee708270 (patch)
treeb0b4e2f63deaafb3d06e0cdbf2f0c2bf82d75721
parent35f29cba23fc56f87acaff1741ec8d921db0c59f (diff)
New upstream version 2.1.0
-rw-r--r--.flake83
-rw-r--r--.github/workflows/continuous-integration.yml48
-rw-r--r--.gitignore4
-rw-r--r--.travis.yml15
-rw-r--r--MANIFEST.in4
-rw-r--r--README.rst16
-rw-r--r--pyproject.toml24
-rwxr-xr-xsetup.py49
-rw-r--r--test_unpaddedbase64.py41
-rw-r--r--tests/__init__.py0
-rw-r--r--tests/test_unpaddedbase64.py41
-rw-r--r--tox.ini27
-rw-r--r--unpaddedbase64/__init__.py (renamed from unpaddedbase64.py)25
-rw-r--r--unpaddedbase64/py.typed0
14 files changed, 134 insertions, 163 deletions
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..e4e5eb3
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 88
+extend-ignore = E203, W503
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 0000000..91426fe
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,48 @@
+name: Continuous Integration
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install flake8 black mypy
+ - name: Lint with flake8
+ run: |
+ flake8 unpaddedbase64/ tests/
+ - name: Lint with black
+ run: |
+ black --check --diff unpaddedbase64/ tests/
+ - name: Lint with mypy
+ run: |
+ mypy --strict unpaddedbase64/ tests/
+
+ test:
+ needs: lint
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ['3.x', '3.6', 'pypy-3.6']
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Test with unittest
+ run: |
+ python -m unittest --verbose
diff --git a/.gitignore b/.gitignore
index 25ccf99..fff554a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,5 @@
.coverage
.tox/
__pycache__/
-unpaddedbase64.egg-info/
-unpaddedbase64.pyc
-build/
dist/
+poetry.lock
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index b10c59a..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-language: python
-env:
-- TOXENV=packaging
-- TOXENV=pep8
-- TOXENV=py3pep8
-- TOXENV=py27
-- TOXENV=py33
-- TOXENV=py34
-- TOXENV=pypy
-
-install:
-- pip install tox
-
-script:
-- tox
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 6429bd5..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,4 +0,0 @@
-include *.in
-include *.py
-include LICENSE
-include tox.ini
diff --git a/README.rst b/README.rst
index 5796b7b..9c211d5 100644
--- a/README.rst
+++ b/README.rst
@@ -1,18 +1,10 @@
Unpadded Base64
===============
-.. image:: https://img.shields.io/pypi/v/unpaddedbase64.svg
- :target: https://pypi.python.org/pypi/unpaddedbase64/
- :alt: Latest Version
-
-.. image:: https://img.shields.io/travis/matrix-org/python-unpaddedbase64.svg
- :target: https://travis-ci.org/matrix-org/python-unpaddedbase64
-
Encode and decode Base64 without "=" padding.
`RFC 4648`_ specifies that Base64 should be padded to a multiple of 4 bytes
-using "=" characters. However this conveys no benefit so many protocols choose
-to use Base64 without the "=" padding.
+using "=" characters. However many protocols choose to omit the "=" padding.
.. _`RFC 4648`: https://tools.ietf.org/html/rfc4648
@@ -21,7 +13,7 @@ Installing
.. code:: bash
- pip install unpaddedbase64
+ python3 -m pip install unpaddedbase64
Using
-----
@@ -29,5 +21,5 @@ Using
.. code:: python
import unpaddedbase64
- assert (unpaddedbase64.encode_base64(b'\x00')) == u'AA'
- assert (unpaddedbase64.decode_base64(u'AA')) == b'\x00'
+ assert (unpaddedbase64.encode_base64(b'\x00')) == 'AA'
+ assert (unpaddedbase64.decode_base64('AA')) == b'\x00'
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..eed1454
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,24 @@
+[build-system]
+requires = ["poetry_core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.poetry]
+name = "unpaddedbase64"
+version = "2.1.0"
+description = 'Encode and decode Base64 without "=" padding'
+license = "Apache-2.0"
+authors = [ "The Matrix.org Foundation C.I.C." ]
+readme = "README.rst"
+homepage = "https://github.com/matrix-org/python-unpaddedbase64"
+keywords = ["base64"]
+
+[tool.poetry.urls]
+"Issue Tracker" = "https://github.com/matrix-org/python-unpaddedbase64/issues"
+
+[tool.poetry.dependencies]
+python = "^3.6"
+
+[tool.poetry.dev-dependencies]
+black = "*"
+flake8 = "*"
+mypy = "*"
diff --git a/setup.py b/setup.py
deleted file mode 100755
index 6d7ee74..0000000
--- a/setup.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2015 OpenMarket Ltd
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from setuptools import setup
-from codecs import open
-import os
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-
-def read_file(path_segments):
- """Read a UTF-8 file from the package. Takes a list of strings to join to
- make the path"""
- file_path = os.path.join(here, *path_segments)
- with open(file_path, encoding="utf-8") as f:
- return f.read()
-
-
-def exec_file(path_segments, name):
- """Extract a constant from a python file by looking for a line defining
- the constant and executing it."""
- result = {}
- code = read_file(path_segments)
- lines = [line for line in code.split('\n') if line.startswith(name)]
- exec("\n".join(lines), result)
- return result[name]
-
-
-setup(
- name="unpaddedbase64",
- version=exec_file(("unpaddedbase64.py",), "__version__"),
- py_modules=["unpaddedbase64"],
- description="Unpadded Base64",
- long_description=read_file(("README.rst",)),
- keywords="base64",
-)
diff --git a/test_unpaddedbase64.py b/test_unpaddedbase64.py
deleted file mode 100644
index a3c8463..0000000
--- a/test_unpaddedbase64.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2015 OpenMarket Ltd
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from unpaddedbase64 import encode_base64, decode_base64
-import unittest
-
-
-class TestUnpaddedBase64(unittest.TestCase):
-
- def test_encode(self):
- self.assertEqual(encode_base64(b''), u'')
- self.assertEqual(encode_base64(b'\x00'), u'AA')
- self.assertEqual(encode_base64(b'\x00\x00'), u'AAA')
- self.assertEqual(encode_base64(b'\x00\x00\x00'), u'AAAA')
-
- def test_decode(self):
- self.assertEqual(decode_base64(u''), b'')
- self.assertEqual(decode_base64(u'AA'), b'\x00')
- self.assertEqual(decode_base64(u'AAA'), b'\x00\x00')
- self.assertEqual(decode_base64(u'AAAA'), b'\x00\x00\x00')
- with self.assertRaises(Exception):
- decode_base64(u'A')
-
- def test_encode_urlunsafe_chars(self):
- self.assertEqual(encode_base64(b'\xff\xe6\x9a'), u'/+aa')
- self.assertEqual(encode_base64(b'\xff\xe6\x9a', True), u'_-aa')
-
- def test_decode_urlunsafe_chars(self):
- self.assertEqual(decode_base64(u'/+aa'), b'\xff\xe6\x9a')
- self.assertEqual(decode_base64(u'_-aa'), b'\xff\xe6\x9a')
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/__init__.py
diff --git a/tests/test_unpaddedbase64.py b/tests/test_unpaddedbase64.py
new file mode 100644
index 0000000..90d21a0
--- /dev/null
+++ b/tests/test_unpaddedbase64.py
@@ -0,0 +1,41 @@
+# Copyright 2015 OpenMarket Ltd
+# Copyright 2021 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from unpaddedbase64 import encode_base64, decode_base64
+import unittest
+
+
+class TestUnpaddedBase64(unittest.TestCase):
+ def test_encode(self) -> None:
+ self.assertEqual(encode_base64(b""), "")
+ self.assertEqual(encode_base64(b"\x00"), "AA")
+ self.assertEqual(encode_base64(b"\x00\x00"), "AAA")
+ self.assertEqual(encode_base64(b"\x00\x00\x00"), "AAAA")
+
+ def test_decode(self) -> None:
+ self.assertEqual(decode_base64(""), b"")
+ self.assertEqual(decode_base64("AA"), b"\x00")
+ self.assertEqual(decode_base64("AAA"), b"\x00\x00")
+ self.assertEqual(decode_base64("AAAA"), b"\x00\x00\x00")
+ with self.assertRaises(Exception):
+ decode_base64("A")
+
+ def test_encode_urlunsafe_chars(self) -> None:
+ self.assertEqual(encode_base64(b"\xff\xe6\x9a"), "/+aa")
+ self.assertEqual(encode_base64(b"\xff\xe6\x9a", True), "_-aa")
+
+ def test_decode_urlunsafe_chars(self) -> None:
+ self.assertEqual(decode_base64("/+aa"), b"\xff\xe6\x9a")
+ self.assertEqual(decode_base64("_-aa"), b"\xff\xe6\x9a")
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index c368ee7..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,27 +0,0 @@
-[tox]
-envlist = packaging, pep8, py3pep8, py27, py33, py34, pypy
-
-[testenv]
-deps =
- coverage
- pytest
-commands =
- coverage run --source unpaddedbase64 -m pytest
- coverage report -m --fail-under 100
-
-[testenv:packaging]
-deps =
- check-manifest
-commands = check-manifest
-
-[testenv:pep8]
-basepython = python2.7
-deps =
- flake8
-commands = flake8 .
-
-[testenv:py3pep8]
-basepython = python3.4
-deps =
- flake8
-commands = flake8 .
diff --git a/unpaddedbase64.py b/unpaddedbase64/__init__.py
index 245697c..9f45bee 100644
--- a/unpaddedbase64.py
+++ b/unpaddedbase64/__init__.py
@@ -1,4 +1,5 @@
# Copyright 2014, 2015 OpenMarket Ltd
+# Copyright 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,27 +15,27 @@
import base64
-__version__ = "1.1.0"
+def encode_base64(input_bytes: bytes, urlsafe: bool = False) -> str:
+ """Encode bytes as an unpadded base64 string."""
-def encode_base64(input_bytes, urlsafe=False):
- """Encode bytes as a base64 string without any padding."""
+ if urlsafe:
+ encode = base64.urlsafe_b64encode
+ else:
+ encode = base64.b64encode
- encode = base64.urlsafe_b64encode if urlsafe else base64.b64encode
output_bytes = encode(input_bytes)
output_string = output_bytes.decode("ascii")
- return output_string.rstrip(u"=")
+ return output_string.rstrip("=")
-def decode_base64(input_string):
- """Decode a base64 string to bytes inferring padding from the length of the
- string."""
+def decode_base64(input_string: str) -> bytes:
+ """Decode an unpadded standard or urlsafe base64 string to bytes."""
input_bytes = input_string.encode("ascii")
input_len = len(input_bytes)
padding = b"=" * (3 - ((input_len + 3) % 4))
- decode = base64.b64decode
- if u'-' in input_string or u'_' in input_string:
- decode = base64.urlsafe_b64decode
- output_bytes = decode(input_bytes + padding)
+
+ # Passing altchars here allows decoding both standard and urlsafe base64
+ output_bytes = base64.b64decode(input_bytes + padding, altchars=b"-_")
return output_bytes
diff --git a/unpaddedbase64/py.typed b/unpaddedbase64/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/unpaddedbase64/py.typed