Skip to content

Commit b3707bd

Browse files
committed
updated to Python 3
1 parent 3572f57 commit b3707bd

13 files changed

+98
-101
lines changed

.coveragerc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# .coveragerc
22
[run]
3-
source=app
3+
source=service
44

55
[report]
66
show_missing = True

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: python
22
python:
3-
- "2.7"
3+
- "3.6"
44

55
# command to install dependencies
66
install: "pip install -r requirements.txt"

Vagrantfile

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Vagrant.configure(2) do |config|
77
# For a complete reference, please see the online documentation at
88
# https://docs.vagrantup.com.
99
config.vm.box = "ubuntu/bionic64"
10-
config.vm.hostname = "flask"
10+
config.vm.hostname = "travis"
1111

1212
config.vm.network "forwarded_port", guest: 5000, host: 5000, host_ip: "127.0.0.1"
1313
config.vm.network "private_network", ip: "192.168.33.10"
@@ -50,14 +50,13 @@ Vagrant.configure(2) do |config|
5050
# documentation for more information about their specific syntax and use.
5151
config.vm.provision "shell", inline: <<-SHELL
5252
apt-get update
53-
apt-get install -y git python-pip python-dev
53+
apt-get install -y git python3 python3-pip python3-venv
5454
apt-get -y autoremove
5555
# Install app dependencies
5656
echo "\n******************************"
5757
echo " Installing App Dependencies"
5858
echo "******************************\n"
59-
cd /vagrant
60-
pip install -r requirements.txt
59+
pip3 install -r /vagrant/requirements.txt
6160
SHELL
6261

6362
######################################################################

requirements.txt

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# Build Dependencies
2-
Flask==1.0.2
3-
Flask-API==1.0
2+
Flask==1.1.1
3+
Flask-API==1.1
44
redis>=2.10
55

66
# Runtime
77
gunicorn==19.9.0
88
honcho==1.0.1
99

1010
# Testing
11-
pylint==1.9.3
12-
mock==2.0.0
1311
nose==1.3.7
1412
pinocchio==0.4.2
1513
httpie>=1.0.3
14+
pylint>=2.4.1
1615

1716
# Code coverage
18-
coverage==4.5.1
17+
coverage==4.5.4
1918
codecov==2.0.15

app/__init__.py renamed to service/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
app = Flask(__name__)
1212
app.config['LOGGING_LEVEL'] = logging.INFO
1313

14-
import service
14+
from service import service, models
1515

1616
# Set up logging for production
17-
print 'Setting up logging for {}...'.format(__name__)
17+
print('Setting up logging for {}...'.format(__name__))
1818
if __name__ != '__main__':
1919
gunicorn_logger = logging.getLogger('gunicorn.error')
2020
if gunicorn_logger:

app/models.py renamed to service/models.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
import os
2727
import json
2828
import logging
29-
import pickle
30-
from redis import Redis
29+
from redis import StrictRedis
3130
from redis.exceptions import ConnectionError
3231

3332
class DataValidationError(Exception):
@@ -53,7 +52,7 @@ def save(self):
5352
raise DataValidationError('name attribute is not set')
5453
if self.id == 0:
5554
self.id = Pet.__next_index()
56-
Pet.redis.set(self.id, pickle.dumps(self.serialize()))
55+
Pet.redis.set(self.id, json.dumps(self.serialize()))
5756

