Skip to content

Commit

Permalink
merge issues
Browse files Browse the repository at this point in the history
  • Loading branch information
JustinGOSSES committed Dec 1, 2020
2 parents f337c49 + 0d02048 commit 3a6f7d5
Show file tree
Hide file tree
Showing 14 changed files with 389 additions and 94 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ lib/
apod/__pycache__/
.elasticbeanstalk/
*.zip*
Archive.zip
Archive.zip
venv/
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
189 changes: 123 additions & 66 deletions README.md

Large diffs are not rendered by default.

File renamed without changes.
64 changes: 57 additions & 7 deletions utility.py → apod/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"""

from bs4 import BeautifulSoup
from datetime import timedelta
import datetime
import requests
import logging
import json
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
64 changes: 64 additions & 0 deletions apod_parser/apod_object_parser.py
Original file line number Diff line number Diff line change
@@ -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")
66 changes: 66 additions & 0 deletions apod_parser/apod_parser_readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# apod_object_parser

get a Nasa api key by clicking <a href="https://api.nasa.gov/#signUp">here</a>.

## 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)
```
57 changes: 40 additions & 17 deletions application.py
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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
Expand All @@ -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'
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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():
Expand All @@ -223,6 +245,10 @@ def home():
methodname=APOD_METHOD_NAME,
usage=_usage(joinstr='", "', prestr='"') + '"')

@application.route('/static/<asset_path>')
def serve_static(asset_path):
return current_app.send_static_file(asset_path)


@application.route('/' + SERVICE_VERSION + '/' + APOD_METHOD_NAME + '/', methods=['GET'])
def apod():
Expand Down Expand Up @@ -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)


Expand All @@ -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)
Loading

0 comments on commit 3a6f7d5

Please sign in to comment.