Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect --index-url in uv pip list #8942

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,9 @@ pub struct PipListArgs {
#[arg(long, overrides_with("strict"), hide = true)]
pub no_strict: bool,

#[command(flatten)]
pub fetch: FetchArgs,

/// The Python interpreter for which packages should be listed.
///
/// By default, uv lists packages in a virtual environment but will show
Expand Down Expand Up @@ -4698,6 +4701,49 @@ pub struct ResolverInstallerArgs {
pub no_sources: bool,
}

/// Arguments that are used by commands that need to fetch from the Simple API.
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct FetchArgs {
#[command(flatten)]
pub index_args: IndexArgs,

/// The strategy to use when resolving against multiple index URLs.
///
/// By default, uv will stop at the first index on which a given package is available, and
/// limit resolutions to those present on that first index (`first-match`). This prevents
/// "dependency confusion" attacks, whereby an attacker can upload a malicious package under the
/// same name to an alternate index.
#[arg(
long,
value_enum,
env = EnvVars::UV_INDEX_STRATEGY,
help_heading = "Index options"
)]
pub index_strategy: Option<IndexStrategy>,

/// Attempt to use `keyring` for authentication for index URLs.
///
/// At present, only `--keyring-provider subprocess` is supported, which configures uv to
/// use the `keyring` CLI to handle authentication.
///
/// Defaults to `disabled`.
#[arg(
long,
value_enum,
env = EnvVars::UV_KEYRING_PROVIDER,
help_heading = "Index options"
)]
pub keyring_provider: Option<KeyringProviderType>,

/// Limit candidate packages to those that were uploaded prior to the given date.
///
/// Accepts both RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`) and local dates in the same
/// format (e.g., `2006-12-02`) in your system's configured time zone.
#[arg(long, env = EnvVars::UV_EXCLUDE_NEWER, help_heading = "Resolver options")]
pub exclude_newer: Option<ExcludeNewer>,
}

#[derive(Args)]
pub struct DisplayTreeArgs {
/// Maximum display depth of the dependency tree
Expand Down
20 changes: 19 additions & 1 deletion crates/uv-cli/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use uv_resolver::PrereleaseMode;
use uv_settings::{Combine, PipOptions, ResolverInstallerOptions, ResolverOptions};

use crate::{
BuildOptionsArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs,
BuildOptionsArgs, FetchArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs,
ResolverInstallerArgs,
};

Expand Down Expand Up @@ -163,6 +163,24 @@ impl From<ResolverInstallerArgs> for PipOptions {
}
}

impl From<FetchArgs> for PipOptions {
fn from(args: FetchArgs) -> Self {
let FetchArgs {
index_args,
index_strategy,
keyring_provider,
exclude_newer,
} = args;

Self {
index_strategy,
keyring_provider,
exclude_newer,
..PipOptions::from(index_args)
}
}
}

