HNHacker News
TopNewBestAskShowJobs

davepeck

3,216 karma · joined January 2, 2009

Independent software person in sunny Seattle. Please say hello if I can help in any way!

https://davepeck.org/about/

submissionscomments
davepeck··on GPT-5
Sam Altman, in the summer update video:

> "[GPT-5] can write an entire computer program from scratch, to help you with whatever you'd like. And we think this idea of software on demand is going to be one of the defining characteristics of the GPT-5 era."

davepeck··on Litestar is worth a look
I think Litestar is superb for building API backends. Love it; use it; only good things to say. Their Advanced Alchemy is coming along nicely, too.

Litestar of course supports old-school server-template-rendered sites, too; it even has a plugin for HTMX requests and responses. In practice, I find that the patterns that serve API endpoints so well sometimes get in the way of old-school "validate form and redirect, or re-render with errors" endpoints. In particular, Litestar has no "true" form support of its own; validation is really intended to flag inbound schema mismatch on API calls, not flag multiple individual error fields. Using `@post("/route", exception_handlers={...})` is pretty awkward for these endpoints. I'd be excited to see some better tools/DX in-the-box here.

davepeck··on Fstrings.wtf
> What can be padded is quite inconsistent.

Yes, I agree. “What works” is type dependent and Python’s builtin types don’t always behave the same way.

I know you know this, but for those who may not have run across it before and are curious:

f-strings invoke the format() builtin on the evaluated value.

In the case of None:

    >>> format(None)  # as in f"{None}"
    'None'
    >>> format(None, '<10')  # as in f"{None:<10}"
    TypeError: unsupported format string passed to NoneType.__format__
Under the hood, format() turns around and calls type(value).__format__(format_spec). Looking at the docstrings:

    >>> help(type(None).__format__)
    Help on built-in function __format__:

    __format__(self, format_spec, /)
        Default object formatter.
        
        Return str(self) if format_spec is empty. Raise Type Error otherwise.
That is, NoneType inherits Python's default object formatter, which doesn't support any format spec; if it's not empty, it's a TypeError.

On the other hand, `str` and `int` both have deep custom __format__ implementations that can do much more, like padding [0].

PS: upcoming t-strings in 3.14 add another twist to format specs: rather than being type dependent, "what works" depends on whatever code processes the Template instance. Unlike with f-strings, format() is not called automatically when t-strings are evaluated; in fact, there's no requirement that processing code does anything with the format specs at all. (Good processing code probably will want to do something!)

[0] https://docs.python.org/3/library/string.html#format-specifi...

davepeck··on Fstrings.wtf
Hah!

T-strings use the exact same syntax as f‑strings, but their “format spec” (the part after the optional :, like .2f) can effectively be anything.

That might make creating a quiz tricky? With f‑strings, Python immediately calls format() on that spec; with t‑strings, it's simply captured in Interpolation.format_spec. It's up to your code to decide whether to call format() or do something entirely different with this value.

davepeck··on I'm switching to Python and actually liking it
> But in a real production environment, for real applications, you still want to avoid it because it isn't particularly easy to create robust systems for industrial use.

This is silly and seems to discount the massive Python codebases found in "real production environment"s throughout the tech industry and beyond, some of which are singlehandedly the codebases behind $1B+ ventures and, I'd wager, many of which are "robust" and fit for "industrial use" without babysitting just because they're Python.

(I get not liking a given language or its ecosystem, but I suspect I could rewrite the same reply for just about any of the top 10-ish most commonly used languages today.)

davepeck··on Diffsitter – A Tree-sitter based AST difftool to get meaningful semantic diffs
yes, although it's sort of the same as Context-Free-Typing-sitter
davepeck··on Local-first software (2019)
No, I didn't know about it -- thank you! (EDIT: and the landscape page has lots of libraries I hadn't run across before. Neat.)
davepeck··on Local-first software (2019)
In theory, I love the local-first mode of building. It aligns well with “small tech” philosophy where privacy and data ownership are fundamental.

In practice, it’s hard! You’re effectively responsible for building a sync engine, handling conflict resolution, managing schema migration, etc.

This said, tools for local-first software development seem to have improved in the past couple years. I keep my eye on jazz.tools, electric-sql, and Rocicorp’s Zero. Are there others?

davepeck··on Salesforce/Heroku down for 8 hours
We're at 14+ hours now (06:17 UTC start; 20:52 UTC most recent update as of this writing).

The post-mortem for this is going to be quite a read. Hugops to all involved.

davepeck··on Design Pressure: The Invisible Hand That Shapes Your Code
I wrote and then quickly deleted that comment; I never want to speak negatively publicly about open source projects — projects that people work incredibly hard to build and maintain. I felt my original comment crossed that line.

In any case, there is a slide in the talk that has both the Pydantic and SQL Alchemy logos. As far as I know, there’s only one (somewhat popular) library that ties these two together. I think the speaker makes a persuasive case that data, domain, API, and other models should remain related but distinct.

davepeck··on A flat pricing subscription for Claude Code
Do you use compilers? Linker loaders? Web bundlers? Linters and formatters? Code gen for or from schema? Image editors? Memory safe or garbage collected languages?

Then you already use levers to build code.

LLMs are a new kind of tool. They’re weird and probabilistic and only sometimes useful. We don’t yet know quite how and when to use them. But they seem like one more lever for us to wield.

davepeck··on Ask HN: What are you working on? (April 2025)
Have you ever visited a Boda Borg? They’re not quite escape rooms; generally, the experiences are fast-paced. Some are puzzles; some physical challenges; some, an interesting mix. Lots of computer automation to make it all work.
davepeck··on Python’s new t-strings
My point was that library authors will need to consider this carefully. If you're writing a library where injection attacks matter, then -- long term -- you almost certainly do not want a single method that accepts `Union[str, Template]`. You probably either want to avoid accepting `str` entirely, or perhaps provide two separate methods. Some period of deprecation seems inevitable.
davepeck··on Python’s new t-strings
> If you can use a string anywhere you can use a t-string

You can't; they're different types. t-strings are not `str`

It's up to good framework/API design to take advantage of this.

davepeck··on Python’s new t-strings
> Caching parameterized prepared statements, etc.

I didn’t explicitly mention this in my post but, yes, the Template type is designed with caching in mind. In particular, the .strings tuple is likely to be useful as a cache key in many cases.

davepeck··on Python’s new t-strings
> This is such a strange take on t-strings

I understand why this seems strange at first!

As Paul mentioned, we spent quite a lot of time considering these issues as PEP 750 came together. In the end, we concluded (a) the PEP leaves open quite a few potential approaches for tools to adopt (not just the one you suggest, as others here have pointed out), and (b) it's ultimately something that the broader tooling community needs to rally around and should probably be out of scope for the PEP itself.

So, with that background in mind, I am indeed hopeful we'll see the ecosystem adapt! :-)

davepeck··on Python’s new t-strings
And $-strings (PEP 292) as well. :-)

I see each of these as distinct but overlapping; I'm (slowly) writing a guide to string formatting with all of these in mind, trying to emphasize when I'd choose one over the other. (fwiw I personally avoid % and + these days; $ is pretty uncommon in practice; f-, t-, and .format() all seem to have good unique uses.)

davepeck··on Python’s new t-strings
We pushed these questions out of the PEP to keep its scope constrained. (See https://peps.python.org/pep-0750/#mechanism-to-describe-the-...)

But yes, the PEP leaves open an important question: how will tools decide to work with common types of content in t-strings, like HTML or SQL?

There are simple approaches that can be taken in the short term (content sniffing) and more robust approaches (type annotations, perhaps) that will take time and the broader tooling community to develop.

davepeck··on Python’s new t-strings
The PEP originally started with a similar-to-javascript syntax but over time we decided it wasn't the right way to expose these ideas in Python. There's more detail about why this approach was rejected in the PEP: https://peps.python.org/pep-0750/#arbitrary-string-literal-p...
davepeck··on Python’s new t-strings
PEP 292's `string.Template` will remain; there are no plans to deprecate it.

PEP 750's `string.templatelib.Template` is a separate and unrelated type. Amongst many differences, unlike PEP 292, `Template` has a literal form too.

I'm hopeful that the confusion will be minimal; in practice, PEP 292 (aka $-strings) is used only in specialized cases, like flufl.i18n, a really deep I18N framework.

davepeck··on Python’s new t-strings
With f-strings, you cannot write code to determine which portions of the resulting `str` were static and which were dynamic; with t-strings, you can. *

(As to your initial example: it's worth considering what will happen as you compose multiple bits of HTML via nesting to generate a large final page. The developer experience may become... unideal.)

* (barring undesirable hacks with inspect, etc.)

davepeck··on Python’s new t-strings
For the reasons discussed above, I'm not sure that it will be the case for t-strings. I think it'll take a little while for frameworks/libraries to adapt (while still maintaining backward compatibility) and a while for best practices to find their way into our linting and other tools.
davepeck··on Python’s new t-strings
Hi! I wrote this. :-)

I'm a little late to the conversation (and a bit surprised to see this trending on HN) but am happy to answer any questions; I'll try to pop in throughout the day.

davepeck··on PEP 750 – Template Strings
> I can easily end up unsafely processed

I’m curious how?

davepeck··on PEP 750 – Template Strings
Yes, fib_slow() will be evaluated immediately, just like it would be if you were using an f-string.
davepeck··on PEP 750 – Template Strings
You can access .strings and .interpolations directly and avoid type checks. There is always one more string than interpolation, of which there may be zero.
davepeck··on PEP 750 – Template Strings
Yeah, they’re unrelated. (PEP 750 places its Template and Interpolation classes in the new string.templatelib)
davepeck··on PEP 750 – Template Strings
Sure, good point; I generally think of evaluation, not stringification, as the likely dominant expense. But maybe it’s sometimes the other way around?
davepeck··on PEP 750 – Template Strings
T-strings, like f-strings, are eagerly evaluated -- so in this sense, no, there's no benefit.
davepeck··on PEP 750 – Template Strings
My hope is to write some new documentation as 3.14 nears release that explains the (growing) constellation of string formatting mechanisms in Python and describes when they might each be useful. They overlap to some degree, but each has a unique twist that makes them useful in different situations. PEP 292 is going nowhere and is used, for instance, in really powerful libraries like `flufl.i18n`
← PreviousPage 2 of 18Next →