Planet Python

Subscribe to Planet Python feed
Planet Python - http://planetpython.org/
Updated: 18 hours 24 min ago

PyPy: Towards PyPy3.11 - an update

Sat, 2025-01-04 05:41

We1 are steadily working towards a Python 3.11 interpreter, which will be part of the upcoming PyPy 7.3.18 release. Along with that, we also recently updated speed.pypy.org to compare PyPy's performance to CPython 3.11 (it used to be CPython 3.7).

Why is there no PyPy for Python 3.11?

TL;DR: we are working on it and hopefully will have a beta version soon

We started by merging the exception groups work by Nico Rittinghaus, merging the CPython stdlib for Python 3.11.9, and updating the regex engine to handle atomic groupings. I think these were the largest changes needed to support Python3.11, maybe I missed something else?

We then created a milestone with many of the changes that might not be caught in testing. As of today that milestone stands at 24/40 issues closed, 16 open. This is in addition to the v7.3.18 milestone, which has 11/23 issues closed, 12 open.

We also updated our infrastructure to run nightly buildbot test of the py3.11 branch, including adding py3.11 to our benchmarking site speed.pypy.org.

Then the real work started: fixing these milestone issues and failing stdlib tests. Some of the changes were cosmetic changes to error messages, some were more involved changes to the interpreter to behave more like CPython. For instance, hex(x) where x is an int calls long.format(x, "#x") on CPython where in PyPy we used x.__format__("#x"). This subtle difference caused a failure in the repr of IntEnum. Tracking down problems like these takes time. We are now down to about 250 failing stdlib tests, with thousands passing. For comparison, PyPy3.10, first released in June 2023, still has around 100 failing stdlib tests.

C-extension support

PyPy supports the Python C-API via a cpyext compatibility layer. We "mangle" the CPython symbols to add an extra Py to prevent loading CPython c-extension modules into PyPy, since the ABI is different. So a function like PyLong_FromLong will be exported from the c shared object as PyPyLong_FromLong. One of my long-standing goals is to remove this mangling, but it then requires that our c declarations, inlined functions, and macros in the headers match 1:1 the CPython headers. We can get by with not declaring and implementing parts of the interfaces, but what is declared must be identical. This is a long-term project, with each release the headers get closer to the CPython versions. I hope to concentrate on the PyUnicode interfaces for this release.

Note that the time to do this is before a new version release. Once the version is released, we cannot change the headers significantly.

So what is left?

