Initialize repository

This commit is contained in:
Michael Hartl 2022-10-19 08:20:50 -07:00
commit 9aa36bfadb
260 changed files with 2759 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.DS_Store

23
LICENSE.md Normal file
View File

@ -0,0 +1,23 @@
```
The MIT License
Copyright (c) 2022 Michael Hartl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```

2
Listing_1.1.txt Normal file
View File

@ -0,0 +1,2 @@
$ python3 --version
Python 3.10.6

1
Listing_1.10.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ pip install Flask==2.2.2

7
Listing_1.11.py Normal file
View File

@ -0,0 +1,7 @@
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>hello, world!</p>"

2
Listing_1.12.txt Normal file
View File

@ -0,0 +1,2 @@
(venv) $ flask --app hello_app.py --debug run
* Running on http://127.0.0.1:5000/

2
Listing_1.13.txt Normal file
View File

@ -0,0 +1,2 @@
(venv) $ flask --app hello_app.py --debug run --port $PORT
* Running on http://127.0.0.1:8080/

16
Listing_1.14.bash Normal file
View File

@ -0,0 +1,16 @@
venv/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
.DS_Store

7
Listing_1.15.txt Normal file
View File

@ -0,0 +1,7 @@
click==8.1.3
Flask==2.2.2
gunicorn==20.1.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
Werkzeug==2.2.2

1
Listing_1.16.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ brew install flyctl

1
Listing_1.17.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ curl -L https://fly.io/install.sh | sh

5
Listing_1.18.bash Normal file
View File

@ -0,0 +1,5 @@
.
.
.
export FLYCTL_INSTALL="/home/ubuntu/.fly"
export PATH="$FLYCTL_INSTALL/bin:$PATH"

1
Listing_1.19.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ flyctl auth login --interactive

4
Listing_1.2.txt Normal file
View File

@ -0,0 +1,4 @@
$ sudo add-apt-repository -y ppa:deadsnakes/ppa
$ sudo apt-get install -y python3.10
$ sudo apt-get install -y python3.10-venv
$ sudo ln -sf /usr/bin/python3.10 /usr/bin/python3

1
Listing_1.20.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ flyctl launch

1
Listing_1.21.py Normal file
View File

@ -0,0 +1 @@
web: gunicorn hello_app:app

1
Listing_1.22.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ flyctl deploy

15
Listing_1.23.txt Normal file
View File

@ -0,0 +1,15 @@
(venv) $ flyctl status # Details will vary
App
Name = restless-sun-9514
Owner = personal
Version = 2
Status = running
Hostname = crimson-shadow-1161.fly.dev # Your URL will differ.
Platform = nomad
Deployment Status
ID = 051e253a-e322-4b2c-96ec-bc2758763328
Version = v2
Status = successful
Description = Deployment completed successfully
Instances = 1 desired, 1 placed, 1 healthy, 0 unhealthy

1
Listing_1.3.txt Normal file
View File

@ -0,0 +1 @@
$ brew install python@3.10

2
Listing_1.4.py Normal file
View File

@ -0,0 +1,2 @@
$ python3
>>>

2
Listing_1.5.py Normal file
View File

@ -0,0 +1,2 @@
>>> print("hello, world!")
hello, world!

22
Listing_1.6.txt Normal file
View File

@ -0,0 +1,22 @@
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

1
Listing_1.7.py Normal file
View File

@ -0,0 +1 @@
print("hello, world!")

1
Listing_1.8.py Normal file
View File

@ -0,0 +1 @@
print("hello, world!", "how's it going?")

3
Listing_1.9.bash Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env python3
print("hello, world!")

12
Listing_10.1.py Normal file
View File

@ -0,0 +1,12 @@
from setuptools import find_packages, setup
setup(
name='palindrome_detector',
version='1.0.0',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=[
'flask',
],
)

24
Listing_10.10.py Normal file
View File

