# Currently, ty is developed together with ruff in # https://github.com/astral-sh/ruff. The repository # https://github.com/astral-sh/ty contains only the ty-specific bits, and # depends on the ruff repository as a git submodule. We therefore *must* # “bundle” ruff, and this spec file is based closely on (and mirrors the # structure of) the one for ruff. %bcond check 1 Name: ty Version: 0.0.7 Release: %autorelease Summary: Extremely fast Python type checker and language server # The license of the ty project is MIT. Other source licenses come from ruff. # The comments below will generally be synchronized with those in the ruff spec # file. # # The license of the ruff project is MIT, except: # # As described in https://github.com/astral-sh/ruff/pull/20222, the README # lists projects whose rules ruff has (re)implemented but from which ruff does # not otherwise reuse or adapt source code. We don’t consider those to be # bundled dependencies, and we don’t consider their licenses to contribute to # the licenses of the binary RPMs. # # Meanwhile, LICENSE documents projects from which parts of ruff are derived, # e.g. by copying and adapting source code. In general, we can’t always readily # identify precisely which source files are derived from each of these upstream # projects, and it doesn’t make sense to treat them as bundled or vendored # dependencies. However, we do need to account for their licenses. # # MIT (same as ruff itself): # - autoflake # - autotyping # - flake8 # - flake8-eradicate # - flake8-pyi # - flake8-simplify # - isort # - pygrep-hooks # - pycodestyle # - pydocstyle # - pyflakes # - Pyright # - pyupgrade # - rome/tools # - RustPython # - rust-analyzer/text-size # # ===== # # Besides the above projects mentioned in LICENSE, the following vendored, # forked, or derived code is present, either directly in the ruff source # archive or as additional sources corresponding to git dependencies. # # Apache-2.0 AND MIT: # - crates/ty_vendored/vendor/typeshed/ is a bundled snapshot of # https://github.com/python/typeshed at a commit hash listed in # ruff/crates/ty_vendored/vendor/typeshed/source_commit.txt; license text # is in crates/ty_vendored/vendor/typeshed/LICENSE # # Within the typeshed snapshot, the docstring of # crates/ty_vendored/vendor/typeshed/stdlib/ast.pyi cites the Python-2.0.1 # license of the ast module from the Python library. We feel that this # type-stub file probably doesn’t contain enough of the original Python # source for the license to apply. If we’re wrong, then SourceLicense and # License should gain a Python-2.0.1 term. # # Apache-2.0 OR MIT: # - crates/ruff_annotate_snippets/ is a fork of the annotate-snippets crate # - salsa, salsa-macros, salsa-macros-rules, Source300 # # MIT: # - book/mermaid.min.js in the vendored salsa snapshot; does not contribute # to the licenses of the binary RPMs, since we do not package the book, and # it is removed in %%prep to be sure # - lsp-types, Source200 # # ===== # # A few other source files carry their own licenses but do not fit into the # above categories. # # Apache-2.0: # - crates/ruff_server/resources/test/fixtures/tensorflow_test_notebook.ipynb # comes from TensorFlow, and some of its content also appears in # crates/ruff_server/tests/notebook.rs and in the snapshots # crates/ruff_server/tests/snapshots/notebook__changed_notebook.snap and # crates/ruff_server/tests/snapshots/notebook__initial_notebook.snap; none # of these should contribute to the licenses of the binary RPMs, since they # are only for testing # # Apache-2.0 OR MIT: # - .github/workflows/release.yml (autogenerated by dist, # https://github.com/astral-sh/cargo-dist; does not contribute to the # licenses of the binary RPMs, since it is only for CI) # # MIT: # - playground/shared/src/Icons.tsx contains icons from the VS code icon set, # https://github.com/microsoft/vscode-icons/; we do not package the # in-browser playground, available at https://play.ruff.rs/, so this file # does not contribute to the licenses of the binary RPMs SourceLicense: %{shrink: MIT AND Apache-2.0 AND (Apache-2.0 OR MIT) } # Rust crates compiled into the executable contribute additional license terms. # To obtain the following list of licenses, build the package and note the # output of %%{cargo_license_summary}. This should automatically include the # licenses of the crates that were bundled as additional Sources. # # (MIT OR Apache-2.0) AND Unicode-3.0 # (MIT OR Apache-2.0) AND Unicode-DFS-2016 # Apache-2.0 # Apache-2.0 OR BSD-2-Clause # Apache-2.0 OR BSL-1.0 # Apache-2.0 OR MIT # Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT # BSD-2-Clause OR Apache-2.0 OR MIT # CC0-1.0 # ISC # MIT # MIT AND (MIT AND PSF-2.0) # MIT AND BSD-3-Clause # MIT OR Apache-2.0 # MIT OR Apache-2.0 OR Zlib # MIT OR BSD-3-Clause # MIT-0 OR Apache-2.0 # MPL-2.0 # Unicode-3.0 # Unlicense OR MIT # WTFPL # Zlib # Zlib OR Apache-2.0 OR MIT License: %{shrink: MIT AND Apache-2.0 AND (Apache-2.0 OR BSD-2-Clause) AND (Apache-2.0 OR BSD-2-Clause OR MIT) AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 OR MIT OR Zlib) AND (Apache-2.0 OR MIT-0) AND (Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT) AND BSD-3-Clause AND (BSD-3-Clause OR MIT) AND CC0-1.0 AND ISC AND (MIT OR Unlicense) AND MPL-2.0 AND PSF-2.0 AND Unicode-3.0 AND Unicode-DFS-2016 AND WTFPL AND Zlib } URL: https://github.com/astral-sh/ty Source: %{url}/archive/%{version}/ty-%{version}.tar.gz # Regarding bundling ruff, see the comments at the beginning of the spec file. %global ruff_git https://github.com/astral-sh/ruff %global ruff_rev f9afcc400ce56b1cc0dd1f20f3910afb0bb37d44 %global ruff_baseversion 0.14.10 %global ruff_snapdate 20251224 Source100: %{ruff_git}/archive/%{ruff_rev}/ruff-%{ruff_rev}.tar.gz # Currently, ruff must use a fork of lsp-types, # https://github.com/astral-sh/ruff/issues/20449. Upstream has not ruled out # “unforking,” but indicates they are in no particular hurry to do so. We # therefore bundle the fork; full details and justification are in the ruff # package. %global lsp_types_git https://github.com/astral-sh/lsp-types %global lsp_types_rev 3512a9f33eadc5402cfab1b8f7340824c8ca1439 %global lsp_types_baseversion 0.95.1 %global lsp_types_snapdate 20240429 Source200: %{lsp_types_git}/archive/%{lsp_types_rev}/lsp-types-%{lsp_types_rev}.tar.gz # For now, ruff still needs to use a git snapshot of salsa because it # frequently needs bug fixes faster than the salsa release cycle delivers them; # see https://github.com/astral-sh/ruff/pull/17566#issuecomment-2823146473. # # Check https://github.com/salsa-rs/salsa/blob/%%{salsa_rev}/Cargo.toml to # observe the version and https://github.com/salsa-rs/commit/%%{salsa_rev} to # observe the date. %global salsa_git https://github.com/salsa-rs/salsa %global salsa_rev 55e5e7d32fa3fc189276f35bb04c9438f9aedbd1 %global salsa_baseversion 0.24.0 %global salsa_snapdate 20251204 Source300: %{salsa_git}/archive/%{salsa_rev}/salsa-%{salsa_rev}.tar.gz # Get this from ruff/crates/ty_vendored/vendor/typeshed/source_commit.txt. %global typeshed_rev 3c2dbb1fde8e8d1d59b10161c8bf5fd06c0011cd # The typeshed project as a whole has never been versioned. %global typeshed_baseversion 0 # Inspect https://github.com/python/typeshed/commit/%%{typeshed_rev}. %global typeshed_snapdate 20251219 # Downstream patch: always find the system-wide ty executable # # The following issue is for uv, but the situation is exactly the same. # # “Should uv.find_uv_bin() be able to find /usr/bin/uv?” # https://github.com/astral-sh/uv/issues/4451 Patch: 0001-Downstream-patch-always-find-the-system-wide-ty-exec.patch # Downstream patches for ruff, copied from the ruff package # * drop unavailable compile-time diagnostics feature for UUIDs (non-upstreamable) Patch102: 0002-drop-unavailable-features-from-uuid-dependency.patch # * ignore tests in vendored annotate-snippets that hang indefinitely: Patch103: 0003-ignore-vendored-annotate-snippets-tests-that-hang-in.patch # https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval ExcludeArch: %{ix86} # Memory exhaustion can occur. Increase as needed. %global _smp_tasksize_proc 16384 BuildRequires: cargo-rpm-macros >= 24 BuildRequires: rust2rpm-helper BuildRequires: tomcli BuildRequires: python3-devel # See the notes about Source100. %global ruff_snapinfo %{ruff_snapdate}git%{sub %{ruff_rev} 1 7} %global ruff_version %{ruff_baseversion}^%{ruff_snapinfo} Provides: bundled(ruff) = %{ruff_version} # This is a fork of lsp-types; see the notes about Source200. %global lsp_types_snapinfo %{lsp_types_snapdate}git%{sub %{lsp_types_rev} 1 7} %global lsp_types_version %{lsp_types_baseversion}^%{lsp_types_snapinfo} Provides: bundled(crate(lsp-types)) = %{lsp_types_version} # This is a snapshot of salsa; see the notes about Source300. %global salsa_snapinfo %{salsa_snapdate}git%{sub %{salsa_rev} 1 7} %global salsa_version %{salsa_baseversion}^%{salsa_snapinfo} Provides: bundled(crate(salsa)) = %{salsa_version} Provides: bundled(crate(salsa-macros)) = %{salsa_version} Provides: bundled(crate(salsa-macro-rules)) = %{salsa_version} # This is not versioned or released as a whole, and it is normal for # type-checkers to vendor it. See # https://typing.python.org/en/latest/spec/distributing.html#the-typeshed-project. %global typeshed_snapinfo %{typeshed_snapdate}git%{sub %{typeshed_rev} 1 7} %global typeshed_version %{typeshed_baseversion}^%{typeshed_snapinfo} Provides: bundled(typeshed) = %{typeshed_version} # Forked from annotate-snippets upstream at some point after v0.11.5: # https://github.com/astral-sh/ruff/pull/15359 # # In ruff/crates/ruff_annotate_snippets/README.md, upstream writes: # # This is a fork of the [`annotate-snippets` crate]. The principle motivation # for this fork, at the time of writing, is [issue #167]. Specifically, we # wanted to upgrade our version of `annotate-snippets`, but do so _without_ # changing our diagnostic message format. # # This copy of `annotate-snippets` is basically identical to upstream, but # with an extra `Level::None` variant that permits skipping over a new # non-optional header emitted by `annotate-snippets`. # # More generally, it seems plausible that we may want to tweak other aspects # of the output format in the future, so it might make sense to stick with # our own copy so that we can be masters of our own destiny. # # [issue #167]: https://github.com/rust-lang/annotate-snippets-rs/issues/167 # [`annotate-snippets` crate]: https://github.com/rust-lang/annotate-snippets-rs Provides: bundled(crate(annotate-snippets)) = 0.11.5 # forked from lsp-types upstream: https://github.com/gluon-lang/lsp-types # with changes applied: https://github.com/astral-sh/lsp-types/tree/notebook-support Provides: bundled(crate(lsp-types)) = 0.95.1 %global common_description %{expand: An extremely fast Python type checker and language server, written in Rust.} %description %{common_description} %package -n python3-ty Summary: Importable Python module for ty BuildArch: noarch Requires: ty = %{version}-%{release} %description -n python3-ty %{common_description} This package provides an importable Python module for ty. %prep %autosetup -N %autopatch -p1 -M99 %cargo_prep # See comments above Source100: %setup -q -T -D -b 100 -n ty-%{version} # Replace the empty directory corresponding to a git submodule with the # extracted ruff source tree. rmdir ruff mv ../ruff-%{ruff_rev} ruff pushd ruff %autopatch -p1 -m100 -M199 # We have to adjust this both in the top-level pyproject.toml and in the ruff # pyproject.toml. (TODO: Is this really true?) tomcli set pyproject.toml false tool.maturin.strip %cargo_prep popd # Usage: git2path SELECTOR PATH # Replace a git dependency with a path dependency in Cargo.toml git2path() { tomcli set Cargo.toml del "${1}.git" tomcli set Cargo.toml del "${1}.rev" tomcli set Cargo.toml str "${1}.path" "${2}" } # See comments above Source200: %setup -q -T -D -b 200 -n ty-%{version} # Adding the crate to the workspace (in this case implicitly, by linking it # under crates/) means %%cargo_generate_buildrequires can handle it correctly. mv ../lsp-types-%{lsp_types_rev} ruff/crates/lsp-types pushd ruff git2path workspace.dependencies.lsp-types crates/lsp-types pushd crates/lsp-types %autopatch -p1 -m200 -M299 popd popd install -t LICENSE.bundled/lsp-types -D -p -m 0644 ruff/crates/lsp-types/LICENSE # See comments above Source300: %setup -q -T -D -b 300 -n ty-%{version} mv ../salsa-%{salsa_rev} ruff/crates/salsa mv ruff/crates/salsa/components/salsa-macro-rules ruff/crates/salsa-macro-rules mv ruff/crates/salsa/components/salsa-macros ruff/crates/salsa-macros pushd ruff git2path workspace.dependencies.salsa crates/salsa pushd crates/salsa %autopatch -p1 -m300 -M399 popd # These were taken from salsa’s workspace, but we have added the salsa crates # to ruff’s workspace, and we cannot have more than one workspace. tomcli set crates/salsa/Cargo.toml del 'workspace.package.authors' tomcli set crates/salsa/Cargo.toml list package.authors 'Salsa developers' for field in edition license repository rust-version do value="$(tomcli get crates/salsa/Cargo.toml "workspace.package.${field}")" tomcli set crates/salsa/Cargo.toml del "workspace.package.${field}" tomcli set crates/salsa/Cargo.toml str "package.${field}" "${value}" done # Now remove salsa’s workspace entirely. tomcli set crates/salsa/Cargo.toml del workspace # Fix up paths to ancillary salsa crates since we have moved them into the # workspace. tomcli set crates/salsa/Cargo.toml str dependencies.salsa-macro-rules.path \ '../salsa-macro-rules' tomcli set crates/salsa/Cargo.toml str dependencies.salsa-macros.path \ '../salsa-macros' tomcli set crates/salsa/Cargo.toml str \ "target.'cfg(any())'.dependencies.salsa-macros.path" \ '../salsa-macros' # Remove examples, and omit dev-dependencies that are only for examples: rm -rv crates/salsa/examples/ tomcli set crates/salsa/Cargo.toml del example for crate in crossbeam-channel eyre notify-debouncer-mini ordered-float do tomcli set crates/salsa/Cargo.toml del "dev-dependencies.${crate}" done # Remove benchmark-only dev-dependencies for crate in annotate-snippets codspeed-criterion-compat do tomcli set crates/salsa/Cargo.toml del "dev-dependencies.${crate}" done # Remove the shuttle feature since rust-shuttle is not packaged tomcli set crates/salsa/Cargo.toml del features.shuttle tomcli set crates/salsa/Cargo.toml del dependencies.shuttle # Remove bundled, pre-compiled mermaid JavaScript to prove it is not used. rm crates/salsa/book/mermaid.min.js popd install -t LICENSE.bundled/salsa -D -p -m 0644 ruff/crates/salsa/LICENSE-* # Loosen some version bounds. We retain this comment and the following example # even when there are currently no dependencies that need to be adjusted. # # # foocrate # # wanted: 0.2.0 # # currently packaged: 0.1.2 # # https://bugzilla.redhat.com/show_bug.cgi?id=1234567 # tomcli set Cargo.toml str workspace.dependencies.foocrate.version 0.1.2 # Collect license files of vendored dependencies in the main source archive install -t LICENSE.bundled/typeshed -D -p -m 0644 \ ruff/crates/ty_vendored/vendor/typeshed/LICENSE install -t LICENSE.bundled/annotate_snippets -D -p -m 0644 \ ruff/crates/ruff_annotate_snippets/LICENSE-* # Patch out foreign (e.g. Windows-only) dependencies. Follow symbolic links so # that we also patch the bundled crates we just finished setting up. find -L . -type f -name Cargo.toml -print \ -execdir rust2rpm-helper strip-foreign -o '{}' '{}' ';' # Drop unused subproject crates. # binary crate for running micro-benchmarks. rm -rv ruff/crates/ruff_benchmark # binary crate containing utilities used in the development of Ruff itself rm -rv ruff/crates/ruff_dev # library crate for exposing Ruff as a WebAssembly module. Powers the # [Ruff Playground](https://play.ruff.rs/). rm -rv ruff/crates/ruff_wasm ruff/crates/ty_wasm # Verify we have the correct snapshot hash for typeshed typeshed_rev_file='ruff/crates/ty_vendored/vendor/typeshed/source_commit.txt' typeshed_rev_in_source="$(cat "${typeshed_rev_file}")" if [[ '%{typeshed_rev}' != "${typeshed_rev_in_source}" ]] then cat 1>&2 <&2 </dev/null %cargo_generate_buildrequires -a -t pushd crates/ty >/dev/null %cargo_generate_buildrequires -a -t popd >/dev/null popd >/dev/null %pyproject_buildrequires %build export RUSTFLAGS='%{build_rustflags}' %pyproject_wheel LDEPS="${PWD}/LICENSE.dependencies" pushd ruff %{cargo_license_summary} %{cargo_license} > "${LDEPS}" popd %install %pyproject_install %pyproject_save_files ty if [ '%{python3_sitearch}' != '%{python3_sitelib}' ] then # Maturin is really designed to build compiled Python extensions, but (when # the ty executable is not bundled in the Python package) the ty Python # library is actually pure-Python, and the python3-ty subpackage can be # noarch. We can’t tell maturin to install to the appropriate site-packages # directory, but we can fix the installation path manually. install -d %{buildroot}%{python3_sitelib} mv %{buildroot}%{python3_sitearch}/ty* %{buildroot}%{python3_sitelib} sed -r -i 's@%{python3_sitearch}@%{python3_sitelib}@' %{pyproject_files} fi # generate and install shell completions ruff/target/rpm/ty generate-shell-completion bash > ty.bash ruff/target/rpm/ty generate-shell-completion fish > ty.fish ruff/target/rpm/ty generate-shell-completion zsh > _ty install -Dpm 0644 ty.bash -t %{buildroot}/%{bash_completions_dir} install -Dpm 0644 ty.fish -t %{buildroot}/%{fish_completions_dir} install -Dpm 0644 _ty -t %{buildroot}/%{zsh_completions_dir} %check %if %{with check} # Ignore false positive snapshot test failures. #export INSTA_UPDATE=always # We may need this if rustc diagnostics change from what upstream expects. #export TRYBUILD=overwrite # In the bundled salsa, this fails because the source paths are different than # expected, i.e. crates/salsa/tests/backtrace.rs instead of tests/backtrace.rs. # We skip the test because it is unnecessary and potentially brittle, but the # error message notes that exporting UPDATE_EXPECT=1 would also be a way to # ignore this kind of discrepancy. skip="${skip-} --skip backtrace_works" # These also fail due to similar path issues. # color/ann_{eof,insertion,multiline,multiline2,removed_nl}.toml # color/ensure-emoji-highlight-width.toml # color/fold_{ann_multiline,bad_origin_line,leading,trailing}.toml # color/issue_9.toml # color/multiple_annotations.toml # color/simple.toml # color/strip_line{,_char,_non_ws}.toml # We could export SNAPSHOTS=overwrite, but that would ignore many other # possible discrepancies. Skipping the affected tests is better. skip="${skip-} --skip color/" # Fails cryptically: requires network, perhaps? # error: no matching package named `boxcar` found # location searched: crates.io index skip="${skip-} --skip compile_fail" # These tests are flaky, e.g.: # thread 'python_environment::ty_environment_and_discovered_venv' panicked at # /usr/share/cargo/registry/insta-cmd-0.6.0/src/spawn.rs:103:27: # called `Result::unwrap()` on an `Err` value: Os { code: 26, kind: # ExecutableFileBusy, message: "Text file busy" } # This seems to be a testing issue, since the panic comes from insta. It might # be fixed by using “cargo nextest” instead of “cargo test,” as upstream does, # since nextest has better test isolation. For now, we skip these and move on. # Confirmed flaky on ppc64le: skip="${skip-} --skip python_environment::ty_environment_and_active_environment" # Confirmed flaky on ppc64le: skip="${skip-} --skip python_environment::ty_environment_and_discovered_venv" # Confirmed flaky on ppc64le and x86_64: skip="${skip-} --skip python_environment::ty_environment_is_only_environment" # Not confirmed flaky, but the other ty_environment_* ones are, so… skip="${skip-} --skip python_environment::ty_environment_is_system_not_virtual" # This panics consistenly on s390x only; not reported upstream since it # couldn’t be reproduced in a git checkout under qemu-user-static emulation. %ifarch s390x skip="${skip-} --skip mdtest__generics_specialize_constrained" %endif pushd ruff %cargo_test -- -- ${skip-} popd %endif %pyproject_check_import %files %license LICENSE LICENSE.dependencies LICENSE.bundled/ %doc CHANGELOG.md %doc README.md %{_bindir}/ty %{bash_completions_dir}/ty.bash %{fish_completions_dir}/ty.fish %{zsh_completions_dir}/_ty %files -n python3-ty -f %{pyproject_files} %changelog %autochangelog