diff --git a/README.md b/README.md index 1f015d0..eeb02ca 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ This variable will not be available in later sessions. pynigma uses `unittest`. To run the tests ```bash -$ python -m unittest discovery tests/ +$ python -m unittest discover tests/ ``` # Usage @@ -121,6 +121,8 @@ for column in metadata['result']['columns']: print column['label'] ``` +The column metadata returned by pynigma will include an additional key not returned by the endpoint, 'python_type', representing the Python data type that corresponds to the type string returned. Mappings are based on the [PL/Python PostgreSQL to Python mappings](http://www.postgresql.org/docs/9.4/static/plpython-data.html). If pynigma cannot determine the Python data type using these mappings, it will default to `str`, which is consistent with PL/Python. + ### Stats Endpoint The [stats endpoint](https://app.enigma.io/api#stats) provides statistics on columns within table datapaths. The stats endpoint is accessed via the `get_stats()` method. diff --git a/pynigma/__init__.py b/pynigma/__init__.py index 2203523..6a940ee 100644 --- a/pynigma/__init__.py +++ b/pynigma/__init__.py @@ -1,2 +1,2 @@ __all__ = ['client'] -__version__ = '0.0.1' \ No newline at end of file +__version__ = '0.0.2' \ No newline at end of file diff --git a/pynigma/client.py b/pynigma/client.py index 7321348..dbdded2 100644 --- a/pynigma/client.py +++ b/pynigma/client.py @@ -1,3 +1,5 @@ +from datetime import date, datetime +import decimal import requests import warnings @@ -5,6 +7,29 @@ API_VERSION = 'v2' +# Data type mappings are based on PL/Python PostgreSQL to Python mappings +# http://www.postgresql.org/docs/9.4/static/plpython-data.html +_data_type_mapping = { + 'bigint': long, + 'boolean': bool, + 'bytea': str, + 'character varying': str, + 'date': date, + 'double': float, + 'double precision': float, + 'int': int, + 'integer': int, + 'numeric': decimal.Decimal, + 'oid': long, + 'real': float, + 'smallint': int, + 'text': str, + 'timestamp without time zone': datetime, + 'timestamp': datetime, + 'varcahr': str +} + + class EnigmaAPI(object): '''The EnigmaAPI provides access to the five different endpoints of the @@ -96,6 +121,9 @@ def get_data(self, datapath, **kwargs): def get_metadata(self, datapath, **kwargs): '''Returns an HTTP response from the metadata endpoint as decoded JSON. + The column metadata will include an additional key, 'python_type', + representing the corresponding Python data type. If the Python data + type can't be determined, it will default to str. ARGUMENTS --------- @@ -115,7 +143,13 @@ def get_metadata(self, datapath, **kwargs): Full Name Appointment Number ''' - return self._request(resource='meta', datapath=datapath, **kwargs) + metadata_res = self._request( + resource='meta', datapath=datapath, **kwargs) + # Map returned type strings to Python data types + for column in metadata_res['result']['columns']: + column['python_type'] = _data_type_mapping.get( + column['type'].split('_')[1], str) + return metadata_res def get_stats(self, datapath, **kwargs): '''Returns an HTTP response from the stats endpoint as decoded JSON. diff --git a/setup.py b/setup.py index 9458642..a360f27 100644 --- a/setup.py +++ b/setup.py @@ -17,5 +17,5 @@ def readme(): author_email = 'jane@thejunglejane.com', license = 'MIT', url = 'https://github.com/thejunglejane/pynigma', - download_url = 'https://github.com/thejunglejane/pynigma/tarball/0.0.1' + download_url = 'https://github.com/thejunglejane/pynigma/tarball/0.0.2' ) diff --git a/tests/test_client.py b/tests/test_client.py index b9b20c3..84dacb3 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,4 +1,5 @@ from pynigma import client +import decimal import unittest import os @@ -102,6 +103,24 @@ def test_get_metadata_no_datapath_failure(self): with self.assertRaises(TypeError): self.new_client.get_metadata() + def test_get_metadata_python_data_type(self): + '''Does get_metadata() return a dictionary key corresponding to the + Python data type of a column? + ''' + metadata = self.new_client.get_metadata( + datapath='us.gov.whitehouse.visitor-list') + self.assertIsNotNone( + metadata['result']['columns'][0].get('python_type')) + + def test_get_metadata_correct_python_data_type(self): + '''Does get_metadata() return the correct Python data type for the type + string returned? + ''' + metadata = self.new_client.get_metadata( + datapath='us.gov.whitehouse.salaries.2011') + self.assertEquals( + metadata['result']['columns'][2]['python_type'], decimal.Decimal) + def test_get_stats_no_datapath_failure(self): '''Does get_stats() raise a TypeError when no datapath is passed? '''