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
+1
View File
@@ -1,5 +1,6 @@
from flask import Flask
app = Flask(__name__)
@app.route("/")
+7
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
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()
+13 -8
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>
+11 -3
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
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
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
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
View File
@@ -0,0 +1 @@
$ pip install -e .
+12
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()
-6
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
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
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 -16
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>
+16 -2
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
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
View File
@@ -0,0 +1,7 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Detector</h1>
<p>This will be the palindrome detector.</p>
{% endblock %}
+3 -3
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
+2 -11
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 ===============================
+2
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)
+21 -34
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
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
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()
+3 -24
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
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
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
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
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
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>
+9 -23
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>
+9 -2
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
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
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
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
View File
@@ -0,0 +1,9 @@
import os
from flask import Flask, render_template, request
from palindrome_mhartl.phrase import Phrase
.
.
.
+7
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
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
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
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
View File
@@ -0,0 +1,5 @@
{% if Phrase(phrase).ispalindrome() %}
"{{ phrase }}" is a palindrome!
{% else %}
"{{ phrase }}" isn't a palindrome.
{% endif %}
+15
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 %}
+43 -13
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
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">'
+1 -2
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
+2 -10
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
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">'
+10 -2
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 ==========================
+21 -5
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
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 -7
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>
+7 -1
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
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
View File
@@ -0,0 +1,7 @@
{% extends "layout.html" %}
{% block content %}
<h1>Palindrome Detector</h1>
{% include "palindrome_form.html" %}
{% endblock %}
+48
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
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
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
View File
@@ -0,0 +1,2 @@
(venv) $ pip install --upgrade palindrome_YOUR_USERNAME_HERE \
> --index-url https://test.pypi.org/simple/
+1 -1
View File
@@ -1 +1 @@
(venv) $ flyctl launch
(venv) $ flyctl auth login --interactive
+1
View File
@@ -0,0 +1 @@
(venv) $ flyctl launch
+1
View File
@@ -0,0 +1 @@
web: gunicorn palindrome_detector:app
+19 -7
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
+7 -9
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
+9 -3
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]
+3 -7
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
+7 -8
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
+8 -3
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
+3 -15
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()
+2 -2
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)
+15 -4
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()]
+2 -1
View File
@@ -1 +1,2 @@
>>> from sklearn.linear_model import LinearRegression
titanic[(titanic["Sex"] == "female") &
(titanic["Pclass"] == 3)]["Survived"].mean()
+4 -4
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
+4 -5
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()]
+1 -7
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
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
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
+1
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])
+3 -1
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)
+4 -4
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!
+3 -3
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.
+5 -5
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!
+3 -3
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.
+3 -3
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
+3 -3
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.
+5 -5
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.
+3 -9
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'
+9 -2
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
+2 -8
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'
+8 -8
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
View File
@@ -0,0 +1,8 @@
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
+8
View File
@@ -0,0 +1,8 @@
> for (i = 0; i < 5; i++) {
console.log(i);
}
0
1
2
3
4
+2 -2
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
+12 -9
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
:
+2 -2
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
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 ' '
.
.
.
+2 -2
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.
+2 -2
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.
+3 -3
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.
+2 -2
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
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
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