@ -0,0 +1,24 @@
import os
from flask import Flask, render_template
def create_app(test_config=None):
"""Create and configure the app."""
app = Flask(__name__, instance_relative_config=True)
.
.
.
@app.route("/")
def index():
return render_template("index.html")
@app.route("/about")
def about():
return render_template("about.html")
@app.route("/palindrome")
def palindrome():
return render_template("palindrome.html")
return app
app = create_app()

37
Listing_10.11.html Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<div class="content">
<h1>Sample Flask App</h1>
<p>
This is the sample Flask app for
<a href="https://www.learnenough.com/python-tutorial"><em>Learn Enough Python
to Be Dangerous</em></a>. Learn more on the <a href="/about">About</a> page.
</p>
<p>
Click the <a href="https://en.wikipedia.org/wiki/Sator_Square">Sator
Square</a> below to run the custom <a href="/palindrome">Palindrome
Detector</a>.
</p>
<a class="sator-square" href="/palindrome">
<img src="/static/images/sator_square.jpg" alt="Sator Square">
</a>
</div>
</div>
</body>
</html>

32
Listing_10.12.html Normal file
View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<div class="content">
<h1>About</h1>
<p>
This site is the final application in
<a href="https://www.learnenough.com/python-tutorial"><em>Learn Enough Python
to Be Dangerous</em></a>
by <a href="https://www.michaelhartl.com/">Michael Hartl</a>,
a tutorial introduction to the
<a href="https://www.python.org/">Python programming language</a> that
is part of
<a href="https://www.learnenough.com/">LearnEnough.com</a>.
</p>
</div>
</div>
</body>
</html>

24
Listing_10.13.html Normal file
View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<div class="content">
<h1>Palindrome Detector</h1>
<p>This will be the palindrome detector.</p>
</div>
</div>
</body>
</html>

10
Listing_10.14.py Normal file
View File

@ -0,0 +1,10 @@
% import os
% from flask import Flask
% def create_app(test_config=None):
% """Create and configure the app."""
% app = Flask(__name__, instance_relative_config=True,
% static_url_path="/static")
% .
% .
% .

20
Listing_10.15.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<div class="content">
<!-- page-specific content -->
</div>
</div>
</body>
</html>

1
Listing_10.16.txt Normal file
View File

@ -0,0 +1 @@
$ pip install -e .

11
Listing_10.17.py Normal file
View File

@ -0,0 +1,11 @@
def test_index(client):
response = client.get("/")
assert response.status_code == 200
def test_about(client):
response = client.get("/about")
assert response.status_code == 200
def test_palindrome(client):
response = client.get("/palindrome")
assert response.status_code == 200

7
Listing_10.18.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

17
Listing_10.19.py Normal file
View File

@ -0,0 +1,17 @@
def test_index(client):
response = client.get("/")
assert response.status_code == 200
assert "<title>" in response.text
assert "<h1>" in response.text
def test_about(client):
response = client.get("/about")
assert response.status_code == 200
assert "<title>" in response.text
assert "<h1>" in response.text
def test_palindrome(client):
response = client.get("/palindrome")
assert response.status_code == 200
assert "<title>" in response.text
assert "<h1>" in response.text

3
Listing_10.2.py Normal file
View File

@ -0,0 +1,3 @@
graft palindrome_detector/static
graft palindrome_detector/templates
global-exclude *.pyc

7
Listing_10.20.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

20
Listing_10.21.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

21
Listing_10.22.html Normal file
View File

@ -0,0 +1,21 @@
{% extends "layout.html" %}
{% block content %}
<h1>Sample Flask App</h1>
<p>
This is the sample Flask app for
<a href="https://www.learnenough.com/python-tutorial"><em>Learn Enough Python
to Be Dangerous</em></a>. Learn more on the <a href="/about">About</a> page.
</p>
<p>
Click the <a href="https://en.wikipedia.org/wiki/Sator_Square">Sator
Square</a> below to run the custom <a href="/palindrome">Palindrome
Detector</a>.
</p>
<a class="sator-square" href="/palindrome">
<img src="/static/images/sator_square.jpg" alt="Sator Square">
</a>
{% endblock %}

