Skip to content

Instantly share code, notes, and snippets.

@derekmahar
Last active October 8, 2025 20:49
Show Gist options
  • Save derekmahar/45fab72a44e6150609d1131e9e8bd55c to your computer and use it in GitHub Desktop.
Save derekmahar/45fab72a44e6150609d1131e9e8bd55c to your computer and use it in GitHub Desktop.
Python and shell scripts to retrieve exercise sources file from Python Morsels (pym.dev).
#!/usr/bin/env python3
import argparse
import requests
import json
from urllib.parse import urlparse, urlunparse
from pathlib import Path
def filename_from_url(url: str) -> str:
path = urlparse(url).path
name = Path(path).name
return name or "downloaded.file"
def login_url_from_file_url(file_url: str) -> str:
parsed = urlparse(file_url)
scheme = parsed.scheme or "https"
domain = parsed.netloc
return urlunparse((scheme, domain, "", "", "", ""))
def main():
parser = argparse.ArgumentParser(
description="Submit form (fields 'form-name' and 'password'), save cookie, then download a file using that cookie."
)
parser.add_argument("file_url", help="URL of the file to download (protected resource)")
parser.add_argument("--password", required=True, help="Password value for the form (named parameter)")
args = parser.parse_args()
file_url = args.file_url
login_url = login_url_from_file_url(file_url) # derived from file URL domain
cookie_file = Path("cookies.json") # fixed default
output_path = Path(filename_from_url(file_url)) # renamed variable
# Submit the login form and collect cookies
session = requests.Session()
form_data = {
"form-name": "form 1",
"password": args.password
}
login_response = session.post(login_url, data=form_data)
login_response.raise_for_status()
get_file_response = session.get(file_url, stream=True)
get_file_response.raise_for_status()
# Save the file using name derived from file URL
with output_path.open("wb") as output_file:
for chunk in get_file_response.iter_content(chunk_size=8192):
if chunk:
output_file.write(chunk)
if __name__ == "__main__":
main()
#!/usr/bin/env sh
# Set invalid password to intentionally hide the real one.
# Contact Trey Hunner ([email protected]) to get the real
# password or take his Modern Python Testing course on O'Reilly
# Learning (see https://tinyurl.com/2u5r5w8n)!
password=fake_password
# Retrieve exercise source file howdy.py.
uv run --with requests \
python get_exercise_source_file.py \
--password $password \
https://modern-testing.pym.dev/_downloads/c16bccf706c04a8a443ccc5c1eb3b3e7/howdy.py
# Retrieve exercise source file dollars.py.
uv run --with requests \
python get_exercise_source_file.py \
--password $password \
https://modern-testing.pym.dev/_downloads/6c71c5a6c266cbe29d7755889443b8c2/dollars.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment