And these:
- command-line access to stdlib modules (python -m <name>)
- uuid (3.12)
- json (3.14)
- random (3.13)
- sqlite3 (3.12)
- http .server (3.4)
And these:
- command-line access to stdlib modules (python -m <name>)
- uuid (3.12)
- json (3.14)
- random (3.13)
- sqlite3 (3.12)
- http .server (3.4)
Skim the "What's New in Python x.x" notes for the past few releases, there have been some handy things added:
- itertools.batched (3.12)
- access re.Match groups using [] notation (faster than group()) (3.6)
- 1_000_000 is a legal syntax for 1000000 (3.6)
- contextlib.chdir (3.11)
There's no link in this article, but if you like these pieces, many are available as phone cases and laptop skins at www.gelaskins.com/search?q=pau...
I'm excited to share this article published this week in the Artsy Shark blog, on my artistic journey with generative art (which I've been doing since the mid-1980's, so NOT AI). www.artsyshark.com/2026/01/26/f... #art #digitalart #abstractart #generativeart #fractals
Featured this week on the Artsy Shark website! Includes some of my favorite pieces, and some backstory on how they all came about.
Featured Artist Paul McGuire www.artsyshark.com/2026/01/26/f...
If you're a Python developer using Claude Code, or something similar, we just published a blog that covers 10 rules we add to our prompt for drastically improved code gen.
And we include the full prompt at the end of the post!
dagster.io/blog/dignifi...
Even though they have refactored pyparsing out of packaging, I'm proud of its prior inclusion in this core Python component.
Add `time.sleep((366 if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0) else 365)*24*60*60)` to your loop, and you can just leave it running (barring future leap seconds).
Snippet of AI instructions, available by calling `pyparsing.show_best_practices()` from Python
Example showing DeprecationWarning raised when calling pyparsing `parseString` instead of `parse_string`
TINY code example of a leap year determination function. Complete code: int is_divisible(int a, int b) { float quo := a / b; int iquo := quo; return quo = iquo; } int is_leap_year(int yr) { int div_by_400 := is_divisible(yr, 400); if div_by_400 then return 1; end int div_by_100 := is_divisible(yr, 100); if div_by_100 then return 0; end int div_by_4 := is_divisible(yr, 4); return div_by_4; } int main() { string s; int year; int this_year; read this_year; repeat read yr; if yr = "q" then return 0; end year := yr; is_leap := is_leap_year(year); write year; write " "; if is_leap then if year > this_year then write "will be"; elseif year < this_year then write "was"; else write "is"; end else if year > this_year then write "will not be"; elseif year < this_year then write "was not"; else write "is not"; end end write " a leap year"; write endl; until 0 }
This past weekend I pushed version 3.3.1 of pyparsing to PyPI (3.3.0 had a small but CI-stopping packaging blip). Includes AI instructions of pyparsing best practices. Deprecated camelCase names now throw DeprecatedWarnings. TINY teaching language parser+REPL
#PythonDevelopment #python #pyparsing
int is_divisible(int a, int b) { int quo := a / b; return quo * b = a; } int is_prime(int n) { if i = 2 || i = 3 || i = 5 || i = 7 then return 1; end if is_divisible(n, 2) then return 0; end if is_divisible(n, 3) then return 0; end if is_divisible(n, 5) then return 0; end if is_divisible(n, 7) then return 0; end /* n is prime, assuming it is not > 120 */ return 1; } int main() { int i := 2; repeat if is_prime(i) then write i; write endl; end i := i + 1; until i > 120 }
A TINY script for finding prime numbers
The TINY interpreter was written with AI assistance (Junie in PyCharm), using the AI-targeted best practices that ship with this release of pyparsing. The interpreter examples include a transcript of the AI session, including prompts and the corresponding AI plans and actions taken.
I just published pyparsing version 3.3.0b1, with some significant additions:
- example implementation of the TINY language
- performance tests with scripts to run and tabulate results using pyparsing 3.1-3.3 and Python 3.9-3.14
Github link: github.com/pyparsing/py...
#pyparsing #python #parsing
Screenshot of the logmerger utility showing a time-based merge of two large log files, with a progress bar in the lower left corner.
I just released version 0.13.0, with some significant performance speedups, and visibility to loading time while building the display DataTable. Changelog here: github.com/ptmcg/logmer...
But do you pronounce it "toople" or "tupple"?
And even a "<<=" operator!
12 prints of colorful abstract art by Paul McGuire, printed on business cards with simple white and black frames. Arranged on my kitchen table, quarter show for scale.
Mini-gallery of business card-sized prints of my artwork. Submitting these to the Bee Cave Arts Foundation's Christmas Fair. Prints by moo.com #art #digitalart #beecaveartsfoundation
With the upcoming release of #pyparsing 3.3.0, this code would emit DeprecationWarnings: nestedExpr is deprecated in favor of nested_expr, and parseString in favor of parse_string. A conversion utility ships with pyparsing to auto-update all of these pre-PEP8 names to PEP-8 compliant snake case.
`operator.attrgetter("first")` and `operator.attrgetter("last")` would work here too. `attrgetter` can also drill down into the structure of an object, like `operator.attrgetter("address.postal_code")`. Best of all, attrgetter runs at C speed, when lambdas are the Pokey Little Puppy of Python.
Get a post-it note and write CUT ME on it. Attach it to the jacket's coat tail, but do so surreptitiously to avoid embarrassment.
I pushed out version 3.3.0a1 late yesterday, so that folks with existing apps can upgrade their code from the deprecated pre-PEP8 API, or to try out the AI instructions to generate a new parser app. There is a discussion link here: github.com/pyparsing/py...
This pigment is a plot device in the book "Sacre Bleu", a fantasy/light horror with a heavy dose of art history, set in Paris during the Impressionist period.
Snippet extracted from the AI instructions that will be bundled with the upcoming 3.3.0 release of pyparsing: $ python -m pyparsing.ai.show_best_practices <!-- This file contains instructions for best practices for developing parsers with pyparsing, and can be used by AI agents when generating Python code using pyparsing. --> ## Planning - If not provided or if target language definition is ambiguous, ask for examples of valid strings to be parsed - Before developing the pyparsing expressions, define a Backus-Naur Form definition and save this in docs/grammar.md. Update this document as changes are made in the parser. ## Implementing - Import pyparsing using "import pyparsing as pp", and use that for all pyparsing references. - When writing parsers that contain recursive elements (using Forward() or infix_notation()), immediately enable packrat parsing for performance: `pp.ParserElement.enable_packrat()` (call this right after importing pyparsing). See https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html. - For recursive grammars, define placeholders with `pp.Forward()` and assign later using the `<<=` operator; give Forwards meaningful names with `set_name()` to improve errors. - Use PEP8 method and argument names in the pyparsing API ("parse_string", not "parseString"). - Do not include expressions for matching whitespace in the grammar. Pyparsing skips whitespace by default. ...
The upcoming 3.3.0 release of pyparsing will include AI instructions for best practices when using this package. They can be accessed from the command-line using `python -m pyparsing.ai.show_best_practices` (They work for human developers too.) #python #pythondev #pyparsing #ai
#art link: paulmcguireart.com
#python #pyparsing link: pypi.org/project/pypa...
Python #littletable link: pypi.org/project/litt...
I should have added the #Art and #DigitalArt hashtags (always forgetting those hashtags...) :shrug-emoji:
A digital art abstract image of blues and greens, with a ragged white bottom. The title of this piece is "wave"
A digital art abstract image, mostly white, but with a field of pale colors in the lower left corner, with a ragged diagonal border running from upper left to lower right. In the middle of this border is an irregular clump of color, as if it were a stain from multiple colors of ink, washed over the side of a snowy ridge. The title of this piece is "water music II".
Greetings, BlueSky-ers! I'm new here so I wanted to do a quick introduction. My name is Paul McGuire, I've been using Python for about 24 years. I maintain the #pyparsing package, which is about to have its release 3.3.0 next month. I also make digital art. #PythonDev #Python #Introduction
Oh, and you can type hint the hh variable as:
hh: Heapq[tuple[str, int]] = Heapq()
import heapq class Heapq[T]: def __init__(self, data: list[T] = None): self._data = data or [] heapq.heapify(self._data) def push(self, item: T): heapq.heappush(self._data, item) def pop(self) -> T: return heapq.heappop(self._data) def __len__(self) -> int: return len(self._data) def __repr__(self) -> str: return repr(self._data) hh = Heapq() hh.push(('b', 1000)) hh.push(('a', 3)) hh.push(('a', 1)) hh.push(('a', 2)) print(len(hh)) print(bool(hh)) while hh: print(hh.pop())
Output of the Heapq script: 4 True ('a', 1) ('a', 2) ('a', 3) ('b', 1000)
Here is a Heapq class wrapper around those heapq functions, if you really want to en-class-ify them.
Code is in the ALT text.
And math.hypot is not limited to 2 dimensions (or even 3).
And thanks a ton for putting this package together, it's great for documentation (and parser design review too - I cleaned up a number of the example parsers after seeing weirdness in the generated diagram), and it turns pyparsing into a much more powerful teaching tool.
The latest update is to add HREF URLs to the diagram elements that refer to their actual definitions elsewhere in the diagram so that you can interact with them, a huge help when a diagram gets big. Pull the pyparsing repo, you'll see a number of diagrams already generated in the examples directory.