Rubber duck debugging in a hotel room in Darmstadt @ ESA 2019 Space debris conference
Today we will cover
So what is a "bug"
And thus and the term "bug in the computer" caught on
So what is a "bug"
Today it means "unwanted behaviour"
The most common methods
Make a routine out of it!
We are practicing this now with the homework
github analysis-tools-dev has a long list!
We are already doing this (right?!) after our tooling lecture!
Practical examples
Unit testing
class TestAnomalies(unittest.TestCase):
def test_eccentric_true_inverse(self):
nu0 = 1.2345
e = 0.5
nu = kep.eccentric_to_true(kep.true_to_eccentric(nu0, e), e)
self.assertAlmostEqual(nu0, nu)
Integration testing
class TestKeplerSolver(unittest.TestCase):
@pytest.mark.slow
def test_laguerre_solve_kepler(self):
E = np.linspace(0.0, 2.0*np.pi, num=300, dtype=np.float64)
e = np.linspace(0, 0.99, num=500, dtype=np.float64)
for eit in e:
for Eit in E:
M = kep.eccentric_to_mean(Eit, eit)
E0 = kep.kepler_guess(M, eit)
E_calc, it = kep.laguerre_solve_kepler(E0, M, eit, tol=1e-12)
fun_err = np.abs(M - E_calc + eit*np.sin(E_calc))
nt.assert_almost_equal(Eit, E_calc, decimal = 1e-9)
assert fun_err < 1e-11
End-to-end testing
Compatibility testing
test_python_3_10:
image: python:3.10
before_script:
- pip install virtualenv
- virtualenv venv
- source venv/bin/activate
- pip install .
script:
- pip install pytest
- pytest
rules:
- if: $CI_COMMIT_BRANCH == "main"
Compatibility testing
Performance testing
Next lecture!
Stress testing
class TestServer(unittest.TestCase):
...
def test_connect_client(self):
clients = []
for ind in range(10_000):
clients.append(
self.launch_client_request_thread()
)
for client in clients:
self.close_and_validate(client)
Security testing
danielk@IRF081-danielk ~/g/pyorb (main)> grype dir:.
✔ Vulnerability DB [updated]
✔ Indexed file system .
✔ Cataloged contents cdb4ee2aea69cc6a83331bbe96dc2caa9a299d21329efb0336fc02a82e1839a8
├── ✔ Packages [1 packages]
├── ✔ Executables [0 executables]
├── ✔ File metadata [2 locations]
└── ✔ File digests [2 files]
✔ Scanned for vulnerabilities [0 vulnerability matches]
├── by severity: 0 critical, 0 high, 0 medium, 0 low, 0 negligible
└── by status: 0 fixed, 0 not-fixed, 0 ignored
No vulnerabilities found
For example grype (podcast in handouts)
We are already doing this (right?!) after our testing homework and tooling lecture!
The most common methods
The most common methods
Next lecture!
This is the default - no need to cover here
A quick second look (we covered syntax before)
def stack(logger, file: Path, output_folder=Path | None, duration=1.0, clobber=False):
...
if frame_cnt == 0:
raise EmptyVideoFile("Empty video file, cannot produce stack")
...
def worker(file, output_folder, duration, clobber):
logger = logging.getLogger("allsky7station.processing.stack")
logger.info(f"Processing {file.name}")
try:
stack(logger, file, output_folder=output_folder, duration=duration, clobber=clobber)
except EmptyVideoFile:
logger.warning(f"Empty video-file {file}, not writing output stack")
except FileExistsError:
logger.warning(f"{file} exists, not making stack")
python -O my_code.py
python cmdline -O: remove asserts and __debug__ code
mypy understands "type narrowing"
def function(arg: Any):
assert isinstance(arg, int)
reveal_type(arg) # Revealed type: "builtins.int"
Assertion heavy coding! (video in handouts)
# val should never be nan here
vs
assert not np.isnan(val), "this should never happen?!"
# automatically enter post-mortem if abnormal exit
python -m pdb -c continue my_code.py
It will enter debugger with current state at point of error
pdb.post_mortem
The most common methods
import tracemalloc
tracemalloc.start()
# ... code
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
print("[ Top 10 ]")
for stat in top_stats[:10]:
print(stat)
Practical example! Go to handout