diff --git a/.gitignore b/.gitignore index 3d465db..b8025bf 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,6 @@ ENV/ # Rope project settings .ropeproject + +#OSX stuff +.DS_Store diff --git a/pybdot.ini b/pybdot.ini new file mode 100644 index 0000000..1d8ce80 --- /dev/null +++ b/pybdot.ini @@ -0,0 +1,33 @@ +[Global] +api_key = aApglMV0QO74TpuZACRnSUvGel8ayxf7Z067Nnsa + +[PATENT] +url = https://api.nasa.gov/patents/content + +[APOD] +url = https://api.nasa.gov/planetary/apod + +[NEO] +url = https://api.nasa.gov/neo/rest/v1 + +[EPIC] +url = https://api.nasa.gov/EPIC/api + +[IMAGERY] +url = https://api.nasa.gov/planetary/earth/imagery + +[ASSETS] +url = https://api.nasa.gov/planetary/earth/assets + +[IMAGES] +url = https://images-api.nasa.gov + +[ROVERS] +url = https://api.nasa.gov/mars-photos/api/v1/rovers + +[SOUNDS] +url = https://api.nasa.gov/planetary/sounds + +[TECHPORT] +url = https://api.nasa.gov/planetary/sounds + diff --git a/pybluedot/__init__.py b/pybluedot/__init__.py index e69de29..bdcf8bd 100644 --- a/pybluedot/__init__.py +++ b/pybluedot/__init__.py @@ -0,0 +1 @@ +from .api.patent import Patent \ No newline at end of file diff --git a/pybluedot/api/__init__.py b/pybluedot/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pybluedot/api/apod.py b/pybluedot/api/apod.py new file mode 100644 index 0000000..80bccc2 --- /dev/null +++ b/pybluedot/api/apod.py @@ -0,0 +1,38 @@ +class Apod(object): + """A API to return NASA's astronomy picture of the day. + + Args: + date (str, optional): The date of the APOD image to retrieve. + format YYYY-MM-DD + Default is today's date. + dh (bool, optional): Retrieve url for for high res image. + api_key (str, required): api.nasa.gov key for expanded usage. + Default is DEMO_KEY in config.py. + """ + + def __init__(self, date=None, api_key=config.API_KEY, hd=False): + self.date = date + self.api_key = api_key + self.hd = hd + + def get(self): + """Builds parameter dict that requests library + will use for url query. + """ + self.patent_params = {'date': self.date, + 'api_key': self.api_key, + 'hd': self.hd} + + response = requests.get(config.APOD_URL, params=self.patent_params) + + try: + response.raise_for_status() + + except HTTPError as e: + raise HTTPError(str(e)) + + body = response.json() + + if 'error' in body: + raise ValueError(body['error']) + return body diff --git a/pybluedot/api/base.py b/pybluedot/api/base.py new file mode 100644 index 0000000..84e32ad --- /dev/null +++ b/pybluedot/api/base.py @@ -0,0 +1,45 @@ +from .. import pybdotconfig +import json +import requests + +class NasaApiException(Exception): + """Raised for any exception caused by a call to the Nasa API""" + +def get_api_key(): + config = pybdotconfig.init_config() + config.read('pybdot.ini') + api_key = config['Global']['API_KEY'] + return api_key + +def get_url(api): + """Grabs URL from pybdot.ini for the corresponding API.""" + config = pybdotconfig.init_config() + config.read('pybdot.ini') + url = config[api]['url'] + return url + +def api_get(url, payload): + payload = dict((k, v) for k, v in payload.items() if v) + payload['api_key'] = get_api_key() + response = requests.get(url, params=payload) + response.raise_for_status() + body = response.json() + + if 'error' in body: + raise NasaApiException(body['error']) + + return body + + +class Pybdot(object): + """Default base class, all api classes will inherit from this""" + + def __init__(self, **kwargs): + pass + + + + + + + diff --git a/pybluedot/api/patent.py b/pybluedot/api/patent.py new file mode 100644 index 0000000..d12b51c --- /dev/null +++ b/pybluedot/api/patent.py @@ -0,0 +1,33 @@ +from . import base +from pprint import pprint + +class Patent(object): + """A API to search NASA's patent repository. + + Args: + query (str, required): Search text to filter results. + api_key (str, required): api.nasa.gov key for expanded usage. + concept_tags (str, optional): Return an ordered dict of concepts from + the patent abstract. Default is False. + limit (int, optional): Number of patents to return. Default is None. + """ + + def __init__(self, query, concept_tags=None, limit=None): + self.query = query + self.concept_tags = concept_tags + self.limit = limit + self.url = base.get_url('PATENT') + + def get(self): + self.payload = { + 'query' : self.query, + 'concept_tags' : self.concept_tags, + 'limit' : self.limit, + } + self.response = base.api_get(self.url, self.payload) + return self.response + + def __repr__(self): + return pprint(self.response) + + diff --git a/pybluedot/commands.py b/pybluedot/commands.py deleted file mode 100644 index a9f1466..0000000 --- a/pybluedot/commands.py +++ /dev/null @@ -1,41 +0,0 @@ -""" commands.py contains the data structures that cli.py uses to construct the arguments/subcommand structure. -""" - -# global arguments and flags to the command, like '--verbose' or '--debug' -cmd_arg = [ - { - name: "verbose", - action: "store_const" - }, - { - name: "debug", - action: "store_const" - } -] - -# subcommands used by the program, like 'bdot init' or 'bdot search'. -# Subcommands are tied to functions, so you must specify a function to use with each subcommand. -sub_cmd = [ - { - name: "init", - help: "create a pybluedot configuration file", - options: [ - { - name: "--force", - action: "store_const" - }, - { - name: "--display", - action: "store_const" - } - ], - function: "init" - }, - { - name: "sounds", - help: "just useless boilerplate atm!", - options: [], - function: "sounds" - } -] - diff --git a/pybluedot/pybdot.ini b/pybluedot/pybdot.ini new file mode 100644 index 0000000..1d8ce80 --- /dev/null +++ b/pybluedot/pybdot.ini @@ -0,0 +1,33 @@ +[Global] +api_key = aApglMV0QO74TpuZACRnSUvGel8ayxf7Z067Nnsa + +[PATENT] +url = https://api.nasa.gov/patents/content + +[APOD] +url = https://api.nasa.gov/planetary/apod + +[NEO] +url = https://api.nasa.gov/neo/rest/v1 + +[EPIC] +url = https://api.nasa.gov/EPIC/api + +[IMAGERY] +url = https://api.nasa.gov/planetary/earth/imagery + +[ASSETS] +url = https://api.nasa.gov/planetary/earth/assets + +[IMAGES] +url = https://images-api.nasa.gov + +[ROVERS] +url = https://api.nasa.gov/mars-photos/api/v1/rovers + +[SOUNDS] +url = https://api.nasa.gov/planetary/sounds + +[TECHPORT] +url = https://api.nasa.gov/planetary/sounds + diff --git a/pybluedot/pybdotconfig.py b/pybluedot/pybdotconfig.py new file mode 100644 index 0000000..b93d6d7 --- /dev/null +++ b/pybluedot/pybdotconfig.py @@ -0,0 +1,53 @@ +import configparser +import os + +def create_config(path): + """ + Create pybluedot config file + """ + config = configparser.ConfigParser() + config.add_section('Global') + config.set('Global', 'API_KEY', input('Enter your NASA API Key:')) + config.add_section('PATENT') + config.set('PATENT', 'URL', 'https://api.nasa.gov/patents/content') + config.add_section('APOD') + config.set('APOD', 'URL', 'https://api.nasa.gov/planetary/apod') + config.add_section('NEO') + config.set('NEO', 'URL', 'https://api.nasa.gov/neo/rest/v1') + config.add_section('EPIC') + config.set('EPIC', 'URL', 'https://api.nasa.gov/EPIC/api') + config.add_section('IMAGERY') + config.set('IMAGERY', 'URL', 'https://api.nasa.gov/planetary/earth/imagery') + config.add_section('ASSETS') + config.set('ASSETS', 'URL', 'https://api.nasa.gov/planetary/earth/assets') + config.add_section('IMAGES') + config.set('IMAGES', 'URL', 'https://images-api.nasa.gov') + config.add_section('ROVERS') + config.set('ROVERS', 'URL', 'https://api.nasa.gov/mars-photos/api/v1/rovers') + config.add_section('SOUNDS') + config.set('SOUNDS', 'URL', 'https://api.nasa.gov/planetary/sounds') + config.add_section('TECHPORT') + config.set('TECHPORT', 'URL', 'https://api.nasa.gov/planetary/sounds') + + with open(path, 'w') as config_file: + config.write(config_file) + +def get_config(path): + """ + Return config object. + """ + if not os.path.exists(path): + create_config(path) + config = configparser.ConfigParser() + return config + +def init_config(): + path = 'pybdot.ini' + config = get_config(path) + return config + + +if __name__ == '__main__': + init_config() + + diff --git a/pybluedot/tests/base.py b/pybluedot/tests/base.py index 0a299e8..e2f23c4 100644 --- a/pybluedot/tests/base.py +++ b/pybluedot/tests/base.py @@ -1,3 +1,17 @@ +# Copyright 2016 Jeorry Balasabas +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import unittest diff --git a/pybluedot/tests/unit/test_patent.py b/pybluedot/tests/unit/test_patent.py new file mode 100644 index 0000000..dceca0d --- /dev/null +++ b/pybluedot/tests/unit/test_patent.py @@ -0,0 +1,57 @@ +# Copyright 2016 Jeorry Balasabas +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock +from pybluedot.api import patent +from pybluedot.tests import base +from requests.exceptions import HTTPError + + +class PatentTestSuite(base.DietTestCase): + """This test suite provides some common things relevant to the + tests in this file. All tests should inherit from this class + """ + + def setUp(self): + """Perform setup activities + """ + self.testpatent = patent.Patent(query='plastic') + + @mock.patch('pybluedot.api.patent.requests.get', autospec=True) + def test_get_response_ok(self, mock_get): + mock_response = mock.MagicMock() + expected_dict = {'key': 'value'} + mock_response.json.return_value = expected_dict + mock_get.return_value = mock_response + response_dict = self.testpatent.get() + self.assertEqual(1, mock_response.json.call_count) + self.assertEqual(response_dict, expected_dict) + + @mock.patch('pybluedot.api.patent.requests.get', autospec=True) + def test_get_response_raises_HTTPError(self, mock_get): + mock_response = mock.MagicMock() + mock_response.status_code.return_value = 500 + mock_response.raise_for_status.side_effect = HTTPError('NASA API DOWN') + mock_get.return_value = mock_response + with self.assertRaises(HTTPError): + self.testpatent.get() + + @mock.patch('pybluedot.api.patent.requests.get', autospec=True) + def test_get_response_error_in_body(self, mock_get): + mock_response = mock.MagicMock() + mock_body = {'error': 'there is something wrong'} + mock_response.json.return_value = mock_body + mock_get.return_value = mock_response + with self.assertRaises(ValueError): + self.testpatent.get() diff --git a/pybluedot/tests/unit/test_sample.py b/pybluedot/tests/unit/test_sample.py index fc2aad8..3863362 100644 --- a/pybluedot/tests/unit/test_sample.py +++ b/pybluedot/tests/unit/test_sample.py @@ -1,3 +1,17 @@ +# Copyright 2016 Jeorry Balasabas +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from pybluedot.tests import base