From 327f7da4df62a8cc81d993067f9daf4acc9222b1 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:16:19 +1100 Subject: [PATCH 01/16] MASSIVE update. Now for Python 3 and uses the latest RANDOM.org release. --- .gitignore | 1 + LICENSE | 5 +- README.md | 6 +- randomapi.py | 204 ++++++++++++++++++++++++++++++++------------------- setup.py | 25 +++++++ 5 files changed, 159 insertions(+), 82 deletions(-) create mode 100644 .gitignore create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eeb8a6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/__pycache__ diff --git a/LICENSE b/LICENSE index 7bd10cc..b88bd60 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2014 mitchchn +Original work Copyright (c) 2014 mitchchn +Modified work Copyright (c) 2020 Tantusar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/README.md b/README.md index c7db68e..917460e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ randomapi ========= Python implementation of the RANDOM.org JSON-RPC API: -http://api.random.org/json-rpc/1/ +http://api.random.org/json-rpc/2/ RANDOM.org generates true random numbers using a seed based on atmospheric radio noise. This is useful for applications where pseudo-random generators are not good enough, such as cryptography. @@ -18,7 +18,7 @@ Features Requirements ------------ -- Python 2.6 or higher +- Python 3.6 or higher - An API key from: http://api.random.org Example Usage @@ -27,4 +27,4 @@ Example Usage # Returns a list of 5 true random numbers between 0 and 10 random_client = RandomJSONRPC(api_key) # Requires a valid API key - nums = random_client.generate_integers(n=5, min=0, max=10) + nums = random_client.generate_integers(n=5, min=0, max=10).parse() diff --git a/randomapi.py b/randomapi.py index 5ecaabe..a289c1d 100644 --- a/randomapi.py +++ b/randomapi.py @@ -4,15 +4,18 @@ randomapi.py: a Python implementation of the RANDOM.org JSON-RPC API Author: Mitchell Cohen (mitch.cohen@me.com) -http://github.com/mitchchn/randomapi +https://github.com/mitchchn/randomapi -Date: April 20, 2014 -Version: 0.1 +Maintainer: Thomas Chick (twitter.com/Tantusar) +https://github.com/tantusar/randomapi + +Date: January 18, 2020 +Version: 0.2 RANDOM.org API reference: -- https://api.random.org/json-rpc/1/ +- https://api.random.org/json-rpc/2/ -randomapi.py supports all basic and signed methods in Release 1 +randomapi.py supports all basic and signed methods in Release 2 of the RANDOM.ORG API. It respects delay requests from the server and has the ability to verify digitally-signed data. @@ -24,24 +27,25 @@ # Returns a list of 5 random numbers between 0 and 10 random_client = RandomJSONRPC(api_key) # Requires a valid API key - nums = random_client.generate_integers(n=5, min=0, max=10) + nums = random_client.generate_integers(n=5, min=0, max=10).parse() """ import time import json import logging -import urllib2 +import urllib.request, urllib.error, urllib.parse import uuid from collections import OrderedDict ###################### Constants ############################# -JSON_URL = "https://api.random.org/json-rpc/1/invoke" +JSON_URL = "https://api.random.org/json-rpc/2/invoke" # RANDOM.org API method names INTEGER_METHOD = "generateIntegers" +INTEGER_SEQUENCE_METHOD = "generateIntegerSequences" DECIMAL_METHOD = "generateDecimalFractions" GAUSSIAN_METHOD = "generateGaussians" STRING_METHOD = "generateStrings" @@ -50,11 +54,13 @@ USAGE_METHOD = "getUsage" SIGNED_INTEGER_METHOD = "generateSignedIntegers" +SIGNED_INTEGER_SEQUENCE_METHOD = "generateSignedIntegerSequences" SIGNED_DECIMAL_METHOD = "generateDecimalFractions" SIGNED_GAUSSIAN_METHOD = "generateSignedGaussians" SIGNED_STRING_METHOD = "generateSignedStrings" SIGNED_UUID_METHOD = "generateSignedUUIDs" SIGNED_BLOB_METHOD = "generateSignedBlobs" +RESULT_METHOD = "getResult" VERIFY_SIGNATURE_METHOD = "verifySignature" # RANDOM.org API parameters @@ -68,6 +74,7 @@ RANDOM = "random" AUTHENTICITY = "authenticity" SIGNATURE = "signature" +SERIAL_NUMBER = "serialNumber" # RANDOM.org blob formats @@ -77,10 +84,11 @@ def valid_json_methods(): '''Returns a list of valid JSON-RPC method names from the RANDOM.org API''' - return [INTEGER_METHOD, DECIMAL_METHOD, GAUSSIAN_METHOD, STRING_METHOD, - UUID_METHOD, BLOB_METHOD, USAGE_METHOD, SIGNED_INTEGER_METHOD, - SIGNED_BLOB_METHOD, SIGNED_DECIMAL_METHOD, SIGNED_GAUSSIAN_METHOD, - SIGNED_STRING_METHOD, SIGNED_UUID_METHOD, VERIFY_SIGNATURE_METHOD] + return [INTEGER_METHOD, INTEGER_SEQUENCE_METHOD, DECIMAL_METHOD, GAUSSIAN_METHOD, + STRING_METHOD, UUID_METHOD, BLOB_METHOD, USAGE_METHOD, SIGNED_INTEGER_METHOD, + SIGNED_INTEGER_SEQUENCE_METHOD, SIGNED_BLOB_METHOD, SIGNED_DECIMAL_METHOD, + SIGNED_GAUSSIAN_METHOD, SIGNED_STRING_METHOD, SIGNED_UUID_METHOD, + RESULT_METHOD, VERIFY_SIGNATURE_METHOD] def parse_random(json_string): @@ -105,12 +113,13 @@ def compose_api_call(json_method_name, *args, **kwargs): Returns a fully-formed JSON-RPC string for a RANDOM.org API method :param json_method_name: Name of the method. Can be one of: - INTEGER_METHOD, DECIMAL_METHOD, GAUSSIAN_METHOD, STRING_METHOD, - UUID_METHOD, BLOB_METHOD, USAGE_METHOD, SIGNED_INTEGER_METHOD, - SIGNED_BLOB_METHOD, SIGNED_DECIMAL_METHOD, SIGNED_GAUSSIAN_METHOD, - SIGNED_STRING_METHOD, SIGNED_UUID_METHOD, VERIFY_SIGNATURE_METHOD + INTEGER_METHOD, INTEGER_SEQUENCE_METHOD, DECIMAL_METHOD, GAUSSIAN_METHOD, + STRING_METHOD, UUID_METHOD, BLOB_METHOD, USAGE_METHOD, SIGNED_INTEGER_METHOD, + SIGNED_INTEGER_SEQUENCE_METHOD, SIGNED_BLOB_METHOD, SIGNED_DECIMAL_METHOD, + SIGNED_GAUSSIAN_METHOD, SIGNED_STRING_METHOD, SIGNED_UUID_METHOD, + RESULT_METHOD, VERIFY_SIGNATURE_METHOD :param args: Positional parameters - :param kwargs: Named parameters. See: https://api.random.org/json-rpc/1/basic + :param kwargs: Named parameters. See: https://api.random.org/json-rpc/2/basic for descriptions of methods and their parameters. """ @@ -126,12 +135,12 @@ def compose_api_call(json_method_name, *args, **kwargs): params = args request_data = { - "method": unicode(json_method_name), - "id": unicode(uuid.uuid4()), - "jsonrpc": u"2.0", + "method": str(json_method_name), + "id": str(uuid.uuid4()), + "jsonrpc": "2.0", "params": params } - return json.dumps(request_data) + return json.dumps(request_data).encode('utf-8') def http_request(url, json_string): @@ -141,9 +150,9 @@ def http_request(url, json_string): :param json_string: JSON-String """ - request = urllib2.Request(url, data=json_string) + request = urllib.request.Request(url, data=json_string) request.add_header("Content-Type", "application/json") - response = urllib2.urlopen(request) + response = urllib.request.urlopen(request) response_string = response.read() response.close() @@ -160,7 +169,7 @@ def __init__(self, api_key): The class is simple to use: simply instantiate a RandomJSONRPC object with a valid API key, and call the appropriate method on the server. - For a list of available methods and parameters, see: + For a list of available methods and parameters, see: :param api_key: String representing a RANDOM.org JSON-RPC API key """ @@ -168,22 +177,6 @@ def __init__(self, api_key): self._time_of_last_request = 0 self._advisory_delay = 0 - def _refresh(self): - self._json_data = {} - self._result = {} - self._random = [] - self._signature = "" - - def _populate(self): - if RESULT in self._json_data: - self._result = self._json_data[RESULT] - if ADVISORY_DELAY in self._result: - self._advisory_delay = float(self._result[ADVISORY_DELAY]) / 1000.0 - if RANDOM in self._result: - self._random = self._result[RANDOM] - if SIGNATURE in self._result: - self._signature = self._result[SIGNATURE] - def delay_request(self, requested_delay): elapsed = time.time() - self._time_of_last_request remaining_time = requested_delay - elapsed @@ -193,21 +186,12 @@ def delay_request(self, requested_delay): if remaining_time - elapsed > 0: time.sleep(remaining_time) - def check_errors(self): - '''Checks to see if the received JSON object has errors''' - if 'error' in self._json_data: - error = self._json_data['error'] - code = error['code'] - message = error['message'] - raise Exception( -"""Error code: {}. Message: {} -See: https://api.random.org/json-rpc/1/error-codes""".format(code, message)) - - def send_request(self, request_string): + def send_request(self, request_string, method=""): '''Wraps outgoing JSON requests''' - # Wipe out any data from previous request - self._refresh() + # Create a new response class, using an ordered dict to + # preserve the integrity of signed data + # Respect delay requests from the server if self._time_of_last_request == 0: @@ -220,14 +204,11 @@ def send_request(self, request_string): self._time_of_last_request = time.time() # Use an ordered dict to preserve the integrity of signed data - self._json_data = json_to_ordered_dict(json_string) - self.check_errors() - self._populate() - return self - - def parse(self): - '''Parses the received JSON data object and returns the random data''' - return self._random['data'] + response = RandomJSONResponse(json_to_ordered_dict(json_string), method) + if ADVISORY_DELAY in response._result: + self._advisory_delay = float(response._result[ADVISORY_DELAY]) / 1000.0 + response.method = method + return response ####################### RANDOM.org API methods ########################## @@ -236,7 +217,14 @@ def generate_integers(self, n, min, max, replacement=True, base=10): request_string = compose_api_call( INTEGER_METHOD, apiKey=self.api_key, n=n, min=min, max=max, replacement=replacement, base=base) - return self.send_request(request_string).parse() + return self.send_request(request_string, INTEGER_METHOD) + + def generate_integer_sequences(self, n, length, min, max, replacement=True, base=10): + '''Returns a list of lists of true random integers with a user-defined range''' + request_string = compose_api_call( + INTEGER_SEQUENCE_METHOD, apiKey=self.api_key, + n=n, length=length, min=min, max=max, replacement=replacement, base=base) + return self.send_request(request_string, INTEGER_SEQUENCE_METHOD) def generate_decimal_fractions(self, n, decimal_places, replacement=True): '''Returns a list of true random decimal fractions between [0,1] @@ -244,7 +232,7 @@ def generate_decimal_fractions(self, n, decimal_places, replacement=True): request_string = compose_api_call( DECIMAL_METHOD, apiKey=self.api_key, n=n, decimalPlaces=decimal_places, replacement=replacement) - return self.send_request(request_string).parse() + return self.send_request(request_string, DECIMAL_METHOD) def generate_gaussians(self, n, mean, standard_deviation, significant_digits): @@ -254,7 +242,7 @@ def generate_gaussians(self, n, mean, standard_deviation, n=n, mean=mean, standardDeviation=standard_deviation, significantDigits=significant_digits) - return self.send_request(request_string).parse() + return self.send_request(request_string, GAUSSIAN_METHOD) def generate_strings(self, n, length, characters, replacement=True): '''Returns a list of true random strings composed from a user-defined @@ -262,27 +250,27 @@ def generate_strings(self, n, length, characters, replacement=True): request_string = compose_api_call( STRING_METHOD, apiKey=self.api_key, n=n, length=length, characters=characters, replacement=replacement) - return self.send_request(request_string).parse() + return self.send_request(request_string, STRING_METHOD) def generate_uuids(self, n): '''Returns a list of true random UUIDs (version 4)''' request_string = compose_api_call( UUID_METHOD, apiKey=self.api_key, n=n) - return self.send_request(request_string).parse() + return self.send_request(request_string, UUID_METHOD) def generate_blobs(self, n, size, format=FORMAT_BASE64): '''Returns a list of Binary Large OBjects (BLOBs) containing true random data''' request_string = compose_api_call( BLOB_METHOD, apiKey=self.api_key, n=n, size=size, format=format) - return self.send_request(request_string).parse() + return self.send_request(request_string, BLOB_METHOD) def get_usage(self): '''Returns a dictionary of usage information for the client's API key.''' request_string = compose_api_call( USAGE_METHOD, apiKey=self.api_key) - self.send_request(request_string) + self.send_request(request_string, USAGE_METHOD) return self._result ####################### Digitally-signed API methods ########################## @@ -291,14 +279,20 @@ def generate_signed_integers(self, n, min, max, replacement=True, base=10): request_string = compose_api_call( SIGNED_INTEGER_METHOD, apiKey=self.api_key, n=n, min=min, max=max, replacement=replacement, base=base) - return self.send_request(request_string).parse() + return self.send_request(request_string, SIGNED_INTEGER_METHOD) + + def generate_signed_integer_sequences(self, n, length, min, max, replacement=True, base=10): + request_string = compose_api_call( + SIGNED_INTEGER_SEQUENCE_METHOD, apiKey=self.api_key, n=n, length=length, min=min, + max=max, replacement=replacement, base=base) + return self.send_request(request_string, SIGNED_INTEGER_SEQUENCE_METHOD) def generate_signed_decimal_fractions(self, n, decimal_places, replacement=True): request_string = compose_api_call( SIGNED_DECIMAL_METHOD, apiKey=self.api_key, n=n, decimalPlaces=decimal_places, replacement=replacement) - return self.send_request(request_string).parse() + return self.send_request(request_string, SIGNED_DECIMAL_METHOD) def generate_signed_gaussians(self, n, mean, standard_deviation, significant_digits): @@ -307,24 +301,33 @@ def generate_signed_gaussians(self, n, mean, standard_deviation, n=n, mean=mean, standardDeviation=standard_deviation, significantDigits=significant_digits) - return self.send_request(request_string).parse() + return self.send_request(request_string, SIGNED_GAUSSIAN_METHOD) def generate_signed_strings(self, n, length, characters, replacement=True): request_string = compose_api_call( SIGNED_STRING_METHOD, apiKey=self.api_key, n=n, length=length, characters=characters, replacement=replacement) - return self.send_request(request_string).parse() + return self.send_request(request_string, SIGNED_STRING_METHOD) def generate_signed_uuids(self, n): request_string = compose_api_call( SIGNED_UUID_METHOD, apiKey=self.api_key, n=n) - return self.send_request(request_string).parse() + return self.send_request(request_string, SIGNED_UUID_METHOD) def generate_signed_blobs(self, n, size, format=FORMAT_BASE64): request_string = compose_api_call( SIGNED_BLOB_METHOD, apiKey=self.api_key, n=n, size=size, format=format) - return self.send_request(request_string).parse() + return self.send_request(request_string, SIGNED_BLOB_METHOD) + + def get_result(self, serial_number): + '''Returns the result of a previous request given a supplied serial + number.''' + request_string = compose_api_call( + RESULT_METHOD, apiKey=self.api_key, serialNumber=serial_number) + response = self.send_request(request_string, RESULT_METHOD) + response._method = response._random['method'] + return response def verify_signature(self): """ @@ -337,9 +340,56 @@ def verify_signature(self): VERIFY_SIGNATURE_METHOD, random=self._random, signature=self._signature) - self.send_request(json_string) + response = self.send_request(json_string, VERIFY_SIGNATURE_METHOD) - if AUTHENTICITY in self._result: - return self._result[AUTHENTICITY] + if AUTHENTICITY in response._result: + return response._result[AUTHENTICITY] else: raise Exception("Unable to verify authenticity of signed data") + +class RandomJSONResponse: + def __init__(self, json_data, method=""): + self._json_data = json_data + self._result = {} + self._random = [] + self._signature = "" + self._serial_number = 0 + self._method = method + self.check_errors() + self._populate() + + def check_errors(self): + '''Checks to see if the received JSON object has errors''' + if 'error' in self._json_data: + error = self._json_data['error'] + code = error['code'] + message = error['message'] + raise Exception( +"""Error code: {}. Message: {} +See: https://api.random.org/json-rpc/2/error-codes""".format(code, message)) + + def _populate(self): + if RESULT in self._json_data: + self._result = self._json_data[RESULT] + if RANDOM in self._result: + self._random = self._result[RANDOM] + if SIGNATURE in self._result: + self._signature = self._result[SIGNATURE] + if SERIAL_NUMBER in self._random: + self._serial_number = self._random[SERIAL_NUMBER] + + def parse(self): + '''Parses the received JSON data object and returns the random data''' + return self._random['data'] + + def __repr__(self): + try: + return "" + except: + return "" + + def __str__(self): + try: + return str(self._random['data']) + except: + return "" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..876a142 --- /dev/null +++ b/setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +with open("README.md", "r") as fh: + long_description = fh.read() + +setup( + name = 'randomapi', + version = '0.2', + description = 'RANDOM.org JSON-RPC API implementation', + long_description = long_description, + long_description_content_type = 'text/markdown', + author = 'Mitchell Cohen ' + author_email = 'mitch.cohen@me.com' + maintainer = 'Thomas Chick (twitter.com/Tantusar)' + py_modules = ['randomapi'], + url = 'https://github.com/Tantusar/randomapi', + license = 'MIT License', + classifiers = [ + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + "Operating System :: OS Independent", + ], + python_requires='>=3.6' +) From 7a2b592d13292d08dcce62aa3dd723a4f4973029 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:18:28 +1100 Subject: [PATCH 02/16] Fix classifiers. --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 876a142..d8041d6 100644 --- a/setup.py +++ b/setup.py @@ -16,10 +16,12 @@ url = 'https://github.com/Tantusar/randomapi', license = 'MIT License', classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - "Operating System :: OS Independent", + 'Operating System :: OS Independent', ], python_requires='>=3.6' ) From 43fa0bdf2d9b846ad679f7e22a916fb752168162 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:21:26 +1100 Subject: [PATCH 03/16] Setup.CFG --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b88034e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md From 89b026eb9625bf6527879bad2d033d06f53aef03 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:24:15 +1100 Subject: [PATCH 04/16] And a URL. --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d8041d6..51520e0 100644 --- a/setup.py +++ b/setup.py @@ -23,5 +23,6 @@ 'Programming Language :: Python :: 3', 'Operating System :: OS Independent', ], - python_requires='>=3.6' + python_requires = '>=3.6' + download_url = 'https://github.com/Tantusar/randomapi/archive/v0.2.tar.gz' ) From e2b1dd5b1e6df208f7da9d54362053b4fea86956 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:25:05 +1100 Subject: [PATCH 05/16] fix readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 917460e..801605f 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ Requirements Example Usage ------------- + from randomapi import RandomJSONRPC + # Returns a list of 5 true random numbers between 0 and 10 random_client = RandomJSONRPC(api_key) # Requires a valid API key From 6fb05bdca9af7455de0e41c17f5a8abecb04acee Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:27:27 +1100 Subject: [PATCH 06/16] further fix readme --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 801605f..253b43c 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,11 @@ Requirements Example Usage ------------- +```py +from randomapi import RandomJSONRPC - from randomapi import RandomJSONRPC +# Returns a list of 5 true random numbers between 0 and 10 - # Returns a list of 5 true random numbers between 0 and 10 - - random_client = RandomJSONRPC(api_key) # Requires a valid API key - nums = random_client.generate_integers(n=5, min=0, max=10).parse() +random_client = RandomJSONRPC(api_key) # Requires a valid API key +nums = random_client.generate_integers(n=5, min=0, max=10).parse() +``` From b34cc2e70fbcffddc4f877efb5c6ab27a195e253 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:31:27 +1100 Subject: [PATCH 07/16] fix setup.py --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 51520e0..4c2a9a4 100644 --- a/setup.py +++ b/setup.py @@ -9,9 +9,9 @@ description = 'RANDOM.org JSON-RPC API implementation', long_description = long_description, long_description_content_type = 'text/markdown', - author = 'Mitchell Cohen ' + author = 'Mitchell Cohen ', author_email = 'mitch.cohen@me.com' - maintainer = 'Thomas Chick (twitter.com/Tantusar)' + maintainer = 'Thomas Chick (twitter.com/Tantusar)', py_modules = ['randomapi'], url = 'https://github.com/Tantusar/randomapi', license = 'MIT License', @@ -23,6 +23,6 @@ 'Programming Language :: Python :: 3', 'Operating System :: OS Independent', ], - python_requires = '>=3.6' + python_requires = '>=3.6', download_url = 'https://github.com/Tantusar/randomapi/archive/v0.2.tar.gz' ) From 85d86da1f57e54774874810ac16929a3b27f1e1d Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:34:20 +1100 Subject: [PATCH 08/16] really fix setup.py though --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4c2a9a4..2bf7925 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ long_description = long_description, long_description_content_type = 'text/markdown', author = 'Mitchell Cohen ', - author_email = 'mitch.cohen@me.com' + author_email = 'mitch.cohen@me.com', maintainer = 'Thomas Chick (twitter.com/Tantusar)', py_modules = ['randomapi'], url = 'https://github.com/Tantusar/randomapi', From dbd4da4fb5ad68e6a81ac0b9d6039fbf70fce7c8 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:41:12 +1100 Subject: [PATCH 09/16] ignore update --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index eeb8a6e..2f41a33 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ **/__pycache__ +**/dist +**/randomapi.egg-info From 9ab810d0edf8a015bf466e53581ab90e6b9f2930 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 02:48:21 +1100 Subject: [PATCH 10/16] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index b88bd60..ccd2e5e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -The MIT License (MIT) +MIT License (MIT) Original work Copyright (c) 2014 mitchchn Modified work Copyright (c) 2020 Tantusar From 7ce47ad0788783172cf8ae26f3456b7d9b4f542f Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 03:04:18 +1100 Subject: [PATCH 11/16] We are interested in one stinkin' badge. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 253b43c..d21771c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ randomapi ========= +[![PyPI version](https://badge.fury.io/py/randomapi.svg)](https://badge.fury.io/py/randomapi) + Python implementation of the RANDOM.org JSON-RPC API: http://api.random.org/json-rpc/2/ From a58c3a8061f269681a5ed3c28c21f521216d9845 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 10:29:03 +1100 Subject: [PATCH 12/16] We got Python 2, guys! --- README.md | 1 + randomapi.py | 18 ++++++++++++++---- setup.py | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d21771c..6c6928b 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Features Requirements ------------ +- Python 2.6 or higher - Python 3.6 or higher - An API key from: http://api.random.org diff --git a/randomapi.py b/randomapi.py index a289c1d..6ca1c0b 100644 --- a/randomapi.py +++ b/randomapi.py @@ -10,7 +10,7 @@ https://github.com/tantusar/randomapi Date: January 18, 2020 -Version: 0.2 +Version: 0.3 RANDOM.org API reference: - https://api.random.org/json-rpc/2/ @@ -34,7 +34,17 @@ import time import json import logging -import urllib.request, urllib.error, urllib.parse + +# Python 2/3 Compatibility +try: + from urllib.request import urlopen, Request + from urllib.error import HTTPError + from urllib.parse import urlparse, urlencode +except ImportError: + from urlparse import urlparse + from urllib import urlencode + from urllib2 import urlopen, Request, HTTPError + import uuid from collections import OrderedDict @@ -150,9 +160,9 @@ def http_request(url, json_string): :param json_string: JSON-String """ - request = urllib.request.Request(url, data=json_string) + request = Request(url, data=json_string) request.add_header("Content-Type", "application/json") - response = urllib.request.urlopen(request) + response = urlopen(request) response_string = response.read() response.close() diff --git a/setup.py b/setup.py index 2bf7925..eb1cc4a 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name = 'randomapi', - version = '0.2', + version = '0.3', description = 'RANDOM.org JSON-RPC API implementation', long_description = long_description, long_description_content_type = 'text/markdown', @@ -24,5 +24,5 @@ 'Operating System :: OS Independent', ], python_requires = '>=3.6', - download_url = 'https://github.com/Tantusar/randomapi/archive/v0.2.tar.gz' + download_url = 'https://github.com/Tantusar/randomapi/archive/v0.3.tar.gz' ) From 289c96328239e1f209394bf7e6b3e1db64c66811 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 10:30:38 +1100 Subject: [PATCH 13/16] fix README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 6c6928b..aff3ea2 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ Features Requirements ------------ -- Python 2.6 or higher -- Python 3.6 or higher +- Python 2.6 or higher, or 3.6 or higher - An API key from: http://api.random.org Example Usage From eff1dfa5c69f6d55e4896a2a8f8e06827789415c Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 10:36:57 +1100 Subject: [PATCH 14/16] Setup fix. --- randomapi.py | 2 +- setup.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/randomapi.py b/randomapi.py index 6ca1c0b..44fe49f 100644 --- a/randomapi.py +++ b/randomapi.py @@ -10,7 +10,7 @@ https://github.com/tantusar/randomapi Date: January 18, 2020 -Version: 0.3 +Version: 0.3.1 RANDOM.org API reference: - https://api.random.org/json-rpc/2/ diff --git a/setup.py b/setup.py index eb1cc4a..39b4163 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name = 'randomapi', - version = '0.3', + version = '0.3.1', description = 'RANDOM.org JSON-RPC API implementation', long_description = long_description, long_description_content_type = 'text/markdown', @@ -20,9 +20,10 @@ 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Operating System :: OS Independent', ], - python_requires = '>=3.6', - download_url = 'https://github.com/Tantusar/randomapi/archive/v0.3.tar.gz' + python_requires = '>=2.6', '!=3.0.*', '!=3.1.*', '!=3.2.*', '!=3.3.*', '!=3.4.*', '!=3.5.*', '>=3.6', + download_url = 'https://github.com/Tantusar/randomapi/archive/v0.3.1.tar.gz' ) From 777fbbab6fe08269fd7c3e51b240df0fde46a121 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 10:40:07 +1100 Subject: [PATCH 15/16] Really, though. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 39b4163..3c13e57 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,6 @@ 'Programming Language :: Python :: 3', 'Operating System :: OS Independent', ], - python_requires = '>=2.6', '!=3.0.*', '!=3.1.*', '!=3.2.*', '!=3.3.*', '!=3.4.*', '!=3.5.*', '>=3.6', + python_requires = '>=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, >=3.6', download_url = 'https://github.com/Tantusar/randomapi/archive/v0.3.1.tar.gz' ) From c3accc8d5570479821a5d26d6789ca91a4a71338 Mon Sep 17 00:00:00 2001 From: Thomas Chick Date: Sat, 18 Jan 2020 13:53:04 +1100 Subject: [PATCH 16/16] Fix get_usage. --- randomapi.py | 6 ++---- setup.py | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/randomapi.py b/randomapi.py index 44fe49f..794fab1 100644 --- a/randomapi.py +++ b/randomapi.py @@ -10,7 +10,7 @@ https://github.com/tantusar/randomapi Date: January 18, 2020 -Version: 0.3.1 +Version: 0.3.2 RANDOM.org API reference: - https://api.random.org/json-rpc/2/ @@ -217,7 +217,6 @@ def send_request(self, request_string, method=""): response = RandomJSONResponse(json_to_ordered_dict(json_string), method) if ADVISORY_DELAY in response._result: self._advisory_delay = float(response._result[ADVISORY_DELAY]) / 1000.0 - response.method = method return response ####################### RANDOM.org API methods ########################## @@ -280,8 +279,7 @@ def get_usage(self): API key.''' request_string = compose_api_call( USAGE_METHOD, apiKey=self.api_key) - self.send_request(request_string, USAGE_METHOD) - return self._result + return self.send_request(request_string, USAGE_METHOD) ####################### Digitally-signed API methods ########################## diff --git a/setup.py b/setup.py index 3c13e57..1e42452 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name = 'randomapi', - version = '0.3.1', + version = '0.3.2', description = 'RANDOM.org JSON-RPC API implementation', long_description = long_description, long_description_content_type = 'text/markdown', @@ -25,5 +25,5 @@ 'Operating System :: OS Independent', ], python_requires = '>=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, >=3.6', - download_url = 'https://github.com/Tantusar/randomapi/archive/v0.3.1.tar.gz' + download_url = 'https://github.com/Tantusar/randomapi/archive/v0.3.2.tar.gz' )