16
Listing_10.23.html Normal file
View File

@ -0,0 +1,16 @@
{% extends "layout.html" %}
{% block content %}
<h1>About</h1>
<p>
This site is the final application in
<a href="https://www.learnenough.com/python-tutorial"><em>Learn Enough Python
to Be Dangerous</em></a>
by <a href="https://www.michaelhartl.com/">Michael Hartl</a>,
a tutorial introduction to the
<a href="https://www.python.org/">Python programming language</a> that
is part of
<a href="https://www.learnenough.com/">LearnEnough.com</a>.
</p>
{% endblock %}

7
Listing_10.24.html Normal file
View File

@ -0,0 +1,7 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Detector</h1>
<p>This will be the palindrome detector.</p>
{% endblock %}

7
Listing_10.25.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

23
Listing_10.26.py Normal file
View File

@ -0,0 +1,23 @@
def test_index(client):
response = client.get("/")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title}</title>"
assert title in response.text
assert "<h1>" in response.text
def test_about(client):
response = client.get("/about")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title}</title>"
assert title in response.text
assert "<h1>" in response.text
def test_palindrome(client):
response = client.get("/palindrome")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title}</title>"
assert title in response.text
assert "<h1>" in response.text

7
Listing_10.27.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

23
Listing_10.28.py Normal file
View File

@ -0,0 +1,23 @@
def test_index(client):
response = client.get("/")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title} | Home</title>"
assert title in response.text
assert "<h1>" in response.text
def test_about(client):
response = client.get("/about")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title} | About</title>"
assert title in response.text
assert "<h1>" in response.text
def test_palindrome(client):
response = client.get("/palindrome")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title} | Palindrome Detector</title>"
assert title in response.text
assert "<h1>" in response.text

16
Listing_10.29.txt Normal file
View File

@ -0,0 +1,16 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py FFF [100%]
=================================== FAILURES ===================================
__________________________________ test_index __________________________________
.
.
.
=========================== short test summary info ============================
FAILED tests/test_site_pages.py::test_index - assert '<title>Learn Enough Pyt...
FAILED tests/test_site_pages.py::test_about - assert '<title>Learn Enough Pyt...
FAILED tests/test_site_pages.py::test_palindrome - assert '<title>Learn Enoug...
============================== 3 failed in 0.03s ===============================

27
Listing_10.3.py Normal file
View File

@ -0,0 +1,27 @@
import os
from flask import Flask
def create_app(test_config=None):
"""Create and configure the app."""
app = Flask(__name__, instance_relative_config=True)
if test_config is None:
# Load the instance config, if it exists, when not testing.
app.config.from_pyfile("config.py", silent=True)
else:
# Load the test config if passed in.
app.config.from_mapping(test_config)
# Ensure the instance folder exists.
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route("/")
def index():
return "hello, world!"
return app
app = create_app()

36
Listing_10.30.py Normal file
View File

@ -0,0 +1,36 @@
import os
from flask import Flask, render_template
def create_app(test_config=None):
"""Create and configure the app."""
app = Flask(__name__, instance_relative_config=True)
if test_config is None:
# Load the instance config, if it exists, when not testing.
app.config.from_pyfile("config.py", silent=True)
else:
# Load the test config if passed in.
app.config.from_mapping(test_config)
# Ensure the instance folder exists.
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route("/")
def index():
return render_template("index.html", page_title="Home")
@app.route("/about")
def about():
return render_template("about.html", page_title="About")
@app.route("/palindrome")
def palindrome():
return render_template("palindrome.html",
page_title="Palindrome Detector")
return app
app = create_app()

8
Listing_10.31.html Normal file
View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App | {{ page_title }}</title>
.
.
.

7
Listing_10.32.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

29
Listing_10.33.html Normal file
View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App | {{ page_title }}</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<header class="header">
<nav>
<ul class="header-nav">
<li><a href="/">Home</a></li>
<li><a href="/palindrome">Is It a Palindrome?</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

