A small project is a tree, not one 400-line file. Typical pieces: README, config, a package, tests.
Goal
Write that tree under /uploads and import the package.
Build the tree
from pathlib import Path
root = Path("kioskpkg")
root.mkdir(exist_ok=True)
(root / "__init__.py").write_text(
"from kioskpkg.prices import line_total\n",
encoding="utf-8",
)
(root / "prices.py").write_text(
'''def line_total(units, price, tax=0.16):
return round(units * price * (1 + tax), 2)
''',
encoding="utf-8",
)
Path("config.json").write_text(
'{"city": "Nairobi", "tax": 0.16}\n',
encoding="utf-8",
)
Path("README.md").write_text("# Nairobi kiosk\n\nPricing helpers.\n", encoding="utf-8")
Path("test_prices.py").write_text(
'''import unittest
from kioskpkg.prices import line_total
class PriceTests(unittest.TestCase):
def test_two(self):
self.assertEqual(line_total(2, 10), 23.2)
''',
encoding="utf-8",
)
print(sorted(p.name for p in Path(".").iterdir() if p.name != ".browser_decode"))
print(sorted(p.name for p in root.iterdir()))Import from the layout
from pathlib import Path
import json
import unittest
root = Path("kioskpkg")
root.mkdir(exist_ok=True)
(root / "__init__.py").write_text("", encoding="utf-8")
(root / "prices.py").write_text(
'''def line_total(units, price, tax=0.16):
return round(units * price * (1 + tax), 2)
''',
encoding="utf-8",
)
Path("config.json").write_text('{"city": "Nairobi", "tax": 0.16}\n', encoding="utf-8")
from kioskpkg.prices import line_total
cfg = json.loads(Path("config.json").read_text(encoding="utf-8"))
print(cfg["city"], line_total(2, 10, cfg["tax"]))
class PriceTests(unittest.TestCase):
def test_two(self):
self.assertEqual(line_total(2, 10), 23.2)
suite = unittest.defaultTestLoader.loadTestsFromTestCase(PriceTests)
result = unittest.TextTestRunner(verbosity=2).run(suite)
print("ok" if result.wasSuccessful() else "failed")On a laptop the tests would live in tests/ and you would run python -m unittest. Here they run in the same buffer.
Tip
README first. Config next. Package for code. Tests beside or under tests/. Do not dump everything in main.py.