Skip to content

Commit

Permalink
Remove six dependency (#81)
Browse files Browse the repository at this point in the history
* remove top level six dependency

* s/six.binary_type/bytes/g

* 's/six.string_types/str/g'

* remove six.int2byte usage

* 's/six.iteritems(\([^)]*\))/\1.items()/g'

This sed command required a little cleanup

* replace add_metaclass

* 's/six.iterkeys(\([^)]*\))/\1.keys()/g'

This required some manual cleanup

* s/six.itervalues(\([^)]*\))/\1.values()/g

* remove six.PY2 usage

* remove print_ usage

* /import six/d

* delete blank line

* add changelog entry

* add six dependency back to constraints

* fix new uses of six

* fix bad merge
  • Loading branch information
bmw committed Feb 17, 2021
1 parent 70323f9 commit 948ac09
Show file tree
Hide file tree
Showing 11 changed files with 49 additions and 58 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
@@ -1,6 +1,10 @@
Changelog
=========

1.8.0 (master)
-----------------
* Removed dependency on six.

1.7.0 (2021-02-11)
------------------

Expand Down
1 change: 0 additions & 1 deletion setup.py
Expand Up @@ -14,7 +14,6 @@
# For pkg_resources. >=1.0 so pip resolves it to a version cryptography
# will tolerate; see #2599:
'setuptools>=1.0',
'six>=1.9.0', # needed for python_2_unicode_compatible
]

