Add listings

This commit is contained in:
Michael Hartl 2022-11-13 10:39:28 -08:00
parent 9aa36bfadb
commit 256ad44d08
199 changed files with 1834 additions and 657 deletions

View File

@ -1,5 +1,6 @@
from flask import Flask
app = Flask(__name__)
@app.route("/")

7
Listing_10.10.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/

26
Listing_10.11.py Normal file
View File

@ -0,0 +1,26 @@
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()

View File

@ -14,18 +14,23 @@
<div class="container">
<div class="content">
<h1>About</h1>
<h1>Sample Flask App</h1>
<p>
This site is the final application in
This is the sample Flask app for
<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>.
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>

View File

@ -14,10 +14,18 @@
<div class="container">
<div class="content">
<h1>Palindrome Detector</h1>
<p>This will be the palindrome detector.</p>
<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>

24
Listing_10.14.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.15.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.16.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.17.txt Normal file
View File

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

12
Listing_10.18.py Normal file
View File

@ -0,0 +1,12 @@
import pytest
from palindrome_detector import create_app
@pytest.fixture
def app():
return create_app()
@pytest.fixture
def client(app):
return app.test_client()

View File

@ -1,17 +1,11 @@
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

17
Listing_10.21.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

7
Listing_10.22.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 ===============================

View File

@ -1,16 +1,20 @@
{% 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 %}
<!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>

View File

@ -1,7 +1,21 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Detector</h1>
<h1>Sample Flask App</h1>
<p>This will be the palindrome detector.</p>
<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.25.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.26.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 %}

View File

@ -2,7 +2,7 @@ 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>"
title = f"<title>{base_title}</title>"
assert title in response.text
assert "<h1>" in response.text
@ -10,7 +10,7 @@ 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>"
title = f"<title>{base_title}</title>"
assert title in response.text
assert "<h1>" in response.text
@ -18,6 +18,6 @@ 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>"
title = f"<title>{base_title}</title>"
assert title in response.text
assert "<h1>" in response.text

View File

@ -2,15 +2,6 @@
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py FFF [100%]
tests/test_site_pages.py ... [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 ===============================
============================== 3 passed in 0.01s ===============================

View File

@ -1,6 +1,8 @@
import os
from flask import Flask
def create_app(test_config=None):
"""Create and configure the app."""
app = Flask(__name__, instance_relative_config=True)

View File

@ -1,36 +1,23 @@
import os
from flask import Flask, render_template
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 create_app(test_config=None):
"""Create and configure the app."""
app = Flask(__name__, instance_relative_config=True)
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
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()
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.31.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 ===============================

38
Listing_10.32.py Normal file
View File

@ -0,0 +1,38 @@
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()

View File

@ -3,27 +3,6 @@
<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>
.
.
.

7
Listing_10.34.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.35.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.36.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.37.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 ===============================

22
Listing_10.38.html Normal file
View File

@ -0,0 +1,22 @@
<!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">
                              
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

View File

@ -1,23 +1,9 @@
<!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>
<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>

View File

@ -2,6 +2,13 @@
============================= test session starts ==============================
collected 3 items
tests/test_site_pages.py ... [100%]
tests/test_site_pages.py F.. [100%]
============================== 3 passed in 0.01s ===============================
=================================== 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 ==========================

21
Listing_10.41.html Normal file
View File

@ -0,0 +1,21 @@
<!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">
{% include "navigation.html" %}
<div class="content">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

7
Listing_10.42.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.43.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>"

9
Listing_10.44.py Normal file
View File

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

7
Listing_10.45.txt Normal file
View File

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

11
Listing_10.46.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 %}

31
Listing_10.47.py Normal file
View File

@ -0,0 +1,31 @@
import os
from flask import Flask, render_template, request
from palindrome_mhartl.phrase import Phrase
def create_app(test_config=None):
.
.
.
@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")
@app.route("/check", methods=("POST",))
def check():
return request.form
return app
app = create_app()

4
Listing_10.48.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.49.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.50.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 %}

View File