5857
def delete(self):
5958
""" Deletes a Pet from the database """
@@ -102,7 +101,7 @@ def all(cls):
102101
results = []
103102
for key in cls.redis.keys():
104103
if key != 'index': # filer out our id index
105-
data = pickle.loads(cls.redis.get(key))
104+
data = json.loads(cls.redis.get(key))
106105
pet = Pet(data['id']).deserialize(data)
107106
results.append(pet)
108107
return results
@@ -115,7 +114,7 @@ def all(cls):
115114
def find(cls, pet_id):
116115
""" Query that finds Pets by their id """
117116
if cls.redis.exists(pet_id):
118-
data = pickle.loads(cls.redis.get(pet_id))
117+
data = json.loads(cls.redis.get(pet_id))
119118
pet = Pet(data['id']).deserialize(data)
120119
return pet
121120
return None
@@ -132,7 +131,7 @@ def __find_by(cls, attribute, value):
132131
results = []
133132
for key in Pet.redis.keys():
134133
if key != 'index': # filer out our id index
135-
data = pickle.loads(Pet.redis.get(key))
134+
data = json.loads(Pet.redis.get(key))
136135
# perform case insensitive search on strings
137136
if isinstance(data[attribute], str):
138137
test_value = data[attribute].lower()
@@ -165,7 +164,12 @@ def find_by_availability(cls, available=True):
165164
def connect_to_redis(cls, hostname, port, password):
166165
""" Connects to Redis and tests the connection """
167166
cls.logger.info("Testing Connection to: %s:%s", hostname, port)
168-
cls.redis = Redis(host=hostname, port=port, password=password)
167+
cls.redis = StrictRedis(host=hostname,
168+
port=port,
169+
password=password,
170+
charset="utf-8",
171+
decode_responses=True)
172+
169173
try:
170174
cls.redis.ping()
171175
cls.logger.info("Connection established")

app/service.py renamed to service/service.py

+50-47
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,14 @@
3232
import logging
3333
from functools import wraps
3434
from flask import Flask, jsonify, request, url_for, make_response, abort
35-
from models import Pet, DataValidationError
36-
from app import app
35+
from flask_api import status # HTTP Status Codes
36+
from service.models import Pet, DataValidationError
37+
from service import app
3738

3839
# Pull options from environment
3940
DEBUG = (os.getenv('DEBUG', 'False') == 'True')
4041
PORT = os.getenv('PORT', '5000')
4142

42-
# Status Codes
43-
HTTP_200_OK = 200
44-
HTTP_201_CREATED = 201
45-
HTTP_204_NO_CONTENT = 204
46-
HTTP_400_BAD_REQUEST = 400
47-
HTTP_404_NOT_FOUND = 404
48-
HTTP_409_CONFLICT = 409
49-
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
50-
5143
######################################################################
5244
# Error Handlers
5345
######################################################################
@@ -56,40 +48,51 @@ def request_validation_error(error):
5648
""" Handles Value Errors from bad data """
5749
return bad_request(error)
5850

59-
@app.errorhandler(400)
51+
@app.errorhandler(status.HTTP_400_BAD_REQUEST)
6052
def bad_request(error):
6153
""" Handles bad reuests with 400_BAD_REQUEST """
62-
message = error.message or str(error)
63-
app.logger.error(message)
64-
return jsonify(status=400, error='Bad Request', message=message), 400
54+
message = str(error)
55+
app.logger.warning(message)
56+
return jsonify(status=status.HTTP_400_BAD_REQUEST,
57+
error='Bad Request',
58+
message=message), status.HTTP_400_BAD_REQUEST
6559

66-
@app.errorhandler(404)
60+
@app.errorhandler(status.HTTP_404_NOT_FOUND)
6761
def not_found(error):
6862
""" Handles resources not found with 404_NOT_FOUND """
69-
message = error.message or str(error)
70-
app.logger.error(message)
71-
return jsonify(status=404, error='Not Found', message=message), 404
63+
message = str(error)
64+
app.logger.warning(message)
65+
return jsonify(status=status.HTTP_404_NOT_FOUND,
66+
error='Not Found',
67+
message=message), status.HTTP_404_NOT_FOUND
7268

73-
@app.errorhandler(405)
69+
@app.errorhandler(status.HTTP_405_METHOD_NOT_ALLOWED)
7470
def method_not_supported(error):
7571
""" Handles unsuppoted HTTP methods with 405_METHOD_NOT_SUPPORTED """
76-
message = error.message or str(error)
77-
app.logger.error(message)
78-
return jsonify(status=405, error='Method not Allowed', message=message), 405
72+
message = str(error)
73+
app.logger.warning(message)
74+
return jsonify(status=status.HTTP_405_METHOD_NOT_ALLOWED,
75+
error='Method not Allowed',
76+
message=message), status.HTTP_405_METHOD_NOT_ALLOWED
7977