impl From<IndexArgs> for PipOptions {
fn from(args: IndexArgs) -> Self {
let IndexArgs {
Expand Down
3 changes: 2 additions & 1 deletion crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1693,6 +1693,7 @@ impl PipListSettings {
no_outdated,
strict,
no_strict,
fetch,
python,
system,
no_system,
Expand All @@ -1709,7 +1710,7 @@ impl PipListSettings {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system),
strict: flag(strict, no_strict),
..PipOptions::default()
..PipOptions::from(fetch)
},
filesystem,
),
Expand Down
54 changes: 48 additions & 6 deletions crates/uv/tests/it/pip_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,9 @@ fn list_outdated_columns() -> Result<()> {
success: true
exit_code: 0
----- stdout -----
Package Version Latest Type
------- ------- ----------- -----
anyio 3.0.0 4.6.2.post1 wheel
idna 3.6 3.10 wheel
Package Version Latest Type
------- ------- ------ -----
anyio 3.0.0 4.3.0 wheel

----- stderr -----
"###
Expand Down Expand Up @@ -165,7 +164,7 @@ fn list_outdated_json() -> Result<()> {
success: true
exit_code: 0
----- stdout -----
[{"name":"anyio","version":"3.0.0","latest_version":"4.6.2.post1","latest_filetype":"wheel"},{"name":"idna","version":"3.6","latest_version":"3.10","latest_filetype":"wheel"}]
[{"name":"anyio","version":"3.0.0","latest_version":"4.3.0","latest_filetype":"wheel"}]

----- stderr -----
"###
Expand Down Expand Up @@ -231,6 +230,49 @@ fn list_outdated_git() -> Result<()> {
Ok(())
}

#[test]
fn list_outdated_index() -> Result<()> {
let context = TestContext::new("3.12");

let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio==3.0.0")?;

uv_snapshot!(context.pip_install()
.arg("-r")
.arg("requirements.txt")
.arg("--strict"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
+ anyio==3.0.0
+ idna==3.6
+ sniffio==1.3.1
"###
);

uv_snapshot!(context.pip_list()
.arg("--outdated")
.arg("--index-url")
.arg("https://test.pypi.org/simple"), @r###"
success: true
exit_code: 0
----- stdout -----
Package Version Latest Type
------- ------- ------ -----
anyio 3.0.0 3.5.0 wheel

----- stderr -----
"###
);

Ok(())
}

#[test]
fn list_editable() {
let context = TestContext::new("3.12");
Expand Down Expand Up @@ -343,7 +385,7 @@ fn list_editable_only() {
----- stderr -----
error: the argument '--editable' cannot be used with '--exclude-editable'

Usage: uv pip list --cache-dir [CACHE_DIR] --editable
Usage: uv pip list --cache-dir [CACHE_DIR] --editable --exclude-newer <EXCLUDE_NEWER>

For more information, try '--help'.
"###
Expand Down
70 changes: 70 additions & 0 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -6634,6 +6634,13 @@ uv pip list [OPTIONS]
<p>While uv configuration can be included in a <code>pyproject.toml</code> file, it is not allowed in this context.</p>

<p>May also be set with the <code>UV_CONFIG_FILE</code> environment variable.</p>
</dd><dt><code>--default-index</code> <i>default-index</i></dt><dd><p>The URL of the default package index (by default: &lt;https://pypi.org/simple&gt;).</p>

<p>Accepts either a repository compliant with PEP 503 (the simple repository API), or a local directory laid out in the same format.</p>

<p>The index given by this flag is given lower priority than all other indexes specified via the <code>--index</code> flag.</p>

<p>May also be set with the <code>UV_DEFAULT_INDEX</code> environment variable.</p>
</dd><dt><code>--directory</code> <i>directory</i></dt><dd><p>Change to the given directory prior to running the command.</p>

<p>Relative paths are resolved with the given directory as the base.</p>
Expand All @@ -6646,6 +6653,25 @@ uv pip list [OPTIONS]

</dd><dt><code>--exclude-editable</code></dt><dd><p>Exclude any editable packages from output</p>

</dd><dt><code>--exclude-newer</code> <i>exclude-newer</i></dt><dd><p>Limit candidate packages to those that were uploaded prior to the given date.</p>

<p>Accepts both RFC 3339 timestamps (e.g., <code>2006-12-02T02:07:43Z</code>) and local dates in the same format (e.g., <code>2006-12-02</code>) in your system&#8217;s configured time zone.</p>

<p>May also be set with the <code>UV_EXCLUDE_NEWER</code> environment variable.</p>
</dd><dt><code>--extra-index-url</code> <i>extra-index-url</i></dt><dd><p>(Deprecated: use <code>--index</code> instead) Extra URLs of package indexes to use, in addition to <code>--index-url</code>.</p>

<p>Accepts either a repository compliant with PEP 503 (the simple repository API), or a local directory laid out in the same format.</p>

<p>All indexes provided via this flag take priority over the index specified by <code>--index-url</code> (which defaults to PyPI). When multiple <code>--extra-index-url</code> flags are provided, earlier values take priority.</p>

<p>May also be set with the <code>UV_EXTRA_INDEX_URL</code> environment variable.</p>
</dd><dt><code>--find-links</code>, <code>-f</code> <i>find-links</i></dt><dd><p>Locations to search for candidate distributions, in addition to those found in the registry indexes.</p>

<p>If a path, the target must be a directory that contains packages as wheel files (<code>.whl</code>) or source distributions (e.g., <code>.tar.gz</code> or <code>.zip</code>) at the top level.</p>

<p>If a URL, the page must contain a flat list of links to package files adhering to the formats described above.</p>

<p>May also be set with the <code>UV_FIND_LINKS</code> environment variable.</p>
</dd><dt><code>--format</code> <i>format</i></dt><dd><p>Select the output format between: <code>columns</code> (default), <code>freeze</code>, or <code>json</code></p>

<p>[default: columns]</p>
Expand All @@ -6660,6 +6686,48 @@ uv pip list [OPTIONS]
</ul>
</dd><dt><code>--help</code>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>

</dd><dt><code>--index</code> <i>index</i></dt><dd><p>The URLs to use when resolving dependencies, in addition to the default index.</p>

<p>Accepts either a repository compliant with PEP 503 (the simple repository API), or a local directory laid out in the same format.</p>

<p>All indexes provided via this flag take priority over the index specified by <code>--default-index</code> (which defaults to PyPI). When multiple <code>--index</code> flags are provided, earlier values take priority.</p>

<p>May also be set with the <code>UV_INDEX</code> environment variable.</p>
</dd><dt><code>--index-strategy</code> <i>index-strategy</i></dt><dd><p>The strategy to use when resolving against multiple index URLs.</p>

<p>By default, uv will stop at the first index on which a given package is available, and limit resolutions to those present on that first index (<code>first-match</code>). This prevents &quot;dependency confusion&quot; attacks, whereby an attacker can upload a malicious package under the same name to an alternate index.</p>

<p>May also be set with the <code>UV_INDEX_STRATEGY</code> environment variable.</p>
<p>Possible values:</p>

<ul>
<li><code>first-index</code>: Only use results from the first index that returns a match for a given package name</li>

<li><code>unsafe-first-match</code>: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next</li>

<li><code>unsafe-best-match</code>: Search for every package name across all indexes, preferring the &quot;best&quot; version found. If a package version is in multiple indexes, only look at the entry for the first index</li>
</ul>
</dd><dt><code>--index-url</code>, <code>-i</code> <i>index-url</i></dt><dd><p>(Deprecated: use <code>--default-index</code> instead) The URL of the Python package index (by default: &lt;https://pypi.org/simple&gt;).</p>

<p>Accepts either a repository compliant with PEP 503 (the simple repository API), or a local directory laid out in the same format.</p>

<p>The index given by this flag is given lower priority than all other indexes specified via the <code>--extra-index-url</code> flag.</p>

<p>May also be set with the <code>UV_INDEX_URL</code> environment variable.</p>
</dd><dt><code>--keyring-provider</code> <i>keyring-provider</i></dt><dd><p>Attempt to use <code>keyring</code> for authentication for index URLs.</p>

<p>At present, only <code>--keyring-provider subprocess</code> is supported, which configures uv to use the <code>keyring</code> CLI to handle authentication.</p>

<p>Defaults to <code>disabled</code>.</p>

<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p>
<p>Possible values:</p>

<ul>
<li><code>disabled</code>: Do not use keyring for credential lookup</li>

<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
</ul>
</dd><dt><code>--native-tls</code></dt><dd><p>Whether to load TLS certificates from the platform&#8217;s native certificate store.</p>

<p>By default, uv loads certificates from the bundled <code>webpki-roots</code> crate. The <code>webpki-roots</code> are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).</p>
Expand All @@ -6675,6 +6743,8 @@ uv pip list [OPTIONS]
<p>Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.</p>

<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p>
</dd><dt><code>--no-index</code></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p>

</dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p>

<p>For example, spinners or progress bars.</p>
Expand Down
Loading