@ -1,16 +1,46 @@
def test_palindrome_page(client):
response = client.get("/palindrome")
assert form_tag() in response.text
import os
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
from flask import Flask, render_template, request
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
from palindrome_mhartl.phrase import Phrase
def form_tag():
return '<form id="palindrome_tester" action="/check" method="post">'
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")
@app.route("/check", methods=("POST",))
def check():
return render_template("result.html",
Phrase=Phrase,
phrase=request.form["phrase"])
return app
app = create_app()

6
Listing_10.52.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">'

View File

@ -6,10 +6,9 @@ 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"
phrase = "Sator Arepo tenet opera rotas."
response = client.post("/check", data={"phrase": phrase})
assert f'<p>"{phrase}" is a palindrome!</p>' in response.text

View File

@ -2,15 +2,7 @@
============================= test session starts ==============================
collected 6 items
tests/test_palindrome.py .FF [ 50%]
tests/test_palindrome.py ... [ 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 ==========================
============================== 6 passed in 0.03s ===============================

17
Listing_10.55.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">'

View File

@ -2,7 +2,15 @@
============================= test session starts ==============================
collected 6 items
tests/test_palindrome.py ... [ 50%]
tests/test_palindrome.py .FF [ 50%]
tests/test_site_pages.py ... [100%]
============================== 6 passed in 0.03s ===============================
=================================== 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 ==========================

View File

@ -1,5 +1,21 @@
<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>
{% 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 %}
<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.58.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 ===============================

View File

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

View File

@ -1 +1,7 @@
(venv) $ flyctl auth login --interactive
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

19
Listing_10.60.html Normal file
View File

@ -0,0 +1,19 @@
{% 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 %}
<h2>Try another one!</h2>
{% include "palindrome_form.html" %}
{% endblock %}

7
Listing_10.61.html Normal file
View File

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

48
Listing_10.62.py Normal file
View File

@ -0,0 +1,48 @@
import os
from flask import Flask, render_template, request
from palindrome_mhartl.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():
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")
@app.route("/check", methods=("POST",))
def check():
phrase = request.form["phrase"]
is_palindrome = Phrase(phrase).ispalindrome()
return render_template("result.html",
phrase=phrase,
is_palindrome=is_palindrome)
return app
app = create_app()

19
Listing_10.63.html Normal file
View File

@ -0,0 +1,19 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Result</h1>
{% if is_palindrome %}
<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 %}

8
Listing_10.64.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.65.txt Normal file
View File

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

View File

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

1
Listing_10.8.txt Normal file
View File

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

1
Listing_10.9.py Normal file
View File

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

View File

@ -1,7 +1,19 @@
>>> 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
>>> from math import tau
>>> from numpy.random import default_rng
>>> rng = default_rng()
>>> df = pd.DataFrame(
... {
... "Number": 1.0,
... "String": "foo",
... "Angles": np.linspace(0, tau, 5),
... "Random": pd.Series(rng.standard_normal(5)),
... "Timestamp": pd.Timestamp("20221020"),
... "Size": pd.Categorical(["tiny", "small", "mid", "big", "huge"])
... })
>>> df
Number String Angles Random Timestamp Size
0 1.0 foo 0.000000 -1.954002 2022-10-20 tiny
1 1.0 foo 1.570796 0.967171 2022-10-20 small
2 1.0 foo 3.141593 -1.149739 2022-10-20 mid
3 1.0 foo 4.712389 -0.084962 2022-10-20 big
4 1.0 foo 6.283185 0.310634 2022-10-20 huge

View File

@ -1,9 +1,7 @@
>>> 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]
>>> 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

View File

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

View File

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

View File

@ -1,8 +1,7 @@
>>> 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
>>> 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

View File

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

View File

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

View File

@ -1,2 +1,2 @@
titanic[(titanic["Sex"] == "female") &
(titanic["Pclass"] == 3)]["Survived"].mean()
>>> URL = "https://learnenough.s3.amazonaws.com/titanic.csv"
>>> titanic = pd.read_csv(URL)

View File

@ -1,4 +1,15 @@
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()]
>>> 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()]

View File