testing_requires = [
Expand Down
10 changes: 4 additions & 6 deletions src/josepy/b64.py
Expand Up @@ -12,8 +12,6 @@
"""
import base64

import six


def b64encode(data):
"""JOSE Base64 encode.
Expand All @@ -27,8 +25,8 @@ def b64encode(data):
:raises TypeError: if ``data`` is of incorrect type
"""
if not isinstance(data, six.binary_type):
raise TypeError('argument should be {0}'.format(six.binary_type))
if not isinstance(data, bytes):
raise TypeError('argument should be bytes')
return base64.urlsafe_b64encode(data).rstrip(b'=')


Expand All @@ -46,13 +44,13 @@ def b64decode(data):
:raises ValueError: if input is unicode with non-ASCII characters
"""
if isinstance(data, six.string_types):
if isinstance(data, str):
try:
data = data.encode('ascii')
except UnicodeEncodeError:
raise ValueError(
'unicode argument should contain only ASCII characters')
elif not isinstance(data, six.binary_type):
elif not isinstance(data, bytes):
raise TypeError('argument should be a str or unicode')

return base64.urlsafe_b64decode(data + b'=' * (4 - (len(data) % 4)))
15 changes: 7 additions & 8 deletions src/josepy/b64_test.py
@@ -1,7 +1,6 @@
"""Tests for josepy.b64."""
import unittest

import six

# https://en.wikipedia.org/wiki/Base64#Examples
B64_PADDING_EXAMPLES = {
Expand All @@ -14,8 +13,8 @@


B64_URL_UNSAFE_EXAMPLES = {
six.int2byte(251) + six.int2byte(239): b'--8',
six.int2byte(255) * 2: b'__8',
bytes((251, 239)): b'--8',
bytes((255,)) * 2: b'__8',
}


Expand All @@ -31,11 +30,11 @@ def test_empty(self):
self.assertEqual(self._call(b''), b'')

def test_unsafe_url(self):
for text, b64 in six.iteritems(B64_URL_UNSAFE_EXAMPLES):
for text, b64 in B64_URL_UNSAFE_EXAMPLES.items():
self.assertEqual(self._call(text), b64)

def test_different_paddings(self):
for text, (b64, _) in six.iteritems(B64_PADDING_EXAMPLES):
for text, (b64, _) in B64_PADDING_EXAMPLES.items():
self.assertEqual(self._call(text), b64)

def test_unicode_fails_with_type_error(self):
Expand All @@ -51,15 +50,15 @@ def _call(cls, data):
return b64decode(data)

def test_unsafe_url(self):
for text, b64 in six.iteritems(B64_URL_UNSAFE_EXAMPLES):
for text, b64 in B64_URL_UNSAFE_EXAMPLES.items():
self.assertEqual(self._call(b64), text)

def test_input_without_padding(self):
for text, (b64, _) in six.iteritems(B64_PADDING_EXAMPLES):
for text, (b64, _) in B64_PADDING_EXAMPLES.items():
self.assertEqual(self._call(b64), text)

def test_input_with_padding(self):
for text, (b64, pad) in six.iteritems(B64_PADDING_EXAMPLES):
for text, (b64, pad) in B64_PADDING_EXAMPLES.items():
self.assertEqual(self._call(b64 + pad), text)

def test_unicode_with_ascii(self):
Expand Down
8 changes: 3 additions & 5 deletions src/josepy/interfaces.py
Expand Up @@ -2,7 +2,6 @@
import abc
import json

import six

from josepy import errors, util

Expand All @@ -15,8 +14,7 @@
# pylint: disable=too-few-public-methods


@six.add_metaclass(abc.ABCMeta)
class JSONDeSerializable(object):
class JSONDeSerializable(object, metaclass=abc.ABCMeta):
# pylint: disable=too-few-public-methods
"""Interface for (de)serializable JSON objects.
Expand Down Expand Up @@ -139,7 +137,7 @@ def to_json(self):
def _serialize(obj):
if isinstance(obj, JSONDeSerializable):
return _serialize(obj.to_partial_json())
if isinstance(obj, six.string_types): # strings are Sequence
if isinstance(obj, str): # strings are Sequence
return obj
elif isinstance(obj, list):
return [_serialize(subobj) for subobj in obj]
Expand All @@ -149,7 +147,7 @@ def _serialize(obj):
return tuple(_serialize(subobj) for subobj in obj)
elif isinstance(obj, Mapping):
return dict((_serialize(key), _serialize(value))
for key, value in six.iteritems(obj))
for key, value in obj.items())
else:
return obj

Expand Down
31 changes: 15 additions & 16 deletions src/josepy/json_util.py
Expand Up @@ -11,7 +11,6 @@
import logging

import OpenSSL
import six

from josepy import b64, errors, interfaces, util

Expand Down Expand Up @@ -106,7 +105,7 @@ def default_decoder(cls, value):
elif isinstance(value, dict):
return util.frozendict(
dict((cls.default_decoder(key), cls.default_decoder(value))
for key, value in six.iteritems(value)))
for key, value in value.items()))
else: # integer or string
return value

Expand Down Expand Up @@ -164,21 +163,23 @@ def __new__(mcs, name, bases, dikt):
for base in bases:
fields.update(getattr(base, '_fields', {}))
# Do not reorder, this class might override fields from base classes!
for key, value in tuple(six.iteritems(dikt)):
# not six.iterkeys() (in-place edit!)
# We create a tuple based on dikt.items() here because the loop
# modifies dikt.
for key, value in tuple(dikt.items()):
if isinstance(value, Field):
fields[key] = dikt.pop(key)

dikt['_orig_slots'] = dikt.get('__slots__', ())
dikt['__slots__'] = tuple(
list(dikt['_orig_slots']) + list(six.iterkeys(fields)))
list(dikt['_orig_slots']) + list(fields.keys()))
dikt['_fields'] = fields

return abc.ABCMeta.__new__(mcs, name, bases, dikt)


@six.add_metaclass(JSONObjectWithFieldsMeta)
class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable):
class JSONObjectWithFields(util.ImmutableMap,
interfaces.JSONDeSerializable,
metaclass=JSONObjectWithFieldsMeta):
# pylint: disable=too-few-public-methods
"""JSON object with fields.
Expand Down Expand Up @@ -210,7 +211,7 @@ def bar(value):
def _defaults(cls):
"""Get default fields values."""
return dict([(slot, field.default) for slot, field
in six.iteritems(cls._fields)])
in cls._fields.items()])

