Skip to content

Issue #3707 - #3709

Open
pt-klein-bae wants to merge 2 commits into
OpenC3:mainfrom
pt-klein-bae:ISSUE-3707-uvinstall-use-sync
Open

Issue #3707#3709
pt-klein-bae wants to merge 2 commits into
OpenC3:mainfrom
pt-klein-bae:ISSUE-3707-uvinstall-use-sync

Conversation

@pt-klein-bae

Copy link
Copy Markdown

Adds a new path in uvinstall that attempts to use uv sync if pyproject.toml is present but not uv.lock

Decided to add new path so it preserves the fallback uv pip install option.

Addresses #3707

@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.31%. Comparing base (1b3f529) to head (1fbc185).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3709   +/-   ##
=======================================
  Coverage   79.31%   79.31%           
=======================================
  Files         885      885           
  Lines       65365    65365           
  Branches     2543     2543           
=======================================
+ Hits        51846    51847    +1     
+ Misses      12847    12846    -1     
  Partials      672      672           
Flag Coverage Δ
frontend 63.70% <ø> (+0.02%) ⬆️
python 81.53% <ø> (+<0.01%) ⬆️
ruby-api 82.17% <ø> (-0.07%) ⬇️
ruby-backend 84.08% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

uv sync exits 0 while installing nothing for a non-PEP-621 pyproject.toml,
so gate path 2 on a [project] table and on requirements.txt being absent;
poetry/pdm plugins now fall through to uv pip install instead of getting an
empty venv and a runtime ModuleNotFoundError. Also drop the stale venv-base
uv.lock so a widened pin re-resolves, and pass --inexact on both sync paths
so admin-uploaded packages are no longer pruned.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@jmthomas jmthomas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@mcosgriff please review

Comment thread openc3/bin/uvinstall
# lock exactly and uninstalls anything else, including packages an admin
# uploaded into this plugin venv via PythonPackageModel.install (which uses
# the additive `pipinstall`).
uv_offline_then_online sync --frozen --inexact --no-dev --no-install-project ${UV_ARGS}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

--inexact was an existing issue

Comment thread openc3/bin/uvinstall
# does install the deps, so those plugins must fall through to it.
# - requirements.txt must be absent. A pyproject.toml carrying only tool
# config ([tool.ruff], [tool.pytest]) alongside a real requirements.txt
# would otherwise match here and the requirements.txt would never be read.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Added extra gates to prevent uv sync noop

@mcosgriff

Copy link
Copy Markdown
Contributor

pyproject.toml with a uv.lock is the standard path we want to support so that will remain path 1 with path 2 being the fallback. This was intended as a path for plugins have not been updated yet with a uv.lock file. The indexes in the pyproject.toml were not being using because -r "${GEM_PATH}/pyproject.toml" was not being passed into teh elif [ -f "${GEM_PATH}/pyproject.toml" ]; then branch and -i <pypi_url> was being passed into that uv pip install command.

The fallback step can be rewritten like

if [ -f "${GEM_PATH}/requirements.txt" ]; then
    uv_offline_then_online pip install --python "${VENV_DIR}" ${UV_ARGS} -r "${GEM_PATH}/requirements.txt"
    RESULT=$?
elif [ -f "${GEM_PATH}/pyproject.toml" ]; then
    uv_offline_then_online pip install --python "${VENV_DIR}" ${UV_ARGS} -r "${GEM_PATH}/pyproject.toml"
    RESULT=$?
else
    echo "ERROR: No requirements.txt, pyproject.toml, or uv.lock found in ${GEM_PATH}"
    exit 1
fi

Also make sure the Pypi URL is set in Administrator Console > Setting, that is the value that gets passed into uvinstall

# Build the argv array for pypi index and trusted-host arguments.
def self.build_pypi_args(pypi_url)
  args = ["-i", pypi_url]
  args += ["--trusted-host", URI.parse(pypi_url).host] unless ENV['PIP_ENABLE_TRUSTED_HOST'].nil?
  args
end

@mcosgriff mcosgriff left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See comments

@pt-klein-bae

Copy link
Copy Markdown
Author

Thanks Jason for improving the MR!

Quick response to Matthew's comments:

uv pip install by design does not respect [[tool.uv.index]] so sticking with pip won't solve the issue. Also, in my case, we need more than 1 'pypi_url'.. Most packages are installed from our pypi proxy, but we have a few custom ones we install from Gitlab, potentially from different project repositories, so there's at least 2 urls.

Understand that pyproject.toml and uv.lock are preferred, but the current behavior for just pyproject.toml is not as one would expect, after having used uv for some time now. It took me a few hours of troubleshooting to realize/understand why my custom [[tool.uv.index]] (that I use all the time elsewhere) were not being used. If path 1 is really where you're headed, it would be better to just have pyproject.toml without uv.lock throw an error.

@mcosgriff

Copy link
Copy Markdown
Contributor

uv pip install by design does not respect [[tool.uv.index]]

uv pip install does respect [[tool.uv.index]]

[project]
name = "index-demo"
version = "0.0.0"
requires-python = ">=3.11"
dependencies = ["cowsay>=5", "boltons>=21"]

[tool.uv]
package = false

[[tool.uv.index]]
name = "repo-a"
url = "http://127.0.0.1:9101/simple"

[[tool.uv.index]]
name = "repo-b"
url = "http://127.0.0.1:9102/simple"
❯ uv pip install --python .venv  --default-index https://pypi.org/simple .           
⠸ index-demo==0.0.0                                                                                                                                                                                                                                                                                                                                                                                                              error: Request failed after 3 retries in 7.8s
  Caused by: Failed to fetch: `http://127.0.0.1:9101/simple/boltons/`
  Caused by: error sending request for url (http://127.0.0.1:9101/simple/boltons/)
  Caused by: client error (Connect)
  Caused by: tcp connect error
  Caused by: Connection refused (os error 61)

Where the indexes are not respected is when the command is run outside of the project directory

❯ uv pip install --python ./uv-test/.venv  --default-index https://pypi.org/simple ./uv-test
Using Python 3.13.15 environment at: uv-test/.venv
Resolved 3 packages in 142ms
      Built index-demo @ file:///Users/mcosgriff/Development/uv-test                                                                                                                                                                                                                                                                                                                                                             
Prepared 1 package in 372ms
Installed 3 packages in 3ms
 + boltons==26.1.0
 + cowsay==6.1
 + index-demo==0.0.0 (from file:///Users/mcosgriff/Development/uv-test)

Root cause is ours: passing a bare ${GEM_PATH} directory target with no project context, so uv never discovered the plugin's [tool.uv] table. --project "${GEM_PATH}" + -r "${GEM_PATH}/pyproject.toml" fixes it — and the -r half also drops the build, which deletes the recovery block at lines 158–186.

Path 2: Fallback becomes

if [ -f "${GEM_PATH}/requirements.txt" ]; then
    echo "Installing from requirements.txt via uv pip install"
    uv_offline_then_online pip install --python "${VENV_DIR}" ${UV_ARGS} -r "${GEM_PATH}/requirements.txt"
    RESULT=$?
elif [ -f "${GEM_PATH}/pyproject.toml" ]; then
    echo "Installing from pyproject.toml via uv pip install"
    uv_offline_then_online pip install --python "${VENV_DIR}" --project "${GEM_PATH}" ${UV_ARGS} -r "${GEM_PATH}/pyproject.toml"
    RESULT=$?
else
    echo "ERROR: No requirements.txt, pyproject.toml, or uv.lock found in ${GEM_PATH}"
    exit 1
fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch uvinstall to use uv sync instead of uv pip install for pyproject.toml

3 participants