80-
@app.errorhandler(415)
78+
@app.errorhandler(status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
8179
def mediatype_not_supported(error):
8280
""" Handles unsuppoted media requests with 415_UNSUPPORTED_MEDIA_TYPE """
83-
message = error.message or str(error)
84-
app.logger.error(message)
85-
return jsonify(status=415, error='Unsupported media type', message=message), 415
81+
message = str(error)
82+
app.logger.warning(message)
83+
return jsonify(status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
84+
error='Unsupported media type',
85+
message=message), status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
8686

87-
@app.errorhandler(500)
87+
@app.errorhandler(status.HTTP_500_INTERNAL_SERVER_ERROR)
8888
def internal_server_error(error):
8989
""" Handles unexpected server error with 500_SERVER_ERROR """
90-
message = error.message or str(error)
90+
message = str(error)
9191
app.logger.error(message)
92-
return jsonify(status=500, error='Internal Server Error', message=message), 500
92+
return jsonify(status=status.HTTP_500_INTERNAL_SERVER_ERROR,
93+
error='Internal Server Error',
94+
message=message), status.HTTP_500_INTERNAL_SERVER_ERROR
95+
9396

9497
######################################################################
9598
# DECORATORS
@@ -102,15 +105,15 @@ def decorator(func):
102105
def wrapper(*args, **kwargs):
103106
""" Checks that the content type is correct """
104107
if not 'Content-Type' in request.headers:
105-
abort(HTTP_415_UNSUPPORTED_MEDIA_TYPE,
108+
abort(status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
106109
'Content-Type must be set')
107110

108111
for content_type in content_types:
109112
if request.headers['Content-Type'] == content_type:
110113
return func(*args, **kwargs)
111114

112115
app.logger.error('Invalid Content-Type: %s', request.headers['Content-Type'])
113-
abort(HTTP_415_UNSUPPORTED_MEDIA_TYPE,
116+
abort(status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
114117
'Content-Type must be {}'.format(content_types))
115118
return wrapper
116119
return decorator
@@ -145,7 +148,7 @@ def list_pets():
145148
pets = Pet.all()
146149

147150
results = [pet.serialize() for pet in pets]
148-
return make_response(jsonify(results), HTTP_200_OK)
151+
return make_response(jsonify(results), status.HTTP_200_OK)
149152

150153
######################################################################
151154
# RETRIEVE A PET
@@ -160,8 +163,8 @@ def get_pets(pet_id):
160163
app.logger.info('Request to get Pet with id %s', pet_id)
161164
pet = Pet.find(pet_id)
162165
if not pet:
163-
abort(HTTP_404_NOT_FOUND, "Pet with id '{}' was not found.".format(pet_id))
164-
return make_response(jsonify(pet.serialize()), HTTP_200_OK)
166+
abort(status.HTTP_404_NOT_FOUND, "Pet with id '{}' was not found.".format(pet_id))
167+
return make_response(jsonify(pet.serialize()), status.HTTP_200_OK)
165168

166169
######################################################################
167170
# ADD A NEW PET
@@ -192,7 +195,7 @@ def create_pets():
192195
pet.deserialize(data)
193196
pet.save()
194197
message = pet.serialize()
195-
return make_response(jsonify(message), HTTP_201_CREATED,
198+
return make_response(jsonify(message), status.HTTP_201_CREATED,
196199
{'Location': url_for('get_pets', pet_id=pet.id, _external=True)})
197200

198201
######################################################################
@@ -209,11 +212,11 @@ def update_pets(pet_id):
209212
app.logger.info('Request to update Pet with id %s', pet_id)
210213
pet = Pet.find(pet_id)
211214
if not pet:
212-
abort(HTTP_404_NOT_FOUND, "Pet with id '{}' was not found.".format(pet_id))
215+
abort(status.HTTP_404_NOT_FOUND, "Pet with id '{}' was not found.".format(pet_id))
213216
pet.deserialize(request.get_json())
214217
pet.id = pet_id
215218
pet.save()
216-
return make_response(jsonify(pet.serialize()), HTTP_200_OK)
219+
return make_response(jsonify(pet.serialize()), status.HTTP_200_OK)
217220

218221

219222
######################################################################
@@ -230,7 +233,7 @@ def delete_pets(pet_id):
230233
pet = Pet.find(pet_id)
231234
if pet:
232235
pet.delete()
233-
return make_response('', HTTP_204_NO_CONTENT)
236+
return make_response('', status.HTTP_204_NO_CONTENT)
234237

235238
######################################################################
236239
# PURCHASE A PET
@@ -241,12 +244,12 @@ def purchase_pets(pet_id):
241244
app.logger.info('Request to purchase Pet with id %s', pet_id)
242245
pet = Pet.find(pet_id)
243246
if not pet:
244-
abort(HTTP_404_NOT_FOUND, "Pet with id '{}' was not found.".format(pet_id))
247+
abort(status.HTTP_404_NOT_FOUND, "Pet with id '{}' was not found.".format(pet_id))
245248
if not pet.available:
246-
abort(HTTP_400_BAD_REQUEST, "Pet with id '{}' is not available.".format(pet_id))
249+
abort(status.HTTP_400_BAD_REQUEST, "Pet with id '{}' is not available.".format(pet_id))
247250
pet.available = False
248251
pet.save()
249-
return make_response(jsonify(pet.serialize()), HTTP_200_OK)
252+
return make_response(jsonify(pet.serialize()), status.HTTP_200_OK)
250253

251254

252255
######################################################################
@@ -273,13 +276,13 @@ def data_reset():
273276
# if request.headers['Content-Type'] == content_type:
274277
# return
275278
# app.logger.error('Invalid Content-Type: %s', request.headers['Content-Type'])
276-
# abort(HTTP_415_UNSUPPORTED_MEDIA_TYPE, 'Content-Type must be {}'.format(content_type))
279+
# abort(status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, 'Content-Type must be {}'.format(content_type))
277280

278281
# @app.before_first_request
279282
def initialize_logging(log_level=logging.INFO):
280283
""" Initialized the default logging to STDOUT """
281284
if not app.debug:
282-
print 'Setting up logging...'
285+
print('Setting up logging...')
283286
# Set up default logging for submodules to use STDOUT
284287
# datefmt='%m/%d/%Y %I:%M:%S %p'
285288
fmt = '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
@@ -301,8 +304,8 @@ def initialize_logging(log_level=logging.INFO):
301304
# M A I N
302305
######################################################################
303306
if __name__ == "__main__":
304-
print "************************************************************"
305-
print " P E T R E S T A P I S E R V I C E "
306-
print "************************************************************"
307+
print("************************************************************")
308+
print(" P E T R E S T A P I S E R V I C E ")
309+
print("************************************************************")
307310
initialize_logging(app.config['LOGGING_LEVEL'])
308311
app.run(host='0.0.0.0', port=int(PORT), debug=DEBUG)
File renamed without changes.

setup.cfg

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
[nosetests]
22
verbosity=2
3-
nologcapture=1
43
with-spec=1
54
spec-color=1
65
with-coverage=1
76
cover-erase=1
8-
cover-package=app
7+
cover-package=service

tests/test_pets.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
import os
2323
import json
2424
import unittest
25-
from mock import patch
25+
from unittest.mock import patch
2626
from redis import Redis, ConnectionError
27-
from app.models import Pet, DataValidationError
27+
from service.models import Pet, DataValidationError
2828

2929
VCAP_SERVICES = {
3030
'rediscloud': [

0 commit comments

Comments
 (0)