From 2aa7409a7c06e2d550d57e1b4748aba5a37d6dc5 Mon Sep 17 00:00:00 2001 From: Yoichi Fujimoto Date: Mon, 21 Apr 2025 16:17:46 +0900 Subject: [PATCH 1/2] refactor: remove six dependency and update code for Python 3 compatibility --- README.md | 5 ++--- payjp/api_requestor.py | 14 ++++---------- payjp/error.py | 4 ++-- payjp/resource.py | 10 ++++------ payjp/test/helper.py | 4 +--- payjp/test/test_integration.py | 10 ++++------ payjp/test/test_requestor.py | 20 ++++++++------------ requirements.txt | 1 - setup.py | 6 +++--- 9 files changed, 28 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 6c99d50..2dc7e9b 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,10 @@ source code") for `payjp-python`, and then run: Please see our official [documentation](https://pay.jp/docs/api). -## Dependencies +## Dependencies - requests -- six Install dependencies from using [pip](http://www.pip-installer.org/en/latest/): - + pip install -r requirements.txt diff --git a/payjp/api_requestor.py b/payjp/api_requestor.py index 69ec46a..24bbafe 100644 --- a/payjp/api_requestor.py +++ b/payjp/api_requestor.py @@ -8,9 +8,7 @@ import platform import time import random - -from six import PY3 -from six.moves.urllib.parse import urlencode, urlsplit, urlunsplit +from urllib.parse import urlencode, urlsplit, urlunsplit import payjp from . import ( @@ -128,12 +126,9 @@ def request_raw(self, method, url, params=None, supplied_headers=None): val = '!! %s' % (e,) ua[attr] = val - if PY3: - encoded_api_key = str( - base64.b64encode( - bytes(''.join([my_api_key, ':']), 'utf-8')), 'utf-8') - else: - encoded_api_key = base64.b64encode(''.join([my_api_key, ':'])) + encoded_api_key = str( + base64.b64encode( + bytes(''.join([my_api_key, ':']), 'utf-8')), 'utf-8') headers = { 'X-Payjp-Client-User-Agent': json.dumps(ua), @@ -215,4 +210,3 @@ def _build_api_url(url, query): query = '%s&%s' % (base_query, query) return urlunsplit((scheme, netloc, path, query, fragment)) - diff --git a/payjp/error.py b/payjp/error.py index c1a82ac..027f130 100644 --- a/payjp/error.py +++ b/payjp/error.py @@ -16,7 +16,7 @@ def __init__(self, message=None, http_body=None, http_status=None, self.http_body = http_body self.http_status = http_status - self.json_body = json_body + self.json_body = json_body class APIError(PayjpException): @@ -33,7 +33,7 @@ def __init__(self, message, param, code, http_body=None, super(CardError, self).__init__(message, http_body, http_status, json_body) self.param = param - self.code = code + self.code = code class AuthenticationError(PayjpException): diff --git a/payjp/resource.py b/payjp/resource.py index 1b55c27..157e18a 100644 --- a/payjp/resource.py +++ b/payjp/resource.py @@ -3,9 +3,7 @@ import json import logging import sys - -from six import string_types -from six.moves.urllib.parse import quote_plus +from urllib.parse import quote_plus from payjp import api_requestor, error, util @@ -34,7 +32,7 @@ def convert_to_payjp_object(resp, api_key, account, api_base=None): elif isinstance(resp, dict) and not isinstance(resp, PayjpObject): resp = resp.copy() klass_name = resp.get('object') - if isinstance(klass_name, string_types): + if isinstance(klass_name, str): klass = types.get(klass_name, PayjpObject) else: klass = PayjpObject @@ -206,10 +204,10 @@ def request(self, method, url, params=None, headers=None): def __repr__(self): ident_parts = [type(self).__name__] - if isinstance(self.get('object'), string_types): + if isinstance(self.get('object'), str): ident_parts.append(self.get('object')) - if isinstance(self.get('id'), string_types): + if isinstance(self.get('id'), str): ident_parts.append('id=%s' % (self.get('id'),)) unicode_repr = '<%s at %s> JSON: %s' % ( diff --git a/payjp/test/helper.py b/payjp/test/helper.py index a93c706..ae6d366 100644 --- a/payjp/test/helper.py +++ b/payjp/test/helper.py @@ -8,8 +8,6 @@ from mock import patch, Mock -from six import string_types - import payjp NOW = datetime.datetime.now() @@ -72,7 +70,7 @@ def assertRaisesRegexp(self, exception, regexp, callable, *args, **kwargs): if regexp is None: return True - if isinstance(regexp, string_types): + if isinstance(regexp, str): regexp = re.compile(regexp) if not regexp.search(str(err)): raise self.failureException('"%s" does not match "%s"' % diff --git a/payjp/test/test_integration.py b/payjp/test/test_integration.py index 9e7a6b4..749201b 100644 --- a/payjp/test/test_integration.py +++ b/payjp/test/test_integration.py @@ -3,8 +3,6 @@ import unittest import payjp -from six import string_types - from payjp.test.helper import (PayjpTestCase, NOW, DUMMY_CARD) @@ -17,7 +15,7 @@ def test_invalid_credentials(self): payjp.Customer.create() except payjp.error.AuthenticationError as e: self.assertEqual(401, e.http_status) - self.assertTrue(isinstance(e.http_body, string_types)) + self.assertTrue(isinstance(e.http_body, str)) self.assertTrue(isinstance(e.json_body, dict)) finally: payjp.api_key = key @@ -33,7 +31,7 @@ def test_invalid_card_props(self): payjp.Charge.create(amount=100, currency='jpy', card=EXPIRED_CARD) except payjp.error.InvalidRequestError as e: self.assertEqual(400, e.http_status) - self.assertTrue(isinstance(e.http_body, string_types)) + self.assertTrue(isinstance(e.http_body, str)) self.assertTrue(isinstance(e.json_body, dict)) @@ -44,7 +42,7 @@ def test_nonexistent_object(self): payjp.Charge.retrieve('invalid') except payjp.error.InvalidRequestError as e: self.assertEqual(404, e.http_status) - self.assertTrue(isinstance(e.http_body, string_types)) + self.assertTrue(isinstance(e.http_body, str)) self.assertTrue(isinstance(e.json_body, dict)) def test_invalid_data(self): @@ -52,7 +50,7 @@ def test_invalid_data(self): payjp.Charge.create() except payjp.error.InvalidRequestError as e: self.assertEqual(400, e.http_status) - self.assertTrue(isinstance(e.http_body, string_types)) + self.assertTrue(isinstance(e.http_body, str)) self.assertTrue(isinstance(e.json_body, dict)) diff --git a/payjp/test/test_requestor.py b/payjp/test/test_requestor.py index be8e6c7..ecbeb8e 100644 --- a/payjp/test/test_requestor.py +++ b/payjp/test/test_requestor.py @@ -3,10 +3,9 @@ import base64 import datetime import unittest +from urllib.parse import parse_qsl, urlsplit from mock import Mock, MagicMock, patch -from six.moves.urllib.parse import parse_qsl, urlsplit -from six import PY3 import payjp @@ -45,12 +44,9 @@ def __eq__(self, other): self._extra_match(other)) def _encode(self, api_key): - if PY3: - return str( - base64.b64encode( - bytes(''.join([api_key, ':']), 'utf-8')), 'utf-8') - else: - return base64.b64encode(''.join([api_key, ':'])) + return str( + base64.b64encode( + bytes(''.join([api_key, ':']), 'utf-8')), 'utf-8') def _keys_match(self, other): expected_keys = self.EXP_KEYS + list(self.extra.keys()) @@ -413,7 +409,7 @@ def test_retry_disabled(self): with self.request_raw_patch: with self.assertRaises(payjp.error.APIError) as error: self.requestor.request('get', '/test', {}) - + self.assertEqual(error.exception.http_status, 499) def test_no_retry(self): @@ -423,7 +419,7 @@ def test_no_retry(self): with self.request_raw_patch: with self.assertRaises(payjp.error.APIError) as error: self.requestor.request('get', '/test', {}) - + self.assertEqual(error.exception.http_status, 599) def test_full_retry(self): @@ -434,7 +430,7 @@ def test_full_retry(self): with self.request_raw_patch: with self.assertRaises(payjp.error.APIError) as error: self.requestor.request('get', '/test', {}) - + self.assertEqual(error.exception.http_status, 429) def test_success_at_halfway_of_retries(self): @@ -464,7 +460,7 @@ def test_retry_initial_delay(self): self.assertTrue(16 <= self.requestor._get_retry_delay(10) <= 32) - + if __name__ == '__main__': unittest.main() diff --git a/requirements.txt b/requirements.txt index 640e3d4..f229360 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ requests -six diff --git a/setup.py b/setup.py index c1f5546..3c79c79 100644 --- a/setup.py +++ b/setup.py @@ -6,11 +6,10 @@ install_requires = [] -if sys.version_info < (2, 7): - raise DeprecationWarning('Python 2.6 and older are no longer supported by PAY.JP. ') +if sys.version_info < (3, 0): + raise DeprecationWarning('Python 2 is no longer supported by PAY.JP. Please use Python 3.') install_requires.append('requests >= 2.7.0') -install_requires.append('six >= 1.9.0') setup( name="payjp", @@ -21,4 +20,5 @@ packages=['payjp', 'payjp.test'], url='https://github.com/payjp/payjp-python', install_requires=install_requires, + python_requires='>=3.0', ) From e9edb1f1f13fe4be5a18ac9efb9c2c8d74bdb083 Mon Sep 17 00:00:00 2001 From: Yoichi Fujimoto Date: Mon, 21 Apr 2025 16:24:48 +0900 Subject: [PATCH 2/2] refactor: remove util.utf8 usage and update deprecation warning for Python version support --- payjp/api_requestor.py | 6 ++---- payjp/resource.py | 7 +------ payjp/test/test_requestor.py | 2 +- payjp/util.py | 9 --------- setup.py | 6 ++---- 5 files changed, 6 insertions(+), 24 deletions(-) delete mode 100644 payjp/util.py diff --git a/payjp/api_requestor.py b/payjp/api_requestor.py index 24bbafe..168bff4 100644 --- a/payjp/api_requestor.py +++ b/payjp/api_requestor.py @@ -14,7 +14,6 @@ from . import ( error, http_client, - util, version, ) @@ -185,14 +184,13 @@ def _encode_datetime(dttime): def _api_encode(data): for key, value in data.items(): - key = util.utf8(key) if value is None: continue elif hasattr(value, 'payjp_id'): yield (key, value.payjp_id) elif isinstance(value, list) or isinstance(value, tuple): for subvalue in value: - yield ("%s[]" % (key,), util.utf8(subvalue)) + yield ("%s[]" % (key,), subvalue) elif isinstance(value, dict): subdict = dict(('%s[%s]' % (key, subkey), subvalue) for subkey, subvalue in value.items()) @@ -201,7 +199,7 @@ def _api_encode(data): elif isinstance(value, datetime.datetime): yield (key, _encode_datetime(value)) else: - yield (key, util.utf8(value)) + yield (key, value) def _build_api_url(url, query): scheme, netloc, path, base_query, fragment = urlsplit(url) diff --git a/payjp/resource.py b/payjp/resource.py index 157e18a..b4e9f8b 100644 --- a/payjp/resource.py +++ b/payjp/resource.py @@ -5,7 +5,7 @@ import sys from urllib.parse import quote_plus -from payjp import api_requestor, error, util +from payjp import api_requestor, error logger = logging.getLogger('payjp') @@ -239,7 +239,6 @@ def create(self, **params): def retrieve(self, id, **params): base = self.get('url') - id = util.utf8(id) extn = quote_plus(id) url = "%s/%s" % (base, extn) @@ -380,7 +379,6 @@ def instance_url(self): id = self.get('id') if not id: return "/v1/accounts" - id = util.utf8(id) base = self.class_url() extn = quote_plus(id) return "%s/%s" % (base, extn) @@ -389,11 +387,8 @@ def instance_url(self): class Card(UpdateableAPIResource, DeletableAPIResource): def instance_url(self): - self.id = util.utf8(self.id) extn = quote_plus(self.id) if (hasattr(self, 'customer')): - self.customer = util.utf8(self.customer) - base = Customer.class_url() owner_extn = quote_plus(self.customer) diff --git a/payjp/test/test_requestor.py b/payjp/test/test_requestor.py index ecbeb8e..cdc79d3 100644 --- a/payjp/test/test_requestor.py +++ b/payjp/test/test_requestor.py @@ -133,7 +133,7 @@ class APIRequestorRequestTests(PayjpUnitTestCase): ('%s[]', 'baz'), ], 'string': [('%s', 'boo')], - 'unicode': [('%s', payjp.util.utf8(u'\u1234'))], + 'unicode': [('%s', u'\u1234')], 'datetime': [('%s', 1356994801)], 'none': [], } diff --git a/payjp/util.py b/payjp/util.py deleted file mode 100644 index 248d3ff..0000000 --- a/payjp/util.py +++ /dev/null @@ -1,9 +0,0 @@ -# coding: utf-8 - -import sys - -def utf8(value): - if sys.version_info < (3, 0) and isinstance(value, unicode): - return value.encode('utf-8') - else: - return value diff --git a/setup.py b/setup.py index 3c79c79..696ad9c 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,11 @@ -# coding: utf-8 - import sys from setuptools import setup install_requires = [] -if sys.version_info < (3, 0): - raise DeprecationWarning('Python 2 is no longer supported by PAY.JP. Please use Python 3.') +if sys.version_info < (3, 8): + raise DeprecationWarning('Python versions below 3.8 are no longer supported by PAY.JP. Please use Python 3.8 or higher.') install_requires.append('requests >= 2.7.0')