9 ms·
Now that we have another Nix post, maybe someone can enlighten me about something I've been wondering about. I'm one of the maintainers of a popular django app
by scandinavian 3y ago
Now that we have another Nix post, maybe someone can enlighten me about something I've been wondering about.
I'm one of the maintainers of a popular django application. Someone made a nix package of the project, but we've now twice gotten invalid bug reports from people using the package because the package depends on "django_4" and whenever someone updates that nix package, the package for our project breaks.
Of course we, like all other python projects, don't support using other dependency versions then the ones in the requirements.txt file. So when someone just uses a different minor version of django, stuff breaks. What's the disconnect here? Why does all nix packages that use django_4 need to use the same version, that seems super prone to breaking all kinds of stuff. Same for the other 35+ dependencies that run arbitrary versions instead of the ones defined in the requirements.txt file.
- jacereda 3y agoThe answer today would probably be to use flakes: https://nixos.wiki/wiki/Flakes https://nixos.wiki/wiki/Flakes
- hamandcheese 3y agoIt seems like Nixpkgs aims to minimize the number of package versions in use at one time. Not just nix, most package managers do, it seems (i.e. you wouldn't expect to find different minor versions of Nginx in Debian, would you?) So by that same logic, there is only one version of Django 4. It is definitely possible with Nix to use the precise versions of what's in your requirements.txt, but I'm not sure if the Nixpkgs maintainers would allow all that extra duplication upstream.
- scandinavian 3y agoI get what you are saying, but nothing you said works in practice for python packages, so not sure that I actually learned anything. Is it fair to summize that python applications with python dependencies do not really work well as nix packages and shouldn't be used?
- nrabulinski 3y agoSounds like the problem is with Python maintainers who don’t understand that breaking changes should only be made between major versions. If that’s not possible though then as sibling comment said - you can override the dependencies and the nix maintainer should make sure the package works as expected
- hfkwer 3y agoSounds like the problem could also be with Nix maintainers who don't understand that "semver" is not a universal law of nature and that not all projects and ecosystems follow it. This kind of blanket dismissal can cut both ways. Semver (the website and "spec") was created in 2009 by some guy. It's not an RFC, a standard, or anything like that. Yes, it gained widespread adoption. Yes, the guy in question is a cofounder of GitHub. So what? You cannot force it upon everyone. Python is about 20 years older than semver. Django is several years older. Should the whole ecosystem change their conventions because it's more convenient for a few people?
- nrabulinski 3y agoExcept Django site says that a.b are feature releases which should be backwards compatible except for specific exceptions. If their software truly breaks “with every update to django_4” then it’s either a problem on Django’s side or a problem in how said person uses Django
- hfkwer 3y agoI don't know if it's deliberate or a communication/comprehension problem, but you're misquoting Django's release process https://docs.djangoproject.com/en/dev/internals/release-process/ https://docs.djangoproject.com/en/dev/internals/release-proc... > * Versions are numbered in the form A.B or A.B.C. > * A.B is the feature release version number. Each version will be mostly backwards compatible with the previous release. Exceptions to this rule will be listed in the release notes. > * C is the patch release version number, which is incremented for bugfix and security releases. These releases will be 100% backwards-compatible with the previous patch release. The only exception is when a security or data loss issue can’t be fixed without breaking backwards-compatibility. If this happens, the release notes will provide detailed upgrade instructions. Going from "mostly backwards compatible with the previous release. Exceptions to this rule will be listed" to "should be backwards compatible except for specific exceptions" is quite the stretch. There are no "specific exceptions": incompatibilities can be anywhere and you need to read the release notes to know where. In semver, a minor version increment is backwards-compatible, no exception, no ifs or buts. If you want to shoehorn Django's release process into "semver", then act as if the product is called "Django 4". If the version is "Django v4.X.Y", then X is the major version number, Y is the minor version number, and there is no patch version. It should be version in Nix as "django4 vX.Y.0".
- traxys 3y agoI packaged some python applications in nixpkgs, and it seems the consensus is to try and relax the dependency so that the globally packaged version is used, but if it fails the you can override the version yourself. Though this is not done through the requirements.txt because that file does not have enough information (no integrity hash for example).
- lolinder 3y agoDoesn't this auto-upgrade behavior punch straight through the reproducibility Nix is supposed to be giving you? It's not exactly a functional build system if the results you get depend on when you download the dependencies. (I mean, I guess you could say that time is an input to the function, but that seems to miss the point.)
- assbuttbuttass 3y agoYou can think of the function inputs as: 1. All the package definitions in nixpkgs 2. Any external sources When a package is updated in nixpkgs, input #1 changes.
- lolinder 3y agoI mean, I get that, but that means that the reproducibility of my build depends on the whims of the nixpkgs maintainers, it's not a property guaranteed by the package manager.
- tymscar 3y agoYou can however define inputs that are not the whole of nixpkgs. You would use something like this and you would pin it to a very exact version and hash of a package: https://nixos.org/guides/nix-pills/nixpkgs-overriding-packages.html https://nixos.org/guides/nix-pills/nixpkgs-overriding-packag...
- deleted 3y ago[deleted]
- pxc 3y agoThe goal of a downstream Linux distribution is never to reproduce whatever builds you run on your own machine as an upstream developer. It's to produce a collection of installable software that meets various constraints and goals, like cohesion (can all be installed and managed uniformly), minimal size, easy/manageable security updates, integration (compatibility and so on). That can involve things like building the software against particular library versions mandated by downstream needs or even patching it. Some distros try hard to avoid patching upstream and some don't, and in all distros there may be cases where other priorities take precedence over the value of leaving upstream untouched. In the case of Nixpkgs and Python, the community wants to maintain a collection of Python libraries that are all interoperable, and Python doesn't support vendorization well enough to allow multiple versions of the same library in a single Python process, which is one reason for preferring singular versions of most Python libraries in Nixpkgs. The other factor is likely just reducing the maintenance across Nixpkgs by maintaining as few redundant versions within the tree as possible. If you want to control/determine the entire runtime your end users use, you have to do the packaging work required to ship them that runtime with some tooling that's capable of the reproducibility you desire. Python doesn't have one a reproducible package manager, so your options are basically creating your own Nix package (probably as a flake.nix in your repo), Docker, and Flatpak. That said, it's perfectly possibly to include multiple minor releases of Django 4 in a single snapshot of the Nixpkgs tree and maybe that should be done. Have you talked with the maintainers of your downstream package of Nixpkgs to let them know Django breaks things on minor releases, and so using different versions of Django 4 interchangeably is not tested or supported in your application?
- pxc 3y ago> It is definitely possible with Nix to use the precise versions of what's in your requirements.txt, but I'm not sure if the Nixpkgs maintainers would allow all that extra duplication upstream. They do for end user applications, but not for Python libraries. The libraries in Nixpkgs are expected to be interoperable, which requires converging certain versions because otherwise transitive dependencies on varying library versions mean that libraries used together are subject to serious, mysterious bugs. But applications packaged in Nixpkgs can pull in an exact set of libraries of their own if that's what it takes for them to run reliably.
- otabdeveloper4 3y agonixpkgs doesn't use requirements.txt for whatever reason. (That reason probably being the utter brokenness and braindead state of Python packaging; Node packages work much better.)
- the_gipsy 3y agoYou can package simple python projects, but as soon as there are too many huge deoendecies that use CPython and whatnot, it becomes impossible to generate the nix derivation. I just use imperative python-venv + pip install on those.
- goodpoint 3y agoWasn't Nix supposed to solve these problems?
- Filligree 3y agoAnd it does, for most languages. Python seems more difficult than average.
- the_gipsy 3y agoYea python is the exception. Go, rust, nodejs, have been easy to get running with specific versions and dev envs .
- goodpoint 3y ago...and yet there's tons of Python packaged in traditional distributions including Django. Nix promises to solve exactly this problem... so it's not clear what the real benefit of Nix is. EDIT: a rain of silent downvotes?
- the_gipsy 3y agoNix hasn't been a benefit when working with python for me, but again, python is the outlier. It has been a benefit for projects in other languages. I guess the reason is because python packaging/tooling varies wildly between projects, and there are a lot of bindings. BTW a colleague was setting up the python project on a non-nix machine, and also had problems with dependencies, and ultimately had to do some nasty workarounds (disabling deps/features). To me, it seems endemic.
- globular-toast 3y ago> Of course we, like all other python projects, don't support using other dependency versions then the ones in the requirements.txt file. So when someone just uses a different minor version of django, stuff breaks That sounds wrong. A Python package should not have a requirements.txt file at all. A requirements.txt file is for "freezing" and fully reproducing an environment (ie. in a virtualenv or docker container). This is useful for certain applications like deploying services or sharing notebooks etc. It is not for packages. A package should document its requirements via setup.py/pyproject.toml and do so in the loosest way possible. Django uses semver and Django apps don't generally need to pin to minor versions. Stuff like this is why people think Python packaging is worse than it really is.
- reuben364 3y agoWith my ignorance of the python packaging ecosystem, I was always under the impression that requirements.txt was the version constraints, not the lock file.
- scandinavian 3y agoThe application is not distributed via pypi, nor is it installed as a package and thus have no setup.py file. > A requirements.txt file is for "freezing" and fully reproducing an environment (ie. in a virtualenv or docker container). No, it's just for specifying which versions of packages should be installed by pip. There's no such concept of a lock file with pip. Poetry and the likes have lock files though.
- duped 3y ago> There's no such concept of a lock file with pip. There's the --require-hashes flag and the ability to specify the hashes in your requirements.txt
- SAI_Peregrinus 3y agoDjango doesn't use semver. It uses a Major.Feature.Patch release notation, not Major.Minor.Patch. Feature releases usually contain breaking changes, where SemVer minor releases never should.
- matklad 3y agoI am not an expert, but here’s my attempt at a useful comment. On the highest level, `nix` is an alternative build system. So, if someone packages your app with `nix`, there’s now extra work to keep that working, and it’s on the packager to keep it working. If they packaged your app such that it’s using different dependencies than those required, that’s a bug in the package. As a maintainer, you can help here by making it clearer what versions are accepted, and by making it easier to run the tests for a package. If we open a black box, there are two things in play here: Nix-the-build-system and nixpkgs package collection. The build system is very open ended and can specify all dependencies precisely, but it’s on the user to define what that means exactly. nixpkgs is a coherent collection of nix packages, a bit like a Linux distro. In particular, it _generally_ has one version of each package, and there’s some testing to make sure that all the packages work together. Now, to package a Python app with Nix you can either pull dependencies from nixpkgs, in which case the situation would be similar to, eg, packaging for Debian. Or you could create a hermetic environment, where an app gets an isolated copy of dependencies, specific just to the single app, a situation similar to using virtual env. It sounds like what happened here is that your app got packaged in the fist way, but actually it can work only in the second way. I assume you do specify specific compatible version of Django somewhere, and if a package (be it .deb, .rpm, or .nix) doesn’t respect that, that’s a bug in the package. Hope this helps!
- SuperSandro2000 3y ago> packaging for Debian. Not really, nix is way more flexible and more up to date and nix also often runs tests and different pythons cannot interfere with each other that easily. On a high level things are similar but the details are wastly different. > Or you could create a hermetic environment, where an app gets an isolated copy of dependencies, specific just to the single app, a situation similar to using virtual env. That could also be done with nix but is often not because upstream pin quality is often lacking.
- goodpoint 3y ago> Of course we, like all other python projects, don't support using other dependency versions then the ones in the requirements.txt file. That's really bad. You should always support reasonable version ranges. > when someone just uses a different minor version of django, stuff breaks That's why some people say that managing dependencies in Python is difficult and move to statically compiled languages.
- SuperSandro2000 3y ago> That's why some people say that managing dependencies in Python is difficult and move to statically compiled languages. Yes, completely agreeing with that.
- goodpoint 3y agoI don't.
- pxc 3y agoIt's not even really about static compilation. NixOS (and many Linux distros) include tons of dynamically linked C applications that just do a way, way better job of compatibility. Imagine if GNU grep were as fussy about only being built against 1 version of glibc as many Python libraries and applications seem to be about their dependencies.
- lolinder 3y agoWhat makes you think that the versions specified in the requirements.txt aren't reasonable ranges? All OP is saying is that if you're outside the version ranges in requirements.txt then you're outside the supported range. It's literally in the name of the file—requirements.
- goodpoint 3y ago> What makes you think that the versions specified in the requirements.txt aren't reasonable ranges? Because that's what the parent wrote.
- SuperSandro2000 3y agoThey don't need to use the same version of the Django package but Python dependency pins are often either way to tight and can easily be expanded or outright missing, so they often get ignored.
- nurple 3y agoIt sounds like the package is implemented improperly. If the input from your repo to the package is not targetting a specific commit, it should be. Building from "latest" is really not how nix is ever meant to operate. In that case, when you update your requirements.txt, it is now out of sync with the package definition; the inputs _have_ changed and your guarantees are gone. When your project repo is updated, that should never result in a change to what gets installed by nixpkgs until you also update the package to point at that commit and do any work necessary to fix breaking changes. Once you do that work, that version of your package picks up a guarantee to always be producable. Like another comment mentioned, this is all much easier to accomplish with flakes as they have a lockfile that sits next to the flake, both of which reside in your repo and can be updated atomically with your releases instead of also needing to make a PR for nixpkgs. I've actually been working on learning how to better package python with nix and found the historical information on python packaging infrastructure in this talk incredibly enlightening (I think this landed on HN a few days back): https://www.youtube.com/watch?v=ADSM4vR2EQ0 https://www.youtube.com/watch?v=ADSM4vR2EQ0
- pxc 3y agoAre you opposed to filing a bug in Nixpkgs for your application? Alternatively, are you willing to point to your application or its package in Nixpkgs so that someone else can do so?
- dlahoda 3y agofor rust or haskell i point nix to my version and lock and toolchain files. and it uses exact tools and versions default build uses, but built with nix. hope such solution exists for python.