24
Listing_10.34.py Normal file
View File

@ -0,0 +1,24 @@
def test_index(client):
response = client.get("/")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title} | Home</title>"
assert title in response.text
assert "<h1>" in response.text
assert "<nav>" in response.text
def test_about(client):
response = client.get("/about")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title} | About</title>"
assert title in response.text
assert "<h1>" in response.text
def test_palindrome(client):
response = client.get("/palindrome")
assert response.status_code == 200
base_title = "Learn Enough Python Sample App"
title = f"<title>{base_title} | Palindrome Detector</title>"
assert title in response.text
assert "<h1>" in response.text

7
Listing_10.35.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

24
Listing_10.36.html Normal file
View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App | {{ page_title }}</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<header class="header">
                              
</header>
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

9
Listing_10.37.html Normal file
View File

@ -0,0 +1,9 @@
<header class="header">
<nav>
<ul class="header-nav">
<li><a href="/">Home</a></li>
<li><a href="/palindrome">Is It a Palindrome?</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>

14
Listing_10.38.txt Normal file
View File

@ -0,0 +1,14 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py F.. [100%]
=================================== FAILURES ===================================
__________________________________ test_index __________________________________
.
.
.
=========================== short test summary info ============================
FAILED tests/test_site_pages.py::test_index - assert '<nav>' in '<!DOCTYPE ht...
========================= 1 failed, 2 passed in 0.03s ==========================

23
Listing_10.39.html Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learn Enough Python Sample App | {{ page_title }}</title>
<link rel="stylesheet" type="text/css" href="/static/stylesheets/main.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"
rel="stylesheet">
</head>
<body>
<a href="/" class="header-logo">
<img src="/static/images/logo_b.png" alt="Learn Enough logo">
</a>
<div class="container">
<header class="header">
{% include "navigation.html" %}
</header>
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

2
Listing_10.4.txt Normal file
View File

@ -0,0 +1,2 @@
(venv) $ flask --app palindrome_detector --debug run
* Running on http://127.0.0.1:5000/

7
Listing_10.40.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ pytest
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
============================== 3 passed in 0.01s ===============================

23
Listing_10.41.py Normal file
View File

@ -0,0 +1,23 @@
def test_index(client):
response = client.get("/")
assert response.status_code == 200
assert full_title("Home") in response.text
assert "<h1>" in response.text
assert "<nav>" in response.text
def test_about(client):
response = client.get("/about")
assert response.status_code == 200
assert full_title("About") in response.text
assert "<h1>" in response.text
def test_palindrome(client):
response = client.get("/palindrome")
assert response.status_code == 200
assert full_title("Palindrome Detector") in response.text
assert "<h1>" in response.text
def full_title(variable_title):
"""Return the full title."""
base_title = "Learn Enough Python Sample App"
return f"<title>{base_title} | {variable_title}</title>"

6
Listing_10.42.py Normal file
View File

@ -0,0 +1,6 @@
import os
from flask import Flask, render_template, request
from palindrome.phrase import Phrase
.
.
.

6
Listing_10.43.txt Normal file
View File

@ -0,0 +1,6 @@
--extra-index-url https://testpypi.python.org/pypi
click==8.1.3
Flask==2.2.2
.
.
.

11
Listing_10.44.html Normal file
View File

@ -0,0 +1,11 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Detector</h1>
<form id="palindrome_tester" action="/check" method="post">
<textarea name="phrase" rows="10" cols="60"></textarea>
<br>
<button class="form-submit" type="submit">Is it a palindrome?</button>
</form>
{% endblock %}

30
Listing_10.45.py Normal file
View File

@ -0,0 +1,30 @@
import os
from flask import Flask, render_template, request
from palindrome.phrase import Phrase
def create_app(test_config=None):
.
.
.
@app.route("/")
def index():
page_title = "Home"
return render_template("index.html", page_title=page_title)
@app.route("/about")
def about():
page_title = "About"
return render_template("about.html", page_title=page_title)
@app.route("/palindrome")
def palindrome():
page_title = "Palindrome Detector"
return render_template("palindrome.html", page_title=page_title)
@app.route("/check", methods=("POST",))
def check():
return request.form
return app
app = create_app()