@ -1 +1,2 @@
>>> from sklearn.linear_model import LinearRegression
titanic[(titanic["Sex"] == "female") &
(titanic["Pclass"] == 3)]["Survived"].mean()

View File

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

View File

@ -1,5 +1,4 @@
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
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()]

View File

@ -1,7 +1 @@
Model
Score
0.854749 Decision Tree
0.854749 Random Forest
0.787709 Logistic Regression
0.770950 Naive Bayes
0.743017 Perceptron
>>> from sklearn.linear_model import LinearRegression

5
Listing_11.22.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.23.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

View File

@ -3,5 +3,6 @@ Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: only size-1 arrays can be converted to Python scalars
>>> a = np.cos(angles)
>>> a
array([ 1.0000000e+00, 6.1232340e-17, -1.0000000e+00, -1.8369702e-16,
1.0000000e+00])

View File

@ -1,6 +1,8 @@
from math import tau
import numpy as np
import matplotlib.pyplot as plt
from math import tau
x = np.linspace(0, tau, 100)

View File

@ -1,9 +1,9 @@
>>> password = "goldilocks"
>>> if len(password) < 6:
... "Password is too short."
... print("Password is too short.")
... elif len(password) < 50:
... "Password is just right!"
... print("Password is just right!")
... else:
... "Password is too long."
... print("Password is too long.")
...
'Password is just right!'
Password is just right!

View File

@ -1,8 +1,8 @@
>>> x = "foo"
>>> y = ""
>>> if len(x) == 0 and len(y) == 0:
... "Both strings are empty!"
... print("Both strings are empty!")
... else:
... "At least one of the strings is nonempty."
... print("At least one of the strings is nonempty.")
...
'At least one of the strings is nonempty.'
At least one of the strings is nonempty.

View File

@ -1,6 +1,6 @@
>>> if len(x) == 0 or len(y) == 0
... "At least one of the strings is empty!"
... else
... "Neither of the strings is empty."
>>> if len(x) == 0 or len(y) == 0:
... print("At least one of the strings is empty!")
... else:
... print("Neither of the strings is empty.")
...
'At least one of the strings is empty!'
At least one of the strings is empty!

View File

@ -1,6 +1,6 @@
>>> if not (len(x) == 0): # Not Pythonic
... "x is not empty."
... print("x is not empty.")
... else:
... "x is empty."
... print("x is empty.")
...
'x is not empty.'
x is not empty.

View File

@ -1,6 +1,6 @@
>>> if len(x) != 0: # Not quite Pythonic
... "x is not empty."
... print("x is not empty.")
... else:
... "x is empty."
... print("x is empty.")
...
'x is not empty'
x is not empty

View File

@ -1,6 +1,6 @@
>>> if x: # Pythonic
... "x is not empty."
... print("x is not empty.")
... else:
... "x is empty."
... print("x is empty.")
...
'x is not empty'
x is not empty.

View File

@ -1,6 +1,6 @@
>>> if x or y
... "At least one of the strings is nonempty."
... else
... "Both strings are empty!"
>>> if x or y:
... print("At least one of the strings is nonempty.")
... else:
... print("Both strings are empty!")
...
'At least one of the strings is nonempty.'
At least one of the strings is nonempty.

View File

@ -1,9 +1,3 @@
>>> soliloquy = "To be, or not to be, that is the question:" # Just a reminder
>>> "To be" in soliloquy # Does it include the substring "To be"?
True
>>> "question" in soliloquy # What about "question"?
True
>>> "nonexistent" in soliloquy # This string doesn't appear.
False
>>> "TO BE" in soliloquy # String inclusion is case-sensitive.
False
>>> password = "a" * 50
>>> password
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

View File

@ -1,2 +1,9 @@
>>> " spacious ".FILL_IN()
'spacious'
>>> soliloquy = "To be, or not to be, that is the question:" # Just a reminder
>>> "To be" in soliloquy # Does it include the substring "To be"?
True
>>> "question" in soliloquy # What about "question"?
True
>>> "nonexistent" in soliloquy # This string doesn't appear.
False
>>> "TO BE" in soliloquy # String inclusion is case-sensitive.
False

