Skip to content

Commit

Permalink
Adds in-browser notebook demo
Browse files Browse the repository at this point in the history
  • Loading branch information
jadudm committed Jun 20, 2024
1 parent dc209ea commit d7081ee
Show file tree
Hide file tree
Showing 21 changed files with 1,384 additions and 0 deletions.
2 changes: 2 additions & 0 deletions notebook-example/three/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.venv
dist/
51 changes: 51 additions & 0 deletions notebook-example/three/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash

set -e

DIST=dist
FILES=notebooks

# https://stackoverflow.com/a/76208774

# I don't want to have anything lingering.
# Environments affect the build. Use the
# one that we build here... for the build.
# conda deactivate >/dev/null 2>&1
# deactivate >/dev/null 2>&1

echo "Removing venv"
rm -rf .venv
sleep 2
echo "Creating clean venv"
python3 -m venv .venv
source .venv/bin/activate

if [[ "$VIRTUAL_ENV" != "" ]]
then
INVENV=1
echo "In environment $VIRTUAL_ENV"
sleep 2
else
INVENV=0
fi

pip install --upgrade pip
pip install --no-cache-dir -r requirements.txt

echo "Cleaning up for install"
rm -f *.db
rm -rf $DIST
rm -rf $FILES/__pycache__

sleep 1

echo "Launching build"
sleep 1
jupyter lite init
jupyter lite build

if [[ $RUN = 1 ]]; then
pushd $DIST
python -m http.server 8080
popd
fi
6 changes: 6 additions & 0 deletions notebook-example/three/jupyter_lite_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"LiteBuildConfig": {
"contents": ["notebooks"],
"output_dir": "dist"
}
}
1 change: 1 addition & 0 deletions notebook-example/three/notebooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bye.
12 changes: 12 additions & 0 deletions notebook-example/three/notebooks/api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
##############################################
# To obtain a key for use with the FAC.
#
# 1. Visit https://api.data.gov/signup/
# 2. Enter your name and email address.
# 3. You will receive a key in the email.
# 4. Copy that key.
# 5. Paste your key in-between the quotes below,
# being careful not to add spaces before or after
# the key.

FAC_API_KEY = ""
19 changes: 19 additions & 0 deletions notebook-example/three/notebooks/fac.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os
import pyodide_http
import requests
pyodide_http.patch_all()

from api_key import FAC_API_KEY

##############################################
# This patches the FAC_API_KEY variable
# so that we can test the workbook locally.
# It will have no effect in the WWW environment.
if os.getenv("FAC_API_KEY") not in [None, ""]:
FAC_API_KEY = os.getenv("FAC_API_KEY")

def get(endpoint,
params={"limit": 1}
):
return requests.get(f"https://api.fac.gov/{endpoint}",
params = params)
23 changes: 23 additions & 0 deletions notebook-example/three/notebooks/files/treasury.alns
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
21.003
21.004
21.006
21.008
21.009
21.010
21.011
21.012
21.014
21.015
21.016
21.017
21.018
21.019
21.020
21.021
21.023
21.024
21.027
21.028
21.029
21.031
21.032
43 changes: 43 additions & 0 deletions notebook-example/three/notebooks/findings_by_aln.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install pyodide-http requests peewee openpyxl pandas sqlite3\n",
"from libraries import findings_by_aln as fba\n",
"from fac import FAC_API_KEY"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Findings per ALN\n",
"\n",
"There was a 5-day period where search was not available. During that time, we published Excel workbooks that provided Federal users a set of spreadsheets that tracked findings on a per-ALN basis."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Set the API key for the library\n",
"fba.set_api_key(FAC_API_KEY)\n",
"# Changing the date generates a different workbook in the `xlsx` directory\n",
"fba.findings_by_aln(\"2024-06-17\")"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Empty file.
133 changes: 133 additions & 0 deletions notebook-example/three/notebooks/libraries/aln.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import re
import logging

class ALN:
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("accuracy_alns")

def __init__(self, agency, program=None):
self.agency = agency
self.program = program

def __repr__(self):
if self.program:
return f"{self.agency}.{self.program}"
else:
return f"{self.agency}"

def __str__(self):
return self.__repr__()

def __eq__(self, other):
return (self.agency == other.agency
and self.program == other.program)

def __hash__(self):
return hash(str(self))

def streq(self, string_aln):
parts = string_aln.split(".")
return (self.agency == parts[0]
and self.program == parts[1])

def is_valid(self):
return (
self.is_all_numeric()
or self.is_u_program()
or self.is_rd_program()
or self.is_gsa_migration()
or self.is_alpha_program()
)
def category(self):
if self.is_all_numeric():
return "NUMERIC"
elif self.is_u_program():
return "U"
elif self.is_rd_program():
return "RD"
elif self.is_alpha_program():
return "ALPHA"
elif self.is_gsa_migration():
return "GSA"
else:
ALN.logger(f"UNK ALN: {self.agency} {self.program}")
return "UNK"

def is_numeric_agency(self):
try:
int(self.agency)
return True
except:
return False

def is_numeric_program(self):
try:
int(self.program)
return True
except:
return False

def is_all_numeric(self):
return self.is_numeric_agency() and self.is_numeric_program()

def is_u_program(self):
return self.is_numeric_agency() and bool(re.match(r"^U[0-9]{2}$", self.program))

def is_rd_program(self):
return self.is_numeric_agency() and bool(re.match(r"^RD([0-9]{1})?$", self.program))

def is_gsa_migration(self):
return self.is_numeric_agency() and bool(re.match(r"^GSA_MIGRATION$", self.program))

def is_alpha_program(self):
return (
self.is_numeric_agency()
and bool(re.match("^[0-9]{2}$", self.agency))
and bool(re.match("^[0-9]{3}([A-Z])?$", self.program)))

######################################
# TESTS
######################################

def test_is_numeric_agency():
assert ALN("10", "ABC").is_numeric_agency() is True
assert ALN("AB", "ABC").is_numeric_agency() is False

numeric_programs_valid = [
ALN("10", "123"),
ALN("10", "000")
]
numeric_programs_invalid = [
ALN("10", "ABC"),
ALN("AB", "ABC")
]
def test_is_numeric_program():
for aln in numeric_programs_valid:
assert aln.is_numeric_program() is True
for aln in numeric_programs_invalid:
assert aln.is_numeric_program() is False

rd_alns_valid = [
ALN("93", "RD"),
ALN("93", "RD1")
]
def test_is_rd_program():
for aln in rd_alns_valid:
assert aln.is_rd_program() is True

def test_validity():
for aln in rd_alns_valid:
assert aln.is_valid() is True
for aln in numeric_programs_valid:
assert aln.is_valid() is True
for aln in numeric_programs_invalid:
assert aln.is_valid() is False
assert ALN("11", "123").is_valid() is True
assert ALN("92", "RD1").is_valid() is True
assert ALN("92", "RD").is_valid() is True
assert ALN("92", "RDX").is_valid() is False
assert ALN("84", "483A").is_valid() is True
assert ALN("84", "483AB").is_valid() is False
assert ALN("84", "48A").is_valid() is False
assert ALN("21", "U23").is_valid() is True
assert ALN("45", "GSA_MIGRATION").is_valid() is True
Loading

0 comments on commit d7081ee

Please sign in to comment.