def __init__(self, **kwargs):
# pylint: disable=star-args
Expand All @@ -237,7 +238,7 @@ def fields_to_partial_json(self):
"""Serialize fields to JSON."""
jobj = {}
omitted = set()
for slot, field in six.iteritems(self._fields):
for slot, field in self._fields.items():
value = getattr(self, slot)

if field.omit(value):
Expand All @@ -257,7 +258,7 @@ def to_partial_json(self):
@classmethod
def _check_required(cls, jobj):
missing = set()
for _, field in six.iteritems(cls._fields):
for _, field in cls._fields.items():
if not field.omitempty and field.json_name not in jobj:
missing.add(field.json_name)

Expand All @@ -271,7 +272,7 @@ def fields_from_json(cls, jobj):
"""Deserialize fields from JSON."""
cls._check_required(jobj)
fields = {}
for slot, field in six.iteritems(cls._fields):
for slot, field in cls._fields.items():
if field.json_name not in jobj and field.omitempty:
fields[slot] = field.default
else:
Expand Down Expand Up @@ -311,10 +312,9 @@ def decode_b64jose(data, size=None, minimum=False):
:rtype: bytes
"""
error_cls = TypeError if six.PY2 else binascii.Error
try:
decoded = b64.b64decode(data.encode())
except error_cls as error:
except binascii.Error as error:
raise errors.DeserializationError(error)

if size is not None and ((not minimum and len(decoded) != size) or
Expand Down Expand Up @@ -350,10 +350,9 @@ def decode_hex16(value, size=None, minimum=False):
if size is not None and ((not minimum and len(value) != size * 2) or
(minimum and len(value) < size * 2)):
raise errors.DeserializationError()
error_cls = TypeError if six.PY2 else binascii.Error
try:
return binascii.unhexlify(value)
except error_cls as error:
except binascii.Error as error:
raise errors.DeserializationError(error)


Expand Down Expand Up @@ -433,7 +432,7 @@ def register(cls, type_cls, typ=None):
@classmethod
def get_type_cls(cls, jobj):
"""Get the registered class for ``jobj``."""
if cls in six.itervalues(cls.TYPES):
if cls in cls.TYPES.values():
if cls.type_field_name not in jobj:
raise errors.DeserializationError(
"Missing type field ({0})".format(cls.type_field_name))
Expand Down
12 changes: 5 additions & 7 deletions src/josepy/json_util_test.py
Expand Up @@ -3,7 +3,6 @@
import unittest

import mock
import six

from josepy import errors, interfaces, test_util, util

Expand Down Expand Up @@ -90,8 +89,7 @@ def setUp(self):
# pylint: disable=invalid-name,missing-docstring,too-few-public-methods
# pylint: disable=blacklisted-name

@six.add_metaclass(JSONObjectWithFieldsMeta)
class A(object):
class A(object, metaclass=JSONObjectWithFieldsMeta):
__slots__ = ('bar',)
baz = self.field

Expand Down Expand Up @@ -246,13 +244,13 @@ def setUp(self):
def test_encode_b64jose(self):
from josepy.json_util import encode_b64jose
encoded = encode_b64jose(b'x')
self.assertTrue(isinstance(encoded, six.string_types))
self.assertTrue(isinstance(encoded, str))
self.assertEqual(u'eA', encoded)

def test_decode_b64jose(self):
from josepy.json_util import decode_b64jose
decoded = decode_b64jose(u'eA')
self.assertTrue(isinstance(decoded, six.binary_type))
self.assertTrue(isinstance(decoded, bytes))
self.assertEqual(b'x', decoded)

def test_decode_b64jose_padding_error(self):
Expand All @@ -278,13 +276,13 @@ def test_encode_hex16(self):
from josepy.json_util import encode_hex16
encoded = encode_hex16(b'foo')
self.assertEqual(u'666f6f', encoded)
self.assertTrue(isinstance(encoded, six.string_types))
self.assertTrue(isinstance(encoded, str))

def test_decode_hex16(self):
from josepy.json_util import decode_hex16
decoded = decode_hex16(u'666f6f')
self.assertEqual(b'foo', decoded)
self.assertTrue(isinstance(decoded, six.binary_type))
self.assertTrue(isinstance(decoded, bytes))

def test_decode_hex16_minimum_size(self):
from josepy.json_util import decode_hex16
Expand Down
9 changes: 4 additions & 5 deletions src/josepy/jwk.py
Expand Up @@ -5,7 +5,6 @@
import logging

import cryptography.exceptions
import six
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes # type: ignore
from cryptography.hazmat.primitives import serialization
Expand Down Expand Up @@ -48,7 +47,7 @@ def thumbprint(self, hash_function=hashes.SHA256):
"""
digest = hashes.Hash(hash_function(), backend=default_backend())
digest.update(json.dumps(
dict((k, v) for k, v in six.iteritems(self.to_json())
dict((k, v) for k, v in self.to_json().items()
if k in self.required),
**self._thumbprint_json_dumps_params).encode())
return digest.finalize()
Expand Down Expand Up @@ -114,7 +113,7 @@ def load(cls, data, password=None, backend=None):
key, cls.cryptography_key_types):
raise errors.Error('Unable to deserialize {0} into {1}'.format(
key.__class__, cls.__class__))
for jwk_cls in six.itervalues(cls.TYPES):
for jwk_cls in cls.TYPES.values():
if isinstance(key, jwk_cls.cryptography_key_types):
return jwk_cls(key=key)
raise errors.Error('Unsupported algorithm: {0}'.format(key.__class__))
Expand Down Expand Up @@ -251,7 +250,7 @@ def fields_to_partial_json(self):
'qi': private.iqmp,
}
return dict((key, self._encode_param(value))
for key, value in six.iteritems(params))
for key, value in params.items())


