Planet Python
Last update: October 22, 2024 04:43 PM UTC
October 22, 2024
Real Python
Understanding Python's Global Interpreter Lock (GIL)
The Python Global Interpreter Lock or GIL, in simple words, is a mutex (or a lock) that allows only one thread to hold the control of the Python interpreter.
This means that only one thread can be in a state of execution at any point in time. The impact of the GIL isn’t visible to developers who execute single-threaded programs, but it can be a performance bottleneck in CPU-bound and multi-threaded code.
Since the GIL allows only one thread to execute at a time even in a multi-threaded architecture with more than one CPU core, the GIL has gained a reputation as an “infamous” feature of Python.
In this video course you’ll learn how the GIL affects the performance of your Python programs, and how you can mitigate the impact it might have on your code.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Python Anywhere
Improving PythonAnywhere's File Storage System
PythonAnywhere has been around for over 10 years, and as our platform continues to grow with thousands of users, we’re committed to keeping it in top shape. Part of this involves upgrading some of the older parts of our infrastructure, with a special focus on our file storage serversâsome of the oldest systems we have.
Julien Tayon
Tune your guitar with python
Today's exercice is just about turning a very nice example of the python soundevice module into something that works for me© to help me tune my bass.
Long story short, I suck at tuning my instrument and just lost my tuner...
This will require the python module soundevice and matplotlib.
So in order to tune my guitar I indeed need a spectrosonogram that displays the frequencies captured in real time by an audio device with an output readable enough I can actually know if I am nearing a legit frequency called a Note.
I chose the frequency between 100 and 2000 knowing that anyway any frequency below will trigger harmonics and above will trigger reasonance in the right frequency frame.
Plotting a spectrogram is done by tweaking the eponym matplotlib grapher with values chosen to fit my need and show me a laser thin beam around the right frequency.
#!/usr/bin/env python3 """Show a text-mode spectrogram using live microphone data.""" import argparse import math import shutil import matplotlib.pyplot as plt from multiprocessing import Process, Queue import matplotlib.animation as animation import numpy as np import sounddevice as sd usage_line = ' press enter to quit,' def int_or_str(text): """Helper function for argument parsing.""" try: return int(text) except ValueError: return text try: columns, _ = shutil.get_terminal_size() except AttributeError: columns = 80 parser = argparse.ArgumentParser(add_help=False) parser.add_argument( '-l', '--list-devices', action='store_true', help='show list of audio devices and exit') args, remaining = parser.parse_known_args() if args.list_devices: print(sd.query_devices()) parser.exit(0) parser = argparse.ArgumentParser( description=__doc__ + '\n\nSupported keys:' + usage_line, formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parser]) parser.add_argument( '-b', '--block-duration', type=float, metavar='DURATION', default=50, help='block size (default %(default)s milliseconds)') parser.add_argument( '-d', '--device', type=int_or_str, help='input device (numeric ID or substring)') parser.add_argument( '-g', '--gain', type=float, default=10, help='initial gain factor (default %(default)s)') parser.add_argument( '-r', '--range', type=float, nargs=2, metavar=('LOW', 'HIGH'), default=[50, 4000], help='frequency range (default %(default)s Hz)') args = parser.parse_args(remaining) low, high = args.range if high <= low: parser.error('HIGH must be greater than LOW') q = Queue() try: samplerate = sd.query_devices(args.device, 'input')['default_samplerate'] def plot(q): global samplerate fig, ( ax,axs) = plt.subplots(nrows=2) plt.ioff() def animate(i,q): data = q.get() ax.clear() axs.clear() axs.plot(data) ax.set_yticks([ 41.20, 82.41, 164.8, 329.6, 659.3, # E 55.00, 110.0, 220.0, 440.0, 880.0, # A 73.42, 146.8, 293.7, 587.3, # D 49.00, 98.00, 196.0, 392.0, 784.0, #G 61.74, 123.5, 246.9, 493.9, 987.8 ])#B ax.specgram(data[:,-1],mode="magnitude", Fs=samplerate*2, scale="linear",NFFT=9002) ax.set_ylim(150,1000) ani = animation.FuncAnimation(fig, animate,fargs=(q,), interval=500) plt.show() plotrt = Process(target=plot, args=(q,)) plotrt.start() def callback(indata, frames, time, status): if any(indata): q.put(indata) else: print('no input') with sd.InputStream(device=args.device, channels=1, callback=callback, blocksize=int(samplerate * args.block_duration /50 ), samplerate=samplerate) as sound: while True: response = input() if response in ('', 'q', 'Q'): break for ch in response: if ch == '+': args.gain *= 2 elif ch == '-': args.gain /= 2 else: print('\x1b[31;40m', usage_line.center(args.columns, '#'), '\x1b[0m', sep='') break except KeyboardInterrupt: parser.exit('Interrupted by user') except Exception as e: parser.exit(type(e).__name__ + ': ' + str(e))
October 21, 2024
Real Python
Python's property(): Add Managed Attributes to Your Classes
With Pythonâs property()
, you can create managed attributes in your classes. You can use managed attributes when you need to modify an attributeâs internal implementation and donât want to change the classâs public API. Providing stable APIs will prevent you from breaking your usersâ code when they rely on your code.
Properties are arguably the most popular way to create managed attributes quickly and in the purest Pythonic style.
In this tutorial, youâll learn how to:
- Create managed attributes or properties in your classes
- Perform lazy attribute evaluation and provide computed attributes
- Make your classes Pythonic using properties instead of setter and getter methods
- Create read-only and read-write properties
- Create consistent and backward-compatible APIs for your classes
Youâll also write practical examples that use property()
for validating input data, computing attribute values dynamically, logging your code, and more. To get the most out of this tutorial, you should know the basics of object-oriented programming, classes, and decorators in Python.
Get Your Code: Click here to download the free sample code that shows you how to use Pythonâs property() to add managed attributes to your classes.
Take the Quiz: Test your knowledge with our interactive âPython's property(): Add Managed Attributes to Your Classesâ quiz. Youâll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Python's property(): Add Managed Attributes to Your ClassesIn this quiz, you'll test your understanding of Python's property(). With this knowledge, you'll be able to create managed attributes in your classes, perform lazy attribute evaluation, provide computed attributes, and more.
Managing Attributes in Your Classes
When you define a class in an object-oriented programming language, youâll probably end up with some instance and class attributes. In other words, youâll end up with variables that are accessible through the instance, class, or even both, depending on the language. Attributes represent and hold the internal state of a given object, which youâll often need to access and mutate.
Typically, you have at least two ways to access and mutate an attribute. Either you can access and mutate the attribute directly or you can use methods. Methods are functions attached to a given class. They provide the behaviors and actions that an object can perform with its internal data and attributes.
If you expose attributes to the user, then they become part of the classâs public API. This means that your users will access and mutate them directly in their code. The problem comes when you need to change the internal implementation of a given attribute.
Say youâre working on a Circle
class and add an attribute called .radius
, making it public. You finish coding the class and ship it to your end users. They start using Circle
in their code to create a lot of awesome projects and applications. Good job!
Now suppose that you have an important user that comes to you with a new requirement. They donât want Circle
to store the radius any longer. Instead, they want a public .diameter
attribute.
At this point, removing .radius
to start using .diameter
could break the code of some of your other users. You need to manage this situation in a way other than removing .radius
.
Programming languages such as Java and C++ encourage you to never expose your attributes to avoid this kind of problem. Instead, you should provide getter and setter methods, also known as accessors and mutators, respectively. These methods offer a way to change the internal implementation of your attributes without changing your public API.
Note: Getter and setter methods are often considered an anti-pattern and a signal of poor object-oriented design. The main argument behind this proposition is that these methods break encapsulation. They allow you to access and mutate the components of your objects from the outside.
These programming languages need getter and setter methods because they donât have a suitable way to change an attributeâs internal implementation when a given requirement changes. Changing the internal implementation would require an API modification, which can break your end usersâ code.
The Getter and Setter Approach in Python
Technically, thereâs nothing that stops you from using getter and setter methods in Python. Hereâs a quick example that shows how this approach would look:
point_v1.py
class Point:
def __init__(self, x, y):
self._x = x
self._y = y
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
def get_y(self):
return self._y
def set_y(self, value):
self._y = value
In this example, you create a Point
class with two non-public attributes ._x
and ._y
to hold the Cartesian coordinates of the point at hand.
Note: Python doesnât have the notion of access modifiers, such as private
, protected
, and public
, to restrict access to attributes and methods. In Python, the distinction is between public and non-public class members.
If you want to signal that a given attribute or method is non-public, then you have to use the well-known Python convention of prefixing the name with an underscore (_
). Thatâs the reason behind the naming of the attributes ._x
and ._y
.
Note that this is just a convention. It doesnât stop you and other programmers from accessing the attributes using dot notation, as in obj._attr
. However, itâs bad practice to violate this convention.
To access and mutate the value of either ._x
or ._y
, you can use the corresponding getter and setter methods. Go ahead and save the above definition of Point
in a Python module and import the class into an interactive session. Then run the following code:
>>> from point_v1 import Point
>>> point = Point(12, 5)
>>> point.get_x()
12
>>> point.get_y()
5
>>> point.set_x(42)
>>> point.get_x()
42
>>> # Non-public attributes are still accessible
>>> point._x
42
>>> point._y
5
With .get_x()
and .get_y()
, you can access the current values of ._x
and ._y
. You can use the setter method to store a new value in the corresponding managed attribute. From the two final examples, you can confirm that Python doesnât restrict access to non-public attributes. Whether or not you access them directly is up to you.
Read the full article at https://realpython.com/python-property/ »
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Python Bytes
#406 What's on Django TV tonight?
<strong>Topics covered in this episode:</strong><br> <ul> <li><a href="https://opensourcepledge.com?featured_on=pythonbytes"><strong>Open Source Pledge</strong></a></li> <li><strong>Jeff Triplet's <a href="https://djangotv.com?featured_on=pythonbytes">DjangoTV</a></strong></li> <li><strong><a href="https://peps.python.org/pep-0735/?featured_on=pythonbytes">PEP 735 â Dependency Groups in pyproject.toml</a></strong></li> <li><strong><a href="https://livereload.readthedocs.io/en/latest/index.html?featured_on=pythonbytes">livereload</a></strong></li> <li><strong>Extras</strong></li> <li><strong>Joke</strong></li> </ul><a href='https://www.youtube.com/watch?v=XzXG6cRP2Mk' style='font-weight: bold;'data-umami-event="Livestream-Past" data-umami-event-episode="406">Watch on YouTube</a><br> <p><strong>About the show</strong></p> <p>Sponsored by ScoutAPM: <a href="https://pythonbytes.fm/scout"><strong>pythonbytes.fm/scout</strong></a></p> <p><strong>Connect with the hosts</strong></p> <ul> <li>Michael: <a href="https://fosstodon.org/@mkennedy"><strong>@mkennedy@fosstodon.org</strong></a></li> <li>Brian: <a href="https://fosstodon.org/@brianokken"><strong>@brianokken@fosstodon.org</strong></a></li> <li>Show: <a href="https://fosstodon.org/@pythonbytes"><strong>@pythonbytes@fosstodon.org</strong></a></li> </ul> <p>Join us on YouTube at <a href="https://pythonbytes.fm/stream/live"><strong>pythonbytes.fm/live</strong></a> to be part of the audience. Usually <strong>Monday</strong> at 10am PT. Older video versions available there too.</p> <p>Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to <a href="https://pythonbytes.fm/friends-of-the-show">our friends of the show list</a>, we'll never share it. </p> <p><strong>Brian #1:</strong> <a href="https://opensourcepledge.com?featured_on=pythonbytes"><strong>Open Source Pledge</strong></a></p> <ul> <li>Learned about this because of this post <ul> <li><a href="https://www.djangoproject.com/weblog/2024/oct/08/why-django-supports-the-open-source-pledge/?featured_on=pythonbytes">Why Django supports the Open Source Pledge</a></li> </ul></li> <li>Steps <ul> <li>Pay Open Source maintainers. <ul> <li>Min to participate is 2k/year/dev at your company</li> </ul></li> <li>Self-report annually <ul> <li>Publish a blog post outlining your payments</li> </ul></li> </ul></li> <li><a href="https://lucumr.pocoo.org/2024/10/14/mixing-oss-and-money/?featured_on=pythonbytes">Arminâs post</a> about launching Open Source Pledge and mixing money with open source</li> </ul> <p><strong>Michael #2:</strong> Jeff Triplet's <a href="https://djangotv.com?featured_on=pythonbytes">DjangoTV</a></p> <ul> <li>A nice aggregation of lots of Django conference talks</li> <li>Filter by conference</li> <li>Good search as well</li> </ul> <p><strong>Brian #3:</strong> <a href="https://peps.python.org/pep-0735/?featured_on=pythonbytes">PEP 735 â Dependency Groups in pyproject.toml</a></p> <ul> <li>Author: Stephen Rosen, Sponsor: Brett Cannon, PEP-Delegate: Paul Moore</li> <li>Accepted. Resolotion Oct 10, 2024</li> <li>âThis PEP specifies a mechanism for storing package requirements in pyproject.toml files such that they are not included in any built distribution of the project.â</li> <li>Allow us to define named groups of dependencies that can be independent of the main project.</li> <li><p>ex:</p> <pre><code>[dependency-groups] test = ["pytest", "coverage"] docs = ["sphinx", "sphinx-rtd-theme"] typing = ["mypy", "types-requests"] typing-test = [{include-group = "typing"}, {include-group = "test"}, "useful-types"] </code></pre></li> <li><p>âmightâ work like this: pip install --dependency-groups=test,typing</p> <ul> <li>but tool venders are able to define how they use groups. Of course.</li> </ul></li> <li>Similar solutions <ul> <li>multiple requirements.txt files: requirements_test.txt, requirements_docs.txt, etc. <ul> <li>no standard naming convention, not standardized </li> </ul></li> <li>package extras: <ul> <li>not gauranteed to be statically defined (TIL)</li> <li>additional to main dependencies, so not independent</li> </ul></li> </ul></li> </ul> <p><strong>Michael #4:</strong> <a href="https://livereload.readthedocs.io/en/latest/index.html?featured_on=pythonbytes">livereload</a></p> <ul> <li>Example from talkpython.fm: <a href="https://gist.github.com/mikeckennedy/4e1378477a6d174aa8d59921f8db89c3?featured_on=pythonbytes"><strong>asset_bundler_watcher.py</strong></a></li> <li><a href="https://livereload.readthedocs.io/en/latest/index.html?featured_on=pythonbytes">The docs are sparse</a>, so see the gist above</li> </ul> <p><strong>Extras</strong> </p> <p>Brian:</p> <ul> <li><a href="https://kjaymiller.com/blog/personal-blogs-are-no-longer-personal-when-ai-gets-too-involved.html?featured_on=pythonbytes">Personal Blogs are no longer personal when AI gets too involved</a> - KJayMiller</li> <li><a href="https://stefaniemolin.com/articles/devx/pre-commit/exif-stripper/?featured_on=pythonbytes">Mind Your Image Metadata</a> - Stefanie Molin</li> </ul> <p>Michael:</p> <ul> <li>14% of our listeners are in Germany, thanks Germany! <ul> <li>Prost!</li> </ul></li> <li><a href="https://www.hetzner.com/cloud/?featured_on=pythonbytes">Hetzner comes to the US</a></li> </ul> <p><strong>Joke:</strong> </p> <ul> <li>A programmerâs partner asks them: âWould you go get a loaf of bread from the store? And if they have eggs, get a dozen.â </li> <li>A while later, the programmer returns with 12 loaves of bread and says âThey had eggs.â <ul> <li>From https://savvyprogrammer.io/software-jokes/</li> </ul></li> </ul>
Zato Blog
HL7 FHIR Security with Basic Auth, OAuth and SSL/TLS
HL7 FHIR Security with Basic Auth, OAuth and SSL/TLS
HL7 FHIR Security
Preliminary reading: HL7 FHIR Integrations in Python
FHIR servers offer their APIs using REST, which in turn means that they are HTTP servers under the hood. As a result, a few common security mechanisms can be employed to secure access to the servers when you invoke them.
- Basic Auth
- OAuth
- SSL/TLS encryption
When you integrate with a FHIR server, consult with its maintainers what of these, if any, should be used.
Note that Basic Auth and OAuth, when used over HTTP, are mutually exclusive. The HTTP protocol reserves only one header, called Authorization, for the authorization credentials and there is no standard way in the protocol to use more than one authorization mechanism.
On the other hand, the SSL/TLS encryption is independent of the credentials used and can be employed with Basic Auth, OAuth, or in scenarios when no authorization header is sent at all.
This is why, when you create or update a FHIR connection, you can set Basic Auth or OAuth and SSL/TLS options independently, as in the screenshot below:
Basic Auth
Basic Auth is a combination of username and password credentials. They are allocated in advance by the maintainers of a FHIR server.
To use them in your integrations, create a new Basic Auth definition in the Dashboard, set its password, and assign it to an existing or new outgoing FHIR connection. No restarts nor reloads are required.
OAuth
Authentication with OAuth is built around a notion of short-lived tokens, which are simple strings. Your Zato server has credentials, much like a username and password although they are called a client ID and secret, based on which an authentication server issues tokens that let Zato prove that in fact it does have the correct credentials and that it is allowed to invoke a particular API as it is defined through scopes.
Scopes can be likened to permissions to access a subset of resources from a FHIR server. When Zato receives a token from an authentication server the token is inherently linked to specific scopes within which it can interact with the FHIR server.
That tokens are short-lived means that they need to be refreshed periodically, e.g. at least once per hour Zato needs to ask the authentication server for a new token based on its credentials. This process takes place under the hood and requires no configuration on your part.
To use OAuth in your integrations, create a new OAuth definition in the Dashboard, set its secret, and assign it to an existing or new outgoing FHIR connection. No restarts nor reloads are required.
SSL/TLS encryption
If the FHIR server that a connection points to uses SSL/TLS then a question arises of how to validate the certificate of the Certificate Authority (CA) that signed the certificate that the FHIR server uses. There are several options:
- Skip validation - the certificate will not be validated at all and it will be always accepted.
- Default bundle - the certificate will have to belong to one of the publicly recognized CAs. The bundle contains the same certificates that common web browsers do so this option is good if the FHIR server is available in the public Internet, e.g. https://fhir.example.com
- Custom bundle - if the FHIR server's certificate was signed by an internal, non-public CA then the CA's certificate bundle, in the PEM format, can be uploaded through the Dashboard to make it possible to choose it when the FHIR connection is being created or updated.
Next steps:
†Read about how to use Python to build and integrate enterprise APIs that your tests will cover
†Python API integration tutorial
†Python Integration platform as a Service (iPaaS)
†What is an Enterprise Service Bus (ESB)? What is SOA?
Julien Tayon
Hello world part II : actually recoding print
In part I we explored the pre-requisite in order to code print : having a grasp on the framebuffer.
Here, we are gonna deep inside one of the most overlooked object oriented abastraction : a file and actually print what we can of hello world in 100 lines of code.
The file handler and the file descriptor
These two abstractions are the low level and high level abstractions of the same thing : a view on something more complex which access has been encapsulated in generic methods. Actually when you code a framebuffer driver you provide function pointers that are specialized to your device and you may omit those common to the class. This is done with a double lookup on the major node, minor node number. Of those « generic » methods you have : seek, write, tell, truncate, open, read, close ...
The file handler in python also handles extra bytes (pun) of facilities : like character encoding, stats, and buffering.
Here, we work with the low level abstraction : the file which we access with fileno through its file descriptor. And thanks to this abstraction, you don't care if the underlying implementation fragments the file itself (ex: on a hard drive), you can magically always ask without caring for the gory details to read any arbitrary block or chararacters at any given position.
Two of the most used methods on files here are seek and write.
The file descriptor method write is sensitive to the positionning set by seek. Hence, we can write a line, and position ourselves one line below to write the next line in a character.
matrices as a view of a row based array
When I speak of rows and columns I evocate abstractions that are not related to the framebuffer.
The coordinates are an abstraction we build for convenience to say I want to write from this line at this column.
And since human beings bug after 2 dimensions we split the last dimnension in a vector of dimension 4 called a pixel.
get_at function illustrates our use of this trick to position the (invisible) cursor at any given position on the screen expressed for clarity in size of glyphes.
We could actually code all this exercice through a 3D view of the framebuffer. I just wouldn't be able to pack the code in less than 100 lines of code and would introduce useless abstractions.
But if you have doubt on the numerous seek I do and why I mutiply lines and columns value the way I do check the preceding link for an understanding of raw based array nth matricial dimensionnal views.
fonts, chars glyphs...
Here we are gonna take matrices defining the glyphes (what you actually see on screen) by 8x8 = 64 1D array and map them on the screen with put_char. Put char does a little bit of magic by relying on python to do the chararcter to glyph conversion through the dict lookup that expecting strings does a de factor codepoint to glyph conversion without having to pass the codepoint conversion.
The set of characters to glyphs conversion with their common property is a font.
The hidden console
The console is an abstraction that keeps track of the global states such as : what is the current line we print at. Thus, here, being lazy I use the global variables instead of a singleton named « console » or « term » to keep track of them. But first and foremost, these « abstractions » are just expectations we share in a common mental mode. Like we expect « print » to add a newline at the end of the string and begin the printing at the next line.
The to be finished example
I limited the code to 100 lines so that it's fairly readable. I let as an exercise the following points :
- encoding the missing glyphes in the font to actually be able to write "hello world!",
- handling the edge case of reaching the bottom of the screen,
This example is a part of a project to write « hello world » on the framebuffer in numerous languages, bash included.
Annexe : the code
#!/usr/bin/env python3 from struct import pack from os import SEEK_CUR, lseek as seek, write w,h =map(int, open("/sys/class/graphics/fb0/virtual_size").read().split(",")) so_pixel = 4 stride = w * so_pixel encode = lambda b,g,r,a : pack("4B",b,g,r,a) font = { "height":8, "width":8, 'void' : [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, ], "l":[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, ], "o": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0], "h": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0], } def go_at(fh, x, y): global stride seek(fh.fileno(),x*so_pixel + y *stride, 0) def next_line(fh, reminder): seek(fh.fileno(), stride - reminder, SEEK_CUR) def put_char(fh, x,y, letter): go_at(fh, x, y) black = encode(0,0,0,255) white = encode(255,255,255,255) char = font.get(letter, None) or font["void"] line = "" for col,pixel in enumerate(char): write(fh.fileno(), white if pixel else black) if (col%font["width"]==font["width"]-1): next_line(fh, so_pixel * font["width"]) COL=0 LIN=0 OUT = open("/dev/fb0", "bw") FD = OUT.fileno() def newline(): global OUT,LIN,COL LIN+=1 go_at(OUT, 0, LIN * font["height"]) def print_(line): global OUT, COL, LIN COL=0 for c in line: if c == "\n": newline() put_char(OUT,COL * font["width"] , LIN * font['height'], c) COL+=1 newline() for i in range(30): print_("hello lol")
Seth Michael Larson
Python and Sigstore
Python and Sigstore
This critical role would not be possible without funding from the Alpha-Omega project. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!
I was a guest on the Open Source Security podcast this week talking about Sigstore and Python among other things I'm working on at the Python Software Foundation.
Sigstore is a digital signing method that has been used by CPython since 3.11.0 which focuses on ergonomics and uses short-lived keys with strongly-bound human-readable identities via OpenID Connect.
CPython also provides digital signatures using PGP and has been doing so for much longer. Below is a diagram showing the current state of affairs:
...@python.org
Release
Package
(deb, rpm)
Build
Infra
CPython offers two verification methods: PGP and Sigstore. Verifiers choose which method to use.
From this diagram you can see the two "sources" of identity provided by PGP and Sigstore both link back to release managers. PGP relies on private keys which
are maintained and protected by individual release managers to create signatures of artifacts. Sigstore uses third-parties which support OpenID Connect such as GitHub
and Google to bind a human-readable identity like "thomas@python.org
" to a signing certificate and signature that can be later verified.
Why Sigstore?
The problem is that securely maintaining PGP private keys is not an easy task and the burden rests on volunteers for a minimum of 7 years (1 year of pre-releases then 5 years of bug and security fixes across at least two consecutive releases). Contrast that experience to Sigstore where release managers only need to click a button to OAuth sign-in during the release process.
Sigstore externalizes the operational burden of maintaining long-lived signing keys from individual volunteers to teams of people who run an identity platform professionally and the public-good code-signing certificate authority Fulcio. This seems like a pretty good trade-off, considering we already trust these platforms' identity management teams for things like GitHub accounts.
For this reason, I've authored PEP 761 providing a deprecation and discontinuance plan of PGP signatures for CPython artifacts. You can join the discussion of this PEP on discuss.python.org. Big thank-you to Hugo van Kemenade, the release manager for Python 3.14 for sponsoring my first PEP and helping me with the process and thanks to William Woodruff for reviewing the PEP draft and explaining the nitty-gritty details of Sigstore.
This PEP deprecates the expectation that future CPython releases will provide PGP signatures and sets a timeline for discontinuance (Python 3.14) and a mechanism for that timeline to be extended by a vote of the Steering Council, if necessary.
What do verifiers need?
Signatures are only useful if they are verified, so we must weigh the needs of verifiers!
CPython's expected downstream verifiers are primarily "distributions" of CPython, such as through a Linux distro (Debian, Fedora, Gentoo, etc) or in a container image. There are other distributions of Python such as pyenv and python-build-standalone.
These users of CPython's source code are great places to verify signatures, as they're likely to be high value targets themselves and can provide a consistent stream of verifications. If any one signature verification were to fail, it would signal that something is wrong with upstream CPython artifacts or python.org and would likely be investigated and remediated quickly.
This further constrains attackers looking to affect CPython downstream users, as compromising python.org would no longer be enough. Instead, attackers would need to compromise the build infrastructure or CPython source code.
From discussions, the requirements that I've gathered from verifiers are:
- Need a tool for verification that can be packaged by distros. The recommended tool for verifying with a CLI is either Cosign or sigstore-python, both of which have challenges for Linux distro packagers.
- OS packages would require Cosign to be packaged in those OS package managers. This isn't trivial as it requires the Go toolchain to build.
- Docker and other container images want verification tools to be available at the OS level. Needing to pull these externally (from Cosign's GitHub releases) would require multi-stage builds which they want to avoid if possible. Today Cosign is available in Alpine, but not yet in Debian (but there is the beginnings of support), Gentoo, or Fedora.
- Offline verification is important. Many package ecosystems ship the signatures inside the packages to enable "build from source" (such as Gentoo), and there's no guarantee that the package is being built online. It's okay that revocation or root of trust updates can't happen when offline. Cosign and other Sigstore verification tools support offline verification if the root of trust is "bundled" as a file locally.
- Online periodic updates to revocations and root of trust. Cosign and other Sigstore verifiers supports this use-case as the default behavior.
Overall, the availability of Cosign in OS package managers appears to be the biggest blocker to see adoption for verifying CPython's Sigstore signatures.
Why adopt a new signature method?
So why have CPython's Sigstore signatures not seen adoption despite being available for multiple years? Here's a short list of self-reinforcing reasons:
- Verifiers don't need to adopt the new signature method (Sigstore), because the existing one (PGP) works and there's no expectation for discontinuance.
- Signers can't migrate away from the old signature method because there's apparent demand from verifiers for the old signature method.
- Verifiers don't try or test the new signature method, so the maintainers of signature tooling can't learn about or improve verifier use-cases.
- Concurrently supporting multiple signature methods is more work for both signers and verifiers.
- There are fewer available signatures using the new signing method, so the value of adopting the method as a verifier is less (but maybe this will change soon?).
Keep in mind that almost everyone involved in the above scenarios are volunteers. Doing work to adopt a new process when existing processes are working can feel like "busy-work", but I don't think that's the case for Sigstore.
Sigstore's benefits for ergonomics paired with its ability to use workload identity are two stand-out features compared to PGP. Workload identity being extra important now that many projects are moving to hosted build infrastructure for releases.
Workload Identity
Sigstore supporting workload identity means that release manager accounts can no longer be hijacked to produce bad signatures. Artifacts get signed by the build infrastructure provider directly:
python/release
Release
Package
(deb, rpm)
Build
Infra
Workload identity: verify artifacts came from CPython release infra
Switching to workload identity also means downstream verifiers no longer need to
make changes when new release managers join the project, the expected identity would always be gh/python/release-tools/...
.
We still have a ways to go to adopt workload identity for CPython because our macOS and Windows release processes don't use hosted build platforms that support OpenID Connect and Sigstore. That means that for now we'll keep using release manager identities.
But this future may not be far off for Python packages hosted on PyPI...
Many more signatures are coming!
William Woodruff and the team at Trail of Bits have authored PEP 740 which is provisionally accepted. The PEP specifies how attestations that can be verified by PyPI (like Sigstore) using workload identities specified with the secure publishing feature "Trusted Publishers" and then served alongside artifacts on PyPI.
There's a lot more to this story (but it's not for me to tell). Given Trusted Publishers' success, there clearly are exciting times are ahead. Subscribe to the PyPI blog to learn more once the project is complete.
That's all for this post! đ If you're interested in more you can read the last report.
︎Have thoughts or questions? Let's chat over email or social:
Want more articles like this one? Get notified of new posts by subscribing to the RSS feed or the email newsletter. I won't share your email or send spam, only whatever this is!
Want more content now? This blog's archive has ready-to-read articles. I also curate a list of cool URLs I find on the internet.
Find a typo? This blog is open source, pull requests are appreciated.
Thanks for reading! ⥠This work is licensed under CC BY-SA 4.0
October 20, 2024
Real Python
Quiz: Pydantic: Simplifying Data Validation in Python
In this quiz, you’ll test your understanding of
Pydantic. Pydantic is a powerful data validation library for Python. You can also use a related library, pydantic-settings
, for settings management.
By working through this quiz, you’ll revisit how to work with data schemas with Pydantic’s BaseModel
,
write custom validators for complex use cases, validate function arguments with Pydantic’s @validate_call
,
and manage settings and configure applications with pydantic-settings
.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Julien Tayon
Revisiting hello world : coding print from scratch part I
The « hello world » example is about standing on the shoulders of the giant and learn how to use function as tools.
Most coders will use print during their whole life without actually coding it. However, it is a fun exercise.
The framebuffer
Given you are on linux you probably have a device named /dev/fb0 if you don't, you can't do this. The framebuffer is a view of the linear graphical memory used by your video card where what you see on the screen is stored ... at the condition you are in console mode and you have the rights.
On my debian centric distribution, to give the_user permissions to write in the framebuffer I must add the_user to group_video. This can be done with
sudo adduser the_user video
or sudo vigr
.Then, you have to be in console mode. To switch from xorg/wayland to the console back and forth I use the Ctrl + Alt + Fn combination to switch off from X and Alt + Fn to switch back to X (it's called switching the virtual console).
Once this is done you check you have rights by doing
cat /dev/urandom > /dev/fb0which should fill your screen with random colors and insult you stating there is no more room left on the device. SNAFU : everyhting works as intended.
The pixel
Framebuffer don't know about pixels made of Red, Green, Blue and alpha (given you have a video card that is less than 20 years old), they are just made of memory. We will have to slowly build up our understanding of what this is all about.
The in memory layout may differ according to the hardware, some are having a RGBA layout, mine, the i915 is having a BGRA layout. The following example may need to be rewritten with different hardware if the output is not consistent with your assumption.
Determining the memory layout and coordinates
We will do a test and validate code session : first we make assumption on where the colours are by writting 3 squares of Red, Blue and Green on the screen, then, we will snapshot the screen.
$ cat fb.py #!/usr/bin/env python3 from struct import pack w,h =map(int, open("/sys/class/graphics/fb0/virtual_size").read().split(",")) midx = w//2 midy = h//2 encode = lambda b,g,r,a : pack("4B",b,g,r,a) with open("/dev/fb0", "wb") as f: for y in range(0,h): for x in range(0,w): f.write(encode( not x%100 and 0xA0 or x<midx and 0xFF or 0, #blue y<midy and 0xFF or 0, #green x>midx and y>midy and 0xFF or 0, #red 0, ))The only « trick » is the use of pack to encode the four colour bytes in a byte array that is written to the framebuffer filehandler. If the code works correctly we should validate the following assumptions:
- coordinates are such as 0 is top left of the screen where green and blue should superpose
- my 1920x1080 screen should have 19 weired stripes (hence validating the geometry)
- each colours should be in its square, red bottom right, green top right, blue bottom left.
- RAM as a char device is accessing a low level file
- a magic number P3 followed by
- width
- height
- the maximum colour value (here 255)
- the 3 colour bytes Red, Blue, Green without Alpha value per pixel
The code for this is straigh forward :
$ cat snap.py #!/usr/bin/env python from struct import unpack w,h = map( int,open("/sys/class/graphics/fb0/virtual_size").read().split(",")) # returns b g r a decode = lambda pixel : unpack("4B", pixel) def pr(b,g,r,a): print("%d %d %d" % (r,g,b)) print(f"""P3 {w} {h} 255 """) with open("/dev/fb0", "rb") as fin: while pixel := fin.read(4): pr(*decode(pixel))Here the only trick is we use the symetrical function of pack, unpack to decode the pixel in the four colour bytes.
wrapping up part one
Asumming you can install fim the framebuffer image wiewer and you installed imagemagick : you can now do
./fb.py && snap.py > this.ppm && convert this.ppm this.jpg && fim this.jpgDoing so, you should have the same picture showing twice without an error like this : As an exercise, you can vary the fb.py to make funny output, or code a PPM viewer that print back your ppm to the screen.
October 19, 2024
Python Does What?!
Enums make good singletons
It's simple and common to allocate a marker object to represent missing or null data.
MISSING = object()
There's a slightly more verbose construct with some advantages:import enum
class MissingType(enum.Enum):
MISSING = "MISSING"
MISSING = MissingEnum.MISSING
Type checkers understand that MISSING is the only possible value of MissingType; so you can use is checks:def or_1(val: float | MissingType = MISSING) -> float:
if scale is not MISSING:
return 1.0
return scale
mypy understands this is type correct.More broadly, the semantics of a single-value enum are the same as a singleton. For example, neither singletons nor enums should have additional instances allocated. Instead of fixing bugs one by one with custom __init__ and __deepcopy__, the correct behaviors come for free.
Armin Ronacher
Serendipity
October 18, 2024
Real Python
The Real Python Podcast â Episode #224: Narwhals: Expanding DataFrame Compatibility Between Libraries
How does a Python tool support all types of DataFrames and their various features? Could a lightweight library be used to add compatibility for newer formats like Polars or PyArrow? This week on the show, we speak with Marco Gorelli about his project, Narwhals.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Programiz
Python matchâŠcase Statement
The matchâŠcase statement allows us to execute different actions based on the value of an expression. In this tutorial, you will learn how to use the Python matchâŠcase with the help of examples.
Matt Layman
Epic Debugging, Hilarious Outcome - Building SaaS #205
In this episode, I dug into an issue with sign up. What I thought was going to be a minor issue to fix turned into a massively intense debugging session. We ended up going very deep with the django-allauth package to understand what was going on.
October 17, 2024
Real Python
Quiz: Single and Double Underscores in Python Names
In this quiz, you’ll test your understanding of Single and Double Underscores in Python Names.
By working through this quiz, you’ll revisit Python naming conventions that rely on using underscores (_
), how to differentiate public and non-public names by using a single leading underscore, how to use double leading underscores to leverage name mangling in Python classes, and other common uses of underscores in Python names.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Talk Python to Me
#481: Python Opinions and Zeitgeist with Hynek
Hynek has been writing and speaking on some of the most significant topics in the Python space and I've enjoyed his takes. So I invited him on the show to share them with all of us. This episode really epitomizes one of the reasons I launched Talk Python 9 years ago. It's as if we run into each other at a bar during a conference and I ask Hynek, "So what are your thoughts on ..." and we dive down the rabbit hole for an hour. I hope you enjoy it.<br/> <br/> <strong>Episode sponsors</strong><br/> <br/> <a href='https://talkpython.fm/workos'>WorkOS</a><br> <a href='https://talkpython.fm/bluehost'>Bluehost</a><br> <a href='https://talkpython.fm/training'>Talk Python Courses</a><br/> <br/> <strong>Links from the show</strong><br/> <br/> <div><b>Hynek Schlawack on Mastodon</b>: <a href="https://mastodon.social/@hynek?featured_on=talkpython" target="_blank" >@hynek</a><br/> <br/> <b>Why I Still Use Python Virtual Environments in Docker</b>: <a href="https://hynek.me/articles/docker-virtualenv/?featured_on=talkpython" target="_blank" >hynek.me</a><br/> <b>Production-ready Python Docker Containers with uv</b>: <a href="https://hynek.me/articles/docker-uv/?featured_on=talkpython" target="_blank" >hynek.me</a><br/> <b>Attrs</b>: <a href="https://github.com/python-attrs/attrs?featured_on=talkpython" target="_blank" >github.com</a><br/> <b>uv</b>: <a href="https://docs.astral.sh/uv/?featured_on=talkpython" target="_blank" >astral.sh</a><br/> <b>Whatâs New In Python 4</b>: <a href="https://docs.python.org/3.13/whatsnew/3.13.html?featured_on=talkpython" target="_blank" >python.org</a><br/> <b>BusyBox</b>: <a href="https://www.busybox.net?featured_on=talkpython" target="_blank" >busybox.net</a><br/> <b>Hynek's YouTube Channel</b>: <a href="https://www.youtube.com/@The_Hynek" target="_blank" >youtube.com</a><br/> <b>MOPUp for macOS</b>: <a href="https://github.com/glyph/MOPUp?featured_on=talkpython" target="_blank" >github.com</a><br/> <b>Homebrew Python Is Not For You</b>: <a href="https://justinmayer.com/posts/homebrew-python-is-not-for-you/?featured_on=talkpython" target="_blank" >justinmayer.com</a><br/> <b>argon2-cffi: Argon2 for Python</b>: <a href="https://github.com/hynek/argon2-cffi?featured_on=talkpython" target="_blank" >github.com</a><br/> <b>pytest-freethreaded</b>: <a href="https://github.com/tonybaloney/pytest-freethreaded?featured_on=talkpython" target="_blank" >github.com</a><br/> <b>LM Studio</b>: <a href="https://lmstudio.ai?featured_on=talkpython" target="_blank" >lmstudio.ai</a><br/> <b>StackOverflow Trends Graph</b>: <a href="https://trends.stackoverflow.co/?tags=java,c,python,c%23,vb.net,javascript,assembly,php,perl,ruby,swift,r,objective-c&featured_on=talkpython" target="_blank" >trends.stackoverflow.co</a><br/> <b>Watch this episode on YouTube</b>: <a href="https://www.youtube.com/watch?v=Tdt4Xa5sCik" target="_blank" >youtube.com</a><br/> <b>Episode transcripts</b>: <a href="https://talkpython.fm/episodes/transcript/481/python-opinions-and-zeitgeist-with-hynek" target="_blank" >talkpython.fm</a><br/> <br/> <b>--- Stay in touch with us ---</b><br/> <b>Subscribe to us on YouTube</b>: <a href="https://talkpython.fm/youtube" target="_blank" >youtube.com</a><br/> <b>Follow Talk Python on Mastodon</b>: <a href="https://fosstodon.org/web/@talkpython" target="_blank" ><i class="fa-brands fa-mastodon"></i>talkpython</a><br/> <b>Follow Michael on Mastodon</b>: <a href="https://fosstodon.org/web/@mkennedy" target="_blank" ><i class="fa-brands fa-mastodon"></i>mkennedy</a><br/></div>
Julien Tayon
3D ploter in python-tk with matplotlib.
Wishing to prove my assertion wrong on python-tk that piping python directly into tk/tcl interpreter is simple I tried to contradict myself by making a full GUI in matplotlib. Because, if you are not aware : matplotlib supports multi-target (Wx, Qt, gtk, tk, html) multi-platform widgets (Button, checkbox, text entry and so much more).
The challenge seemed pretty easy, to assemble an easy demo with simple example :
- One example on how to use text entry in matplotlib that doubles with a 2D plotter,
- and the one from matplotlib on how to draw a 3D surface with a colorbar
- and the one for projecting the contour of the function on the axis
Without the colorbar I would have just been slightly annoyed by the slowness of the reaction of matplotlib as a GUI, but the colorbar posed a new challenge because it would either stack for each drawing or make plt.clf/ax.cla erase too much (see this great resource on when to use cla/clf in matplotlib).
So ... I tried python-tk with matplotlib knowing all too well that you can embed natively matplotlib in tkinter interface.
And since it was working I kept it.
Here is a screenshot of the interface : WARNING this code should not be let in inventive hands (such as bored teenagers) because there is an evil eval; it requires to be in care of consenting adults.
Some highlights of the code :
- bidir python-tk requires setting the Popen PIPEs to non blocking and using select.select on the output
- matplotlib is unusable in non blocking mode : once matplotlib has the focus you need to destroy it to plot another function
- from np import * is evil, but it let you have access to all array oriented math function (sin, cos, exp, ...)
Spyder IDE
Officially announcing the release of Spyder 6!
After two years in development and more than 2600 commits from over two dozen authors around the world, Spyder 6.0.0 had its stable release on September 3, 2024! Now that 6.0.1 is out and the dust has settled, we'd like to formally announce the release here, thank those who've contributed to it, and introduce a series of posts highlighting its major new features and improvements that haven't already been showcased here.
October 16, 2024
Django Weblog
Announcing weekly DSF office hours
For the last year, Thibaud Colas and I have had a weekly DSF co-working session â we get on a video call and spend an hour quietly working together on DSF things. It's worked well to help us carve out time to work on DSF initiatives, so we'd like to expand into an open-to-everyone weekly "office hours" format.
These will be Wednesdays at 6PM UTC (convert to other time zones). (Yes, that means the first one will be in just about 4 hours, short notice I know, so maybe mark it down for next week.)
All you need to do is bring something DSF-related to work on. This is intentionally broad, as long as it's vaguly DSF-related you're welcome to come. It's not a general-purpose Django coding session (you're welcome to be writing code but it should be related the DSF, e.g. working on djangoproject.com or something.)
This week and next, we'll probably be focusing on nominations for the DSF Board -- nominations close October 25th.
For now, we're deliberately not publishing the video call information publicly â we're a bit worried about spammers and scammers. So if you want to join, you'll need to contact the board, or someone on the board, to get the info. You can use the DSF contact form, and anyone's welcome to contact me directly: â email jacob@djangoproject.com, Signal jacobian.01, or @jacob@jacobian.org on Mastodon.
(Yes, this introduces some friction which is at odds with the "everyone's welcome" ethos. If/when we figure out a better way to moderate these calls, we'll change this.)
I look forward to seeing you there!
Python Insider
Python 3.14.0 alpha 1 is now available
It's now time for a new alpha of a new version of Python!
https://www.python.org/downloads/release/python-3140a1/
This is an early developer preview of Python 3.14
Major new features of the 3.14 series, compared to 3.13
Python 3.14 is still in development. This release, 3.14.0a1 is the first of seven planned alpha releases.
Alpha releases are intended to make it easier to test the current state of new features and bug fixes and to test the release process.
During the alpha phase, features may be added up until the start of the beta phase (2025-05-06) and, if necessary, may be modified or deleted up until the release candidate phase (2025-07-22). Please keep in mind that this is a preview release and its use is not recommended for production environments.
Many new features for Python 3.14 are still being planned and written. Among the new major new features and changes so far:
- PEP 649: deferred evaluation of annotations
- Improved error messages
- (Hey, fellow core developer, if a feature you find important is missing from this list, let Hugo know.)
The next pre-release of Python 3.14 will be 3.14.0a2, currently scheduled for 2024-11-19.
More resources
- Online documentation
- PEP 745, 3.14 Release Schedule
- Report bugs at https://github.com/python/cpython/issues
- Help fund Python and its community
Enjoy the new release
Thanks to all of the many volunteers who help make Python Development and these releases possible! Please consider supporting our efforts by volunteering yourself or through organization contributions to the Python Software Foundation.
Regards from a grey yet colourful Helsinki,
Your release team,
Hugo van Kemenade
Ned Deily
Steve Dower
Ćukasz Langa
Mike Driscoll
SSH Scripting with Fabric and Python
Reading and writing files is a basic task that most software applications need to do. You will also find that you sometimes need to read and write files to a remote machine or perhaps run commands on a remote machine as well. Python is well-suited for this type of activity using tools such as Paramiko. However, in this tutorial, you will spend some time learning how to use a different package called Fabric.
Fabric is a high-level Python package designed especially to execute shell commands remotely over SSH and then yielding useful Python objects in return. This article will focus on the latest version of Fabric, which is 3.2.2 at the time of writing.
Getting Fabric
Fabric is a third party package. That means you need to install Fabric to be able to use it. Fortunately, you can use Python’s pip tool to do so.
Open up a terminal application and run the following command:
python -m pip install fabric
If you don’t want to clutter up your main Python environment, then you should use a Python virtual environment. You can learn more about those in An Intro to Python Virtual Environments.
Once you are finished installing Fabric, you can move on to learning how to use it!
Connecting to the Server with Fabric
The Fabric documentation uses the following as a super simple example of running a command on a remote machine using SSH:
from fabric import Connection result = Connection('web1.example.com').run('uname -s', hide=True)
You only need two lines of code to start running commands on a remote machine. But what if the remote machine requires credntials?
In that case, you need to create a Config object and update your instantiation of Connection like this:
from fabric import Connection, Config config = Config(overrides={"sudo": {"password": "MyAmazingPassword123"}}) conn = Connection("mike@10.10.166.128:22", connect_kwargs={"password": "MyAmazingPassword123!"}, config=config)
If you have a machine that uses an SSH key pair, you can use this alternate connect_kwargs dictionary:
connect_kwargs={ "key_filename": "/home/myuser/.ssh/private.key", }
Then simply update the call to Connection and you’re good to go.
Running Commands with Fabric
Now that you have the knowledge needed to connect to the remote machine, you probably want to start running more complex commands. Here is an example of running a ping command:
from fabric import Connection, Config config = Config(overrides={"sudo": {"password": "MyAmazingPassword123"}}) conn = Connection("mike@10.10.166.128:22", connect_kwargs={"password": "MyAmazingPassword123!"}, config=config) conn.run("ping -c 2 www.google.com")
What if you want to be able to use the super user (i.e. root) when running a command? Fabric makes that easy by using the sudo() method:
from fabric import Connection, Config config = Config(overrides={"sudo": {"password": "MyAmazingPassword123"}}) conn = Connection("mike@10.10.166.128:22", connect_kwargs={"password": "MyAmazingPassword123!"}, config=config) conn.sudo("systemctl restart nfs-kernel-server")
Transferring Files with Fabric
If you want to download a file from a remote machine, Fabric makes this rudimentary task even easier. Here’s how to do it:
from fabric import Connection, Config config = Config(overrides={"sudo": {"password": "MyAmazingPassword123"}}) conn = Connection("mike@10.10.166.128:22", connect_kwargs={"password": "MyAmazingPassword123!"}, config=config) conn.get("remote_file_path", "local_file_path")
Note that all you need to do is call get() while specifying the location of the remote file that you want for the first argument and the local path for where you want to download the file as the second argument.
Sending a file to the remote server is done using the put() method:
from fabric import Connection, Config config = Config(overrides={"sudo": {"password": "MyAmazingPassword123"}}) conn = Connection("mike@10.10.166.128:22", connect_kwargs={"password": "MyAmazingPassword123!"}, config=config) conn.put("local_file_path", "remote_file_path")
You reverse the arguments for put() versus get(). The local path is passed in first, followed by the remote location that you want to upload to.
But what if you want to upload to a restricted area of the file system on the remote machine? You know, like to the etc folder or any of the other root-owned folders?
Fabric doesn’t have a built-in way to do that. Instead you use a two-step process:
- Upload the file to a directory that your user owns
- Then use sudo() to move the file to the restricted location
Here’s an example:
from fabric import Connection, Config config = Config(overrides={"sudo": {"password": "MyAmazingPassword123"}}) conn = Connection("mike@10.10.166.128:22", connect_kwargs={"password": "MyAmazingPassword123!"}, config=config) # Send the file to a user directory conn.put("local_file_path", "remote_file_path") # Use sudo to move that file to a root location conn.sudo("mv remote_file_path root_location_path")
Wrapping Up
Fabric is a great tool that greatly simplifies running SSH commands on remote computers. If you know how to use common Linux commands or know Python well, you can do lots of different things. For example, you could even upload a Python script to the remote server, run it, and then remove the file. At that point, you could do just about anything that you needed to.
Give Fabric a try and see what you can do!
The post SSH Scripting with Fabric and Python appeared first on Mouse Vs Python.
Real Python
Structural Pattern Matching in Python
Structural pattern matching is a powerful control flow construct invented decades ago thatâs traditionally used by compiled languages, especially within the functional programming paradigm.
Most mainstream programming languages have since adopted some form of pattern matching, which offers concise and readable syntax while promoting a declarative code style. Although Python was late to join the party, it introduced structural pattern matching in the 3.10 release.
In this tutorial, youâll:
- Master the syntax of the
match
statement andcase
clauses - Explore various types of patterns supported by Python
- Learn about guards, unions, aliases, and name binding
- Extract values from deeply nested hierarchical data structures
- Customize pattern matching for user-defined classes
- Identify and avoid common pitfalls in Pythonâs pattern matching
To get the most out of this tutorial, you should have a basic understanding of conditional statements, loops, functions, and classes in Python. Additionally, familiarity with Pythonâs built-in data structures, such as tuples, lists, and dictionaries, will be beneficial.
Get Your Free Code: Click here to download the free sample code that shows you how to use structural pattern matching in Python.
Take the Quiz: Test your knowledge with our interactive âStructural Pattern Matchingâ quiz. Youâll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Structural Pattern MatchingIn this quiz, you'll test your understanding of structural pattern matching in Python. This powerful control flow construct, introduced in Python 3.10, offers concise and readable syntax while promoting a declarative code style.
Getting to Know Structural Pattern Matching
Before taking advantage of structural pattern matching in your code, make sure that youâre running Python 3.10 or later, as you wonât be able to use it in earlier Python versions. Note that although the name structural pattern matching is often shortened to just pattern matching, the qualifier structural is crucial to understanding the use cases for this feature. In this section, youâll get a high-level overview of structural pattern matching.
What Is Pattern Matching?
You can think of pattern matching as a form of syntactic sugar built on top of existing language constructs, including conditional statements and tuple unpacking. While you can absolutely live without pattern matching, it gives you new superpowers, making this feature more convenient than the conventional syntax in some situations.
Pattern matching often leads to more elegant, concise, and readable code written in a declarative style. To get a taste of it, take a quick look at the following example without trying to fully understand how it works just yet:
import json
def log(event):
match json.loads(event):
case {"keyboard": {"key": {"code": code}}}:
print(f"Key pressed: {code}")
case {"mouse": {"cursor": {"screen": [x, y]}}}:
print(f"Mouse cursor: {x=}, {y=}")
case _:
print("Unknown event type")
The match
statement takes a subject, which can be any valid Python expression, such as a string literal or a function call, and compares the resulting value to one or more patterns listed in the case
clauses. The first pattern that matches the given subject will trigger the corresponding case
block to run. Youâll learn more about the match
statement and case
clauses later in this tutorial.
At first glance, the syntax of structural pattern matching in Python looks a bit like the switch
statement found in the C-family programming languages if you squint your eyes:
void log_event(enum Event event) {
switch (event) {
case KEYBOARD:
printf("Keyboard event\n");
break;
case MOUSE:
printf("Mouse event\n");
break;
default:
printf("Unknown event\n");
}
}
This resemblance is deceptive, though. The classic switch
statement controls the execution flow based on the exact value stored in a variable. It effectively works as a chained sequence of mutually exclusive if..elif...
equality comparisons, but with a more succinct and readable syntax.
Although you can use pattern matching this way, youâd be missing out on its true power and flexibility. Structural pattern matching was designed to go beyond value comparisons. In particular, it combines conditional statements or branching based on a logical predicate with destructuring or object deconstruction, which is the inverse of object construction. Youâll see examples of destructuring in the next section.
Note: Because pattern matching does two things at once, the Python interpreter can take advantage of this to optimize the underlying bytecode with specialized opcodes, making the code run slightly faster.
The brief code snippet above merely scratches the surface of what you can achieve with pattern matching, but it already shows you its expressiveness, especially when you compare it with the traditional if...elif...
statements and isinstance()
checks. Hereâs one of the many ways you can implement the equivalent logic using standard Python:
import json
def log(event):
parsed_event = json.loads(event)
if (
"keyboard" in parsed_event and
"key" in parsed_event["keyboard"] and
"code" in parsed_event["keyboard"]["key"]
):
code = parsed_event["keyboard"]["key"]["code"]
print(f"Key pressed: {code}")
elif (
"mouse" in parsed_event and
"cursor" in parsed_event["mouse"] and
"screen" in parsed_event["mouse"]["cursor"]
):
screen = parsed_event["mouse"]["cursor"]["screen"]
if isinstance(screen, list) and len(screen) == 2:
x, y = screen
print(f"Mouse cursor: x={x}, y={y}")
else:
print("Unknown event type")
else:
print("Unknown event type")
This code is functionally identical to the previous version but is longer and has more indentation levels than before. Additionally, it looks more verbose and imperative in style, describing not only what to do but also how to perform the individual steps. Granted, you could try making it slightly shorter by using the Walrus operator and following the EAFP principle without explicit checks, but itâd remain somewhat convoluted.
Itâs worth noting that structural pattern matching first emerged in compiled functional languages with static typing. The attempt to implement it in Python, which is a dynamic language, presented completely new and unique challenges. You can read more about them in the paper entitled Dynamic Pattern Matching with Python, which was co-authored by Guido van Rossum and published in the proceedings of the Dynamic Languages Symposium in 2020.
Now that youâve seen the most basic form of pattern matching in Python, itâs time to unravel the meaning of a structural pattern.
What Is a Structural Pattern?
Read the full article at https://realpython.com/structural-pattern-matching/ »
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
October 15, 2024
PyCoderâs Weekly
Issue #651 (Oct. 15, 2024)
#651 â OCTOBER 15, 2024
View in Browser »
Exploring the New Features of Python 3.13
Python 3.13 is here! Our regular guests, Geir Arne Hjelle and Christopher Trudeau, return to discuss the new version. This year, Geir Arne coordinated a series of preview articles with members of the Real Python team and a showcase tutorial, “Python 3.13: Cool New Features for You to Try.” Christopher’s video course “What’s New in Python 3.13” covers the topics from the article and shows the new features in action.
REAL PYTHON podcast
HPy: A Better C API for Python
The HPy project is a wrapper to the Python C-API meant to make it easier to integrate with Python code. It allows for universal binaries and has a debug mode. Associated HN Discussion
HPYPROJECT.ORG
Posit Connect: Share the Work You Make With Streamlit, FastAPI, & Other FOSS Frameworks
People use Posit Connect to publish, host, & manage interactive apps, dashboards, Python models, APIs, & much more. It provides a centralized, self-service place to share the products of data science teams. Increase the impact of your work by making it easier for others to integrate with your work â
POSIT sponsor
PyCon Africa 2024: A Summary
This was Vuyisile’s first visit to PyCon Africa and so he posted a summary of the event.
VUYISILE NDLOVU
Articles & Tutorials
__init__.py
Files Are Optional. You Should Still Use Them
If youâve ever googled the question âWhy do Python packages have empty __init__.py
files?â, you could get the idea that Python packages wouldnât work without them. This is a common misconceptionâtheyâve been optional since Python 3.3! Why then, do most Python projects still have them?
BOVENBERG.NET âą Shared by Arie Bovenberg
Build a Contact Book App With Python, Textual, and SQLite
In this tutorial, you’ll be guided step by step through the process of building a basic contact book application. You’ll use Python and Textual to build the application’s text-based user interface (TUI), and then use SQLite to manage the database.
REAL PYTHON
Save 100+ Engineering Hours With the Highest Performing GPU Clusters on the Market
FluidStack provides GPU clusters for LLM training & inference for the top AI labs including Poolside and CharacterAI. Clusters are built on the latest Nvidia GPUs (A100s, H100s, H200s, GB200s) and are deployed on fully managed Kubernetes/Slurm with 24/7Â support, 15 min response time and 99% uptime â
FLUIDSTACK sponsor
PEP 777: How to Re-Invent the Wheel
“The current wheel 1.0 specification was written over a decade ago, and has been extremely robust to changes in the Python packaging ecosystem… this PEP prescribes compatibility requirements on future wheel revisions.”
PYTHON.ORG
PEP 758: Allow except
and except*
Expressions Without Parentheses
“This PEP proposes to allow unparenthesized except
and except*
blocks in Pythonâs exception handling syntax. Currently, when catching multiple exceptions, parentheses are required around the exception types.”
PYTHON.ORG
PEP 761: Deprecating PGP Signatures for CPython Artifacts
Since Python 3.11.0, CPython has provided two verifiable digital signatures for all CPython artifacts: PGP and Sigstore. This PEP proposes moving to Sigstore as the only way of signing artifacts.
PYTHON.ORG
In the Making of Python Fitter and Faster
This post details how Python’s recent performance improvements work under the hood. It covers changes to the interpreter, better memory management, and the newly experimental JIT compiler.
SUMER CIP
The Ultimate Guide to Error Handling in Python
This detailed post covers the variety of ways to deal with errors in your code, why you might choose between the approaches, and what all this theory actually means in the real world.
MIGUEL GRINBERG
TypedDicts Are Better Than You Think
TypedDict was introduced in PEP-589 which landed in Python 3.8. The primary use case was to create type annotations for dictionaries. This post explains why you should use them.
CHANGS.CO.UK
Narrow State of a Django Model Using Python TypeGuard
Bruno came across a problem with type checking for a Django project which led him to use TypeGuard
for the first time. This post explains why.
BRUNO ALLA
If We Had $1,000,000âŠ
Jacob ponders what the Django Software Foundation would look like if they had 4x their current budget.
JACOB KAPLAN-MOSS
Projects & Code
Secure.py: HTTP Security Headers Made Easy
GITHUB.COM/TYPEERROR âą Shared by Caleb Kinney
Events
Weekly Real Python Office Hours Q&A (Virtual)
October 16, 2024
REALPYTHON.COM
Python Brasil 2024
October 16 to October 21, 2024
PYTHONBRASIL.ORG.BR
PyCon PanamĂĄ 2024
October 16 to October 19, 2024
PYCON.PA
Swiss Python Summit 2024
October 17 to October 19, 2024
PYTHON-SUMMIT.CH
PyData Bristol Meetup
October 17, 2024
MEETUP.COM
PyLadies Dublin
October 17, 2024
PYLADIES.COM
PyCon APAC 2024
October 25 to October 27, 2024
PYCON.ID
PyCon Korea 2024
October 25 to October 28, 2024
PYCON.KR
PythonHo Conference 2024
October 26 to October 28, 2024
PYTHONHO.COM
Happy Pythoning!
This was PyCoder’s Weekly Issue #651.
View in Browser »
[ Subscribe to đ PyCoder’s Weekly đ â Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]
Real Python
Using Type Hints for Multiple Return Types in Python
In Python, type hinting is an optional yet useful feature for making your code easier to read, reason about, and debug. With type hints, you let other developers know the expected data types for variables, function arguments, and return values. As you write code for applications that require greater flexibility, you may need to specify multiple return types to make your code more robust and adaptable to different situations.
You’ll encounter different use cases where you may want to annotate multiple return types within a single function in Python. In other words, the data returned can vary in type. In this video course, you’ll walk through examples of how to specify multiple return types for a function that parses a string from an email address to grab the domain name.
In addition, you’ll see examples of how to specify type hints for callback functions or functions that take another function as input. With these examples, you’ll be ready to express type hints in functional programming.
[ Improve Your Python With đ Python Tricks đ â Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]