diff --git a/.gitignore b/.gitignore index 673e9e6..7238156 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ lib/ apod/__pycache__/ .elasticbeanstalk/ *.zip* -Archive.zip \ No newline at end of file +Archive.zip +venv/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dafc9bb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3-alpine + +WORKDIR /usr/src/app +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt +COPY . . +EXPOSE 5000 +ENTRYPOINT ["python"] +CMD ["application.py"] diff --git a/README.md b/README.md index 52089df..1a1812b 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,9 @@ No one watching this repository has anything to do with Astronomy Photo of the D 2. [`virtualenv` environment](#virtualenv) 3. [`conda` environment](#conda) 2. [Docs](#docs) -3. [Feedback](#feedback) -4. [Author](#author) +3. [APOD parser](#TheAPODParser) +4. [Feedback](#feedback) +5. [Author](#author)   ## Getting started @@ -53,7 +54,7 @@ PYTHONPATH=./lib python application.py   ### `virtualenv` environment -1. Clone the rep +1. Clone the repo ```bash git clone https://github.com/nasa/apod-api ``` @@ -104,13 +105,33 @@ pip install -r requirements.txt ```bash python application.py ``` + +### Run it in Docker + +1. Clone the repo +```bash +git clone https://github.com/nasa/apod-api.git +``` +2. `cd` into the new directory +```bash +cd apod-api +``` +3. Build the image +```bash +docker build . -t apod-api +``` +4. Run the image +```bash +docker run -p 5000:5000 apod-api +``` +   ## Docs ### Endpoint: `//apod` There is only one endpoint in this service which takes 2 optional fields -as parameters to a http GET request. A JSON dictionary is returned nominally. +as parameters to a http GET request. A JSON dictionary is returned nominally. **Fields** @@ -151,14 +172,14 @@ localhost:5000/v1/apod?date=2014-10-01&concept_tags=True image_set: "apod" }, concept_tags: "True", - date: "2013-10-01", + date: "2013-10-01", title: "Filaments of the Vela Supernova Remnant", url: "http://apod.nasa.gov/apod/image/1310/velafilaments_jadescope_960.jpg", explanation: "The explosion is over but the consequences continue. About eleven thousand years ago a star in the constellation of Vela could be seen to explode, - creating a strange point of light briefly visible to humans living near the - beginning of recorded history. The outer layers of the star crashed into the - interstellar medium, driving a shock wave that is still visible today. A roughly + creating a strange point of light briefly visible to humans living near the + beginning of recorded history. The outer layers of the star crashed into the + interstellar medium, driving a shock wave that is still visible today. A roughly spherical, expanding shock wave is visible in X-rays. The above image captures some of that filamentary and gigantic shock in visible light. As gas flies away from the detonated star, it decays and reacts with the interstellar medium, producing light @@ -193,50 +214,50 @@ https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&count=5 ```jsoniq [ { - "copyright": "Panther Observatory", - "date": "2006-04-15", - "explanation": "In this stunning cosmic vista, galaxy M81 is on the left surrounded by blue spiral arms. On the right marked by massive gas and dust clouds, is M82. These two mammoth galaxies have been locked in gravitational combat for the past billion years. The gravity from each galaxy dramatically affects the other during each hundred million-year pass. Last go-round, M82's gravity likely raised density waves rippling around M81, resulting in the richness of M81's spiral arms. But M81 left M82 with violent star forming regions and colliding gas clouds so energetic the galaxy glows in X-rays. In a few billion years only one galaxy will remain.", - "hdurl": "https://apod.nasa.gov/apod/image/0604/M81_M82_schedler_c80.jpg", - "media_type": "image", - "service_version": "v1", - "title": "Galaxy Wars: M81 versus M82", + "copyright": "Panther Observatory", + "date": "2006-04-15", + "explanation": "In this stunning cosmic vista, galaxy M81 is on the left surrounded by blue spiral arms. On the right marked by massive gas and dust clouds, is M82. These two mammoth galaxies have been locked in gravitational combat for the past billion years. The gravity from each galaxy dramatically affects the other during each hundred million-year pass. Last go-round, M82's gravity likely raised density waves rippling around M81, resulting in the richness of M81's spiral arms. But M81 left M82 with violent star forming regions and colliding gas clouds so energetic the galaxy glows in X-rays. In a few billion years only one galaxy will remain.", + "hdurl": "https://apod.nasa.gov/apod/image/0604/M81_M82_schedler_c80.jpg", + "media_type": "image", + "service_version": "v1", + "title": "Galaxy Wars: M81 versus M82", "url": "https://apod.nasa.gov/apod/image/0604/M81_M82_schedler_c25.jpg" - }, + }, { - "date": "2013-07-22", - "explanation": "You are here. Everyone you've ever known is here. Every human who has ever lived -- is here. Pictured above is the Earth-Moon system as captured by the Cassini mission orbiting Saturn in the outer Solar System. Earth is the brighter and bluer of the two spots near the center, while the Moon is visible to its lower right. Images of Earth from Saturn were taken on Friday. Quickly released unprocessed images were released Saturday showing several streaks that are not stars but rather cosmic rays that struck the digital camera while it was taking the image. The above processed image was released earlier today. At nearly the same time, many humans on Earth were snapping their own pictures of Saturn. Note: Today's APOD has been updated.", - "hdurl": "https://apod.nasa.gov/apod/image/1307/earthmoon2_cassini_946.jpg", - "media_type": "image", - "service_version": "v1", - "title": "Earth and Moon from Saturn", + "date": "2013-07-22", + "explanation": "You are here. Everyone you've ever known is here. Every human who has ever lived -- is here. Pictured above is the Earth-Moon system as captured by the Cassini mission orbiting Saturn in the outer Solar System. Earth is the brighter and bluer of the two spots near the center, while the Moon is visible to its lower right. Images of Earth from Saturn were taken on Friday. Quickly released unprocessed images were released Saturday showing several streaks that are not stars but rather cosmic rays that struck the digital camera while it was taking the image. The above processed image was released earlier today. At nearly the same time, many humans on Earth were snapping their own pictures of Saturn. Note: Today's APOD has been updated.", + "hdurl": "https://apod.nasa.gov/apod/image/1307/earthmoon2_cassini_946.jpg", + "media_type": "image", + "service_version": "v1", + "title": "Earth and Moon from Saturn", "url": "https://apod.nasa.gov/apod/image/1307/earthmoon2_cassini_960.jpg" - }, + }, { - "copyright": "Joe Orman", - "date": "2000-04-06", - "explanation": "Rising before the Sun on February 2nd, astrophotographer Joe Orman anticipated this apparition of the bright morning star Venus near a lovely crescent Moon above a neighbor's house in suburban Phoenix, Arizona, USA. Fortunately, the alignment of bright planets and the Moon is one of the most inspiring sights in the night sky and one that is often easy to enjoy and share without any special equipment. Take tonight, for example. Those blessed with clear skies can simply step outside near sunset and view a young crescent Moon very near three bright planets in the west Jupiter, Mars, and Saturn. Jupiter will be the unmistakable brightest star near the Moon with a reddish Mars just to Jupiter's north and pale yellow Saturn directly above. Of course, these sky shows create an evocative picture but the planets and Moon just appear to be near each other -- they are actually only approximately lined up and lie in widely separated orbits. Unfortunately, next month's highly publicized alignment of planets on May 5th will be lost from view in the Sun's glare but such planetary alignments occur repeatedly and pose no danger to planet Earth.", - "hdurl": "https://apod.nasa.gov/apod/image/0004/vm_orman_big.jpg", - "media_type": "image", - "service_version": "v1", - "title": "Venus, Moon, and Neighbors", + "copyright": "Joe Orman", + "date": "2000-04-06", + "explanation": "Rising before the Sun on February 2nd, astrophotographer Joe Orman anticipated this apparition of the bright morning star Venus near a lovely crescent Moon above a neighbor's house in suburban Phoenix, Arizona, USA. Fortunately, the alignment of bright planets and the Moon is one of the most inspiring sights in the night sky and one that is often easy to enjoy and share without any special equipment. Take tonight, for example. Those blessed with clear skies can simply step outside near sunset and view a young crescent Moon very near three bright planets in the west Jupiter, Mars, and Saturn. Jupiter will be the unmistakable brightest star near the Moon with a reddish Mars just to Jupiter's north and pale yellow Saturn directly above. Of course, these sky shows create an evocative picture but the planets and Moon just appear to be near each other -- they are actually only approximately lined up and lie in widely separated orbits. Unfortunately, next month's highly publicized alignment of planets on May 5th will be lost from view in the Sun's glare but such planetary alignments occur repeatedly and pose no danger to planet Earth.", + "hdurl": "https://apod.nasa.gov/apod/image/0004/vm_orman_big.jpg", + "media_type": "image", + "service_version": "v1", + "title": "Venus, Moon, and Neighbors", "url": "https://apod.nasa.gov/apod/image/0004/vm_orman.jpg" - }, + }, { - "date": "2014-07-12", - "explanation": "A new star, likely the brightest supernova in recorded human history, lit up planet Earth's sky in the year 1006 AD. The expanding debris cloud from the stellar explosion, found in the southerly constellation of Lupus, still puts on a cosmic light show across the electromagnetic spectrum. In fact, this composite view includes X-ray data in blue from the Chandra Observatory, optical data in yellowish hues, and radio image data in red. Now known as the SN 1006 supernova remnant, the debris cloud appears to be about 60 light-years across and is understood to represent the remains of a white dwarf star. Part of a binary star system, the compact white dwarf gradually captured material from its companion star. The buildup in mass finally triggered a thermonuclear explosion that destroyed the dwarf star. Because the distance to the supernova remnant is about 7,000 light-years, that explosion actually happened 7,000 years before the light reached Earth in 1006. Shockwaves in the remnant accelerate particles to extreme energies and are thought to be a source of the mysterious cosmic rays.", - "hdurl": "https://apod.nasa.gov/apod/image/1407/sn1006c.jpg", - "media_type": "image", - "service_version": "v1", - "title": "SN 1006 Supernova Remnant", + "date": "2014-07-12", + "explanation": "A new star, likely the brightest supernova in recorded human history, lit up planet Earth's sky in the year 1006 AD. The expanding debris cloud from the stellar explosion, found in the southerly constellation of Lupus, still puts on a cosmic light show across the electromagnetic spectrum. In fact, this composite view includes X-ray data in blue from the Chandra Observatory, optical data in yellowish hues, and radio image data in red. Now known as the SN 1006 supernova remnant, the debris cloud appears to be about 60 light-years across and is understood to represent the remains of a white dwarf star. Part of a binary star system, the compact white dwarf gradually captured material from its companion star. The buildup in mass finally triggered a thermonuclear explosion that destroyed the dwarf star. Because the distance to the supernova remnant is about 7,000 light-years, that explosion actually happened 7,000 years before the light reached Earth in 1006. Shockwaves in the remnant accelerate particles to extreme energies and are thought to be a source of the mysterious cosmic rays.", + "hdurl": "https://apod.nasa.gov/apod/image/1407/sn1006c.jpg", + "media_type": "image", + "service_version": "v1", + "title": "SN 1006 Supernova Remnant", "url": "https://apod.nasa.gov/apod/image/1407/sn1006c_c800.jpg" - }, + }, { - "date": "1997-01-21", - "explanation": "In Jules Verne's science fiction classic A Journey to the Center of the Earth, Professor Hardwigg and his fellow explorers encounter many strange and exciting wonders. What wonders lie at the center of our Galaxy? Astronomers now know of some of the bizarre objects which exist there, like vast dust clouds,\r bright young stars, swirling rings of gas, and possibly even a large black hole. Much of the Galactic center region is shielded from our view in visible light by the intervening dust and gas. But it can be explored using other forms of electromagnetic radiation, like radio, infrared, X-rays, and gamma rays. This beautiful high resolution image of the Galactic center region in infrared light was made by the SPIRIT III telescope onboard the Midcourse Space Experiment. The center itself appears as a bright spot near the middle of the roughly 1x3 degree field of view, the plane of the Galaxy is vertical, and the north galactic pole is towards the right. The picture is in false color - starlight appears blue while dust is greenish grey, tending to red in the cooler areas.", - "hdurl": "https://apod.nasa.gov/apod/image/9701/galcen_msx_big.gif", - "media_type": "image", - "service_version": "v1", - "title": "Journey to the Center of the Galaxy \r\nCredit:", + "date": "1997-01-21", + "explanation": "In Jules Verne's science fiction classic A Journey to the Center of the Earth, Professor Hardwigg and his fellow explorers encounter many strange and exciting wonders. What wonders lie at the center of our Galaxy? Astronomers now know of some of the bizarre objects which exist there, like vast dust clouds,\r bright young stars, swirling rings of gas, and possibly even a large black hole. Much of the Galactic center region is shielded from our view in visible light by the intervening dust and gas. But it can be explored using other forms of electromagnetic radiation, like radio, infrared, X-rays, and gamma rays. This beautiful high resolution image of the Galactic center region in infrared light was made by the SPIRIT III telescope onboard the Midcourse Space Experiment. The center itself appears as a bright spot near the middle of the roughly 1x3 degree field of view, the plane of the Galaxy is vertical, and the north galactic pole is towards the right. The picture is in false color - starlight appears blue while dust is greenish grey, tending to red in the cooler areas.", + "hdurl": "https://apod.nasa.gov/apod/image/9701/galcen_msx_big.gif", + "media_type": "image", + "service_version": "v1", + "title": "Journey to the Center of the Galaxy \r\nCredit:", "url": "https://apod.nasa.gov/apod/image/9701/galcen_msx.jpg" } ] @@ -248,7 +269,7 @@ https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&count=5 ```bash -https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&start_date=2017-07-08&end_date=2017-07-10 +https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&start_date=2017-07-08&end_date=2017-07-10 ```
See Return Object @@ -257,31 +278,31 @@ https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&start_date=2017-07-08&end_d ```jsoniq [ { - "copyright": "T. Rector", - "date": "2017-07-08", - "explanation": "Similar in size to large, bright spiral galaxies in our neighborhood, IC 342 is a mere 10 million light-years distant in the long-necked, northern constellation Camelopardalis. A sprawling island universe, IC 342 would otherwise be a prominent galaxy in our night sky, but it is hidden from clear view and only glimpsed through the veil of stars, gas and dust clouds along the plane of our own Milky Way galaxy. Even though IC 342's light is dimmed by intervening cosmic clouds, this sharp telescopic image traces the galaxy's own obscuring dust, blue star clusters, and glowing pink star forming regions along spiral arms that wind far from the galaxy's core. IC 342 may have undergone a recent burst of star formation activity and is close enough to have gravitationally influenced the evolution of the local group of galaxies and the Milky Way.", - "hdurl": "https://apod.nasa.gov/apod/image/1707/ic342_rector2048.jpg", - "media_type": "image", - "service_version": "v1", - "title": "Hidden Galaxy IC 342", + "copyright": "T. Rector", + "date": "2017-07-08", + "explanation": "Similar in size to large, bright spiral galaxies in our neighborhood, IC 342 is a mere 10 million light-years distant in the long-necked, northern constellation Camelopardalis. A sprawling island universe, IC 342 would otherwise be a prominent galaxy in our night sky, but it is hidden from clear view and only glimpsed through the veil of stars, gas and dust clouds along the plane of our own Milky Way galaxy. Even though IC 342's light is dimmed by intervening cosmic clouds, this sharp telescopic image traces the galaxy's own obscuring dust, blue star clusters, and glowing pink star forming regions along spiral arms that wind far from the galaxy's core. IC 342 may have undergone a recent burst of star formation activity and is close enough to have gravitationally influenced the evolution of the local group of galaxies and the Milky Way.", + "hdurl": "https://apod.nasa.gov/apod/image/1707/ic342_rector2048.jpg", + "media_type": "image", + "service_version": "v1", + "title": "Hidden Galaxy IC 342", "url": "https://apod.nasa.gov/apod/image/1707/ic342_rector1024s.jpg" - }, + }, { - "date": "2017-07-09", - "explanation": "Can you find your favorite country or city? Surprisingly, on this world-wide nightscape, city lights make this task quite possible. Human-made lights highlight particularly developed or populated areas of the Earth's surface, including the seaboards of Europe, the eastern United States, and Japan. Many large cities are located near rivers or oceans so that they can exchange goods cheaply by boat. Particularly dark areas include the central parts of South America, Africa, Asia, and Australia. The featured composite was created from images that were collected during cloud-free periods in April and October 2012 by the Suomi-NPP satellite, from a polar orbit about 824 kilometers above the surface, using its Visible Infrared Imaging Radiometer Suite (VIIRS).", - "hdurl": "https://apod.nasa.gov/apod/image/1707/EarthAtNight_SuomiNPP_3600.jpg", - "media_type": "image", - "service_version": "v1", - "title": "Earth at Night", + "date": "2017-07-09", + "explanation": "Can you find your favorite country or city? Surprisingly, on this world-wide nightscape, city lights make this task quite possible. Human-made lights highlight particularly developed or populated areas of the Earth's surface, including the seaboards of Europe, the eastern United States, and Japan. Many large cities are located near rivers or oceans so that they can exchange goods cheaply by boat. Particularly dark areas include the central parts of South America, Africa, Asia, and Australia. The featured composite was created from images that were collected during cloud-free periods in April and October 2012 by the Suomi-NPP satellite, from a polar orbit about 824 kilometers above the surface, using its Visible Infrared Imaging Radiometer Suite (VIIRS).", + "hdurl": "https://apod.nasa.gov/apod/image/1707/EarthAtNight_SuomiNPP_3600.jpg", + "media_type": "image", + "service_version": "v1", + "title": "Earth at Night", "url": "https://apod.nasa.gov/apod/image/1707/EarthAtNight_SuomiNPP_1080.jpg" - }, + }, { - "date": "2017-07-10", - "explanation": "What's happening around the center of this spiral galaxy? Seen in total, NGC 1512 appears to be a barred spiral galaxy -- a type of spiral that has a straight bar of stars across its center. This bar crosses an outer ring, though, a ring not seen as it surrounds the pictured region. Featured in this Hubble Space Telescope image is an inner ring -- one that itself surrounds the nucleus of the spiral. The two rings are connected not only by a bar of bright stars but by dark lanes of dust. Inside of this inner ring, dust continues to spiral right into the very center -- possibly the location of a large black hole. The rings are bright with newly formed stars which may have been triggered by the collision of NGC 1512 with its galactic neighbor, NGC 1510.", - "hdurl": "https://apod.nasa.gov/apod/image/1707/NGC1512_Schmidt_1342.jpg", - "media_type": "image", - "service_version": "v1", - "title": "Spiral Galaxy NGC 1512: The Nuclear Ring", + "date": "2017-07-10", + "explanation": "What's happening around the center of this spiral galaxy? Seen in total, NGC 1512 appears to be a barred spiral galaxy -- a type of spiral that has a straight bar of stars across its center. This bar crosses an outer ring, though, a ring not seen as it surrounds the pictured region. Featured in this Hubble Space Telescope image is an inner ring -- one that itself surrounds the nucleus of the spiral. The two rings are connected not only by a bar of bright stars but by dark lanes of dust. Inside of this inner ring, dust continues to spiral right into the very center -- possibly the location of a large black hole. The rings are bright with newly formed stars which may have been triggered by the collision of NGC 1512 with its galactic neighbor, NGC 1510.", + "hdurl": "https://apod.nasa.gov/apod/image/1707/NGC1512_Schmidt_1342.jpg", + "media_type": "image", + "service_version": "v1", + "title": "Spiral Galaxy NGC 1512: The Nuclear Ring", "url": "https://apod.nasa.gov/apod/image/1707/NGC1512_Schmidt_960.jpg" } ] @@ -291,12 +312,48 @@ https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&start_date=2017-07-08&end_d

+## The APOD Parser + +The APOD Parser is not part of the API itself. Rather is intended to be used for accessing the APOD API quickly with Python without writing much additional code yourself. It is found in the apod_parser folder. + +### Usage + +1. First import the `apod_object_parser.py` file. + +2. Now use the `get_data` function and pass your API key as the only argument. You can get the API key here + +```python +response = apod_object_parser.get_data() +``` + +3. Now you can use the following functions: + +-> `apod_object_parser.get_date(response)` + +-> `apod_object_parser.get_explaination(response)` + +-> `apod_object_parser.get_hdurl(response)` + +-> `apod_object_parser.get_media_type(response)` + +-> `apod_object_parser.get_service_version(response)` + +-> `apod_object_parser.get_title(response)` + +-> `apod_object_parser.get_url(response)` + +**for full docs and more functions visit the readme of the apod parser by clicking here** ## Feedback + Star this repo if you found it useful. Use the github issue tracker to give feedback on this repo. ## Author - Brian Thomas (based on code by Dan Hammer) - Justin Gosses (made changes to allow this repository to run more easily on AWS Elastic Beanstalk after heroku instance was shut-down) +- Please checkout the contributers to this repository on the righthand side of this page. + +## Contributing +We do accept pull requests from the public. Please note that we can be slow to respond. Please be patient. Also, the people with rights on this repository are not people who can debug problems with the APOD website itself. If you would like to contribute, right now we could use some attention to the tests. diff --git a/__init__.py b/apod/__init__.py similarity index 100% rename from __init__.py rename to apod/__init__.py diff --git a/utility.py b/apod/utility.py similarity index 79% rename from utility.py rename to apod/utility.py index 9de9b1b..16f8e82 100644 --- a/utility.py +++ b/apod/utility.py @@ -7,7 +7,7 @@ """ from bs4 import BeautifulSoup -from datetime import timedelta +import datetime import requests import logging import json @@ -53,10 +53,27 @@ def _get_last_url(data): def _get_apod_chars(dt, thumbs): media_type = 'image' - date_str = dt.strftime('%y%m%d') - apod_url = '%sap%s.html' % (BASE, date_str) + if dt: + date_str = dt.strftime('%y%m%d') + apod_url = '%sap%s.html' % (BASE, date_str) + else: + apod_url = '%sastropix.html' % BASE LOG.debug('OPENING URL:' + apod_url) - soup = BeautifulSoup(requests.get(apod_url).text, 'html.parser') + res = requests.get(apod_url) + + if res.status_code == 404: + return None + # LOG.error(f'No APOD entry for URL: {apod_url}') + # default_obj_path = 'static/default_apod_object.json' + # LOG.debug(f'Loading default APOD response from {default_obj_path}') + # with open(default_obj_path, 'r') as f: + # default_obj_props = json.load(f) + + # default_obj_props['date'] = dt.strftime('%Y-%m-%d') + + # return default_obj_props + + soup = BeautifulSoup(res.text, 'html.parser') LOG.debug('getting the data url') hd_data = None if soup.img: @@ -88,7 +105,10 @@ def _get_apod_chars(dt, thumbs): props['media_type'] = media_type if data: props['url'] = _get_last_url(data) - props['date'] = dt.isoformat() + if dt: + props['date'] = dt.strftime('%Y-%m-%d') + else: + props['date'] = _date(soup) if hd_data: props['hdurl'] = _get_last_url(hd_data) @@ -233,6 +253,36 @@ def _explanation(soup): return s +def _date(soup): + """ + Accepts a BeautifulSoup object for the APOD HTML page and returns the + date of the APOD image. + """ + LOG.debug('getting the date from soup data.') + _today = datetime.date.today() + for line in soup.text.split('\n'): + today_year = str(_today.year) + yesterday_year = str((_today-datetime.timedelta(days=1)).year) + # Looks for the first line that starts with the current year. + # This also checks yesterday's year so it doesn't break on January 1st at 00:00 UTC + # before apod.nasa.gov uploads a new image. + if line.startswith(today_year) or line.startswith(yesterday_year): + LOG.debug('found possible date match: ' + line) + # takes apart the date string and turns it into a datetime + try: + year, month, day = line.split() + year = int(year) + month = ['january', 'february', 'march', 'april', + 'may', 'june', 'july', 'august', + 'september', 'october', 'november', 'december' + ].index(month.lower()) + 1 + day = int(day) + return datetime.date(year=year, month=month, day=day).strftime('%Y-%m-%d') + except: + LOG.debug('unable to retrieve date from line: ' + line) + raise Exception('Date not found in soup data.') + + def parse_apod(dt, use_default_today_date=False, thumbs=False): """ Accepts a date in '%Y-%m-%d' format. Returns the URL of the APOD image @@ -251,9 +301,9 @@ def parse_apod(dt, use_default_today_date=False, thumbs=False): # service (can happen because they are deployed in different # timezones). Use the fallback of prior day's date - if use_default_today_date: + if use_default_today_date and dt: # try to get the day before - dt = dt - timedelta(days=1) + dt = dt - datetime.timedelta(days=1) return _get_apod_chars(dt, thumbs) else: # pass exception up the call stack diff --git a/apod_parser/apod_object_parser.py b/apod_parser/apod_object_parser.py new file mode 100644 index 0000000..df2d627 --- /dev/null +++ b/apod_parser/apod_object_parser.py @@ -0,0 +1,64 @@ +import requests +import json +import os +from PIL import Image + +def get_data(api_key): + raw_response = requests.get(f'https://api.nasa.gov/planetary/apod?api_key={api_key}').text + response = json.loads(raw_response) + return response + + +def get_date(response): + date = response['date'] + return date + + +def get_explaination(response): + explaination = response['explanation'] + return explaination + + +def get_hdurl(response): + hdurl = response['hdurl'] + return hdurl + + +def get_media_type(response): + media_type = response['media_type'] + return media_type + +def get_service_version(response): + service_version = response['service_version'] + return service_version + + +def get_title(response): + service_version = response['title'] + return service_version + +def get_url(response): + url = response['url'] + return url + +def download_image(url, date): + if os.path.isfile(f'{date}.png') == False: + raw_image = requests.get(url).content + with open(f'{date}.jpg', 'wb') as file: + file.write(raw_image) + + else: + return FileExistsError + + +def convert_image(image_path): + path_to_image = os.path.normpath(image_path) + + basename = os.path.basename(path_to_image) + + filename_no_extension = basename.split(".")[0] + + base_directory = os.path.dirname(path_to_image) + + image = Image.open(path_to_image) + image.save(f"{base_directory}/{filename_no_extension}.png") diff --git a/apod_parser/apod_parser_readme.md b/apod_parser/apod_parser_readme.md new file mode 100644 index 0000000..86fccb7 --- /dev/null +++ b/apod_parser/apod_parser_readme.md @@ -0,0 +1,66 @@ +# apod_object_parser + +get a Nasa api key by clicking here. + +## How to use +1. import the file +```python +import apod_object_parser +``` +2. Now call the `get_data` function and pass the `nasa api key` as the argument. Note api_key is a string. The response returned will be a Dictionary. Now you can parse the dictionary too + +```python +response = apod_object_parser.get_data(##Pass In Your API key here) +``` +### get_date + +the `get_date` function takes the dictionary we got above and returns the date. + +```python +date = apod_object_parser.get_date(response) +``` +### get_explaination +the `get_explaination` function takes the dictionary we got above and returns the explaintion. + +```python +date = apod_object_parser.get_explaination(response) +``` +### get_hdurl +the `get_hdurl` function takes the dictionary we got above and returns the High Definition url of the image. + +```python +date = apod_object_parser.get_hdurl(response) +``` +### get_title +the `get_title` function takes the dictionary we got above and returns the title of the image. + +```python +date = apod_object_parser.get_title(response) +``` +### get_url +the `get_url` function takes the dictionary we got above and returns the Standard definition url of the image. + +```python +date = apod_object_parser.get_hdurl(response) +``` +### get_media_type +the `get_media_type` function takes the dictionary we got above and returns the media type the file (might be a video of a image). + +```python +date = apod_object_parser.get_hdurl(response) +``` + +## Other functions +there are also other functions that might help you in situations + +### download_image +the `download_image` finction takes the url (hdurl or url) and the date from the function `get_date` and downloads the image in the current directory and with the file name of the date. the image downloaded is in the .jpg format +```python +apod_object_parser.download_image(url, date) +``` + +### convert_image +sometimes the image we downloaded above might not be in the right format (.jpg) so you may call `convert_image` function to convert the image into .png. takes the `image_path` parameter which is the filepath. +```python +apod_object_parser.convert_image(image_path) +``` diff --git a/application.py b/application.py index ecd4819..d9ce8ac 100644 --- a/application.py +++ b/application.py @@ -1,7 +1,7 @@ """ A micro-service passing back enhanced information from Astronomy Picture of the Day (APOD). - + Adapted from code in https://github.com/nasa/planetary-api Dec 1, 2015 (written by Dan Hammer) @@ -18,10 +18,10 @@ sys.path.insert(1, ".") from datetime import datetime, date -from random import sample -from flask import request, jsonify, render_template, Flask +from random import shuffle +from flask import request, jsonify, render_template, Flask, current_app from flask_cors import CORS -from utility import parse_apod, get_concepts +from apod.utility import parse_apod, get_concepts import logging #### added by justin for EB @@ -31,9 +31,10 @@ CORS(application) LOG = logging.getLogger(__name__) +# logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.DEBUG) -# this should reflect both this service and the backing +# this should reflect both this service and the backing # assorted libraries SERVICE_VERSION = 'v1' APOD_METHOD_NAME = 'apod' @@ -91,7 +92,10 @@ def _apod_handler(dt, use_concept_tags=False, use_default_today_date=False, thum served through the API. """ try: + page_props = parse_apod(dt, use_default_today_date, thumbs) + if not page_props: + return None LOG.debug('managed to get apod page characteristics') if use_concept_tags: @@ -122,15 +126,21 @@ def _get_json_for_date(input_date, use_concept_tags, thumbs): use_default_today_date = False if not input_date: # fall back to using today's date IF they didn't specify a date - input_date = datetime.strftime(datetime.today(), '%Y-%m-%d') use_default_today_date = True + dt = input_date # None # validate input date - dt = datetime.strptime(input_date, '%Y-%m-%d').date() - _validate_date(dt) + else: + dt = datetime.strptime(input_date, '%Y-%m-%d').date() + _validate_date(dt) # get data data = _apod_handler(dt, use_concept_tags, use_default_today_date, thumbs) + + # Handle case where no data is available + if not data: + return _abort(code=404, msg=f"No data available for date: {input_date}", usage=False) + data['service_version'] = SERVICE_VERSION # return info as JSON @@ -145,22 +155,27 @@ def _get_json_for_random_dates(count, use_concept_tags, thumbs): :param use_concept_tags: :return: """ - if count > 100 or count <= 0: raise ValueError('Count must be positive and cannot exceed 100') - begin_ordinal = datetime(1995, 6, 16).toordinal() today_ordinal = datetime.today().toordinal() - date_range = range(begin_ordinal, today_ordinal + 1) - random_date_ordinals = sample(date_range, count) + random_date_ordinals = list(range(begin_ordinal, today_ordinal + 1)) + shuffle(random_date_ordinals) all_data = [] for date_ordinal in random_date_ordinals: dt = date.fromordinal(date_ordinal) data = _apod_handler(dt, use_concept_tags, date_ordinal == today_ordinal, thumbs) + + # Handle case where no data is available + if not data: + continue + data['service_version'] = SERVICE_VERSION all_data.append(data) + if len(all_data) >= count: + break return jsonify(all_data) @@ -199,7 +214,14 @@ def _get_json_for_date_range(start_date, end_date, use_concept_tags, thumbs): while start_ordinal <= end_ordinal: # get data dt = date.fromordinal(start_ordinal) + data = _apod_handler(dt, use_concept_tags, start_ordinal == today_ordinal, thumbs) + + # Handle case where no data is available + if not data: + start_ordinal += 1 + continue + data['service_version'] = SERVICE_VERSION if data['date'] == dt.isoformat(): @@ -223,6 +245,10 @@ def home(): methodname=APOD_METHOD_NAME, usage=_usage(joinstr='", "', prestr='"') + '"') +@application.route('/static/') +def serve_static(asset_path): + return current_app.send_static_file(asset_path) + @application.route('/' + SERVICE_VERSION + '/' + APOD_METHOD_NAME + '/', methods=['GET']) def apod(): @@ -273,7 +299,7 @@ def page_not_found(e): """ Return a custom 404 error. """ - LOG.info('Invalid page request: ' + e) + LOG.info('Invalid page request: ' + str(e)) return _abort(404, 'Sorry, Nothing at this URL.', usage=True) @@ -286,7 +312,4 @@ def application_error(e): if __name__ == '__main__': - application.run() - # httpd = make_server('', 8000, application) - # print("Serving on port 8000...") - # httpd.serve_forever() + application.run('0.0.0.0', port=5000) diff --git a/requirements.txt b/requirements.txt index 91511d9..a6c5724 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,4 +14,6 @@ requests>=2.20.0 coverage==4.1 nose==1.3.7 setupext-janitor==1.0.0 -bs4==0.0.1 \ No newline at end of file +bs4==0.0.1 +mock>=3.0.0 +Pillow==7.1.2 \ No newline at end of file diff --git a/run_coverage.sh b/run_coverage.sh index abd053a..25e8ab7 100644 --- a/run_coverage.sh +++ b/run_coverage.sh @@ -1,3 +1,3 @@ # Need to sort out why this is the only way nosetests seem # to work right.. -nosetests -v tests/apod/* +nosetests -v tests/* diff --git a/static/default_apod_image.jpg b/static/default_apod_image.jpg new file mode 100644 index 0000000..5819d12 Binary files /dev/null and b/static/default_apod_image.jpg differ diff --git a/static/default_apod_object.json b/static/default_apod_object.json new file mode 100644 index 0000000..ecbe212 --- /dev/null +++ b/static/default_apod_object.json @@ -0,0 +1,7 @@ +{ + "explanation": "This is a fallback image used in the case where there is a missing/corrupted asset on apod.nasa.gov. Image source: https://en.wikipedia.org/wiki/File:Black_Hole_in_the_universe.jpg", + "hdurl": "https://api.nasa.gov/planetary/apod/static/default_apod_image.jpg", + "media_type": "image", + "title": "Default Image", + "url": "https://api.nasa.gov/planetary/apod/static/default_apod_image.jpg" +} \ No newline at end of file diff --git a/tests/apod/test_service.py b/tests/apod/test_service.py new file mode 100644 index 0000000..8d96f73 --- /dev/null +++ b/tests/apod/test_service.py @@ -0,0 +1,16 @@ +#!/bin/sh/python +# coding= utf-8 +import unittest +from mock import patch +from apod import application +import logging + +logging.basicConfig(level=logging.DEBUG) + + +@patch('application._abort') +class TestPageNotFound(unittest.TestCase): + def test(self, mock_abort): + GIVEN = Exception('example exception') + applicaiton.page_not_found(GIVEN) + mock_abort.assert_called_once() diff --git a/tests/apod/test_utility.py b/tests/apod/test_utility.py index 77b3407..ed17e7c 100644 --- a/tests/apod/test_utility.py +++ b/tests/apod/test_utility.py @@ -26,7 +26,7 @@ class TestApod(unittest.TestCase): 'newer page, Reprocessing & copyright' : { "datetime": datetime(2017, 2, 8), - "copyright": "Jesús M.Vargas & Maritxu Poyal", + "copyright": "Jes�s M.Vargas & Maritxu Poyal", "date": "2017-02-08", "explanation": "The bright clusters and nebulae of planet Earth's night sky are often named for flowers or insects. Though its wingspan covers over 3 light-years, NGC 6302 is no exception. With an estimated surface temperature of about 250,000 degrees C, the dying central star of this particular planetary nebula has become exceptionally hot, shining brightly in ultraviolet light but hidden from direct view by a dense torus of dust. This sharp close-up of the dying star's nebula was recorded by the Hubble Space Telescope and is presented here in reprocessed colors. Cutting across a bright cavity of ionized gas, the dust torus surrounding the central star is near the center of this view, almost edge-on to the line-of-sight. Molecular hydrogen has been detected in the hot star's dusty cosmic shroud. NGC 6302 lies about 4,000 light-years away in the arachnologically correct constellation of the Scorpion (Scorpius). Follow APOD on: Facebook, Google Plus, Instagram, or Twitter", "hdurl": "https://apod.nasa.gov/apod/image/1702/Butterfly_HubbleVargas_5075.jpg",