@JWK.register
Expand Down Expand Up @@ -348,7 +347,7 @@ def fields_to_partial_json(self):
'Supplied key is neither of type EllipticCurvePublicKey nor EllipticCurvePrivateKey')
params['x'] = public.x
params['y'] = public.y
params = {key: self._encode_param(value) for key, value in six.iteritems(params)}
params = {key: self._encode_param(value) for key, value in params.items()}
params['crv'] = self._curve_name_to_crv(public.curve.name)
return params

Expand Down
9 changes: 4 additions & 5 deletions src/josepy/jws.py
Expand Up @@ -4,7 +4,6 @@
import sys

import OpenSSL
import six

from josepy import b64, errors, json_util, jwa, jwk, util

Expand Down Expand Up @@ -76,7 +75,7 @@ class Header(json_util.JSONObjectWithFields):
def not_omitted(self):
"""Fields that would not be omitted in the JSON object."""
return dict((name, getattr(self, name))
for name, field in six.iteritems(self._fields)
for name, field in self._fields.items()
if not field.omit(getattr(self, name)))

def __add__(self, other):
Expand Down Expand Up @@ -357,9 +356,9 @@ def sign(cls, args):
protect=set(args.protect))

if args.compact:
six.print_(sig.to_compact().decode('utf-8'))
print(sig.to_compact().decode('utf-8'))
else: # JSON
six.print_(sig.json_dumps_pretty())
print(sig.json_dumps_pretty())

@classmethod
def verify(cls, args):
Expand All @@ -370,7 +369,7 @@ def verify(cls, args):
try:
sig = JWS.json_loads(sys.stdin.read())
except errors.Error as error:
six.print_(error)
print(error)
return -1

if args.key is not None:
Expand Down

0 comments on commit 948ac09

Please sign in to comment.