Python Advanced (2023-10-24 - 2023-10-26)¶
Day 1¶
Python Basics Recap¶
All optional. But we should not miss the central points like Python’s referencing scheme, im/mutability, memory management, typing. And iteration of course 😎. Everything’s an object, alas.
The Very Basics¶
Exercise time …
range()
, And Iteration In General¶
Modules¶
Group Project Kickoff¶
Draw “Data Logger” sketch
Sensor classes intro
Main loop ⟶ application, simply printing to stdout
Object Oriented Programming¶
From Object Oriented Programming …
Day 2¶
Leftovers From Yesterday¶
float.__int__()
(viaPerson.__str__()
)Where does the
exit()
function come from? It is not documented in the builtin functions documentation, nonetheless it is present as a global function.Built-in Constants: at the bottom, there is a note about the site — Site-specific configuration hook module doing that
site — Site-specific configuration hook does not mention that
⟶ a-ha
frozendict
? There is no such thing, but there’s a frozensetasync
/await
? ⟶ Pointless Blinking
Miscellaneous¶
Object Oriented Programming, Continued¶
From Object Oriented Programming …
Group Project, OO-ified¶
FileSensor
CSVSink
AcquisitionLoop
Bring them live …
Integration into
datalogger.py
Make
datalogger.py
a real program (⟶ Permissions: Mode, User and Group Ownership)Problems
Test data (the test temperature file for
FileSensor
) ⟶ pytest Introduction, By ExampleTesting
AcquisitionLoop
Number of iterations
Timestamps?
Test Driven Development¶
Look into tests
AcquisitionLoop
?Externalize timestamps ⟶ iterables and generators
itertools — Functions creating iterators for efficient looping
Object Oriented Programming, Continued¶
-
Apply inheritance
Create
Sensor
base class (test first)assert
being-aSensor
before entering main loop
Abstract Base Classes (abc), And Duck Typing
Require
Sensor
to be-aabc.ABC
(test first)
Put all sensor implementations under an abstract base class,
sensor.Sensor
.
Decorator Toolcase: *args
, **kwargs
¶
Day 3¶
Morning Greeting¶
How does
pytest
know which fixtures are requested? ⟶ inspect — Inspect live objectsSergey’s OPC-UA sensor
Revisit
test_acquisition_loop.test_mock_csv_sink
. Replaceclass MyMockedThing
with a function that usesnonlocal
⟶ Functions: Global and Local Scope (Livehacking Screenplay) (enter Closures)
Further plan (see below)
Decorator Toolcase, Continued (Including Function Scoping and global
)¶
Multithreading¶
Hack small Load-Modify-Store race (Thread Creation, Race Condition and Synchronization in C++
Same in Python ⟶ nothing
⟶ The GIL (Global Interpreter Lock), and its way out of the Python interpreter
Exercises¶
Sensor Implementation That Receives UDP Datagrams¶
Datagrams contain temperature in millcelsius (just like
FileSensor
)Look into
acquisition_loop_utils.py
for how to receive datagrams on a portAcquisition rate does ont necessarily match datagram rate. It might well be that
Datagrams are received much faster (10ms, for example) than the acquisition loop acquires measurements (1s interval, for example). Samples gather up inside the sensor (roughly 100 samples per measurement with the above rates).
In this case (multiple samples available at the time
sensor.get_temperature()
is called) a call tosensor.get_temperature()
mustcompute the average across available samples
remove the gathered samples to make room for new incoming data
Datagrams are received at a slower rate than the loop acquires. In this case there is nothing available to return from
sensor.get_temperature()
. To overcome that,If a measurement from a previous measurement is available, return that
If no measurement has yet been made, raise an exception
To not drop any packets while the main acquisition loop is busy doing other things (block on file IO, for example, or wait for another sensor to complete its measurement), the sensor implementation must spawn a thread, internally, that does the network communication.
In fact, the whole point of the exercise is to correctly communicate the data to the main (acquisition) thread.
Is it possible to TDD that? Try hard.
CompositeSink
¶
AcquisitionLoop
knows about only oneSink
. That is the plan!Create one
Sink
implementation,CompositeSink
, that dispatcheswrite_measurement()
onto multiple sinks that it ownsWrite a test for that, together.
MQTT Sink Implementation¶
Publish measurement dictionary to an MQTT broker
Define format of transmitted data
TDD?!
Timestamps?¶
Bring timestamps (datatime.datatime
) into the game …
Formally define measurement dictionary (test)
Wrap
sensors
dictionary that is used indatalogger.py
into a class, say,Sensors
.Write a method
Sensors.read_measurements() -> Measurements
class Measurements
is an encapsulation of the raw dictionary that is composed inAcquisitionLoop
, and consumed across allSink
implementations.