View File

@ -1,8 +1,2 @@
>>> print(soliloquy) # Just a reminder of what the string is
To be, or not to be, that is the question:
>>> soliloquy[0]
'T'
>>> soliloquy[1]
'o'
>>> soliloquy[2]
' '
>>> " spacious ".FILL_IN()
'spacious'

View File

@ -1,8 +1,8 @@
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
>>> soliloquy # Just a reminder of what the string is
'To be, or not to be, that is the question:'
>>> soliloquy[0]
'T'
>>> soliloquy[1]
'o'
>>> soliloquy[2]
' '

8
Listing_2.24.py Normal file
View File

@ -0,0 +1,8 @@
>>> for i in range(5):
... print(i)
...
0
1
2
3
4

8
Listing_2.25.js Normal file
View File

@ -0,0 +1,8 @@
> for (i = 0; i < 5; i++) {
console.log(i);
}
0
1
2
3
4

View File

@ -1,5 +1,5 @@
>>> for c in soliloquy: # Pythonic
... print(c)
>>> for i in range(len(soliloquy)): # Not Pythonic
... print(soliloquy[i])
...
T
o

View File

@ -1,13 +1,16 @@
>>> for i in range(len(soliloquy)): # Not Pythonic
... print(f"Character {i+1} is '{soliloquy[i]}'")
>>> for c in soliloquy: # Pythonic
... print(c)
...
Character 1 is 'T'
Character 2 is 'o'
Character 3 is ' '
Character 4 is 'b'
Character 5 is 'e'
Character 6 is ','
Character 7 is ' '
T
o
b
e
.
.
.
t
i
o
n
:

View File

@ -1,5 +1,5 @@
>>> for i, c in enumerate(soliloquy): # Pythonic
... print(f"Character {i+1} is '{c}'")
>>> for i in range(len(soliloquy)): # Not Pythonic
... print(f"Character {i+1} is '{soliloquy[i]}'")
...
Character 1 is 'T'
Character 2 is 'o'

13
Listing_2.29.py Normal file
View File

@ -0,0 +1,13 @@
>>> for i, c in enumerate(soliloquy): # Pythonic
... print(f"Character {i+1} is '{c}'")
...
Character 1 is 'T'
Character 2 is 'o'
Character 3 is ' '
Character 4 is 'b'
Character 5 is 'e'
Character 6 is ','
Character 7 is ' '
.
.
.

View File

@ -1,5 +1,5 @@
>>> password = "foo"
>>> if (len(password) < 6): # Not fully Pythonic
... "Password is too short."
... print("Password is too short.")
...
'Password is too short.'
Password is too short.

View File

@ -1,5 +1,5 @@
>>> password = "foo"
>>> if len(password) < 6: # Pythonic
... "Password is too short."
... print("Password is too short.")
...
'Password is too short.'
Password is too short.

View File

@ -1,7 +1,7 @@
>>> password = "foobar"
>>> if len(password) < 6:
... "Password is too short."
... print("Password is too short.")
... else:
... "Password is long enough."
... print("Password is long enough.")
...
'Password is long enough.'
Password is long enough.

View File

@ -2,5 +2,5 @@
['ant', 'bat', 'cat']
>>> "ant, bat, cat".split(", ")
['ant', 'bat', 'cat']
>>> "antheybatheycathey".split("hey")
['ant', 'bat', 'cat', '']
>>> "antheybatheycat".split("hey")
['ant', 'bat', 'cat']

7
Listing_3.10.py Normal file
View File

@ -0,0 +1,7 @@
>>> for i, e in enumerate(a): # Pythonic
... print(f"a[{i}] = {e}")
...
a[0] = ant
a[1] = bat
a[2] = cat
a[3] = 42

11
Listing_3.11.py Normal file
View File

@ -0,0 +1,11 @@
>>> for i, e in enumerate(a):
... if e == "cat":
... print(f"Found the cat at index {i}!")
... break
... else:
... print(f"a[{i}] = {e}")
...
a[0] = ant
a[1] = bat
Found the cat at index 2!
>>>

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