From 63b0627adbce19d21edc32ca2c77ce04e08042d3 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:31:13 +0300 Subject: [PATCH 01/10] Run python-modernize --- iron_core.py | 1 + setup.py | 1 + test.py | 1 + 3 files changed, 3 insertions(+) diff --git a/iron_core.py b/iron_core.py index 085df33..a49bd96 100644 --- a/iron_core.py +++ b/iron_core.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import time from datetime import datetime import os diff --git a/setup.py b/setup.py index 101ca53..649dd95 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from setuptools import setup import sys diff --git a/test.py b/test.py index 35ccece..b828bfb 100644 --- a/test.py +++ b/test.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import iron_core import unittest import os From 50bbafedd1c4fca29569102dfff362510b97b27b Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:31:23 +0300 Subject: [PATCH 02/10] Run pyupgrade --- iron_core.py | 27 +++++++++++++-------------- setup.py | 2 -- test.py | 1 - 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/iron_core.py b/iron_core.py index a49bd96..8e1affe 100644 --- a/iron_core.py +++ b/iron_core.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import time from datetime import datetime import os @@ -16,7 +15,7 @@ import simplejson as json -class IronTokenProvider(object): +class IronTokenProvider: def __init__(self, token): self.token = token @@ -24,7 +23,7 @@ def getToken(self): return self.token -class KeystoneTokenProvider(object): +class KeystoneTokenProvider: def __init__(self, keystone): self.server = keystone["server"] + ("" if keystone["server"].endswith("/") else "/") self.tenant = keystone["tenant"] @@ -65,7 +64,7 @@ def getToken(self): return self.token -class IronClient(object): +class IronClient: __version__ = "1.2.0" def __init__(self, name, version, product, host=None, project_id=None, @@ -137,7 +136,7 @@ def __init__(self, name, version, product, host=None, project_id=None, for field in required_fields: if config[field] is None: - raise ValueError("No %s set. %s is a required field." % (field, field)) + raise ValueError(f"No {field} set. {field} is a required field.") keystone_configured = False if config["keystone"] is not None: @@ -169,7 +168,7 @@ def __init__(self, name, version, product, host=None, project_id=None, self.headers = { "Accept": "application/json", - "User-Agent": "%s (version: %s)" % (self.name, self.version) + "User-Agent": f"{self.name} (version: {self.version})" } self.path_prefix = config["path_prefix"] @@ -182,9 +181,9 @@ def __init__(self, name, version, product, host=None, project_id=None, self.path_prefix = url.path.rstrip("/") if self.protocol == "https" and self.port == 443: - self.base_url = "%s://%s%s/%s/" % (self.protocol, self.host, self.path_prefix, self.api_version) + self.base_url = f"{self.protocol}://{self.host}{self.path_prefix}/{self.api_version}/" else: - self.base_url = "%s://%s:%s%s/%s/" % (self.protocol, self.host, + self.base_url = "{}://{}:{}{}/{}/".format(self.protocol, self.host, self.port, self.path_prefix, self.api_version) if self.project_id: self.base_url += "projects/%s/" % self.project_id @@ -228,9 +227,9 @@ def request(self, url, method, body="", headers={}, retry=True): headers = self.headers if not sys.version_info >= (3,) and headers: - headers = dict((k.encode('ascii') if isinstance(k, unicode) else k, - v.encode('ascii') if isinstance(v, unicode) else v) - for k, v in headers.items()) + headers = {k.encode('ascii') if isinstance(k, unicode) else k: + v.encode('ascii') if isinstance(v, unicode) else v + for k, v in headers.items()} url = self.base_url + url if not sys.version_info >= (3,): @@ -380,8 +379,8 @@ def configFromFile(config, path, product=None): if not os.path.exists(path): return config try: - file = open(path, "r") - except IOError: + file = open(path) + except OSError: return config raw = json.loads(file.read()) @@ -401,7 +400,7 @@ def configFromEnv(config, product=None): if product is None: product = "iron" for k in config.keys(): - key = "%s_%s" % (product, k) + key = f"{product}_{k}" if key.upper() in os.environ: config[k] = os.environ[key.upper()] return config diff --git a/setup.py b/setup.py index 649dd95..3800c93 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,4 @@ -from __future__ import absolute_import from setuptools import setup -import sys setup( name = "iron-core", diff --git a/test.py b/test.py index b828bfb..35ccece 100644 --- a/test.py +++ b/test.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import iron_core import unittest import os From 1231a528ae61d16dcd08f3a11a3c1cd42b369098 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:31:31 +0300 Subject: [PATCH 03/10] Run flynt --- iron_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iron_core.py b/iron_core.py index 8e1affe..7ac3819 100644 --- a/iron_core.py +++ b/iron_core.py @@ -186,11 +186,11 @@ def __init__(self, name, version, product, host=None, project_id=None, self.base_url = "{}://{}:{}{}/{}/".format(self.protocol, self.host, self.port, self.path_prefix, self.api_version) if self.project_id: - self.base_url += "projects/%s/" % self.project_id + self.base_url += f"projects/{self.project_id}/" def _doRequest(self, url, method, body="", headers={}): if self.token or self.keystone: - headers["Authorization"] = "OAuth %s" % self.token_provider.getToken() + headers["Authorization"] = f"OAuth {self.token_provider.getToken()}" if method == "GET": r = requests.get(url, headers=headers) From 9c07db0ed977e64b286a415d7fc165271c1e5d09 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:34:03 +0300 Subject: [PATCH 04/10] Remove easy_install references from readme --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ed7b40b..a7bbbf5 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,20 @@ that we build at [Iron.io](http://www.iron.io) from Python. ## It Is * Service-agnostic -* Pip- and easy_install-installable +* Pip-installable * Well documented ## It Is Not * An API wrapper. Those are specific to each service, and you can generally find them -by checking the documentation for the service. + by checking the documentation for the service. * A place for service-specific code. This is only meant to handle the basic, common -interaction. + interaction. ## Installation -You can use [pip](http://pip-installer.org) or [easy_install](http://wiki.python.org/moin/EasyInstall) -to install the [release version](http://pypi.python.org/pypi/iron_core_python). If you'd -like to work with a development or beta version, retrieve the files [from Github](https://github.com/iron-io/iron_core_python) +You can use [pip](http://pip-installer.org) to install the [release version](http://pypi.python.org/pypi/iron_core_python). +If you'd like to work with a development or beta version, retrieve the files [from Github](https://github.com/iron-io/iron_core_python) and run `python setup.py install` from the root directory. ## License From 2093883a9a537b207606a3f5fc946ed37856870d Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:34:10 +0300 Subject: [PATCH 05/10] Fix imports --- iron_core.py | 19 ++++++------------- test.py | 13 +++++-------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/iron_core.py b/iron_core.py index 7ac3819..c2d9ae1 100644 --- a/iron_core.py +++ b/iron_core.py @@ -1,18 +1,11 @@ -import time -from datetime import datetime -import os -import sys import dateutil.parser +import json +import os import requests -try: - from urlparse import urlparse -except: - from urllib.parse import urlparse - -try: - import json -except: - import simplejson as json +import sys +import time +from datetime import datetime +from urllib.parse import urlparse class IronTokenProvider: diff --git a/test.py b/test.py index 35ccece..6be392f 100644 --- a/test.py +++ b/test.py @@ -1,12 +1,9 @@ -import iron_core -import unittest +import json import os -from iron_core import KeystoneTokenProvider +import unittest + +import iron_core -try: - import json -except: - import simplejson as json class TestConfig(unittest.TestCase): def setUp(self): @@ -255,7 +252,7 @@ def test_checkTrailingSlash(self): "username": "keystone-username", "password": "keystone-password" } - keystone = KeystoneTokenProvider(keystone_data) + keystone = iron_core.KeystoneTokenProvider(keystone_data) self.assertEqual("http://localhost/", keystone.server) def create_test_config(filename, content): From 610c69a11b921976076327cf8cdeb715b68bec10 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:35:23 +0300 Subject: [PATCH 06/10] Set python_requires >= 3.6 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 3800c93..104bd80 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ author_email = "thirdparty@iron.io", url = "https://www.github.com/iron-io/iron_core_python", keywords = ["Iron.io"], + python_requires=">=3.6", classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", From c9cf2adbe82165fd819801836394165342032c42 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:39:29 +0300 Subject: [PATCH 07/10] Remove unnecessary encode dances --- iron_core.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/iron_core.py b/iron_core.py index c2d9ae1..3a40508 100644 --- a/iron_core.py +++ b/iron_core.py @@ -219,16 +219,7 @@ def request(self, url, method, body="", headers={}, retry=True): else: headers = self.headers - if not sys.version_info >= (3,) and headers: - headers = {k.encode('ascii') if isinstance(k, unicode) else k: - v.encode('ascii') if isinstance(v, unicode) else v - for k, v in headers.items()} - url = self.base_url + url - if not sys.version_info >= (3,): - if isinstance(url, unicode): - url = url.encode('ascii') - r = self._doRequest(url, method, body, headers) retry_http_codes = [503, 504] From 968b93c56a4f67e7719a85ca55499980f648232f Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:41:52 +0300 Subject: [PATCH 08/10] Apply formatting fixes --- iron_core.py | 53 ++++++++++++++++++------------------- setup.py | 59 +++++++++++++++++++++-------------------- test.py | 75 +++++++++++++++++++++++++++------------------------- 3 files changed, 96 insertions(+), 91 deletions(-) diff --git a/iron_core.py b/iron_core.py index 3a40508..022c3a0 100644 --- a/iron_core.py +++ b/iron_core.py @@ -25,7 +25,6 @@ def __init__(self, keystone): self.token = None self.local_expires_at_timestamp = 0 - def getToken(self): date_diff = time.mktime(datetime.now().timetuple()) - self.local_expires_at_timestamp if self.token is None or date_diff > -10: @@ -84,34 +83,34 @@ def __init__(self, name, version, product, host=None, project_id=None, None. """ config = { - "host": None, - "protocol": "https", - "port": 443, - "api_version": None, - "project_id": None, - "token": None, - "keystone": None, - "path_prefix": None, - "cloud": None, + "host": None, + "protocol": "https", + "port": 443, + "api_version": None, + "project_id": None, + "token": None, + "keystone": None, + "path_prefix": None, + "cloud": None, } products = { - "iron_worker": { - "host": "worker-aws-us-east-1.iron.io", - "version": 2 - }, - "iron_mq": { - "host": "mq-aws-us-east-1-1.iron.io", - "version": 3 - }, - "iron_cache": { - "host": "cache-aws-us-east-1.iron.io", - "version": 1 - } + "iron_worker": { + "host": "worker-aws-us-east-1.iron.io", + "version": 2 + }, + "iron_mq": { + "host": "mq-aws-us-east-1-1.iron.io", + "version": 3 + }, + "iron_cache": { + "host": "cache-aws-us-east-1.iron.io", + "version": 1 + } } if product in products: config["host"] = products[product]["host"] config["api_version"] = products[product]["version"] - + try: config = configFromFile(config, os.path.expanduser("~/.iron.json"), product) @@ -145,8 +144,6 @@ def __init__(self, name, version, product, host=None, project_id=None, if config["token"] is None and not keystone_configured: raise ValueError("At least one of token or keystone should be specified.") - - self.name = name self.version = version self.product = product @@ -160,8 +157,8 @@ def __init__(self, name, version, product, host=None, project_id=None, self.cloud = config["cloud"] self.headers = { - "Accept": "application/json", - "User-Agent": f"{self.name} (version: {self.version})" + "Accept": "application/json", + "User-Agent": f"{self.name} (version: {self.version})" } self.path_prefix = config["path_prefix"] @@ -357,6 +354,7 @@ def fromTimestamp(timestamp=None): return timestamp return datetime.fromtimestamp(float(timestamp)) + def configFromFile(config, path, product=None): if path is None: return config @@ -396,5 +394,6 @@ def configFromArgs(config, **kwargs): config[k] = kwargs[k] return config + def intersect(a, b): return list(set(a) & set(b)) diff --git a/setup.py b/setup.py index 104bd80..26045ab 100644 --- a/setup.py +++ b/setup.py @@ -1,35 +1,38 @@ from setuptools import setup -setup( - name = "iron-core", - py_modules = ["iron_core"], - install_requires=["requests >= 1.1.0", "python-dateutil"], - version = "1.2.0", - description = "Universal classes and methods for Iron.io API wrappers to build on.", - author = "Iron.io", - author_email = "thirdparty@iron.io", - url = "https://www.github.com/iron-io/iron_core_python", - keywords = ["Iron.io"], - python_requires=">=3.6", - classifiers = [ - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Intended Audience :: Developers", - "Operating System :: OS Independent", - "Development Status :: 2 - Pre-Alpha", - "License :: OSI Approved :: BSD License", - "Natural Language :: English", - "Topic :: Internet", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Software Development :: Libraries :: Python Modules", - - ], - long_description = """\ +LONG_DESCRIPTION = """ Iron.io common library ---------------------- -This package offers common functions for Iron.io APIs and services. It does not wrap +This package offers common functions for Iron.io APIs and services. It does not wrap any APIs or contain API-specific features, but serves as a common base that wrappers -may be built on. Users looking for API wrappers should instead look at -iron_worker_python and iron_worker_mq.""", +may be built on. Users looking for API wrappers should instead look at +iron_worker_python and iron_worker_mq. +""".strip() + +setup( + name="iron-core", + py_modules=["iron_core"], + install_requires=["requests >= 1.1.0", "python-dateutil"], + version="1.2.0", + description="Universal classes and methods for Iron.io API wrappers to build on.", + author="Iron.io", + author_email="thirdparty@iron.io", + url="https://www.github.com/iron-io/iron_core_python", + keywords=["Iron.io"], + python_requires=">=3.6", + classifiers=[ + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Development Status :: 2 - Pre-Alpha", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Topic :: Internet", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Software Development :: Libraries :: Python Modules", + + ], + long_description=LONG_DESCRIPTION, ) diff --git a/test.py b/test.py index 6be392f..15e3e9a 100644 --- a/test.py +++ b/test.py @@ -69,12 +69,12 @@ def test_fromArgsUseHTTP(self): def test_fromArgsConfigFileGlobal(self): test_config = { - "host": "test-config-host", - "protocol": "test-config-protocol", - "port": "test-config-port", - "api_version": "test-config-api-version", - "project_id": "test-config-project-id", - "token": "test-config-token" + "host": "test-config-host", + "protocol": "test-config-protocol", + "port": "test-config-port", + "api_version": "test-config-api-version", + "project_id": "test-config-project-id", + "token": "test-config-token" } file = open("test_config.json", "w") @@ -95,14 +95,14 @@ def test_fromArgsConfigFileGlobal(self): def test_fromArgsConfigFileProduct(self): test_config = { - "iron_worker": { - "host": "test-config-host", - "protocol": "test-config-protocol", - "port": "test-config-port", - "api_version": "test-config-api-version", - "project_id": "test-config-project-id", - "token": "test-config-token" - } + "iron_worker": { + "host": "test-config-host", + "protocol": "test-config-protocol", + "port": "test-config-port", + "api_version": "test-config-api-version", + "project_id": "test-config-project-id", + "token": "test-config-token" + } } file = open("test_config.json", "w") @@ -110,31 +110,31 @@ def test_fromArgsConfigFileProduct(self): file.close() client = iron_core.IronClient(name="Test", version="0.1.0", - product="iron_worker", config_file="test_config.json") + product="iron_worker", config_file="test_config.json") self.assertEqual(client.host, test_config["iron_worker"]["host"]) self.assertEqual(client.protocol, - test_config["iron_worker"]["protocol"]) + test_config["iron_worker"]["protocol"]) self.assertEqual(client.port, test_config["iron_worker"]["port"]) self.assertEqual(client.api_version, - test_config["iron_worker"]["api_version"]) + test_config["iron_worker"]["api_version"]) self.assertEqual(client.project_id, - test_config["iron_worker"]["project_id"]) + test_config["iron_worker"]["project_id"]) self.assertEqual(client.token, test_config["iron_worker"]["token"]) os.remove("test_config.json") def test_fromArgsConfigFileMixed(self): test_config = { - "host": "test-config-host-global", - "protocol": "test-config-protocol-global", - "port": "test-config-port-global", - "project_id": "test-config-project-id-global", - "iron_worker": { - "api_version": "test-config-api-version-product", - "project_id": "test-config-project-id-product", - "token": "test-config-token-product" - } + "host": "test-config-host-global", + "protocol": "test-config-protocol-global", + "port": "test-config-port-global", + "project_id": "test-config-project-id-global", + "iron_worker": { + "api_version": "test-config-api-version-product", + "project_id": "test-config-project-id-product", + "token": "test-config-token-product" + } } file = open("test_config.json", "w") @@ -142,27 +142,27 @@ def test_fromArgsConfigFileMixed(self): file.close() client = iron_core.IronClient(name="Test", version="0.1.0", - product="iron_worker", config_file="test_config.json") + product="iron_worker", config_file="test_config.json") self.assertEqual(client.host, test_config["host"]) self.assertEqual(client.protocol, test_config["protocol"]) self.assertEqual(client.port, test_config["port"]) self.assertEqual(client.api_version, - test_config["iron_worker"]["api_version"]) + test_config["iron_worker"]["api_version"]) self.assertEqual(client.project_id, - test_config["iron_worker"]["project_id"]) + test_config["iron_worker"]["project_id"]) self.assertEqual(client.token, test_config["iron_worker"]["token"]) os.remove("test_config.json") def test_fromArgsAndArgsConfigFile(self): test_config = { - "host": "test-config-host", - "protocol": "test-config-protocol", - "port": "test-config-port", - "api_version": "test-config-api-version", - "project_id": "test-config-project-id", - "token": "test-config-token" + "host": "test-config-host", + "protocol": "test-config-protocol", + "port": "test-config-port", + "api_version": "test-config-api-version", + "project_id": "test-config-project-id", + "token": "test-config-token" } file = open("test_config.json", "w") @@ -255,13 +255,16 @@ def test_checkTrailingSlash(self): keystone = iron_core.KeystoneTokenProvider(keystone_data) self.assertEqual("http://localhost/", keystone.server) + def create_test_config(filename, content): file = open(filename, "w") file.write(json.dumps(content)) file.close() + def remove_test_config(filename): os.remove(filename) + if __name__ == "__main__": unittest.main() From 0a997530e8ca6a34f1c58e02450ecd598e77be40 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:45:13 +0300 Subject: [PATCH 09/10] Remove test broken by f61e1eaed7aca0be142265581637549541672c2c --- test.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test.py b/test.py index 15e3e9a..b04bce4 100644 --- a/test.py +++ b/test.py @@ -38,12 +38,6 @@ def test_fromArgsMissingProjectID(self): version="0.1.0", product="iron_worker", api_version=2, host="worker-aws-us-east-1.iron.io", token="TEST") - def test_fromArgsProtocolPortMismatch(self): - self.assertRaises(ValueError, iron_core.IronClient, name="Test", - version="0.1.0", product="iron_worker", token="TEST", - api_version=2, project_id="TEST", port=80, - host="worker-aws-us-east-1.iron.io") - def test_fromArgsBareMinimum(self): client = iron_core.IronClient(name="Test", version="0.1.0", product="iron_worker", token="TEST", project_id="TEST2", From 3d14d4c22bbb99241293c3e6e2af8f80e25fc13d Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 12 Oct 2021 13:45:23 +0300 Subject: [PATCH 10/10] Port tests to Python 3 --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index b04bce4..f9af470 100644 --- a/test.py +++ b/test.py @@ -214,7 +214,7 @@ def test_initKeystoneFromJson(self): keystone_required_keys = ["server", "tenant", "username", "password"] config_keystone_keys = client.keystone.keys() - self.assertItemsEqual(config_keystone_keys, keystone_required_keys) + self.assertCountEqual(config_keystone_keys, keystone_required_keys) self.assertEqual(client.project_id, test_keystone_config["project_id"]) remove_test_config("test_keystone_config.json") @@ -233,7 +233,7 @@ def test_initKeystoneFromConstructor(self): keystone_required_keys = ["server", "tenant", "username", "password"] config_keystone_keys = client.keystone.keys() - self.assertItemsEqual(config_keystone_keys, keystone_required_keys) + self.assertCountEqual(config_keystone_keys, keystone_required_keys) def test_ironTokenProvider(self): client = iron_core.IronTokenProvider("iron-token")