Created
May 16, 2019 16:08
-
-
Save danhammer/1055e918822b8261a7987750ddd02259 to your computer and use it in GitHub Desktop.
Basic and simple code for a web service (Heroku and Flask) to serve out data on film scripts, after processing by USC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """A Flask web app to serve locally stored data on film scripts.""" | |
| import glob | |
| import json | |
| import os | |
| from flask import Flask, jsonify, request | |
| app = Flask(__name__) | |
| app.config['JSON_SORT_KEYS'] = False | |
| SCRIPT_DATA_DIR = os.path.join(os.path.dirname(__file__), 'character_files') | |
| DEMO_APIKEY = '0123456789' | |
| @app.route('/') | |
| def welcome(): | |
| invitation = ('This web app provides functionality from the endpoints ' | |
| 'listed below. Click a link for relevant instructions.') | |
| msg = { | |
| 'Invitation': invitation, | |
| 'Retrieve data on character gender and prominence in film scripts': | |
| ''.join((request.url, 'network?')) | |
| } | |
| return jsonify(msg) | |
| @app.route('/network') | |
| def network(): | |
| """Retrieve locally stored data on film scripts.""" | |
| msg = _help_msg( | |
| request.base_url, 'script=star_trek&apikey=MY_SECRET_KEY', | |
| _format_network_args()) | |
| try: | |
| _validate_apikey(request.args) | |
| script_data = _load_script_data(request.args) | |
| except (ValueError, FileNotFoundError) as e: | |
| msg['Exception'] = repr(e) | |
| return jsonify(msg) | |
| return jsonify(script_data) | |
| def _validate_apikey(args): | |
| """Validate key from url args against a static DEMO_KEY. | |
| Raises: ValueError for an invalid key. | |
| Returns: None | |
| """ | |
| key = args.get('apikey', default='') | |
| if key != DEMO_APIKEY: | |
| raise ValueError('A valid API key is required.') | |
| def _load_script_data(args): | |
| """Parse url args for script name and load available data. | |
| Returns: JSON-formatted dict | |
| """ | |
| known_scripts = _gather_script_names(SCRIPT_DATA_DIR) | |
| script = args.get('script', default='') | |
| script = script.lower().strip() | |
| if script not in known_scripts: | |
| raise ValueError('A valid script name is required.') | |
| with open(os.path.join(SCRIPT_DATA_DIR, script + '.json')) as f: | |
| script_data = json.load(f) | |
| return script_data | |
| def _gather_script_names(data_dir): | |
| """Collect names of JSON data files in data_dir. | |
| Returns: List of filenames with suffix stripped. | |
| """ | |
| paths = glob.glob(os.path.join(data_dir, '*.json')) | |
| names = [os.path.basename(p) for p in paths] | |
| names = [n.split('.json')[0] for n in names] | |
| return names | |
| # Help messaging | |
| def _help_msg(base_url, url_args, notes): | |
| msg = { | |
| 'Usage': '{}?{}'.format(base_url, url_args), | |
| 'Notes': notes | |
| } | |
| return msg | |
| def _format_network_args(): | |
| """Produce a dict explaining args for help messaging.""" | |
| known_scripts = _gather_script_names(SCRIPT_DATA_DIR) | |
| network_args = { | |
| 'Required arguments': { | |
| 'script': 'One of {}'.format( | |
| known_scripts), | |
| 'apikey': 'A secret alpha-numeric key.' | |
| } | |
| } | |
| return network_args | |
| if __name__ == '__main__': | |
| app.run(debug=False, host='0.0.0.0') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| version: '2' | |
| services: | |
| web: | |
| build: . | |
| ports: | |
| - "5000:5000" | |
| volumes: | |
| - ./webapp:/opt/webapp | |
| tty: true | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| FROM ubuntu:latest | |
| RUN apt-get update && apt-get install -y software-properties-common | |
| RUN apt-get install -y python3-pip python3-dev build-essential | |
| RUN pip3 install --upgrade pip | |
| ENV DEBIAN_FRONTEND noninteractive | |
| ADD ./requirements.txt /tmp/requirements.txt | |
| # Install dependencies | |
| RUN pip install -r /tmp/requirements.txt | |
| # Add our code | |
| ADD ./webapp /opt/webapp/ | |
| WORKDIR /opt/webapp | |
| # To deploy locally | |
| CMD python3 app.py |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {"nodes": [{"count": 8, "name": "LIEUTENANT MITAKA", "sno": 1, "bechdel": 0, "race": "caucasian", "gender": "male"}, {"count": 141, "name": "REY", "sno": 2, "bechdel": 1, "race": "caucasian", "gender": "female"}, {"count": 10, "name": "CAPTAIN PHASMA", "sno": 3, "bechdel": 0, "race": "caucasian", "gender": "female"}, {"count": 136, "name": "HAN", "sno": 4, "bechdel": 0, "race": "caucasian", "gender": "male"}, {"count": 11, "name": "BALATIK", "sno": 5, "bechdel": 0, "race": "unknown", "gender": "male"}, {"count": 19, "name": "MAZ", "sno": 6, "bechdel": 1, "race": "african", "gender": "female"}, {"count": 23, "name": "GENERAL HUX", "sno": 7, "bechdel": 0, "race": "caucasian", "gender": "male"}, {"count": 7, "name": "SNAP", "sno": 8, "bechdel": 0, "race": "caucasian", "gender": "male"}, {"count": 27, "name": "LEIA", "sno": 9, "bechdel": 0, "race": "caucasian", "gender": "female"}, {"count": 151, "name": "FINN", "sno": 10, "bechdel": 0, "race": "african", "gender": "male"}, {"count": 11, "name": "STORMTROOPER", "sno": 11, "bechdel": 0, "race": "unknown", "gender": "male"}, {"count": 63, "name": "POE", "sno": 12, "bechdel": 0, "race": "mixed", "gender": "male"}, {"count": 58, "name": "KYLO REN", "sno": 13, "bechdel": 0, "race": "caucasian", "gender": "male"}, {"count": 19, "name": "CONTINUED", "sno": 14, "bechdel": 0, "race": "unknown", "gender": "unknown"}, {"count": 14, "name": "SNOKE", "sno": 15, "bechdel": 0, "race": "mixed", "gender": "male"}], "edges": [{"source": 0, "strength": 3.0, "target": 6}, {"source": 0, "strength": 1.0, "target": 9}, {"source": 0, "strength": 1.0, "target": 11}, {"source": 0, "strength": 7.0, "target": 12}, {"source": 1, "strength": 60.0, "target": 3}, {"source": 1, "strength": 2.0, "target": 4}, {"source": 1, "strength": 9.0, "target": 5}, {"source": 1, "strength": 3.0, "target": 6}, {"source": 1, "strength": 3.0, "target": 8}, {"source": 1, "strength": 115.0, "target": 9}, {"source": 1, "strength": 4.0, "target": 10}, {"source": 1, "strength": 1.0, "target": 11}, {"source": 1, "strength": 15.0, "target": 12}, {"source": 1, "strength": 7.0, "target": 13}, {"source": 1, "strength": 3.0, "target": 14}, {"source": 2, "strength": 1.0, "target": 3}, {"source": 2, "strength": 3.0, "target": 6}, {"source": 2, "strength": 4.0, "target": 9}, {"source": 2, "strength": 2.0, "target": 11}, {"source": 2, "strength": 3.0, "target": 12}, {"source": 2, "strength": 1.0, "target": 13}, {"source": 3, "strength": 60.0, "target": 1}, {"source": 3, "strength": 1.0, "target": 2}, {"source": 3, "strength": 13.0, "target": 4}, {"source": 3, "strength": 14.0, "target": 5}, {"source": 3, "strength": 1.0, "target": 6}, {"source": 3, "strength": 3.0, "target": 7}, {"source": 3, "strength": 27.0, "target": 8}, {"source": 3, "strength": 60.0, "target": 9}, {"source": 3, "strength": 3.0, "target": 10}, {"source": 3, "strength": 5.0, "target": 11}, {"source": 3, "strength": 16.0, "target": 12}, {"source": 3, "strength": 6.0, "target": 13}, {"source": 3, "strength": 1.0, "target": 14}, {"source": 4, "strength": 2.0, "target": 1}, {"source": 4, "strength": 13.0, "target": 3}, {"source": 4, "strength": 4.0, "target": 9}, {"source": 4, "strength": 1.0, "target": 14}, {"source": 5, "strength": 9.0, "target": 1}, {"source": 5, "strength": 14.0, "target": 3}, {"source": 5, "strength": 6.0, "target": 9}, {"source": 5, "strength": 1.0, "target": 10}, {"source": 5, "strength": 1.0, "target": 12}, {"source": 5, "strength": 1.0, "target": 13}, {"source": 6, "strength": 3.0, "target": 0}, {"source": 6, "strength": 3.0, "target": 1}, {"source": 6, "strength": 3.0, "target": 2}, {"source": 6, "strength": 1.0, "target": 3}, {"source": 6, "strength": 1.0, "target": 7}, {"source": 6, "strength": 4.0, "target": 9}, {"source": 6, "strength": 4.0, "target": 11}, {"source": 6, "strength": 8.0, "target": 12}, {"source": 6, "strength": 1.0, "target": 13}, {"source": 6, "strength": 10.0, "target": 14}, {"source": 7, "strength": 3.0, "target": 3}, {"source": 7, "strength": 1.0, "target": 6}, {"source": 7, "strength": 6.0, "target": 11}, {"source": 7, "strength": 2.0, "target": 13}, {"source": 8, "strength": 3.0, "target": 1}, {"source": 8, "strength": 27.0, "target": 3}, {"source": 8, "strength": 8.0, "target": 9}, {"source": 8, "strength": 1.0, "target": 10}, {"source": 8, "strength": 7.0, "target": 11}, {"source": 8, "strength": 1.0, "target": 13}, {"source": 9, "strength": 1.0, "target": 0}, {"source": 9, "strength": 115.0, "target": 1}, {"source": 9, "strength": 4.0, "target": 2}, {"source": 9, "strength": 60.0, "target": 3}, {"source": 9, "strength": 4.0, "target": 4}, {"source": 9, "strength": 6.0, "target": 5}, {"source": 9, "strength": 4.0, "target": 6}, {"source": 9, "strength": 8.0, "target": 8}, {"source": 9, "strength": 2.0, "target": 10}, {"source": 9, "strength": 28.0, "target": 11}, {"source": 9, "strength": 8.0, "target": 12}, {"source": 9, "strength": 8.0, "target": 13}, {"source": 10, "strength": 4.0, "target": 1}, {"source": 10, "strength": 3.0, "target": 3}, {"source": 10, "strength": 1.0, "target": 5}, {"source": 10, "strength": 1.0, "target": 8}, {"source": 10, "strength": 2.0, "target": 9}, {"source": 10, "strength": 1.0, "target": 11}, {"source": 10, "strength": 4.0, "target": 12}, {"source": 10, "strength": 2.0, "target": 13}, {"source": 11, "strength": 1.0, "target": 0}, {"source": 11, "strength": 1.0, "target": 1}, {"source": 11, "strength": 2.0, "target": 2}, {"source": 11, "strength": 5.0, "target": 3}, {"source": 11, "strength": 4.0, "target": 6}, {"source": 11, "strength": 6.0, "target": 7}, {"source": 11, "strength": 7.0, "target": 8}, {"source": 11, "strength": 28.0, "target": 9}, {"source": 11, "strength": 1.0, "target": 10}, {"source": 11, "strength": 11.0, "target": 12}, {"source": 11, "strength": 1.0, "target": 13}, {"source": 12, "strength": 7.0, "target": 0}, {"source": 12, "strength": 15.0, "target": 1}, {"source": 12, "strength": 3.0, "target": 2}, {"source": 12, "strength": 16.0, "target": 3}, {"source": 12, "strength": 1.0, "target": 5}, {"source": 12, "strength": 8.0, "target": 6}, {"source": 12, "strength": 8.0, "target": 9}, {"source": 12, "strength": 4.0, "target": 10}, {"source": 12, "strength": 11.0, "target": 11}, {"source": 12, "strength": 5.0, "target": 13}, {"source": 12, "strength": 8.0, "target": 14}, {"source": 13, "strength": 7.0, "target": 1}, {"source": 13, "strength": 1.0, "target": 2}, {"source": 13, "strength": 6.0, "target": 3}, {"source": 13, "strength": 1.0, "target": 5}, {"source": 13, "strength": 1.0, "target": 6}, {"source": 13, "strength": 2.0, "target": 7}, {"source": 13, "strength": 1.0, "target": 8}, {"source": 13, "strength": 8.0, "target": 9}, {"source": 13, "strength": 2.0, "target": 10}, {"source": 13, "strength": 1.0, "target": 11}, {"source": 13, "strength": 5.0, "target": 12}, {"source": 13, "strength": 1.0, "target": 14}, {"source": 14, "strength": 3.0, "target": 1}, {"source": 14, "strength": 1.0, "target": 3}, {"source": 14, "strength": 1.0, "target": 4}, {"source": 14, "strength": 10.0, "target": 6}, {"source": 14, "strength": 8.0, "target": 12}, {"source": 14, "strength": 1.0, "target": 13}]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment