stared 3 days ago

My pet peeve (in general, not specific to UV, which I genuinely appreciate) is using comment sections for controlling code execution.

Using comments for linters and developer notes is perfectly acceptable. However, for configuration or execution-related data, a far superior pattern would be something like:

  UV_ENV = {
    "dependencies": { "requests":  "2.32.3", "pandas": "2.2.3" }
  }

This approach has clear advantages:

- It's valid Python syntax.

- It utilizes standard, easily-parsable data structures rather than ad-hoc comment parsing. It makes creation and validation smooth.

- Crucially, it adheres to a core principle: if you remove all comments from your code, it should still execute identically.

6
gorgoiler 3 days ago

I agree, but I would go a step further.

You’re using a magic constant that doesn’t do anything at runtime. It’s only there to be parsed by static analysis. In your case that’s uv doing the parsing but another tool might delete it as unused code. In the sense that it’s one thing pretending to be another, for me, it’s in the same category as a magic comment.

Instead, why not make a call to uv telling it what to do?:

  import uv

  uv.exec(
    dependencies=[“clown”],
    python=“>=3.10”,
  )

  from clown import nose
The first call can be with any old python runtime capable of locating this hypothetical uv package. The uv package sets up the venv and python runtime and re-exec(3)s with some kind of flag, say, an environment variable.

In the second runtime uv.exec is a noop because it detects the flag.

gorgoiler 3 days ago

Thanks for the link.

My counterpoints to the PEP’s arguments are (1) we’re about to run Python so we presumably have a Python parser on hand anyway; and (2) for the foreseeable future it is going to be capable of parsing all previous versions of Python.

It’s a bit fast and loose though. I can see though that it’s helpful for long term stability to have two completely separate languages for dependencies versus the actual code, with the former being far more reduced and conservative than the latter.

If you use Python4.98 triple walrus operators to say requires_version:::=“>=4.98” it would definitely be annoying for any version prior to that to not even be able to parse the requirements, let alone try to meet them.

atoav 3 days ago

So but that means instead of uv running python python runs uv now, which (I would imagine) has all kind of implications from a development perspective.

I agree that theoretically your proposed way of doing things would be conceptionally among the cleanest, but on the other hand in all kind of scripts the shebang was sort of a comment with big implications as well, so I am not sure if being dogmatic is worth it here.

stared 3 days ago

I don't agree with it the argumentation.

It might be specified that I needs to be proper JSON. And a proper JSON is much more maintainable (and extendible) than impromptu syntax (that first starts manageable, but step by stem moves into parsing hell).

skeledrew 3 days ago

One of uv's justifications is that it isn't dependent on Python, and so there's no circular bootstrap problem. Things are now at the point with uv were you tell the person you're sharing a script with: 1. Get the install command from the uv site and run it (if they don't already have it installed). 2. Run the script with uv.

Literally cannot get simpler than that. Making uv an importable means assuming Python is present or easily installed on every system, which if it were the case then uv wouldn't be becoming a thing.

loloquwowndueo 3 days ago

That makes your code depend on UV where otherwise it wouldn’t.

Remember the specification to indicate dependencies in a comment on a script is a PEP (723) and it’s tool-agnostic.

nickpsecurity 3 days ago

" In your case that’s uv doing the parsing but another tool might delete it as unused code."

That's probably the goal. It's only there for one tool. If it's not used, we want it to have no impact on the running app. Like comments.

simonw 3 days ago

Because now your code won't run unless you have installed uv previously.

Retr0id 3 days ago

Different python versions have different syntax grammars, so if the rest of your file has new syntax, and older python might not be able to execute even the first few lines.

For example if you run this on python3.6:

    print("hello")
    match 123:
        case _: pass
you won't even get a "hello".

maleldil 3 days ago

What is the problem with that? I see no reason to expect that would work.

Retr0id 3 days ago

The whole point of writing a "self-contained" script is that it should run anywhere. uv bundles its own cpython runtime(s) for this purpose, but relying on script execution prior to invocation of uv breaks this.

The trick in the featured article would allow me to drop a script written in modern python syntax on my outdated ubuntu LTS box and have it "just work", while GP's suggestion would not.

dagw 3 days ago

Instead, why not make a call to uv telling it what to do?

One important aspect to remember is that this isn't intended to be a uv specific feature. It's a (proposed) python standard feature that in the future other python package managers will implement. So whatever solution they come up with it has to work with any standard compliant package manager, not just uv.

sorenjan 3 days ago

This isn't a uv invention, uv is only using the standard PEP 723 like other tools.

https://peps.python.org/pep-0723/

stared 3 days ago

As I mentioned, it is not criticism of uv, but of this general approach.

JimDabell 3 days ago

That’s fair. I agree with other replies though that parsing and evaluating imperative code is a lot tougher and less flexible than adhering to the principle of least power and making it declarative data.

It’s also worth noting that using comments is exactly how the shebang line works in the first place. It’s just so well-ingrained after 45 years that people don’t notice that it’s a shell comment.

wavemode 3 days ago

> if you remove all comments from your code, it should still execute identically

It still -does- execute identically. Provided you install the same dependencies.

I don't see this as changing the semantics of the code itself, rather just changing the environment in which the code runs. In that respect it is no different from a `#!/bin/bash` comment at the top of a shell script.

petters 3 days ago

I completely agree. Hope something like this is eventually standardized.

Problem is that uv probably does not want to execute anything to find out dependencies, so it would have to be a very restrictive subset of python syntax.

The fact that is is needed at all of course highlights a weakness in the language. The import statements themselves should be able to convey all information about dependencies

SAI_Peregrinus 3 days ago

UV just implemented PEP 723[1], which is now PyPA Inline Script Metadata[2]. That's no longer provisional, it is standardized already! It's unfortunate that Python didn't have some non-comment way to provide this functionality.

[1] https://peps.python.org/pep-0723/

[2] https://packaging.python.org/en/latest/specifications/inline...

pedrosorio 3 days ago

> The fact that is is needed at all of course highlights a weakness in the language. The import statements themselves should be able to convey all information about dependencies

What languages convey the version of the dependencies in a script’s import statements?

stared 3 days ago

It can be specified that it is a valid, static structure before imports.

nemetroid 3 days ago

Between future statements and other imports, then?

Svoka 3 days ago

I generally agree but it literally uses shebang