Skip to content

Assignment04 - WSGI calculator.py #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
*pycache*
*solution*
*.idea*

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# USER SPECIFIC/IDE FILES
.idea/

# GENERAL PYTHON FILES
__pycache__/
152 changes: 97 additions & 55 deletions calculator.py
Original file line number Diff line number Diff line change
@@ -1,84 +1,126 @@
#!/usr/bin/env python
"""
# ------------------------------------------------------------------------ #
# Title: Lesson 4 - WSGI (The Web Server Gateway Interface) example. This script
# is a set of simple calculator web pages allowing the user to pass values in and get
# calculated values back.
# Description: This is the main "calculator.py" script.
# ChangeLog (Who,When,What):
# ASimpson, 10/21/2020, Modified code to complete lesson4 - Assignment04
# ------------------------------------------------------------------------ #
"""
For your homework this week, you'll be creating a wsgi application of
your own.

You'll create an online calculator that can perform several operations.
import re
import functools

You'll need to support:
DEFAULT = "No Value Set"

* Addition
* Subtractions
* Multiplication
* Division

Your users should be able to send appropriate requests and get back
proper responses. For example, if I open a browser to your wsgi
application at `http://localhost:8080/multiple/3/5' then the response
body in my browser should be `15`.
def index():
funcs = ['add', 'subtract', 'multiply', 'divide']

Consider the following URL/Response body pairs as tests:
body = ['<h1>Calculator!!</h1>', '<h2>To use this calculator, select the<br>'
' operation below and add a "/" between each<br>'
' number in the URL address bar. <br> <br> Ex: /multiply/3/5</h2>', '<br>']

```
http://localhost:8080/multiply/3/5 => 15
http://localhost:8080/add/23/42 => 65
http://localhost:8080/subtract/23/42 => -19
http://localhost:8080/divide/22/11 => 2
http://localhost:8080/ => <html>Here's how to use this page...</html>
```
item_template = '<ul><li><a href="/{0}/">{0} numbers</a></li>'
for func in funcs:
body.append(item_template.format(func))
body.append('</ul>')
return '\n'.join(body)

To submit your homework:

* Fork this repository (Session03).
* Edit this file to meet the homework requirements.
* Your script should be runnable using `$ python calculator.py`
* When the script is running, I should be able to view your
application in my browser.
* I should also be able to see a home page (http://localhost:8080/)
that explains how to perform calculations.
* Commit and push your changes to your fork.
* Submit a link to your Session03 fork repository!
def add(*args):
""" Returns a STRING with the sum of the arguments """
response_body = '<h1>Your total is: {0}</h1><br><a href="/">Back to the ' \
'list of operations</a>'.format(str(sum(map(int, args))))
return response_body


"""
def subtract(*args):
""" Returns a STRING with the sum of the arguments """
if len(args) == 0:
sum = 0
else:
sum = functools.reduce(lambda a, b: a - b, map(int, args))
response_body = '<h1>Your total is: {0}</h1><br><a href="/">Back to the list of operations</a>'.format(str(sum))
return response_body


def add(*args):
def multiply(*args):
""" Returns a STRING with the sum of the arguments """
if len(args) == 0:
sum = 0
else:
sum = functools.reduce(lambda a, b: a * b, map(int, args))
response_body = '<h1>Your total is: {0}</h1><br><a href="/">Back to the list of operations</a>'.format(str(sum))
return response_body

# TODO: Fill sum with the correct value, based on the
# args provided.
sum = "0"

return sum
def divide(*args):
""" Returns a STRING with the sum of the arguments """
try:
sum = 0
if "0" in args:
raise ZeroDivisionError
if 0 in args:
raise ZeroDivisionError
if len(args) == 0:
raise ValueError
sum = functools.reduce(lambda a, b: a / b, map(int, args))
response_body = '<h1>Your total is: {0}</h1><br><a href="/">Back to the list of operations</a>'.format(str(sum))
return response_body
except ZeroDivisionError:
response_body = '<h1>Cannot divide by zero. Try Again!</h1><br><a href="/">Back to the list of operations</a>'
return response_body
except ValueError:
response_body = '<h1>No values were provided for Division Operation.<br>Please provide values and Try Again!' \
'</h1><br><a href="/">Back to the list of operations</a>'
return response_body


def application(environ, start_response):
"""Application function used to create a response in bytes bak to the client"""
try:
headers = [("Content-type", "text/html")]
func, args = resolve_path(environ.get('PATH_INFO', DEFAULT))
body = func(*args)
status = "200 OK"
except NameError:
status = "404 Not Found"
body = "<h1>Not Found</h1>"
except Exception:
status = "500 Internal Server Error"
body = "<h1>Internal Server Error</h1>"
except ZeroDivisionError:
status = "Can not divide by zero"
body = "<h1>Zero Division Error. Please Try again!!</h1>"
finally:
headers.append(('Content-length', str(len(body))))
start_response(status, headers)
return [body.encode('utf8')]

# TODO: Add functions for handling more arithmetic operations.

def resolve_path(path):
"""
Should return two values: a callable and an iterable of
arguments.
"""
funcs = {"": index, "add": add, "subtract": subtract,
"multiply": multiply, "divide": divide}

# TODO: Provide correct values for func and args. The
# examples provide the correct *syntax*, but you should
# determine the actual values of func and args using the
# path.
func = add
args = ['25', '32']
path = path.strip('/').split('/')
func_name = path[0]
args = path[1:]

try:
func = funcs[func_name]
except KeyError:
raise NameError
return func, args

def application(environ, start_response):
# TODO: Your application code from the book database
# work here as well! Remember that your application must
# invoke start_response(status, headers) and also return
# the body of the response in BYTE encoding.
#
# TODO (bonus): Add error handling for a user attempting
# to divide by zero.
pass

if __name__ == '__main__':
# TODO: Insert the same boilerplate wsgiref simple
# server creation that you used in the book database.
pass
from wsgiref.simple_server import make_server
srv = make_server('localhost', 8080, application)
srv.serve_forever()
Loading