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#
FileSensorCSVSinkAcquisitionLoop
Bring them live …
Integration into
datalogger.pyMake
datalogger.pya real program (⟶ Permissions: Mode, User and Group Ownership)Problems
Test data (the test temperature file for
FileSensor) ⟶ pytest Introduction, By ExampleTesting
AcquisitionLoopNumber 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
Sensorbase class (test first)assertbeing-aSensorbefore entering main loop
Abstract Base Classes (abc), And Duck Typing
Require
Sensorto 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
pytestknow which fixtures are requested? ⟶ inspect — Inspect live objectsSergey’s OPC-UA sensor
Revisit
test_acquisition_loop.test_mock_csv_sink. Replaceclass MyMockedThingwith 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.pyfor 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#
AcquisitionLoopknows about only oneSink. That is the plan!Create one
Sinkimplementation,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
sensorsdictionary that is used indatalogger.pyinto a class, say,Sensors.Write a method
Sensors.read_measurements() -> Measurementsclass Measurementsis an encapsulation of the raw dictionary that is composed inAcquisitionLoop, and consumed across allSinkimplementations.