4
Listing_10.46.py Normal file
View File

@ -0,0 +1,4 @@
if Phrase(phrase).ispalindrome():
print(f'"{phrase}" is a palindrome!"
else:
print(f'"{phrase}" isn\'t a palindrome."

5
Listing_10.47.html Normal file
View File

@ -0,0 +1,5 @@
{% if Phrase(phrase).ispalindrome() %}
"{{ phrase }}" is a palindrome!
{% else %}
"{{ phrase }}" isn't a palindrome.
{% endif %}

15
Listing_10.48.html Normal file
View File

@ -0,0 +1,15 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Result</h1>
{% if Phrase(phrase).ispalindrome() %}
<div class="result result-success">
<p>"{{ phrase }}" is a palindrome!</p>
</div>
{% else %}
<div class="result result-fail">
<p>"{{ phrase }}" isn't a palindrome.</p>
</div>
{% endif %}
{% endblock %}

45
Listing_10.49.py Normal file
View File

@ -0,0 +1,45 @@
import os
from flask import Flask, render_template, request
from palindrome.phrase import Phrase
def create_app(test_config=None):
"""Create and configure the app."""
app = Flask(__name__, instance_relative_config=True)
if test_config is None:
# Load the instance config, if it exists, when not testing.
app.config.from_pyfile("config.py", silent=True)
else:
# Load the test config if passed in.
app.config.from_mapping(test_config)
# Ensure the instance folder exists.
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route("/")
def index():
page_title = "Home"
return render_template("index.html", page_title=page_title)
@app.route("/about")
def about():
page_title = "About"
return render_template("about.html", page_title=page_title)
@app.route("/palindrome")
def palindrome():
page_title = "Palindrome Detector"
return render_template("palindrome.html", page_title=page_title)
@app.route("/check", methods=("POST",))
def check():
return render_template("result.html",
Phrase=Phrase,
phrase=request.form["phrase"])
return app
app = create_app()

16
Listing_10.5.bash Normal file
View File

@ -0,0 +1,16 @@
venv/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
.DS_Store

6
Listing_10.50.py Normal file
View File

@ -0,0 +1,6 @@
def test_palindrome_page(client):
response = client.get("/palindrome")
assert form_tag() in response.text
def form_tag():
return '<form id="palindrome_tester" action="/check" method="post">'

16
Listing_10.51.py Normal file
View File

@ -0,0 +1,16 @@
def test_palindrome_page(client):
response = client.get("/palindrome")
assert form_tag() in response.text
def test_non_palindrome_submission(client):
phrase = "Not a palindrome."
response = client.post("/check", data={"phrase": phrase})
assert f'<p>"{phrase}" isn\'t a palindrome.</p>' in response.text
def test_palindrome_submission(client):
phrase = "Sator Arepo tenet opera rotas"
response = client.post("/check", data={"phrase": phrase})
assert f'<p>"{phrase}" is a palindrome!</p>' in response.text
def form_tag():
return '<form id="palindrome_tester" action="/check" method="post">'

8
Listing_10.52.txt Normal file
View File

@ -0,0 +1,8 @@
(venv) $ pytest
============================= test session starts ==============================
collected 6 items
tests/test_palindrome.py ... [ 50%]
tests/test_site_pages.py ... [100%]
============================== 6 passed in 0.03s ===============================

17
Listing_10.53.py Normal file
View File

@ -0,0 +1,17 @@
def test_palindrome_page(client):
response = client.get("/palindrome")
assert form_tag() in response.text
def test_non_palindrome_submission(client):
phrase = "Not a palindrome."
response = client.post("/check", data={"phrase": phrase})
assert f'<p>"{phrase}" isn\'t a palindrome.</p>' in response.text
assert form_tag() in response.text
def test_palindrome_submission(client):
phrase = "Sator Arepo tenet opera rotas"
response = client.post("/check", data={"phrase": phrase})
assert f'<p>"{phrase}" is a palindrome!</p>' in response.text
def form_tag():
return '<form id="palindrome_tester" action="/check" method="post">'

16
Listing_10.54.txt Normal file
View File

@ -0,0 +1,16 @@
(venv) $ pytest
============================= test session starts ==============================
collected 6 items
tests/test_palindrome.py .FF [ 50%]
tests/test_site_pages.py ... [100%]
=================================== FAILURES ===================================
________________________ test_non_palindrome_submission ________________________
.
.
.
=========================== short test summary info ============================
FAILED tests/test_palindrome.py::test_non_palindrome_submission - assert '<fo...
FAILED tests/test_palindrome.py::test_palindrome_submission - assert '<form i...
========================= 2 failed, 4 passed in 0.04s ==========================

21
Listing_10.55.html Normal file
View File

@ -0,0 +1,21 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Result</h1>
{% if ispalindrome %}
<div class="result result-success">
<p>"{{ phrase }}" is a palindrome!</p>
</div>
{% else %}
<div class="result result-fail">
<p>"{{ phrase }}" isn't a palindrome.</p>
</div>
{% endif %}
<form id="palindrome_tester" action="/check" method="post">
<textarea name="phrase" rows="10" cols="60"></textarea>
<br>
<button class="form-submit" type="submit">Is it a palindrome?</button>
</form>
{% endblock %}

8
Listing_10.56.txt Normal file
View File

@ -0,0 +1,8 @@
(venv) $ pytest
============================= test session starts ==============================
collected 6 items
tests/test_palindrome.py ... [ 50%]
tests/test_site_pages.py ... [100%]
============================== 6 passed in 0.03s ===============================

5
Listing_10.57.html Normal file
View File

@ -0,0 +1,5 @@
<form id="palindrome_tester" action="/check" method="post">
<textarea name="phrase" rows="10" cols="60"></textarea>
<br>
<button class="form-submit" type="submit">Is it a palindrome?</button>
</form>

19
Listing_10.58.html Normal file
View File

@ -0,0 +1,19 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Result</h1>
{% if ispalindrome %}
<div class="result result-success">
<p>"{{ phrase }}" is a palindrome!</p>
</div>
{% else %}
<div class="result result-fail">
<p>"{{ phrase }}" isn't a palindrome.</p>
</div>
{% endif %}
<h2>Try another one!</h2>
{% include "palindrome_form.html" %}
{% endblock %}

7
Listing_10.59.html Normal file
View File

@ -0,0 +1,7 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Detector</h1>
{% include "palindrome_form.html" %}
{% endblock %}

1
Listing_10.6.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ flyctl auth login --interactive

8
Listing_10.60.txt Normal file
View File

@ -0,0 +1,8 @@
(venv) $ pytest
============================= test session starts ==============================
collected 6 items
tests/test_palindrome.py ... [ 50%]
tests/test_site_pages.py ... [100%]
============================== 6 passed in 0.03s ===============================

2
Listing_10.61.txt Normal file
View File

@ -0,0 +1,2 @@
(venv) $ pip install --upgrade your-package \
> --index-url https://test.pypi.org/simple/

1
Listing_10.7.txt Normal file
View File

@ -0,0 +1 @@
(venv) $ flyctl launch

1
Listing_10.8.py Normal file
View File

@ -0,0 +1 @@
web: gunicorn palindrome_detector:app

7
Listing_10.9.txt Normal file
View File

@ -0,0 +1,7 @@
(venv) $ deactivate
$ rm -rf venv/
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip install -r requirements.txt
(venv) $ flask --app palindrome_detector --debug run
* Running on http://127.0.0.1:5000/

18
Listing_11.1.bash Normal file
View File

@ -0,0 +1,18 @@
venv/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
.ipynb_checkpoints
.DS_Store

7
Listing_11.10.py Normal file
View File

@ -0,0 +1,7 @@
>>> sizes = {"tiny": 4, "small": 8, "mid": 12, "big": 16, "huge": 24}
>>> df["Size"].map(sizes)
0 4
1 8
2 12
3 16
4 24

9
Listing_11.11.py Normal file
View File

@ -0,0 +1,9 @@
>>> nobel.head()
id firstname ... city country
0 1 Wilhelm Conrad ... Munich Germany
1 2 Hendrik A. ... Leiden the Netherlands
2 3 Pieter ... Amsterdam the Netherlands
3 4 Henri ... Paris France
4 5 Pierre ... Paris France
[5 rows x 20 columns]

3
Listing_11.12.py Normal file
View File

@ -0,0 +1,3 @@
>>> nobel.loc[nobel["firstname"].str.contains("Kip")]
id firstname surname ... name city country
916 943 Kip S. Thorne ... LIGO/VIRGO Collaboration NaN NaN

7
Listing_11.13.py Normal file
View File

@ -0,0 +1,7 @@
>>> curies = nobel.loc[nobel["surname"].str.contains("Curie", na=False)]
>>> curies
id firstname ... city country
4 5 Pierre ... Paris France
5 6 Marie ... NaN NaN
6 6 Marie ... Paris France
191 194 Irène ... Paris France

8
Listing_11.14.py Normal file
View File

@ -0,0 +1,8 @@
>>> laureates = nobel.groupby(["id", "firstname", "surname"])
>>> sizes = laureates.size()
>>> sizes[sizes > 1]
id firstname surname
6 Marie Curie 2
66 John Bardeen 2
217 Linus Pauling 2
222 Frederick Sanger 2

3
Listing_11.15.py Normal file
View File

@ -0,0 +1,3 @@
>>> nobel.hist(column="lifespan")
array([[<AxesSubplot:title={'center':'lifespan'}>]], dtype=object)
>>> plt.show()

15
Listing_11.16.py Normal file
View File

@ -0,0 +1,15 @@
>>> titanic["Age"].notna()
Name
Braund, Mr. Owen Harris True
Cumings, Mrs. John Bradley (Florence Briggs Thayer) True
Heikkinen, Miss. Laina True
Futrelle, Mrs. Jacques Heath (Lily May Peel) True
Allen, Mr. William Henry True
...
Montvila, Rev. Juozas True
Graham, Miss. Margaret Edith True
Johnston, Miss. Catherine Helen "Carrie" False
Behr, Mr. Karl Howell True
Dooley, Mr. Patrick True
Name: Age, Length: 891, dtype: bool
>>> valid_ages = titanic[titanic["Age"].notna()]

2
Listing_11.17.py Normal file
View File

@ -0,0 +1,2 @@
titanic[(titanic["Sex"] == "female") &
(titanic["Pclass"] == 3)]["Survived"].mean()

4
Listing_11.18.py Normal file
View File

@ -0,0 +1,4 @@
male_passengers = titanic[titanic["Sex"] == "male"]
female_passengers = titanic[titanic["Sex"] == "female"]
valid_male_ages = male_passengers[titanic["Age"].notna()]
valid_female_ages = female_passengers[titanic["Age"].notna()]

1
Listing_11.19.py Normal file
View File

@ -0,0 +1 @@
>>> from sklearn.linear_model import LinearRegression

4
Listing_11.2.txt Normal file
View File

@ -0,0 +1,4 @@
(venv) $ pip install numpy==1.23.3 \
> matplotlib==3.6.1 \
> pandas==1.5.0 \
> scikit-learn==1.1.2

5
Listing_11.20.py Normal file
View File

@ -0,0 +1,5 @@
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import Perceptron
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier

7
Listing_11.21.py Normal file
View File

@ -0,0 +1,7 @@
Model
Score
0.854749 Decision Tree
0.854749 Random Forest
0.787709 Logistic Regression
0.770950 Naive Bayes
0.743017 Perceptron

Some files were not shown because too many files have changed in this diff Show More