Summarizing the milestones and other things to do:

  • Update to the recently released 3.11.11 stdlib
  • Make sure vmprof works
  • Update the time module to use more MONOTONIC_CLOCK, implement time.sleep differently, and clean up the many duplicate time like interfaces we have across the codebase. We have the time module, some time routines in the _threading moduleand RPython threading support in therpython/rlib` code. We should also make sure we are using 64-bit time interfaces.
  • Decide whether zero-cost exceptions gain us in performance and whether we should implement them even if they do not improve performance.
  • Update our hpy backend to the latest HEAD, which would allow running the hpy numpy fork
  • Reintegrate the pure-python pyrepl libbrary from CPython 3.13.

What else did I forget?

Why did the benchmark results get worse on speed.pypy.org?

TL;DR: running a benchmark site is hard. Something changed in the benchmark runner, and suddenly benchmarks got 10-15% slower.

PyPy run an instance of codepseed with a very old benchmarking suite that can still run Python2 (remember: that is the language of RPython underlying PyPy). The site runs on PSA infrastructure and the benchmarking machine is generously sponsored by Baroque Software. On Nov 9, there was a sudden jump in benchmarking times. For instance here is the result for the float benchmark. This happened across various benchmark runs: both PyPy2.7 and PyPy3.11alpha, with and without the JIT. After spending some time rerunning various benchmarks, I could only conclude the machine itself had gotten slower, maybe due to some security update in the linux kernel, maybe some change in the hosting platform. This "broke" the front-page comparsison: suddenly "latest" is much slower than the historic benchmarks run previous to the changes in the machine.

That page also recently (as of last week) uses CPython 3.11 as a baseline for comparison, where previously it used CPython3.7. It is common knowledge that the newer CPython versions are faster, and we see this now quite clearly. Diving into individual benchmarks, we can see that ones where PyPy-with-a-jit was comparable to CPython3.7 seem to be the ones that CPython3.11 improved greatly. Looking at a comparison of the runs this can be seen in benchmarks like deltablue and the sqlalchemy family. So the new graph has more lines that extend past 1.5 than the old graph.

New graph with PyPy3.11

Older graph with PyPy3.10

.

  1. These days most of the work is done by CF Bolz-Tereick and me on a volunteer basis. Want to get involved? Reach out, we would love to expand the team. Have an idea for funding the work? Fantastic, let's talk. 

Categories: FLOSS Project Planets

Real Python: The Real Python Podcast – Episode #233: PyCoder's Weekly 2024 Top Articles & Missing Gems

Fri, 2025-01-03 07:00

PyCoder's Weekly included over 1,500 links to articles, blog posts, tutorials, and projects in 2024. Christopher Trudeau is back on the show this week to help wrap it all up by sharing some highlights and uncovering a few missing gems from the pile.

[ 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 ]

Categories: FLOSS Project Planets

Hugo van Kemenade: Moved to hugovk.dev

Thu, 2025-01-02 14:51
🚀 See you over at hugovk.dev!
Categories: FLOSS Project Planets

Daniel Roy Greenfeld: Exploring fastcore bunch classes

Wed, 2025-01-01 14:25
For the past six months or so I've been using fastcore. It provides two handy bunch-class style that I've leveraged into projects.
Categories: FLOSS Project Planets

Vinayak Mehta: IPychat — An AI extension for IPython

Wed, 2025-01-01 13:30

Recently, I've been exploring geospatial data about Paris. Although I've seen others work with this type of data and know basic terms like shapefiles and polygons, this is my first time working with it myself. I've been looking up terms and going through docs to learn how various geospatial data …

Categories: FLOSS Project Planets

Go Deh: Me, Chatgpt, copilot, gemini, and google search classify quadrilaterals

Wed, 2025-01-01 09:13

 (Best viewed on a larger than phone screen)

I decided to use AI more in coding, so found some free tools and incorporated them into my coding experience.

My initial goal

Someone on Linkedin posted their classification of types of quadrilaterals with a view to how they would implement each of them using OO principles. I commented on it, but was more interested in creating a program to state what type of quadrilateral it is given.

Starting off

I won't go through all the many questions I put to the AI's but you ask something of the AI, do background searches on results, revise a question, think of implementation, revise the questions to the AI again, ....

Early on I thought the best way to input a quadrilateral would be by entering four ordered points that traced their way around the periphery of the shape so after chatgpt had given a different definition of a quadrilateral I asked:

Is that the same as defining a quadrilateral as "A closed figure constructed from tracing four ordered, unequal, noncollinear points closing by tracing from the last to the first point"

 Because their were crucial occasions were lengths were computed and compared as floating point values I got the AI to align all input points onto a grid. After a while, I had to weigh how precise I would need to be to make specific changes to parts of the source in the AI, (and keeping track of those changes), versus just fixing my copy of some function and then just using select parts of AI generated code - with edits if it was from a different AI or something from a search.

Testing

I was using Vscode as my Python editor, I was not writing a Jupyter notebook, but I started using 

# %%

comments to split my source into cells that I could easily run/rerun in its interactive and graphical interpreter.

I needed some test data so, with the aid of image searches for types of quadrilaterals, I defined my type of quadrilaterals, and stated what features they have as:

test_cases = [  # ([points], "classification", "description")    ([(1, 1), (7, 3), (6, 6), (4, 9)], "Convex", "Non crossing, all angles <180"),    ([(1, 1), (7, 1), (7, 4), (1, 4)], "Rectangle1", "Non-crossing, all ang == 90, opp sides =="),    ([(1, 1), (1, 7), (4, 7), (4, 1)], "Rectangle2", "Non-crossing, all ang == 90, all sides =="),    ([(0, 3), (3, 0), (9, 6), (6, 9)], "Rectangle3", "Non-crossing, all ang == 90, opp sides ==, rotated"),    ([(1, 1), (7, 1), (7, 7), (1, 7)], "Square1", "Non-crossing, all ang == 90, opp sides =="),    ([(1, 5), (4, 1), (8, 4), (5, 8)], "Square2", "Non-crossing, all ang == 90, all sides ==, rotated"),    ([(1, 1), (6, 1), (9, 5), (4, 5)], "Rhombus", "Non-crossing, ang !=90, opp sides || and all sides =="),    ([(1, 1), (6, 1), (9, 10), (4, 10)], "Parallelogram", "Non-crossing, opp sides || and opp sides =="),    ([(1, 1), (7, 1), (5, 5), (2, 5)], "Trapezium1", "Non-crossing, at least one set of opposite || sides"),    ([(1, 1), (5, 3), (5, 6), (1, 7)], "Trapezium2", "Non-crossing, at least one set of opposite || sides"),    ([(1, 4), (5, 1), (7, 4), (5, 7)], "Kite1", "Non crossing, No interior ang >180, two non== sets of == lines that touch"),    ([(4, 1), (1, 5), (4, 11), (7, 5)], "Kite2", "Non crossing, No interior ang >180, two non== sets of == lines that touch"),    ([(1, 1), (5, 5), (7, 4), (4, 8)], "Reflex", "Non crossing, one interior ang >180"),    ([(1, 4), (7, 1), (4, 4), (7, 7)], "Dart1", "Non crossing, one interior ang >180, two non== sets of == lines that touch"),    ([(4, 1), (1, 7), (4, 4), (7, 7)], "Dart2", "Non crossing, one interior ang >180, two non== sets of == lines that touch"),    ([(1, 1), (6, 6), (7, 2), (3, 9)], "Crossed", "Crossing"),    ([(1, 1), (7, 7), (7, 3), (1, 9)], "Truss1", "Crossing, crossing lines ==, none-crossing lines ||"),    ([(1, 1), (7, 7), (3, 7), (9, 1)], "Truss2", "Crossing, crossing lines ==, none-crossing lines ||"),    ([(1, 1), (7, 9), (7, 1), (1, 9)], "Bowtie1", "Crossing, crossing lines ==, none-crossing lines || and =="),    ([(1, 1), (9, 7), (1, 7), (9, 1)], "Bowtie2", "Crossing, crossing lines ==, none-crossing lines || and =="),    ([(0, 3), (9, 6), (6, 9), (3, 0)], "Bowtie3", "Crossing, crossing lines ==, none-crossing lines || and ==, rotated"),]

It took some time working out a few of the points necessary as the AI's "can't count" very well so most were done by my hand calculations after giving up on AI help for this. (One gets tired of the confident but wrong replies).

You may not see the truss type of quadrilateral elsewhere, Bowties, to me always have that extra symmetry, but I needed a name for the category so chose truss.

Somewhere, there is a cell defining a function that visualises all the quadrilaterals. I started with chatgpt's help in starting function visualise_test_cases then modified it by hand, as necessary. The picture at the start of the blog is the final matplotlib output. Note: I used several versions of Python in development and some did not have matplotlib so used # %% cell shenanigans, and if 0: blocks so that the matplotlib stuff only runs in the vscode interpreter).

With testing, and debugging came another lot of AI and google searches, and AI describing some of the algorithms used. A google search lead to a StackOverflow q&A's where the second most used answer for finding the angles between two lines used atan2, and with an explanation of its benefits. I decided to use it and asked chatgpt to do this:

in _angle() is it better to use atan2?

 That was most of what was needed to update def _angle() to that shown. Because float angles are also being compared, I wrote _round_angle myself and applied it appropriately.

_classify becomes _categorise 

I did not like the first, "default", method of classification from chatgpt, which was refined as function _classify which returned only one type of quadrilateral for the given points, and was  a bit untidy in how it got there.. I asked several questions to get chatgpt to first calculate properties of  the quadrilateral, and refined it to form function _categorise. Putting my tests through it I got all the properties for my named quadrilaterals and pared them and reordered them to form dict quad2features. If the quadrilaterals features are a superset of those shown in quad2features then the quadrilateral is of the type in the key.

OK output

I started to get output that looked correct:


Convex Non crossing, all angles <180 [(1, 1), (7, 3), (6, 6), (4, 9)] QuadrilateralClassifier(points).classify() =['Convex'] Rectangle1 Non-crossing, all ang == 90, opp sides == [(1, 1), (7, 1), (7, 4), (1, 4)] QuadrilateralClassifier(points).classify() =['Convex', 'Parallelogram', 'Rectangle'] Rectangle2 Non-crossing, all ang == 90, all sides == [(1, 1), (1, 7), (4, 7), (4, 1)] QuadrilateralClassifier(points).classify() =['Convex', 'Parallelogram', 'Rectangle'] Rectangle3 Non-crossing, all ang == 90, opp sides ==, rotated [(0, 3), (3, 0), (9, 6), (6, 9)] QuadrilateralClassifier(points).classify() =['Convex', 'Parallelogram', 'Rectangle'] Square1 Non-crossing, all ang == 90, opp sides == [(1, 1), (7, 1), (7, 7), (1, 7)] QuadrilateralClassifier(points).classify() =['Convex', 'Rhombus', 'Square'] Square2 Non-crossing, all ang == 90, all sides ==, rotated [(1, 5), (4, 1), (8, 4), (5, 8)] QuadrilateralClassifier(points).classify() =['Convex', 'Rhombus', 'Square'] Rhombus Non-crossing, ang !=90, opp sides || and all sides == [(1, 1), (6, 1), (9, 5), (4, 5)] QuadrilateralClassifier(points).classify() =['Convex', 'Rhombus'] Parallelogram Non-crossing, opp sides || and opp sides == [(1, 1), (6, 1), (9, 10), (4, 10)] QuadrilateralClassifier(points).classify() =['Convex', 'Parallelogram'] Trapezium1 Non-crossing, at least one set of opposite || sides [(1, 1), (7, 1), (5, 5), (2, 5)] QuadrilateralClassifier(points).classify() =['Convex', 'Trapezium'] Trapezium2 Non-crossing, at least one set of opposite || sides [(1, 1), (5, 3), (5, 6), (1, 7)] QuadrilateralClassifier(points).classify() =['Convex', 'Trapezium'] Kite1 Non crossing, No interior ang >180, two non== sets of == lines that touch [(1, 4), (5, 1), (7, 4), (5, 7)] QuadrilateralClassifier(points).classify() =['Convex', 'Kite'] Kite2 Non crossing, No interior ang >180, two non== sets of == lines that touch [(4, 1), (1, 5), (4, 11), (7, 5)] QuadrilateralClassifier(points).classify() =['Convex', 'Kite'] Reflex Non crossing, one interior ang >180 [(1, 1), (5, 5), (7, 4), (4, 8)] QuadrilateralClassifier(points).classify() =['Reflex'] Dart1 Non crossing, one interior ang >180, two non== sets of == lines that touch [(1, 4), (7, 1), (4, 4), (7, 7)] QuadrilateralClassifier(points).classify() =['Reflex', 'Dart'] Dart2 Non crossing, one interior ang >180, two non== sets of == lines that touch [(4, 1), (1, 7), (4, 4), (7, 7)] QuadrilateralClassifier(points).classify() =['Reflex', 'Dart'] Crossed Crossing [(1, 1), (6, 6), (7, 2), (3, 9)] QuadrilateralClassifier(points).classify() =['Reflex', 'Crossed'] Truss1 Crossing, crossing lines ==, none-crossing lines || [(1, 1), (7, 7), (7, 3), (1, 9)] QuadrilateralClassifier(points).classify() =['Reflex', 'Crossed', 'Truss'] Truss2 Crossing, crossing lines ==, none-crossing lines || [(1, 1), (7, 7), (3, 7), (9, 1)] QuadrilateralClassifier(points).classify() =['Reflex', 'Crossed', 'Truss'] Bowtie1 Crossing, crossing lines ==, none-crossing lines || and == [(1, 1), (7, 9), (7, 1), (1, 9)] QuadrilateralClassifier(points).classify() =['Reflex', 'Crossed', 'Truss', 'Bowtie'] Bowtie2 Crossing, crossing lines ==, none-crossing lines || and == [(1, 1), (9, 7), (1, 7), (9, 1)] QuadrilateralClassifier(points).classify() =['Reflex', 'Crossed', 'Truss', 'Bowtie'] Bowtie3 Crossing, crossing lines ==, none-crossing lines || and ==, rotated [(0, 3), (9, 6), (6, 9), (3, 0)] QuadrilateralClassifier(points).classify() =['Reflex', 'Crossed', 'Truss', 'Bowtie']

The code

Remember, my goal was to learn more about coding with added AI assistance - not to create production ready code.

#!/bin/env python3.11
# %%"""Quadrilateral taxonomy
Classification of quadrilaterals defined by a closed figure constructed bytracing four ordered, distinct, and noncollinear points, connecting consecutiveoints with straight lines, and closing the shape by connecting the last pointto the first.
"""
import math
class QuadrilateralClassifier:
    # Features of quadrilaterals    quad2features = {        'Convex':        {'Convex',},        'Kite':          {'Convex', 'No Parallel Sides', 'Two Touching Equal Sides'},        'Trapezium':     {'Convex', 'One Pair of Parallel Sides'},        'Parallelogram': {'Convex', 'Two Pairs of Parallel Sides', 'Two Pairs of Equal Sides'},        'Rhombus':       {'Convex', 'Two Pairs of Parallel Sides', 'Four Equal Sides'},        'Rectangle':     {'Convex', 'Two Pairs of Parallel Sides', 'Two Pairs of Equal Sides', '4 Right Angles'},        'Square':        {'Convex', 'Two Pairs of Parallel Sides', 'Four Equal Sides', '4 Right Angles'},        'Reflex':        {'Concave'},        'Dart':          {'Concave', 'No Parallel Sides', 'Two Touching Equal Sides'},        'Crossed':       {'Crossed'},        'Truss':         {'Crossed', 'One Pair of Parallel Sides'},        'Bowtie':        {'Crossed', 'One Pair of Parallel Sides', 'Two Pairs of Equal Sides'},    }
    def __init__(self, points, grid_size=0.01):        """        Initializes the QuadrilateralClassifier with points and grid size.
        Parameters:            points (list of tuples): List of four ordered points (x, y).            grid_size (int): Size of the grid to which points will be aligned.        """        if len(points) != 4:            raise ValueError("Exactly four points are required to define a quadrilateral.")
        self.original_points = points        self.grid_size = grid_size        self.points = self._align_to_grid(points)
        # Check if points remain four distinct and noncollinear after alignment        if len(set(self.points)) != 4:            raise ValueError("Aligned points are not four distinct points.")        if not self._is_noncollinear():            raise ValueError("Aligned points are collinear, not forming a quadrilateral.")
    def _align_to_grid(self, points):        """        Aligns points to the nearest grid size.
        Parameters:            points (list of tuples): List of points to align.
        Returns:            list of tuples: List of aligned points.        """        return [(round(x / self.grid_size) * self.grid_size, round(y / self.grid_size) * self.grid_size) for x, y in points]
    def _round_length(self, length: float | int) -> float | int:        """        Rounds length to grid/10 size.
        Parameters:            length: distance to round.
        Returns:            Rounded length.        """        grid = self.grid_size / 10        return round(length / grid) * grid
    def _round_angle(self, angle: float | int, _unit=0.01) -> float | int:        """        Rounds angle to multiples of _unit size.
        Parameters:            angle: Angle to round.
        Returns:            Rounded angle.        """        return round(angle / _unit) * _unit
    def _is_noncollinear(self):        """        Checks if the points are noncollinear.
        Returns:            bool: True if points are noncollinear, False otherwise.        """        def are_points_collinear(p1, p2, p3):            """            Checks if three points are collinear.            """            x1, y1 = p1            x2, y2 = p2            x3, y3 = p3            return (x2 - x1) * (y3 - y1) == (y2 - y1) * (x3 - x1)
        # Check all combinations of three points        return not (            are_points_collinear(self.points[0], self.points[1], self.points[2]) or            are_points_collinear(self.points[0], self.points[1], self.points[3]) or            are_points_collinear(self.points[0], self.points[2], self.points[3]) or            are_points_collinear(self.points[1], self.points[2], self.points[3])        )
    def _distance(self, p1, p2):        """        Calculates the Euclidean distance between two points.
        Parameters:            p1, p2 (tuple): Two points.
        Returns:            float: Distance between the points.        """        return self._round_length(math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2))
    def _angle(self, p1, p2, p3):        """        Calculates the angle (in degrees) at p2 formed by segments (p1, p2) and (p2, p3).
        Parameters:            p1, p2, p3 (tuple): Three points.
        Returns:            float: Angle in degrees.        """        dx1, dy1 = p1[0] - p2[0], p1[1] - p2[1]        dx2, dy2 = p3[0] - p2[0], p3[1] - p2[1]        angle1 = math.atan2(dy1, dx1)        angle2 = math.atan2(dy2, dx2)        angle = math.degrees((angle2 - angle1) % (2 * math.pi))        if angle > 180:            angle = 360 - angle        return self._round_angle(angle)        def _is_convex(self):        """        Determines if the quadrilateral is convex by analyzing the cross product of vectors formed by consecutive points.         A quadrilateral is convex if all cross products have the same sign, indicating consistent rotational direction.
        Returns:            bool: True if the quadrilateral is convex, False otherwise.        """        def cross_product_sign(p1, p2, p3):            """            Computes the sign of the cross product of vectors (p1->p2) and (p2->p3).            """            return (p2[0] - p1[0]) * (p3[1] - p2[1]) - (p2[1] - p1[1]) * (p3[0] - p2[0])
        signs = []        for i in range(4):            p1 = self.points[i]            p2 = self.points[(i + 1) % 4]            p3 = self.points[(i + 2) % 4]            signs.append(cross_product_sign(p1, p2, p3))
        return all(s > 0 for s in signs) or all(s < 0 for s in signs)
    def _is_crossed(self):        """        Checks if the quadrilateral is crossed (self-intersecting).
        Returns:            bool: True if the quadrilateral is crossed, False otherwise.        """        def do_segments_intersect(p1, p2, p3, p4):            """            Checks if segments (p1, p2) and (p3, p4) intersect.
            This is determined using orientation tests to check if the endpoints of each segment lie on opposite sides of the other segment.            If the segments intersect, the intersection point lies within the bounds of each segment.
            Parameters:                p1, p2 (tuple): Endpoints of the first segment.                p3, p4 (tuple): Endpoints of the second segment.
            Returns:                bool: True if the segments intersect, False otherwise.            """            def orientation(a, b, c):                val = (b[1] - a[1]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[1] - b[1])                if math.fabs(val) < 0.000001:                    return 0                if val == 0:                    return 0  # Collinear                return 1 if val > 0 else -1
            o1 = orientation(p1, p2, p3)            o2 = orientation(p1, p2, p4)            o3 = orientation(p3, p4, p1)            o4 = orientation(p3, p4, p2)
            # General case            if o1 != o2 and o3 != o4:                return True
            return False
        def has_crossed_lines(points):            """Check if a quadrilateral has crossed lines."""            p1, p2, p3, p4 = points            return (                do_segments_intersect(p1, p2, p3, p4) or  # Check if line 1-2 intersects with line 3-4                do_segments_intersect(p2, p3, p4, p1)     # Check if line 2-3 intersects with line 4-1            )
        return has_crossed_lines(self.points)
    def _parallel_sides(self):        """        Counts the number of pairs of parallel sides.
        Returns:            int: Number of pairs of parallel sides (0, 1, or 2).        """        def is_parallel(p1, p2, p3, p4):            """            Checks if lines (p1, p2) and (p3, p4) are parallel.            """            return (p2[1] - p1[1]) * (p4[0] - p3[0]) == (p2[0] - p1[0]) * (p4[1] - p3[1])
        parallel_count = 0        if is_parallel(self.points[0], self.points[1], self.points[2], self.points[3]):            parallel_count += 1        if is_parallel(self.points[1], self.points[2], self.points[3], self.points[0]):            parallel_count += 1        return parallel_count
    def _classify(self):        """        Classifies the type of quadrilateral.
        Returns:            str: Type of quadrilateral.        """        if not self._is_noncollinear():            return "Not a quadrilateral (points are collinear)"
        # Precompute distances        d = [            self._distance(self.points[i], self.points[(i + 1) % 4])            for i in range(4)        ]        diag1 = self._distance(self.points[0], self.points[2])        diag2 = self._distance(self.points[1], self.points[3])
        # Check if crossed        if self._is_crossed():            # Check for bowtie or hourglass            if d[0] == d[2] and d[1] == d[3]:                return "Bowtie (Crossed Quadrilateral)"            if d[0] != d[2] and d[1] != d[3]:                return "Hourglass (Crossed Quadrilateral)"            return "Crossed Quadrilateral"
        # Check convexity        is_convex = self._is_convex()        if not is_convex:            # Check for dart            if d[0] == d[3] and d[1] == d[2]:                return "Dart (Concave Quadrilateral)"            return "Concave Quadrilateral"
        # Check properties        if d[0] == d[2] and d[1] == d[3]:  # Opposite sides equal            if diag1 == diag2:  # Diagonals equal                if d[0] == d[1]:                    return "Square (Convex)"                return "Rectangle (Convex)"            if d[0] == d[1]:                return "Rhombus (Convex)"            return "Parallelogram (Convex)"        elif (d[0] == d[2] or d[1] == d[3]) and not (d[0] == d[1] == d[2] == d[3]):            return "Trapezium (Convex)"        elif d[0] == d[1] == d[2] == d[3]:            return "Rhombus (Convex, Degenerate as Square)"
        return "Irregular Quadrilateral (Convex)"

    def _categorise(self):        """        Categorises the quadrilaterals properties.
        Returns:            set of str: Properties of the quadrilateral.        """        types = []
        # Check convexity        is_convex = self._is_convex()        if is_convex:            types.append("Convex")        else:            types.append("Concave")
        # Check if crossed        if self._is_crossed():            types.append("Crossed")
        # Check for angles > 180°        reflex_angles = [            self._angle(self.points[i], self.points[(i + 1) % 4], self.points[(i + 2) % 4]) > 180            for i in range(4)        ]        if any(reflex_angles):            types.append("Reflex")
        # Check number of right angles        right_angle_count = sum(            abs(self._angle(self.points[i], self.points[(i + 1) % 4], self.points[(i + 2) % 4]) - 90) < 1e-6            for i in range(4)        )        types.append(f"{right_angle_count} Right Angles")
        # Check number of equal sides        d = [            self._distance(self.points[i], self.points[(i + 1) % 4])            for i in range(4)        ]        unique_lengths = set(d)        if len(unique_lengths) == 1:            types.append("Four Equal Sides")        elif len(unique_lengths) == 2:            if d[0] == d[2] and d[1] == d[3]:                types.append("Two Pairs of Equal Sides")            else:                types.append("Two Touching Equal Sides")
        # Check number of parallel sides        parallel_sides = self._parallel_sides()        if parallel_sides == 2:            types.append("Two Pairs of Parallel Sides")        elif parallel_sides == 1:            types.append("One Pair of Parallel Sides")        elif parallel_sides == 0:            types.append("No Parallel Sides")
        return set(types)

    def classify(self):        """        Aligns points, validates them, and classifies the quadrilateral.
        Returns:            str: Classification of the quadrilateral.        """        features = self._categorise()        quads = [name                 for name, needed in self.quad2features.items()                 if needed.issubset(features)]        return quads

# %%# Example usage of visualize_test_cases functiontest_cases = [  # ([points], "classification", "description")    ([(1, 1), (7, 3), (6, 6), (4, 9)], "Convex", "Non crossing, all angles <180"),    ([(1, 1), (7, 1), (7, 4), (1, 4)], "Rectangle1", "Non-crossing, all ang == 90, opp sides =="),    ([(1, 1), (1, 7), (4, 7), (4, 1)], "Rectangle2", "Non-crossing, all ang == 90, all sides =="),    ([(0, 3), (3, 0), (9, 6), (6, 9)], "Rectangle3", "Non-crossing, all ang == 90, opp sides ==, rotated"),    ([(1, 1), (7, 1), (7, 7), (1, 7)], "Square1", "Non-crossing, all ang == 90, opp sides =="),    ([(1, 5), (4, 1), (8, 4), (5, 8)], "Square2", "Non-crossing, all ang == 90, all sides ==, rotated"),    ([(1, 1), (6, 1), (9, 5), (4, 5)], "Rhombus", "Non-crossing, ang !=90, opp sides || and all sides =="),    ([(1, 1), (6, 1), (9, 10), (4, 10)], "Parallelogram", "Non-crossing, opp sides || and opp sides =="),    ([(1, 1), (7, 1), (5, 5), (2, 5)], "Trapezium1", "Non-crossing, at least one set of opposite || sides"),    ([(1, 1), (5, 3), (5, 6), (1, 7)], "Trapezium2", "Non-crossing, at least one set of opposite || sides"),    ([(1, 4), (5, 1), (7, 4), (5, 7)], "Kite1", "Non crossing, No interior ang >180, two non== sets of == lines that touch"),    ([(4, 1), (1, 5), (4, 11), (7, 5)], "Kite2", "Non crossing, No interior ang >180, two non== sets of == lines that touch"),    ([(1, 1), (5, 5), (7, 4), (4, 8)], "Reflex", "Non crossing, one interior ang >180"),    ([(1, 4), (7, 1), (4, 4), (7, 7)], "Dart1", "Non crossing, one interior ang >180, two non== sets of == lines that touch"),    ([(4, 1), (1, 7), (4, 4), (7, 7)], "Dart2", "Non crossing, one interior ang >180, two non== sets of == lines that touch"),    ([(1, 1), (6, 6), (7, 2), (3, 9)], "Crossed", "Crossing"),    ([(1, 1), (7, 7), (7, 3), (1, 9)], "Truss1", "Crossing, crossing lines ==, none-crossing lines ||"),    ([(1, 1), (7, 7), (3, 7), (9, 1)], "Truss2", "Crossing, crossing lines ==, none-crossing lines ||"),    ([(1, 1), (7, 9), (7, 1), (1, 9)], "Bowtie1", "Crossing, crossing lines ==, none-crossing lines || and =="),    ([(1, 1), (9, 7), (1, 7), (9, 1)], "Bowtie2", "Crossing, crossing lines ==, none-crossing lines || and =="),    ([(0, 3), (9, 6), (6, 9), (3, 0)], "Bowtie3", "Crossing, crossing lines ==, none-crossing lines || and ==, rotated"),]
# %%if 0:    ...        # %%    from  matplotlib import pyplot as plt
    def visualize_test_cases(test_cases):        """        Visualizes the test cases and labels them with their classification.
        Parameters:            test_cases (list of tuples): List of tuples, each containing points and classification.        """        fig, axs = plt.subplots(3, 7, figsize=(15, 6))        axs = axs.flatten()
        # Determine the global axis limits        all_points = [point for points, __classification, _description in test_cases for point in points]        xs, ys = zip(*all_points)        x_min, x_max = min(xs), max(xs)        y_min, y_max = min(ys), max(ys)
        for ax, (points, classification, _description) in zip(axs, test_cases):            points = points[::]            points.append(points[0])  # To complete the quadrilateral loop            xs, ys = zip(*points)            ax.plot(xs, ys, marker='o')
            ax.set_title(classification)            ax.set_xticks([])            ax.set_yticks([])            ax.set_xlim(x_min - 1, x_max + 1)            ax.set_ylim(y_min - 1, y_max + 1)
        plt.tight_layout()        plt.show()
    visualize_test_cases(test_cases)
# %%head = \'NAME           CONVEX  REFLEX  CROSSING    >180DEG     =90DEG  SIDES==     PARALLEL'.strip().split()body = [line.strip().split() for line in '''Convex          True    False   False           0       -         -           -Rectangle       True    False   False           0       4       2,pairs     2,pairsSquare          True    False   False           0       4       4           2,pairsRhombus         True    False   False           0       0       4           2,pairsParallelogram   True    False   False           0       0       2,pairs     2,pairsTrapezium       True    False   False           -       -       -           1,pairKite            True    False   False           0       0       2,Tpairs    0Reflex          False   True    False           1       0       -           -Dart            False   True    False           1       0       2,Tpairs    0Crossed         False   False   True            -       -       -           -Truss           False   False   True            -       -       -           1,pairBowtie          False   False   True            -       -       2,pairs     1,pair
# KEY## CONVEX        not REFLEX and not CROSSED# REFLEX        One angle greater than 180 degrees# CROSSING      two lines in figure cross over# >180DEG       Interior angles greater than 180 degrees# =90DEG        Interior right-angles# SIDES==       Number of equal length sides# PARALLEL      Number of parallel sides## -             Don't care# Tpairs        Pair of equal length sides Touching at one shared point
'''.strip().splitlines() if line.strip() and not line.startswith('#')]# %%
#for points, classification, description in test_cases[4:5]:#for points, classification, description in test_cases[-1:]:quad2features = {}for points, classification, description in test_cases:    quad2features[classification] = QuadrilateralClassifier(points).classify()    print(f"\n{classification}\n  {description}\n  {points}")    print(f"  {QuadrilateralClassifier(points).classify() =}")


IS AI Worth it?

I was surprised by just how much AI will do on early prompts, but days are then spent honing and checking, again and again.. Some things, like the has_crossed_lines function just could not be done correctly by chatgpt. It continuousely got the line segments and points of the line segments wrong. In the end I had to cut-n-paste the correct points andintersection checks into my query for it to then "generate" the right function. I had to know what I was doing to have first found the error.

One needs to know more, or find out more, than the AI to spot mistakes. The AI can help with this by asking it to explain parts of its code then searching for corroborating evidence, or for limitations in the algorithms it has chosen.

The AI's can't calculate worth a damn, and this can affect their orderings too. It helps if the AI interface can not only generate code, but also run it. Asking AI to generate points for various types of quadrilateral was error prone, leading me to do it without AI aid.

Free AI accounts have limits! I had to wait till the next day on several occasions after using up my free time.


In summary, I will carry on trying out AI, hopefully both it and I will get better!

Categories: FLOSS Project Planets

Real Python: Learn From 2024's Most Popular Python Tutorials and Courses

Wed, 2025-01-01 09:00

As we welcome 2025, it’s the perfect time to reflect on the exciting advancements the Python community made in 2024. Python 3.13 stood out as a milestone release, introducing ground-breaking experimental features like free threading and a just-in-time (JIT) compiler, both designed to boost performance.

The REPL also received an upgrade, with a modern redesign that enhances the coding experience for developers of all levels. These updates, along with other cool new features, have reinforced Python’s reputation as a continually evolving and versatile language.

Python’s influence continued to grow in 2024. It secured the top spot in IEEE Spectrum’s annual ranking of programming languages, while the 2023 Python Developers Survey further highlighted its widespread popularity and global appeal.

Other notable developments include the release of Astral’s uv project manager and major releases of both NumPy and Polars. Plus, the release of Python 3.14 Alpha 1 introduced lazy evaluation for annotations, fixing a long-standing pain point in Python’s type hinting capabilities.

Here at Real Python, we’re excited to showcase the tutorials and video courses that engaged our readers and viewers throughout 2024. From mastering Python basics to building innovative projects, sharpening data science skills, and optimizing your workflow, this list covers a wide range of topics to help you grow as a Python developer.

Take a moment to explore the highlights of the year that inspired our community to learn, create, and achieve more with Python.

Join Now: Click here to join the Real Python Newsletter and you'll never miss another Python tutorial, course update, or post.

Set Up Your Work Environment

Before getting down to the business of coding, it’s important to have a well-organized workspace that boosts productivity and keeps frustrations at bay. Whether you’re customizing your code editor, setting up virtual environments, or managing project dependencies, the right tools can make all the difference.

With these resources, you can learn how to set up a Python environment that works for you:

By learning how to set up your Python environment correctly from the start, you’ll save time, reduce headaches, and enjoy a smoother, more pleasant coding experience.

Get Back to Basics

No matter where you are in your Python journey, revisiting the basics can sharpen your skills and improve your coding habits. Building a solid foundation in topics like dictionaries, functions, loops, lists, and tuples will give you what it takes to write clean and maintainable code.

In these exercise courses, you’ll practice Python fundamentals to help solidify your understanding:

Working through these courses will give you the clarity you need to explore more advanced programming topics.

Familiarize Yourself With Functions Read the full article at https://realpython.com/popular-python-tutorials-2024/ »

[ 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 ]

Categories: FLOSS Project Planets

Tryton News: Newsletter January 2025

Wed, 2025-01-01 02:00

During the last month we continued to fix bugs, improve the behaviour of things, and resolve performance issues - building on the other changes since our last release. We also added some new features which you can find out more about in this newsletter.

For an in depth overview of Tryton development you can take a look at our issue tracker and also see the issues and merge requests filtered by label.

Changes for the User Sales, Purchases and Projects

It is common, for marketing purposes, to show the sale amount before the promotion and also the amount once the promotion has been applied. So we’ve now added the original amounts before the promotion.

We’ve strengthened the process of confirming sales with a payment and added a scheduled task to confirm sales based on payments.

Accounting, Invoicing and Payments

We now use the payment-element for Stripe checkouts.

To help users decide if they really want to overrule a credit limit, we now show the amount the credit limit has been exceeded by, the dunning level, the amount and the account code.

We’ve now added reporting with latest date and amount per statement journal.

Stock, Production and Shipments

The move description and description on the general ledger line have been merged together. As the move origin is a fall-back of the line origin, the description is now calculated as the move description.

Most of the time users are only interested by the storage, view and warehouse location types, so we filter out the other location types by default now.

User Interface

We’ve now added the relation to a foreign model for relational fields listed in Administration → Models → Models.

The search on model.fields.Char and model.fields.Text in the client will give different results when using Text: = or Text: ="" depending on whether the text is NULL or an empty string. So we now convert NULL values for Char and Text fields to an empty string when searching for Char or Text field values.

We now display the link symbol when hovering over a many2one or reference column in tree views.

We now prevent iOS input zooming in Sao.

The icons that we use are now more explicit:

Form List Form List Tree System Data and Configuration

We updated the country subdivision types:

More (click for more details)

We now support searching on subdivision codes when searching a pattern.

We’ve merged the Colombian Business Tax Number (co_rut) tax identifier into the Colombian Identity Code (co_nit).

We’ve also updated the tax identifiers:

More (click for more details) New Documentation

The contents of the Migration Topic have been moved into the Migration section of the Tryton documentation.

New Releases

We released bug fixes for the currently maintained long term support series
7.0 and 6.0, and for the penultimate series 7.4 and 7.2.

Security

We enforce the record rules for resources now like we did with model access rules.

We now also use the party access rules for address, contact mechanism and identifier.

Changes for the System Administrator

We now log the request-duration at the wsgi-app-level instead of the with_pool level to get more accurate timings.

Changes for Implementers and Developers

We now test that the on_change_with getter has the same name as the Function-field using it.

Updating XML-records which could be modified manually by the users is a complex task. In general the process works automatically, but sometimes the user has to manually check and decide whether to synchronize the model data from the menu entry Administration → Models → Data.
As we no longer import data like countries or currencies from the XML files, the whole mechanism is no longer necessary.
So we now, in general, forbid the manual modification of XML introduced data and always synchronise the XML-data with the database, even if it was modified. The only exception to this is if the noupdate flag is set on the XML data, in this case we just apply the XML-data once when the module is activated and leave the maintenance of that data to the users.

We now propagate notifications to the parent group on screens without an info bar, like a One2Many with an editable list.

Also we now call on_change_notify for fields updated by on_change and on_change_with methods.

We now support object-instances in addition to object-ids as default values.

We’ve added the metadata columns, by default, to ModelSQL based on table queries:

More (click for more details)

The data is now included as part of the ir.model.Report header key.

We now test that ids are of the right type when instantiating ModelStorage.

We now validate integer digits when they are not None.

We support EXTRACT from INTERVAL in the SQLite backend to be able to extract epoch durations.

Both msg_gettext and msg_ngettext have been added to the Report context.

Authors: @dave @pokoli @udono

1 post - 1 participant

Read full topic

Categories: FLOSS Project Planets

PyCoder’s Weekly: Issue #662 (Dec. 31, 2024)

Tue, 2024-12-31 14:30

#662 – DECEMBER 31, 2024
View in Browser »

A lot has happened in the Python ecosystem in 2024 and with our final issue of the year, the featured section contains the top five most clicked articles of the year. This is in addition to your usual articles, discussions and projects of the week.

Thanks for continuing to be with us at PyCoder’s Weekly. I’m sure 2025 will be just as interesting as 2024. And if in 2025 you come across a cool article or a project you think deserves notice, send it to us.

Happy Pythoning!

— The PyCoder’s Weekly Team
    Christopher Trudeau, Curator
    Dan Bader, Editor

#1: Build Captivating Display Tables With Great Tables

Do you need help making data tables in Python look interesting and attractive? How can you create beautiful display-ready tables as easily as charts and graphs in Python? This week on the show, we speak with Richard Iannone and Michael Chow from Posit about the Great Tables Python library.
REAL PYTHON podcast

#2 Module Itertools Overview

This article proposes the top 3 iterators that are most useful from the module itertools, classifies all of the 19 iterators into 5 categories, and then provides brief usage examples for all the iterators in the module itertools.
RODRIGO GIRÃO SERRÃO

#3: Customize VS Code Settings

In this course, Philipp helps you customize your Visual Studio Code settings to switch from a basic cluttered look to a clean presentable look. This is not just pleasant on the eyes, but also gives you a nice user interface if you want to share on a zoom call or screen recording.
REAL PYTHON video

#4: Modern Good Practices for Python Development

This is a very detailed list of best practices for developing in Python. It includes tools, language features, application design, which libraries to use an more.
STUART ELLIS

#5: Asyncio Event Loop in Separate Thread

Typically, the asyncio event loop runs in the main thread, but as that is the one used by the interpreter, sometimes you want the event loop to run in a separate thread. This article talks about why and how to do just that.
JASON BROWNLEE

🎓 Master Python’s Core Principles (Live Course)

Transform your Python skills in just eight weeks, with live expert guidance. No more second-guessing if your code is “Pythonic enough.” Master Python’s object model, advanced iteration, decorators, and clean system design through live instruction and hands-on practice in a small group setting:
REAL PYTHON sponsor

Textualize 1.0 Released

GITHUB.COM/TEXTUALIZE

Discussions Ask HN: Predictions for 2025?

HACKER NEWS

Ask HN: Who’s Building on Python NoGIL?

HACKER NEWS

Articles & Tutorials How to Remove Items From Lists in Python

In this how-to guide, you’ll explore different ways to remove items from lists in Python. Using practical examples, like managing a library book list and a contact book application, you’ll learn efficient techniques for handling list item removal.
REAL PYTHON

Sentry Turret Straight Out of the ‘Portal’ Franchise

“Reckless_commenter has created a Raspberry Pi-powered sentry turret that looks and sounds just like the creepy machines found in the ‘Portal’ franchise.” Logic and sound effects managed through the PyGame library.
TOM'S HARDWARE

Python in 2024: Faster and More Popular Than Ever

A summary of some of the changes in Python 2024, including the performance improvements from the no-GIL and JIT experiments, dead battery removal, and how your favorite language is topping the charts.
SERDAR YEGULALP

Top Python Libraries of 2024

For the past ten years, Tyrolabs has put together a list of their favorite Python libraries of the year. This list includes ten general purpose libraries and ten more specific to AI/ML and Data.
DESCOINS, BUDELLI, & ALFARO

Python Packaging: Why We Can’t Have Nice Things

A long explanation on the state of Python packaging and why it is the way it is. It covers what has changed with more recent PEPs and why things are still complicated.
KARL KNECHTEL

Django Ninja

Talk Python to Me interviews Vitaliy Kucheryaviy, the creator of Django Ninja, a FastAPI inspired, decorator based API library for Django.
KENNEDY & KUCHERYAVIY podcast

Deploying a Django App to AWS ECS With AWS Copilot

This tutorial looks at how to deploy a Django app to AWS Elastic Container Service (ECS) using AWS Copilot.
NIK TOMAZIC • Shared by Michael Herman

Confessions of a Django Dev: Mistakes To Avoid in Production

This post covers some of the common mistakes you might make when taking a Django project into production.
RAM MEEGADA

Projects & Code wowy: E-Commerce Platform Built With Django

GITHUB.COM/MANJURULHOQUE

A Python-Powered English Vocabulary Builder

GITHUB.COM/PIGLEI • Shared by piglei

python-hiccup: HTML Using Python Data Structures

GITHUB.COM/DAVIDVUJIC • Shared by David Vujci

psutil: Cross-Platform Lib for Process and System Monitoring

GITHUB.COM/GIAMPAOLO

prophet: Forecast for Time Series Data

GITHUB.COM/FACEBOOK

Events Canberra Python Meetup

January 2, 2025
MEETUP.COM

Sydney Python User Group (SyPy)

January 2, 2025
SYPY.ORG

Melbourne Python Users Group, Australia

January 6, 2025
J.MP

PyBodensee Monthly Meetup

January 6, 2025
PYBODENSEE.COM

Python North East

January 8, 2025
PYTHONNORTHEAST.COM

Happy Pythoning!
This was PyCoder’s Weekly Issue #662.
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 ]

Categories: FLOSS Project Planets

Real Python: Building HTTP APIs With Django REST Framework

Tue, 2024-12-31 09:00

REST is a loosely defined protocol for listing, creating, changing, and deleting data on your server over HTTP. The Django REST framework (DRF) is a toolkit built on top of the Django web framework that reduces the amount of code you need to write to create REST HTTP API interfaces.

In this course you’ll learn about:

  • The REST protocol
  • DRF Serializers and how to use them with Django objects
  • Using Django views and DRF ViewSet classes to create REST end-points
  • Multiple flavors of renderers and how to control their output
  • Specifying permissions and limiting who can see what data in your REST API

[ 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 ]

Categories: FLOSS Project Planets

Paolo Melchiorre: My 2024 in review

Mon, 2024-12-30 18:00

A quick review of my 2024 done in a hurry, trying to remember the many experiences I had, the people I met, the places I visited and the changes I went through.

Categories: FLOSS Project Planets

Zero to Mastery: Python Monthly Newsletter 💻🐍

Sat, 2024-12-28 23:42
61st issue of Andrei Neagoie's must-read monthly Python Newsletter: Octoverse Results Reveal, GPU Computing, and much more. Read the full newsletter to get up-to-date with everything you need to know from last month.
Categories: FLOSS Project Planets

TestDriven.io: Deploying a Django App to AWS ECS with AWS Copilot

Sat, 2024-12-28 17:28
This tutorial looks at how to deploy a Django app to AWS ECS with AWS Copilot.
Categories: FLOSS Project Planets

Spyder IDE: Spyder 6 project lead: Remote development interface and application UI/UX improvements

Fri, 2024-12-27 19:00
Spyder's lead maintainer, Carlos Cordoba, shares his insights on the projects and features he helped develop for Spyder 6.0, particularly UI/UX and where the IDE is headed next.
Categories: FLOSS Project Planets

Daniel Roy Greenfeld: TIL: yield from

Fri, 2024-12-27 18:06
A variant of the yield statement that can result in more concise code.
Categories: FLOSS Project Planets

Kushal Das: pastewindow.nvim my first neovim plugin

Fri, 2024-12-27 03:19

pastewindow is a neovim plugin written in Lua to help to paste text from a buffer to a different window in Neovim. This is my first attempt of writing a plugin.

We can select a window (in the GIF below I am using a bash terminal as target) and send any text to that window. This will be helpful in my teaching sessions. Specially modifying larger Python functions etc.

I am yet to go through all the Advent of Neovim videos from TJ DeVries. I am hoping to improve (and more features) to the plugin after I learn about plugin development from the videos.

Categories: FLOSS Project Planets

Talk Python to Me: #491: DuckDB and Python: Ducks and Snakes living together

Fri, 2024-12-27 03:00
Join me for an insightful conversation with Alex Monahan, who works on documentation, tutorials, and training at DuckDB Labs. We explore why DuckDB is gaining momentum among Python and data enthusiasts, from its in-process database design to its blazingly fast, columnar architecture. We also dive into indexing strategies, concurrency considerations, and the fascinating way MotherDuck (the cloud companion to DuckDB) handles large-scale data seamlessly. Don’t miss this chance to learn how a single pip install could totally transform your Python data workflow!<br/> <br/> <strong>Episode sponsors</strong><br/> <br/> <a href='https://talkpython.fm/sentry'>Sentry Error Monitoring, Code TALKPYTHON</a><br> <a href='https://talkpython.fm/citizens'>Data Citizens Podcast</a><br> <a href='https://talkpython.fm/training'>Talk Python Courses</a><br/> <br/> <h2>Links from the show</h2> <div><strong>Alex on Mastodon</strong>: <a href="https://data-folks.masto.host/@__Alex__?featured_on=talkpython" target="_blank" >@__Alex__</a><br/> <br/> <strong>DuckDB</strong>: <a href="https://duckdb.org/?featured_on=talkpython" target="_blank" >duckdb.org</a><br/> <strong>MotherDuck</strong>: <a href="https://motherduck.com/?featured_on=talkpython" target="_blank" >motherduck.com</a><br/> <strong>SQLite</strong>: <a href="https://sqlite.org/?featured_on=talkpython" target="_blank" >sqlite.org</a><br/> <strong>Moka-Py</strong>: <a href="https://github.com/deliro/moka-py?featured_on=talkpython" target="_blank" >github.com</a><br/> <strong>PostgreSQL</strong>: <a href="https://www.postgresql.org/?featured_on=talkpython" target="_blank" >www.postgresql.org</a><br/> <strong>MySQL</strong>: <a href="https://www.mysql.com/?featured_on=talkpython" target="_blank" >www.mysql.com</a><br/> <strong>Redis</strong>: <a href="https://redis.io/?featured_on=talkpython" target="_blank" >redis.io</a><br/> <strong>Apache Parquet</strong>: <a href="https://parquet.apache.org/?featured_on=talkpython" target="_blank" >parquet.apache.org</a><br/> <strong>Apache Arrow</strong>: <a href="https://arrow.apache.org/?featured_on=talkpython" target="_blank" >arrow.apache.org</a><br/> <strong>Pandas</strong>: <a href="https://pandas.pydata.org/?featured_on=talkpython" target="_blank" >pandas.pydata.org</a><br/> <strong>Polars</strong>: <a href="https://pola.rs/?featured_on=talkpython" target="_blank" >pola.rs</a><br/> <strong>Pyodide</strong>: <a href="https://pyodide.org/?featured_on=talkpython" target="_blank" >pyodide.org</a><br/> <strong>DB-API (PEP 249)</strong>: <a href="https://peps.python.org/pep-0249/?featured_on=talkpython" target="_blank" >peps.python.org/pep-0249</a><br/> <strong>Flask</strong>: <a href="https://flask.palletsprojects.com/?featured_on=talkpython" target="_blank" >flask.palletsprojects.com</a><br/> <strong>Gunicorn</strong>: <a href="https://gunicorn.org/?featured_on=talkpython" target="_blank" >gunicorn.org</a><br/> <strong>MinIO</strong>: <a href="https://min.io/?featured_on=talkpython" target="_blank" >min.io</a><br/> <strong>Amazon S3</strong>: <a href="https://aws.amazon.com/s3/?featured_on=talkpython" target="_blank" >aws.amazon.com/s3</a><br/> <strong>Azure Blob Storage</strong>: <a href="https://azure.microsoft.com/products/storage/?featured_on=talkpython" target="_blank" >azure.microsoft.com/products/storage</a><br/> <strong>Google Cloud Storage</strong>: <a href="https://cloud.google.com/storage?featured_on=talkpython" target="_blank" >cloud.google.com/storage</a><br/> <strong>DigitalOcean</strong>: <a href="https://www.digitalocean.com/?featured_on=talkpython" target="_blank" >www.digitalocean.com</a><br/> <strong>Linode</strong>: <a href="https://www.linode.com/?featured_on=talkpython" target="_blank" >www.linode.com</a><br/> <strong>Hetzner</strong>: <a href="https://www.hetzner.com/?featured_on=talkpython" target="_blank" >www.hetzner.com</a><br/> <strong>BigQuery</strong>: <a href="https://cloud.google.com/bigquery?featured_on=talkpython" target="_blank" >cloud.google.com/bigquery</a><br/> <strong>DBT (Data Build Tool)</strong>: <a href="https://docs.getdbt.com/?featured_on=talkpython" target="_blank" >docs.getdbt.com</a><br/> <strong>Mode</strong>: <a href="https://mode.com/?featured_on=talkpython" target="_blank" >mode.com</a><br/> <strong>Hex</strong>: <a href="https://hex.tech/?featured_on=talkpython" target="_blank" >hex.tech</a><br/> <strong>Python</strong>: <a href="https://www.python.org/?featured_on=talkpython" target="_blank" >www.python.org</a><br/> <strong>Node.js</strong>: <a href="https://nodejs.org/?featured_on=talkpython" target="_blank" >nodejs.org</a><br/> <strong>Rust</strong>: <a href="https://www.rust-lang.org/?featured_on=talkpython" target="_blank" >www.rust-lang.org</a><br/> <strong>Go</strong>: <a href="https://go.dev/?featured_on=talkpython" target="_blank" >go.dev</a><br/> <strong>.NET</strong>: <a href="https://dotnet.microsoft.com/?featured_on=talkpython" target="_blank" >dotnet.microsoft.com</a><br/> <strong>Watch this episode on YouTube</strong>: <a href="https://www.youtube.com/watch?v=3wGeadcKens" target="_blank" >youtube.com</a><br/> <strong>Episode transcripts</strong>: <a href="https://talkpython.fm/episodes/transcript/491/duckdb-and-python-ducks-and-snakes-living-together" target="_blank" >talkpython.fm</a><br/> <br/> <strong>--- Stay in touch with us ---</strong><br/> <strong>Subscribe to Talk Python on YouTube</strong>: <a href="https://talkpython.fm/youtube" target="_blank" >youtube.com</a><br/> <strong>Talk Python on Bluesky</strong>: <a href="https://bsky.app/profile/talkpython.fm" target="_blank" >@talkpython.fm at bsky.app</a><br/> <strong>Talk Python on Mastodon</strong>: <a href="https://fosstodon.org/web/@talkpython" target="_blank" ><i class="fa-brands fa-mastodon"></i>talkpython</a><br/> <strong>Michael on Bluesky</strong>: <a href="https://bsky.app/profile/mkennedy.codes?featured_on=talkpython" target="_blank" >@mkennedy.codes at bsky.app</a><br/> <strong>Michael on Mastodon</strong>: <a href="https://fosstodon.org/web/@mkennedy" target="_blank" ><i class="fa-brands fa-mastodon"></i>mkennedy</a><br/></div>
Categories: FLOSS Project Planets

Matt Layman: Optimizing SQLite - Building SaaS #210

Thu, 2024-12-26 19:00
In this episode, when worked on the newly migrated JourneyInbox site and focused on the database. Since me moved from Postgres to SQLite, I needed to make sure that SQLite was ready for users. We examined common configuration to optimize the database and applied that config to JourneyInbox.
Categories: FLOSS Project Planets

Armin Ronacher: Reflecting on Life

Wed, 2024-12-25 19:00

Last year I decided that I want to share my most important learnings about engineering, teams and quite frankly personal mental health. My hope is that those who want to learn from me find it useful. This is a continuation to this.

Over the years, I've been asked countless times: “What advice would you give to young programmers or engineers?” For the longest time, I struggled to answer. I wasn't sure I had anything definitive or profound to offer. And truthfully, even now, I'm not convinced I have enough answers. But as I've reflected on my journey to here, I've formulated some ideas that I believe are worth sharing — if only to provide a bit of guidance to those just starting out. For better or worse, I think those things are applicable regardless of profession.

My core belief is that fulfillment and happiness comes from deliberate commitment to meaningful work, relationships, and personal growth and purpose. I don't claim that these things can be replicated, but they worked for me and some others, so maybe they can be of use for you.

Put Time In

Putting time into work and skills — and by that truly investing oneself — is always worth it.

Whether it's working on a project, solving a difficult problem, or even refining soft skills like communication, the act of showing up and putting in the hours is essential. Practice makes perfect, but more so it's all about progress rather than perfection. Each hour you spend iterating, refining, failing and retrying brings you closer to excellence. It doesn't always feel that way in the moment but when you look back at what you did before, you will see your progress. And that act of looking back, and seeing how you improved, is immensely rewarding and in turn makes you enjoy your work.

I did not start out enjoying programming, not at all. I had a friend in school who was just better than me at everything. It felt demotivating. Programming turned out to be a necessary tool that I had to build things and to share with others, and through that, I eventually ended up enjoying it.

There is a narrative that working hard is inherently bad for your health or that long hours lead to burnout. I disagree. It's not about how many hours you put in, but about the enjoyment and quality of the work you're doing. Still some of my most favorite memories were some all-nighters I did when I was younger working on something. It wasn't even necessarily on projects that ended up meaningful or successful, but it was the act in itself. When you find joy in what you're building in the moment, work does not feel like a burden. Instead it feels exciting and exhilarating. These memories, that some might describe as unhealthy are some of my most pleasant ones.

Work And The Man

The key isn't avoiding hard work but finding meaning in it. Practice and effort, when coupled with a sense of purpose, not only make you better at what you do but also make the journey itself fulfilling. There is one catch however, and that is that your payout should not just be your happiness in the moment, but it should be long lasting.

The best way to completely destroy your long term satisfaction is if the effort you are putting into something is not reciprocated or the nature of the work feels meaningless. It's an obvious privilege to recommend that one shall not work for exploitative employers but you owe yourself to get this right. With time you build trust in yourself, and the best way to put this trust to use, is to break out of exploitative relationships.

If you end up doing things you do not believe in, it will get to you. It will not just demotivate you and make you unhappy at work, it will eventually make every hour you spent miserable and eventually get to your health.

Other than sleeping, work is what you spent the most time with for a significant portion of your life. If that is not fulfilling a core pillar of what can provide happiness is not supporting you. I have seen people advocate for just not caring to fix the work aspect, instead to work less and spend more free time. I have not found that to work for me. Work needs to be fulfilling, even if work is just a few hours a day.

Dare To Commit

Life isn't about sampling everything; it’s about making deliberate choices and committing to the ones that matter. You don't need to date twenty people to find the right partner, nor do you need a network of hundred acquaintances to succeed. Similarly, you don't need to work at ten different companies to build a meaningful career. Those things can be hugely beneficial, don't get me wrong, but you can do more with less too. When you focus on taking one step at a time, choosing the best option available to you in that moment you can accomplish great things. Feel free to look to others for inspiration, but do not to compare what they have versus what you don't. Nothing good will come from that. Everyone's journey is unique, shaped by the opportunities they encounter and the paths they decide to follow. Value grows not with the breadth of options explored but with the depth of commitment to the path you've chosen.

Just as mastering a skill pays dividends, so does committing on your personal or professional journey. Even if the world around you shifts — like the rise of AI in software engineering — your experience and expertise aren't wasted. Your gained experience makes it much easier for you to adjust course and it will give you the necessary trust in yourself. It allows to leverage what you've learned in new ways. While it's true that choosing from limited options might not always lead to the “best” possible outcome, the time and effort you invest in your chosen path can often outweigh the hypothetical gains of a different choice. In many cases, mastery and fulfillment come not from chasing endless possibilities but from fully embracing the one path you're on and making it your own.

Date to Marry

To me this happened through a lucky accident but it's something I strongly believe in. I'm an agnostic, I don't hold strong religious beliefs but I do believe in the purpose of and benefits of a lasting marriage. When my wife and I met I did not think I was in a position in my life where I had interest, desire or necessity in a deep relationship, let alone to marry. We did not live in the same country when we met and we had a long distance relationship for almost a year. That kind of relationship (particularly when visa issues are involved) has one incredible benefit: you really have to commit to your relationship. It's expensive and you spend a lot of time talking and sharing intimate thoughts. It also forces you to make a concious decision if the two of you believe it's worth continuing. You don't have the option to just “test drive” it. It forces you to figure out all the hard things upfront. Career, values, ambitions, children, the whole thing. That's a very different experience to swiping right and see what comes from it.

That one year of intensive dating changed me. I started to recognize the benefits of committing to something on a much deeper level. It taught me that vulnerability and opening yourself up can be a beautiful thing. It showed me that there was a whole part to myself I did not look into. It showed me that really committing to something, opens up a whole new world of opportunity and it allowed us to really invest into our relationship.

When you commit to your partner fully you get a lot in the process. Yes, there are risks and while you're dating, you need to figure these things out. You need to know on a fundamental level that the person you're dating is going to be the one you want to be with for a lifetime. That's not easy, because no human is perfect. Yet if that is the goal, you can poke at the parts where dragons can be. Only in situations of stress and challenge will you truly find out how the other person works and if that works for you.

I have heard people talk about “going to IKEA” for a date. I think that's a brilliant idea. Imagining a life together and struggling a bit through conflict and resolution is exactly the right way to go about it.

Having Children

Very few things have so profoundly changed me as our first child.

Seeing children grow up is such a moving experience. I enjoy being with them in moments of achievements or sadness alike and I love when they surprise me in the morning with their newfound wisdom or after school with their proud achievements. It's fun to play with them, to help them learn new things and you can do things together you haven't done since your own childhood.

I'm lucky to have kids. I grew up in a society that has largely painted a pretty dark picture about having children but I do not share those views. We knew we wanted children and I'm glad we didn't wait. You can't cheat nature on this thing and at the present state of scientific development, things still are much harder if you try to have children late.

Nothing will ever be perfect. There were sleepless nights, there are the sicknesses that come in autumn with daycare and school. You need to arrange things in different ways than you were used to. You will hear a lot from parents and educators about what is is like to have children but the reality however is that I don't think it's possible to know how it is to have kids until you do. In a way you have to jump into the cold water and there is no going back.

There are some important prerequisites though, but I think differently about them now then I did before. I don't think that you need a lot of money or a stable career, but you need to have your marriage and house in order. The most important thing I learned about having children is that you first and foremost need to take care of yourself. Any stress you experience, you will pass on to your children and it will harm them in the process. This is really important. There are lots of dysfunctional households and bad parents and you should not have children if you can't take care of yourself.

Those are the important parts, but then there are superficial issues. I almost entirely opted out of reading parental advise books because I could feel how they stress me out. I found it easier to take on challenges as they arrive naturally. If you have a loving relationship with your spouse you can extend that to your children and learn how to deal with challenges calmly (or as calmly as you can). You need to be there for each other. Your children will not become more successful because you mastered breast feeding on day one or if you taught them sign language before they can talk. They will however be significantly better off if you can jump on a moment's notice to take care of your spouse or child when something goes wrong.

Our experience is unlikely to be your experience, but there are some things that are shared among parents. You grow above yourself when all the sudden become fully responsible for another human being and you can't opt out of it. It also invites you to reflect on yourself more and how you came to be the person that you are. I also don't think it makes you any less ambitious, but it changes how you define success for yourself. Your horizon opens up and it really makes you think more about the totality of your family rather than yourself.

My life isn't about perfection or constantly chasing what's next; it's about being present and committing to the things that matter. This is also what I'm passing on to my children. Whatever your journey may look like, I hope you find joy, purpose, and the courage to commit fully to it and that you found something useful in my writings.

Categories: FLOSS Project Planets

Daniel Roy Greenfeld: TIL: types.SimpleNamespace is a Bunch class

Tue, 2024-12-24 22:14
Did you know that Python's types library has a bunch class implementation? How did I not see this before?!
Categories: FLOSS Project Planets

Pages