Skip to content

Conversation

cybardev
Copy link
Contributor

@cybardev cybardev commented Jun 1, 2025

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • Nixpkgs 25.11 Release Notes (or backporting 24.11 and 25.05 Nixpkgs Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
  • NixOS 25.11 Release Notes (or backporting 24.11 and 25.05 NixOS Release notes)
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@github-actions github-actions bot added the 8.has: maintainer-list (update) This PR changes `maintainers/maintainer-list.nix` label Jun 1, 2025
@github-actions github-actions bot added 10.rebuild-darwin: 1 This PR causes 1 package to rebuild on Darwin. 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-linux: 1 This PR causes 1 package to rebuild on Linux. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. labels Jun 1, 2025
@NixOSInfra NixOSInfra added the 12.first-time contribution This PR is the author's first one; please be gentle! label Jun 1, 2025
@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

Closes #412559

Copy link
Member

@pluiedev pluiedev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome to Nixpkgs 💜 Here are some suggestions for your addition:

Comment on lines 10 to 11
rustPlatform.buildRustPackage {
inherit pname version;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildRustPackage now supports the finalAttrs pattern too, so using a let-in here shouldn't be necessary

};

# requires unstable rust features
RUSTC_BOOTSTRAP = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Place environment variables inside env

Suggested change
RUSTC_BOOTSTRAP = 1;
env.RUSTC_BOOTSTRAP = 1;

# requires unstable rust features
RUSTC_BOOTSTRAP = 1;

nativeBuildInputs = [ rustPlatform.cargoSetupHook ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not be necessary for buildRustPackage

description = "A fast type checker and IDE for Python";
homepage = "https://github.com/facebook/pyrefly";
license = licenses.mit;
mainProgram = pname;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mainProgram is not guaranteed to always be the same as the package name, and it's better to spell it out explicitly

Suggested change
mainProgram = pname;
mainProgram = "pyrefly";


nativeBuildInputs = [ rustPlatform.cargoSetupHook ];

meta = with lib; {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New uses of with lib; are discouraged as they introduce unclear variable references and scoping rules. Prefix each item under lib explicitly instead

nativeBuildInputs = [ rustPlatform.cargoSetupHook ];

meta = with lib; {
description = "A fast type checker and IDE for Python";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Descriptions shouldn't start with an article (see pkgs/README.md)

Suggested change
description = "A fast type checker and IDE for Python";
description = "Fast type checker and IDE for Python";

Comment on lines 28 to 24
cargoDeps = rustPlatform.importCargoLock {
# generated by running `cargo generate-lockfile` in the `pyrefly` directory
lockFile = ./Cargo.lock;
outputHashes = {
"ruff_python_ast-0.0.0" = "sha256-YQmkmn6fWKmKz+Lw9wwgPG2O9E+2/ZJcclRs97SOWK4=";
};
};
Copy link
Member

@pluiedev pluiedev Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the recommended practice nowadays is to use fetchCargoVendor, and specify patches that add the required lockfile. This has the advantage of not requiring explicit Git hashes in the Nix source file, and would also eliminate the postPatch phase here

Copy link
Contributor Author

@cybardev cybardev Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having some trouble with this. Since there's no Cargo.lock present in the pyrefly repo (removed in facebook/pyrefly@dfe73ff), I get a FileNotFound error for it. Do I add the Cargo.lock file via a patch? Nvm, I just read your reply properly...

specify patches that add the required lockfile

my bad. I'll do that

(sorry, I have never touched or even been near Rust, let alone in combination with Nix 😓 so a bit unfamiliar)

Copy link
Contributor Author

@cybardev cybardev Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I tried this to generate a .patch file (not sure how else to do it if there's an easier way):

But it still shows Cargo.lock is missing (I did stage my .patch file in the local repo):

error.txt
Running phase: unpackPhase
@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking source archive /nix/store/hdwyx26pi61g77cg9r60gznc39gyrbz0-source
source root is source
Running phase: patchPhase
@nix { "action": "setPhase", "phase": "patchPhase" }
Running phase: updateAutotoolsGnuConfigScriptsPhase
@nix { "action": "setPhase", "phase": "updateAutotoolsGnuConfigScriptsPhase" }
Running phase: buildPhase
@nix { "action": "setPhase", "phase": "buildPhase" }
Traceback (most recent call last):
  File "/nix/store/qswdimncl2mlgc42915qkc4a9dw7xkq3-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 349, in <module>
    main()
  File "/nix/store/qswdimncl2mlgc42915qkc4a9dw7xkq3-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 345, in main
    subcommand_func()
  File "/nix/store/qswdimncl2mlgc42915qkc4a9dw7xkq3-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 336, in <lambda>
    "create-vendor-staging": lambda: create_vendor_staging(lockfile_path=Path(sys.argv[2]), out_dir=Path(sys.argv[3])),
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/qswdimncl2mlgc42915qkc4a9dw7xkq3-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 127, in create_vendor_staging
    cargo_lock_toml = load_toml(lockfile_path)
                      ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/qswdimncl2mlgc42915qkc4a9dw7xkq3-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 23, in load_toml
    with open(path, "rb") as f:
         ^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'Cargo.lock'

Copy link
Contributor Author

@cybardev cybardev Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For context, here's my current code:

Failing is not because of empty hash. It fails with the previously posted error (not finding Cargo.lock) and does not get to the stage of failing while outputting the correct hash.

It also seems way more convenient to just generate and add the lock file instead of a patch. Not sure how much of a "bad practice" that is considered... Just thinking about having to update the patch every new update. 😓

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that's how it is unfortunately until upstream decides to commit lockfiles again 🤷‍♀️

Copy link
Contributor Author

@cybardev cybardev Jun 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that's how it is unfortunately until upstream decides to commit lockfiles again

facebook/pyrefly#432

Submitted an issue. What are they doing?? Why? They had to go out of their way to not commit the Cargo.lock...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They fixed it. Apparently they are using their own in-house build system to do this, which does not generate the lockfile. I find this very strange as usually any cargo command that fetches the dependencies creates the lockfile, but ok. But now at least cargoHash should just work...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buck does generate a lockfile but they chose not to commit it before. But yeah, next update will be much better without all the Python/Maturin bloat.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dtomvan Actually there's still issues... See facebook/pyrefly#432 (comment)

src = fetchFromGitHub {
owner = "facebook";
repo = "pyrefly";
rev = version;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use tag for tagged releases and rev only for commit hashes

Suggested change
rev = version;
tag = version;

@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

@QuiNzX shared this code that uses buildPythonPackage instead, doesn't need us to vendor the lockfile (because PyPI has it), and would be simpler to maintain:

pyrefly/package.nix
{
  lib,
  python3,
  fetchPypi,
  rustPlatform,
  maturin,
}:
python3.pkgs.buildPythonPackage rec {
  pname = "pyrefly";
  version = "0.17.1";
  format = "pyproject";

  src = fetchPypi {
    inherit pname version;
    hash = "sha256-w4ivRtmApXiXQT95GI4vvYBop7yxdbbkpW+YTyFtgXM=";
  };

  cargoDeps = rustPlatform.fetchCargoVendor {
    inherit src;
    hash = "sha256-Op5ueVkzZTiJ1zeBGVi8oeLcfSzXMYfk5zEg4OGyA5g=";
  };

  build-system = [ maturin ];

  nativeBuildInputs = with rustPlatform; [
    cargoSetupHook
    maturinBuildHook
  ];

  # requires unstable rust features
  env.RUSTC_BOOTSTRAP = 1;

  meta = with lib; {
    description = "A fast type checker and IDE for Python";
    homepage = "https://github.com/facebook/pyrefly";
    license = lib.licenses.mit;
    mainProgram = "pyrefly";
    platforms = lib.platforms.linux ++ lib.platforms.darwin;
    maintainers = with lib.maintainers; [ cybardev ];
  };
}

The caveat being, with buildRustPackage we only produced a single binary (result/bin/pyrefly) but with this we also produce a result/lib which contains a bunch of Python stuff. Not sure what to prioritize here - maintainability, or package size for user?

@pluiedev
Copy link
Member

pluiedev commented Jun 1, 2025

Interesting. I didn't know that the PyPI version has the lockfile - that is a very peculiar choice IMO. (We normally prefer packaging software directly from source, but I guess we can make an exception for this one.) I think the Python stuff is mainly for using Pyrefly as a wheel (Python library)? I'm not sure how, but it does appear to be something upstream supports. In that case, then I think it's fair to build this as a Python + Maturin package instead.

@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

Ok, sorry, I saw your message after the rebase push... I will do the Python version then.

@pluiedev
Copy link
Member

pluiedev commented Jun 1, 2025

Also if we were to support the case of using Pyrefly as a library, then we should move the main derivation to pkgs/development/python-modules and leave the one inside pkgs/by-name as a sort-of alias, like this:

{
  python3Packages
}:
python3Packages.toPythonApplication python3Packages.pyrefly

See the Nixpkgs manual for more detailed reasoning as to why we want to do this

@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

I can check with upstream but from what I understand it cannot be used like a Python library. That is, it is pip installable to get the command-line tool but not import pyreflyable in Python code. In that case I assume it's fine to leave it in by-name?

@pluiedev
Copy link
Member

pluiedev commented Jun 1, 2025

Oh yeah, then leave it in by-name and instead use buildPythonApplication and not buildPythonPackage like the snippet you have

@cybardev cybardev force-pushed the pkgs/pyrefly branch 2 times, most recently from 7edb455 to 2ce7b8a Compare June 1, 2025 22:14
@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

I think I've ironed out the issues. Let me know if there's anything to change. Thanks for the review and help. 🙂

Copy link
Member

@pluiedev pluiedev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking very, very good. Just one last stretch!

python3.pkgs.buildPythonApplication rec {
pname = "pyrefly";
version = "0.17.1";
format = "pyproject";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format is deprecated, actually 😅

Suggested change
format = "pyproject";
pyproject = true;

Copy link
Contributor

@dtomvan dtomvan Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think pyproject = true; an indirect default nowadays. You can safely remove it. It causes a rebuild, and it has a different output. But with --check I found out that the build isn't reproducible anyways:

error: derivation '/nix/store/pcinwg72q15sykpq7jc6pi8psh3sck2a-pyrefly-0.17.1.drv' may not be deterministic: output '/nix/store/a8w3n650dwvv0qiwly397wf7fq9m49dd-pyrefly-0.17.1-dist' differs

But diffoscope with-pyproject-true without-pyproject-true only reports differences in the python bytecode, the pyrefly binary, and lib/python3.12/site-packages/pyrefly-0.17.1.dist-info/RECORD, where the latter contains a sha256sum of the pyrefly binary so that doesn't really count. The new output still works though.

Diffoscope (pyproject set/unset): diff.html.gz
Diffoscope (pyproject unset, two builds): diff.html.gz

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dtomvan Thanks. Changed in 5c1f314

@cybardev cybardev force-pushed the pkgs/pyrefly branch 2 times, most recently from 5cd9812 to 37d02cd Compare June 1, 2025 22:25
@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

@pluiedev One more thing. @QuiNzX would like to be added as a maintainer. Do I add a new commit to add to maintainers-list.nix, then force-push a rebase of the package init commit with the new maintainer? Not sure how to approach this best...

@pluiedev
Copy link
Member

pluiedev commented Jun 1, 2025

Add another commit adding them as a maintainer, and then rebase the main commit on top of that I think

@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

I think I got it right? Let me know if this is ok or changes are needed. Thanks.

(apologies, I have not used Git to this extent before 😓)

Copy link
Member

@pluiedev pluiedev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent. Thank you so much!

@cybardev
Copy link
Contributor Author

cybardev commented Jun 1, 2025

Thanks for the reviews, help, and guidance. 😊

maturinBuildHook
];

nativeInstallCheckInputs = [ versionCheckHook ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's normally nativeCheckInputs for Python packages

Copy link
Contributor Author

@cybardev cybardev Jun 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in de8144a. Thanks.

Co-authored-by: QuiNzX <76129478+QuiNzX@users.noreply.github.com>
Copy link
Contributor

@dtomvan dtomvan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builds and runs. LGTM!

@dtomvan dtomvan added the 12.approvals: 2 This PR was reviewed and approved by two persons. label Jun 4, 2025
@dtomvan
Copy link
Contributor

dtomvan commented Jun 5, 2025

I am so sorry. I must've been mistaken. I was wrong about pyproject = true;:
https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/python.section.md#buildpythonpackage-parameters-buildpythonpackage-parameters

  • pyproject: Whether the pyproject format should be used. As all other formats
    are deprecated, you are recommended to set this to true. When you do so,
    pypaBuildHook will be used, and you can add the required build dependencies
    from build-system.requires to build-system. Note that the pyproject
    format falls back to using setuptools, so you can use pyproject = true
    even if the package only has a setup.py. When set to false, you can
    use the existing hooks or provide your own logic to build the
    package. This can be useful for packages that don't support the pyproject
    format. When unset, the legacy setuptools hooks are used for backwards
    compatibility.

It will definitely work when unset, so it doesn't entirely matter. But apparently the best practice isn't to only set it when needed, it should almost always be set, but it just isn't a default yet. They did set a pyproject.toml upstream, so I guess it should be set after all.

Sorry for the confusion and the extra work, was just trying to do a thorough review, but I kinda achieved the opposite of what I wanted. I am new here, so I still make a bunch of mistakes.

That being said, I see no reason why this could not get merged in its current state. The behaviour is the same whether it's set or not, because it's using maturin anyways, so it doesn't reach the setuptools fallback codepath.

@cybardev
Copy link
Contributor Author

cybardev commented Jun 5, 2025

@dtomvan No probs. Reverted in de8144a . Thanks for the thorough check. I appreciate it. 😊

@DieracDelta
Copy link
Member

nixpkgs-review result

Generated using nixpkgs-review.

Command: nixpkgs-review pr 412863
Commit: de8144a7e356e0adfcae232d3a3bd25522e75ad1


x86_64-linux

✅ 2 packages built:
  • pyrefly
  • pyrefly.dist

aarch64-linux

✅ 2 packages built:
  • pyrefly
  • pyrefly.dist

@cybardev
Copy link
Contributor Author

cybardev commented Jun 11, 2025

After locally verifying it works, I added nix-update-script in b92f1fd

@Aleksanaa Aleksanaa merged commit abd98ed into NixOS:master Jun 11, 2025
20 of 22 checks passed
@cybardev cybardev deleted the pkgs/pyrefly branch June 12, 2025 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
8.has: maintainer-list (update) This PR changes `maintainers/maintainer-list.nix` 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-darwin: 1 This PR causes 1 package to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-linux: 1 This PR causes 1 package to rebuild on Linux. 12.approvals: 2 This PR was reviewed and approved by two persons. 12.first-time contribution This PR is the author's first one; please be gentle!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants