---
updatedAt: 2026-05-13T06:39:51.000Z
agentTools:
  siteIndex: https://docs.jfrog.com/llms.txt
  projectIndex: https://docs.jfrog.com/artifactory/llms.txt
---

# PyPI Repositories

The JFrog Artifactory integration with the Python Package Index (PyPI) allows you to manage PyPI packages in Artifactory. PyPI is a repository of software for the Python programming language. For more information, see the <Anchor label="Python Packaging User Guide" target="_blank" href="https://packaging.python.org/en/latest/">Python Packaging User Guide</Anchor> and <Anchor label="Common Questions" target="_blank" href="https://pypi.org/help/">Common Questions</Anchor> on the PyPI website.

![PyPI\_diagram2.png](https://files.readme.io/269777922ddc651af15d36ba0fc0bde76d4c00659662d1be5db077b1754311fe-uuid-0d132986-23dd-d34b-7a27-37d58c0c321d.png)

Artifactory fully supports PyPI repositories, including:

* Provisioning PyPI packages from Artifactory to the Poetry, Twine, `pip`, and `uv` command line tools from all repository types.
* Calculating metadata for PyPI packages hosted in Artifactory's local repositories.
* Accessing remote PyPI repositories (such as `https://pypi.org/`) through <Anchor label="Remote Repositories" title="Remote Repositories" href="/docs/remote-repositories">Remote Repositories</Anchor>, which provide proxy and caching functionality.
* Accessing multiple PyPI repositories from a single URL by aggregating them under a <Anchor label="Virtual Repository" title="Virtual Repositories" href="/docs/virtual-repositories">Virtual Repository</Anchor>.
* Compatibility with the <Anchor label="setuptools" target="_blank" href="https://pypi.org/project/setuptools/">setuptools</Anchor> (and its predecessor <Anchor label="distutils" target="_blank" href="https://docs.python.org/2.7/distutils/">distutils</Anchor>) libraries for uploading PyPI packages.

## Get Started with PyPI

To get started working with PyPI, complete the following main steps:

1. <Anchor label="Create a PyPI Repository" title="Create a PyPI Repository" href="#create-a-pypi-repository">Create a PyPI Repository</Anchor>
2. <Anchor label="Connect Your PyPI Client to Artifactory" title="Connect Your PyPI Client to Artifactory" href="#connect-your-pypi-client-to-artifactory">Connect Your PyPI Client to Artifactory</Anchor>
3. Publish and install PyPI packages using a supported PyPI client:

   * <Anchor label="Poetry" title="Poetry Client" href="#poetry-client">Poetry</Anchor>
   * <Anchor label="Twine" title="Twine Client" href="#twine-client">Twine</Anchor>
   * <Anchor label="Pip" title="Pip Client" href="#pip-client">Pip</Anchor>
   * <Anchor label="uv Client" title="uv Client" href="#uv-client">uv Client</Anchor>

     ![](https://files.readme.io/fafd1b9ae23e5d07f265f339638ae4316a77d806759ea02c2298d4756725ecf7-uuid-504845e2-692c-7e10-c179-ce3a184f75d7.png)

<Callout icon="📘" theme="info">
  **Note**

  As Artifactory supports legacy PyPI, both underscores (_) and dots (.) are allowed in package names. However, they will not be aggregated into one package.

  For example, `jfrog.pypi` and `jfrog_pypi` will be treated as two separate packages with the same behavior as in the PyPI registry.
</Callout>

## Create a PyPI Repository

This topic describes how to create a PyPI Repository. This is required before publishing and installing PyPI packages. There are three primary types of repositories:

* **Local repositories**: Where you store and share 1st and 2nd party packages with your organization
* **Remote repositories**: Enable you to download from any remote location, including external package registries or other Artifactory instances
* **Virtual repositories**: Enable aggregating remote and local repositories, enabling your organization to scale by providing a single URL that allows access to multiple repositories and types

For more information on JFrog repositories, see [Repository Management](https://docs.jfrog.com/artifactory/docs/repository-management).

**Prerequisite**: You need Admin or Project Admin permissions to create a PyPI repository. If you don't have Admin permissions, the option will not be available.

**To create a PyPI repository**:

1. In the **Administration** tab, click **Repositories.**

   ![CreateAnsibleLocal1.png](https://files.readme.io/b02eb36eb4afad9821c963279b44bd3db6e080afe847bb6a99b57bcd0b35e4de-uuid-ae0a9517-c524-8487-f4f9-315e244ac422.png)
2. Click **Create a Repository** and then select the repository type you want to create (local, remote, or virtual).
3. In the Select Package Type window, click **PyPI**.
4. Configure the repository, as described below:

   * **Local repository**: Enter a meaningful name for the repository (for example, **pypi-local-repository-1**) and configure other basic and advanced settings, as required. For more information, see [Basic Settings for Local Repositories](/docs/local-repositories#basic-settings-for-local-repositories) and [Advanced Settings for Local Repositories](/docs/local-repositories#advanced-settings-for-local-repositories).
   * **Remote repository**: In addition to providing a name, verify the URL of the remote registry, and configure other basic and advanced settings, as required. For more information, see [Basic Settings for Remote Repositories](/docs/remote-repositories#basic-settings-for-remote-repositories) and [Advanced Settings for Remote Repositories](/docs/remote-repositories#advanced-settings-for-remote-repositories).
   * **Virtual repository**: In addition to providing a name, select one or more local or remote repositories to include in the virtual repository. For more information, see [Basic Settings for Virtual Repositories](/docs/virtual-repositories#basic-settings-for-virtual-repositories).
5. Click **Create Repository**.

## Connect Your PyPI Client to Artifactory

This topic provides details on configuring PyPI to work with Artifactory.

**Prerequisite**: Before connecting your PyPI client to Artifactory, you must have an existing PyPI repository in Artifactory. For more information, see [Create a PyPI Repository](#create-a-pypi-repository).

**Supported PyPI clients**:

* For installing and publishing packages: [Poetry](#poetry-client) (from version 1.2.0 and later), [uv](#connect-the-uv-client-to-artifactory) (from version 0.8.15 and later)
* For installing packages only: [Pip](#pip-client) (from version 20.2 and later)
* For publishing packages only: [Twine](#twine-client) (from version 3.3.0 and later)

### Poetry Client

The following topics describe how to connect Poetry as well as install and publish packages:

* [Connect the Poetry PyPI Client to Artifactory](#connect-the-poetry-pypi-client-to-artifactory)
* [Install Python Packages with Poetry](#install-python-packages-with-poetry)
* [Publish Python Packages with Poetry](#publish-python-packages-with-poetry)

#### Connect the Poetry PyPI Client to Artifactory

The <Anchor label="Poetry" target="_blank" href="https://python-poetry.org/">Poetry</Anchor> client can be used to both install and publish Python packages.

**To connect the Poetry PyPI Client to Artifactory:**

1. In the command line, configure the upload endpoint for your publishable repository with the following commands:

   ```
   poetry config repositories.artifactory-<REPOSITORY_NAME>
   https://<YOUR_JFROG_DOMAIN>/artifactory/api/pypi/<REPOSITORY_KEY>

   poetry config http-basic.artifactory-<REPOSITORY_NAME> <USER> <PASSWORD/TOKEN>
   ```

   For example:

   ```
   poetry config repositories.artifactory-pypi-local
   https://my-awesome.jfrog.io/artifactory/api/pypi/pypi-local

   poetry config http-basic.artifactory-pypi-local johnfrog RANDOM_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT
   ```

2. Add the repository source with the `source add` command as follows:

   ```
   poetry config http-basic.<REPOSITORY_NAME> <USER><PASSWORD/TOKEN>

   poetry source add <REPOSITORY_NAME> https://<YOUR_JFROG_DOMAIN>/artifactory/api/pypi/<REPOSITORY_NAME>/simple
   ```

   For example:

   ```
   poetry config http-basic.pypi-local johnfrog RANDOM_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT

   poetry source add pypi-local https://my-awesome.jfrog.io/artifactory/api/pypi/pypi-local/simple
   ```

<Callout icon="📘" theme="info">
  **Note**

  The `source add` command inserts the URL into the project's `pyproject.toml`.
</Callout>

**Next steps:**

* [Install Python Packages with Poetry](#install-python-packages-with-poetry)
* [Publish Python Packages with Poetry](#publish-python-packages-with-poetry)

#### Install Python Packages with Poetry

**To install Python packages with Poetry:**

Run the following command:

```
poetry add --source <REPOSITORY_NAME> <PACKAGE_NAME>
```

For example:

```
poetry add --source pypi-local my_pypi_package
```

#### Publish Python Packages with Poetry

**To publish Python packages with Poetry:**

Run the following command:

```
poetry publish --repository artifactory-<REPOSITORY_NAME> --dist-dir dist
```

For example:

```
poetry publish --repository artifactory-pypi-local --dist-dir dist
```

### Twine Client

The following topics describe how to connect the Twine client and publish packages:

* [Connect the Twine PyPI Client to Artifactory](#connect-the-twine-pypi-client-to-artifactory)
* [Publish Python Packages with Twine](#publish-python-packages-with-twine)

#### Connect the Twine PyPI Client to Artifactory

The <Anchor label="Twine" target="_blank" href="https://pypi.org/project/twine/">Twine</Anchor> client can be used to publish Python packages on PyPI.

**To connect the Twine PyPI client with Artifactory:**

To deploy packages using Twine, add an Artifactory repository to the `.pypirc` file (usually located in your home directory) as follows:

```
[distutils]
index-servers = <REPOSITORY_NAME>
[<REPO_NAME>]
repository: https://<YOUR_JFROG_DOMAIN>/artifactory/api/pypi/<REPOSITORY_NAME>
username: <USER>
password: <PASSWORD/TOKEN>
```

For example:

```
[distutils]
index-servers = pypi-local
[pypi-local]
repository: https://my-awesome.jfrog.io/artifactory/api/pypi/pypi-local
username: johnfrog
password: RANDOM_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT
```

**Next step:**

* [Publish Python Packages with Twine](#publish-python-packages-with-twine)

#### Publish Python Packages with Twine

**To publish (upload) Python packages with Twine:**

To upload a Python package to Artifactory, use the following command:

```
twine upload --repository <REPOSITORY_NAME> <PATH_TO_FILE>
```

For example:

```
twine upload --repository pypi-local ~/workspace/my_file.tar.gz
```

### Pip Client

The following topics describe how to connect the Pip client and install packages:

* [Connect the Pip PyPI Client to Artifactory](#connect-the-pip-pypi-client-to-artifactory)
* [Install Python Packages with Pip](#install-python-packages-with-pip)

#### Connect the Pip PyPI Client to Artifactory

The <Anchor label="pip" target="_blank" href="https://pypi.org/project/pip/">pip</Anchor> client can be used to install Python packages on your local system.

<Callout icon="✅" theme="okay">
  **Running on Windows**

  To use Artifactory PyPI repositories on Windows, you must set the required environment variables for Python and pip.

  On Windows, the per-user configuration file is named `pip.ini` and is located at `%APPDATA%\pip\pip.ini`. A legacy per-user configuration file at `%HOME%\pip\pip.ini` is also respected.

  The `pip.ini` file replaces the `pip.conf` file used on other operating systems.
</Callout>

**To connect the pip PyPI client with Artifactory:**

Add the following to `~/.pip/pip.conf`:

```
[global]
index-url = https://<USER>:<PASSWORD/TOKEN>@<YOUR_JFROG_DOMAIN>/artifactory/api/pypi/<REPO_NAME>/simple
```

For example:

```
[global]
index-url = https://johnfrog:RANDOM_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT@my-awesome.jfrog.io/artifactory/api/pypi/pypi-local/simple
```

<Callout icon="📘" theme="info">
  **Note**

  If credentials are required, they should be embedded in the URL.
</Callout>

**Next step:**

* [Install Python Packages with Pip](#install-python-packages-with-pip)

#### Install Python Packages with Pip

**To install Python packages with the pip client:**

Run the following command:

```
pip3 install <PACKAGE_NAME>
```

For example:

```
pip3 install my_pypi_package
```

### uv Client

The following topics describe how to connect the `uv` client to Artifactory and use it to manage Python packages:

* [Connect the uv Client to Artifactory](#connect-the-uv-client-to-artifactory)
* [Install Python Packages with uv](#install-python-packages-with-uv)
* [Publish Python Packages with uv](#publish-python-packages-with-uv)

#### Connect the uv Client to Artifactory

The `uv` client can be used to publish Python packages on PyPI. For more information, see <Anchor label="uv" target="_blank" href="https://pypi.org/project/uv/">uv</Anchor>.

To connect `uv` to Artifactory, complete the following steps:

1. [Set up authentication](#authenticate-the-uv-client-to-artifactory)
2. [Add environment variables for publishing](#add-uv-environment-variables-for-publishing)
3. [Configure default registry](#add-artifactory-as-the-default-registry-for-uv)

##### Authenticate the `uv` Client to Artifactory

Authenticate the `uv` client to Artifactory to be able to read and install Python packages from your repositories. There are two ways to authenticate the `uv` client to Artifactory:

* [`uv auth login` command](#connect-uv-to-artifactory-using-uv-auth-login)
* [`.netrc`](#connect-uv-to-artifactory-using-netrc)

###### Connect `uv` to Artifactory using `uv auth login`

Use `uv auth login` to securely store your Artifactory credentials and connect the `uv` client to Artifactory.

**To connect the `uv` client to Artifactory using `uv auth login`:**

* Run the following command:

  ```
  uv auth login https://[JFrogPlatformURL]/artifactory/api/pypi/<REPO> --username <USERNAME> --password <AUTH>
  ```

  Where:

  * `[JFrogPlatformURL]`: The URL of your Artifactory service endpoint
  * `<REPO>`: The name of the target repository
  * `<USERNAME>`: Your Artifactory username
  * `<AUTH>`: Your Artifactory identity token

  For example:

  ```
  uv auth login https://company.jfrog.io/artifactory/api/pypi/pypi-local --username jeffry --RANDOM_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT
  ```

<Callout icon="📘" theme="info">
  **Note**

  You can also use JFrog Set me up to copy the snippet populated with your token and environment. For more information, see <Anchor label="Use Artifactory Set Me Up for Configuring Package Manager Clients" title="Use Artifactory Set Me Up for Configuring Package Manager Clients" href="/docs/use-artifactory-set-me-up-for-configuring-package-manager-clients">Use Artifactory Set Me Up for Configuring Package Manager Clients</Anchor>.
</Callout>

###### Connect `uv` to Artifactory using `.netrc`

You can manually configure `uv` to connect to Artifactory by storing your credentials in the `.netrc` file.

**To manually connect the `uv` client to Artifactory**:

1. Open your `.netrc` file in a text editor. The file location varies by operating system:

   * **Linux/Unix**: `~/.netrc`
   * **Windows**: `%USERPROFILE%\_netrc`
2. Add the following snippet to the file:

   ```
   machine [JFrogPlatformURL]
   login <USERNAME>
   password <AUTH>
   ```

   Where:

   * `[JFrogPlatformURL]`: The hostname of your JFrog service endpoint
   * `<USERNAME>`: Your Artifactory username
   * `<AUTH>`: Your Artifactory identity token

   For example:

   ```
   machine company.jfrog.io
   login jeffry
   password RANDOM_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT
   ```
3. Save the changes to the file.

<Callout icon="📘" theme="info">
  **Note**

  You can also use JFrog Set me up to copy the snippet populated with your token and environment. For more information, see <Anchor label="Use Artifactory Set Me Up for Configuring Package Manager Clients" title="Use Artifactory Set Me Up for Configuring Package Manager Clients" href="/docs/use-artifactory-set-me-up-for-configuring-package-manager-clients">Use Artifactory Set Me Up for Configuring Package Manager Clients</Anchor>.
</Callout>

##### Add `uv` Environment Variables for Publishing

While authenticating the `uv` client allows you to install packages, you need to add environment variables to be able to publish packages to Artifactory.

**To add environment variables for publishing:**

* Run the following command:

  ```
  export UV_PUBLISH_USERNAME=<USERNAME>
  export UV_PUBLISH_PASSWORD=<AUTH>
  ```

  Where:

  * `<USERNAME>`: Your Artifactory username
  * `<AUTH>`: The Artifactory identity token you want to use for publish permissions

  For example:

  ```
  export UV_PUBLISH_USERNAME=jeffry
  export UV_PUBLISH_PASSWORD=PUBLISH_TOKEN_YWRtaW46QVBBVWJjTExkZTU4WT
  ```

<Callout icon="📘" theme="info">
  **Note**

  You can also use JFrog Set me up to copy the snippet populated with your token and environment. For more information, see <Anchor label="Use Artifactory Set Me Up for Configuring Package Manager Clients" title="Use Artifactory Set Me Up for Configuring Package Manager Clients" href="/docs/use-artifactory-set-me-up-for-configuring-package-manager-clients">Use Artifactory Set Me Up for Configuring Package Manager Clients</Anchor>.
</Callout>

##### Add Artifactory as the Default Registry for `uv`

To publish to Artifactory using the `uv` client, configure Artifactory as the default registry in the `uv.toml` file.

**To add Artifactory as your default registry:**

1. Open the `uv.toml` file in a text editor. The location of the file varies by operating system:

   * **Linux/Unix**: `~/.config/uv/uv.toml`
   * **Windows**: `%APPDATA%\uv\uv.toml`

   If the file doesn't exist, create it in the appropriate location.
2. Add the following snippet to the `uv.toml` file:

   ```
   [[index]]
   name="<REPO>"
   publish-url = "https://[JFrogPlatformURL]/artifactory/api/pypi/<REPO>"
   url = "https://[JFrogPlatformURL]/artifactory/api/pypi/<REPO>/simple"
   default = true
   ```

   Where:

   * `<REPO>`: The name of the target repository
   * `[JFrogPlatformURL]`: The hostname for your JFrog service endpoint

   For example:

   ```
   [[index]]
   name="pypi_local"
   publish-url = "https://company.jfrog.io/artifactory/api/pypi/pypi_local"
   url = "https://company.jfrog.io/artifactory/api/pypi/pypi_local/simple"
   default = true
   ```
3. Save the changes to the file.

<Callout icon="📘" theme="info">
  **Note**

  You can also use JFrog Set me up to copy the snippet populated with your token and environment. For more information, see [Use Artifactory Set Me Up for Configuring Package Manager Clients](/docs/use-artifactory-set-me-up-for-configuring-package-manager-clients).
</Callout>

**Next step:**

* [Install Python Packages with uv](#install-python-packages-with-uv)
* [Publish Python Packages with uv](#publish-python-packages-with-uv)

#### Install Python Packages with uv

You can use the `uv` client to install Python packages from Artifactory.

**To resolve packages from Artifactory with `uv`:**

* Run one of the following commands:

  * Using the `uv`-native project API:

    ```
    uv add <PACKAGE>
    ```

    Where `<PACKAGE>` is the name of the package you want to resolve. For example:

    ```
    uv add pandas
    ```
  * Using the `pip` compatibility API:

    ```
    uv pip install <PACKAGE>
    ```

    Where `<PACKAGE>` is the name of the package you want to install. For example:

    ```
    uv pip install flask
    ```

#### Publish Python Packages with uv

You can use `uv` to natively publish Python packages to Artifactory.

**To publish to Artifactory with `uv`:**

* Run the following command:

  ```
  uv publish <FILE_PATH> --index <REPO>
  ```

  Where:

  * `<FILE_PATH>`: The file path to the project you want to publish
  * `<REPO>`: The name of the target repository in Artifactory

  For example:

  ```
  uv publish dist/* --index pypi_local
  ```

## Additional PyPI Information

The following additional actions are available with PyPI repositories:

* [Use PyPI Package Naming Tools](#use-pypi-package-naming-tools)
* <Anchor label="Search for PyPI Packages" title="Search for PyPI Packages" href="#search-for-pypi-packages">Search for PyPI Packages</Anchor>
* [View Metadata of PyPI Packages](#view-metadata-of-pypi-packages)
* [Work with PyPI Remote Repositories with the Custom Registry Suffix](#work-with-pypi-remote-repositories-with-the-custom-registry-suffix)
* <Anchor label="Resolve from Artifactory Using Pip" title="Resolve from Artifactory Using Pip" href="#resolve-from-artifactory-using-pip">Resolve from Artifactory Using Pip</Anchor>
* [Additional PyPI Publishing Tools](#additional-pypi-publishing-tools)
* [Publish PyPI Packages Manually Using the Web UI or the REST API](#publish-pypi-packages-manually-using-the-web-ui-or-the-rest-api)
* [Enable JSON Indexing in PyPI Repositories](#enable-json-indexing-in-pypi-repositories)

### Use PyPI Package Naming Tools

Artifactory provides the following tools for naming PyPI packages correctly:

* [Use PyPI Enforce Layout](#use-pypi-enforce-layout)
* [Use PyPI File Path Name Normalization](#use-pypi-file-path-name-normalization)
* [Use Both PyPI File Path Naming Normalization and Enforce Layout](#use-both-pypi-file-path-naming-normalization-and-enforce-layout)

Used either together or separately, these tools help you keep a consistent naming method for PyPI artifacts to reduce potential package name duplications.

#### Use PyPI Enforce Layout

The PyPI Enforce Layout feature ensures that uploaded packages adhere to a standardized physical directory structure, filenames, and internal metadata, to promote a consistent and compliant repository.

JFrog recommends using this feature in conjunction with File Path Name Normalization. For more information, see [Use File Path Name Normalization](#use-pypi-file-path-name-normalization) and [Using Both File Path Name Normalization and Enforce Layout](#use-both-pypi-file-path-naming-normalization-and-enforce-layout).

PyPI Enforce Layout is available in Artifactory starting from version 7.70.2.

<Callout icon="📘" theme="info">
  **Backward Compatibility**

  Enforce Layout applies to all PyPI repositories in your Artifactory instance. Previously uploaded packages that already exist in your instance will not be updated but if you attempt to upload a newer version or overwrite an existing one you will be prevented from doing so since the file path name sections must match the metadata values.
</Callout>

This feature enables you to restrict uploads to artifacts where the file name and version in the path match the package name and version stored in the artifact’s metadata.

The following examples explain how this feature applies **without** File Path Name Normalization:

![enforce\_layout\_table.png](https://files.readme.io/8e081949f014ce5933ac7a05046cc34f1daa0270df3ed26b7df7d914df161eb9-uuid-7c2ae3f9-df9f-0dbe-95da-954e16b8f6d8.png)

To enable PyPI Enforce Layout, in the **artifactory.system.properties** settings file set the system property:

```
artifactory.pypi.enforce.layout = true
```

Artifactory will return an error when trying to perform actions on an artifact with a name that does not match the package metadata, with a description of the issue:

| Error | Description                                                                                                                                                                           |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 403   | `Action prevented due to Enforce Layout policy - package file name/version <ARTIFACT_NAME> does not match the ” + package internal name/version <ARTIFACT_NAME> in the metadata file` |
| 403   | `Action prevented due to Enforce Layout policy - could not find metadata file to compare`                                                                                             |

#### Use PyPI File Path Name Normalization

The PyPI File Path Name Normalization feature brings Artifactory closer in alignment with the **PyPI.org** registry by enforcing a consistent naming method for PyPI artifacts, which reduces potential package name duplications due to the use of non-normalized characters.

JFrog recommends using this feature in conjunction with PyPI Enforce Layout. For more information, see [Use PyPI Enforce Layout](#use-pypi-enforce-layout) and [Using Both PyPI File Path Name Normalization and Enforce Layout](#use-both-pypi-file-path-naming-normalization-and-enforce-layout).

PyPI Enforce Layout is available in Artifactory starting from version 7.70.2.

<Callout icon="📘" theme="info">
  **Backward Compatibility**

  File Path Name Normalization applies to all PyPI repositories in your Artifactory instance, previously uploaded packages that already exist in your instance will not be updated, but if you attempt to upload a newer version or overwrite an existing one you will be prevented from doing so since the file path name does not conform to the normalization rules.
</Callout>

When this feature is enabled, Artifactory blocks the deployment of files with path name/distribution values that do not conform to standard PyPI naming conventions, as specified in the Python documentation pages (see <Anchor label="Distribution File Name" target="_blank" href="https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-file-name">Distribution File Name</Anchor> and <Anchor label="File Format" target="_blank" href="https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format">File Format</Anchor>).

```
{NAME}-{VERSION}-{OPTIONAL-PARAMETERS}.tar.gz
{DISTRIBUTION}-{VERSION}-{OPTIONAL-PARAMETERS}.whl
```

The most common example of how this feature provides value is the prevention of the dash (-), which is considered a Reserved Character between the different segments of the naming path (name/distribution, version, optional parameters, etc.), from being used within the name/distribution segment.

The table below describes which names would be allowed when File Path Name Normalization is enabled:

![Normalization\_table.png](https://files.readme.io/561997529b9392a262af2f770bc77597061b40a843a03f1709e41411aad3f19f-uuid-0d26973d-eb89-706d-e615-9c4b152155b3.png)

To enable PyPI File Path Name Normalization, in the **artifactory.system.properties** settings file set the following system property:

```
artifactory.pypi.enforce.naming.normalization = true 
```

Artifactory will return an error when trying to perform actions on an artifact whose name does not match the naming conventions, with a description of the issue:

| Error | Description                                                                                                                                         |
| ----- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| 403   | `Action prevented due to artifact file name normalization requirements - artifact name <ARTIFACT_NAME> does not conform to normalized requirements` |

#### Use Both PyPI File Path Naming Normalization and Enforce Layout

[PyPI Path Name Normalization](#use-pypi-file-path-name-normalization) and [PyPI Enforce Layout](#use-pypi-enforce-layout) work both independently and together to create a safety net for correct package naming.

The Enforce Layout setting ensures that the file path and metadata have matching properties, while the File Path Name Normalization setting verifies that the names conform to standard PyPI naming conventions. Using both features will ensure that you do not have duplicate or redundant packages.

<Callout icon="❗️" theme="error">
  **Important**

  Please note that although PyPI allows the use of the dash in the internal metadata names, our enforce layout feature is strict, and your metadata names must always match the file path name.
</Callout>

For example, this will be the behavior when both File Path Name Normalization and Enforce Layout are enabled:

![Normalization\_and\_enforce\_layout\_table.png](https://files.readme.io/7b7c8e677d91966892189e66cd4863128bd98eea38040b9512a34eec7b1aad49-uuid-92b1c6d4-5a10-b308-7ac0-f8cd3cba4f58.png)

### Search for PyPI Packages

#### Use Pip Search

Artifactory supports search using the pip *search* command in local and virtual repositories. For example:

```
$ pip search frog-fu --index http://localhost:8081/artifactory/api/pypi/pypi-virtual/
frog-fu                   - 0.2a
  INSTALLED: 0.2a (latest)

$ pip search irbench --index http://localhost:8081/artifactory/api/pypi/pypi-virtual/
irbench                   - Image Retrieval Benchmark.
```

In this example, **frog-fu** and **irbench** are two locally installed packages in different local repositories, and both repositories are aggregated by the **pypi-virtual** repository.

<Callout icon="📘" theme="info">
  **Note**

  Since <Anchor label="pip search has been deprecated" target="_blank" href="https://pip.pypa.io/en/stable/cli/pip_search/">pip search has been deprecated</Anchor>, Artifactory no longer supports pip search in remote repositories, including [Smart Remote repositories](/docs/smart-remote-repositories). As such, if a virtual repository includes remote repositories, those remote repositories will not be scanned for search results.
</Callout>

<Callout icon="📘" theme="info">
  **Specifying the index**

  When using the search command, the index should be specified explicitly (without the `/simple` at the end), as pip will ignore the `index-url` variable in its `pip.conf` file.
</Callout>

#### Use Artifactory Search

PyPI packages can also be searched for using Artifactory's [Property Search](/docs/application-search#property-search). All PyPI packages have the properties `pypi.name`, `pypi.version` and `pypi.summary` set by the uploading client, or later during indexing for supported file types.

### View Metadata of PyPI Packages

Artifactory lets you view selected metadata for a PyPI package directly from the UI.

In the **Artifacts** module **Tree Browser**, drill down to select the file you want to inspect. The metadata is displayed in the **PyPI Info** tab.

![PyPIInfo.jpg](https://files.readme.io/6509c7cc0c6f3ef6175cde10eb89c70fdc3f14cd53294ac0d411816a33e3ee39-uuid-e44f9afa-249a-d329-c3aa-1e36dafd6383.jpg)

### Work with PyPI Remote Repositories with the Custom Registry Suffix

You can set a custom suffix instead of the default suffix, for example to work with a non-default index layout.

**To set a custom registry suffix:**

When creating the repository, enter the same root URL for both the **URL** and **Registry URL** fields. For example: `http://somepyserver.net`.

<Image align="center" border={true} width="90% " src="https://files.readme.io/4188953f6e36972342d7d79a567802ae14ce1d7d0fdf8945447e31ab93207359-url_registry_url.png" className="border" />

To search, include the required scope in the index URL (as in the `somepyserver` example, it could be `myorg/mypypi`).

```
$ pip search frog-fu --index http://localhost:8081/artifactory/api/pypi/somepyserver/myorg/mypypi/
```

To install, include the desired scope in the index URL (as in the `somepyserver` example, it could be `myorg/mypypi`).

```
$ pip install frog-bar -i http://localhost:8081/artifactory/api/pypi/somepyserver/myorg/mypypi/simple
```

### Resolve from Artifactory Using Pip

To install the `pip` command line tool refer to <Anchor label="pip documentation" target="_blank" href="https://pip.pypa.io/en/stable/installation/">pip documentation</Anchor>. We recommend using <Anchor label="virtualenv" target="_blank" href="https://virtualenv.pypa.io/en/latest/">virtualenv</Anchor> to separate your environment when installing PIP.

<Callout icon="📘" theme="info">
  **Using a Valid SSL Certificate with pip and Artifactory**

  pip uses packages from the local cache, (i.e. from the machine on which the pip client is running on), only if the download URL of the package is a trusted host with a valid SSL certificate. This means that if your Artifactory instance is not running with a valid SSL certificate, requests for packages will always first reach Artifactory even if the packages exist on the local cache.
</Callout>

To display code snippets you can use to configure `pip` and `setup.py` to use your PyPI repository, select the repository and then click **Set Me Up.**

<Image align="center" alt="PyPISetMeUp.jpg" border={true} src="https://files.readme.io/462ec9d9ed1d80c955829cefcdb2ac6e2cadf31413112b2aa4d2480b842aabe4-uuid-73011630-6353-9d46-ded5-036ddd7e0104.jpg" className="border" />

#### Specify the PyPI Repository on the Command Line

<Callout icon="📘" theme="info">
  **Index URL**

  When accessing a PyPI repository through Artifactory, the repository URL should be prefixed with `api/pypi` in the path. This applies to all `pip` commands and `distutils` URLs including `pip install.`

  When using `pip` to resolve PyPI packages it must point to `<Artifactory URL>/api/pypi/<repository key>/simple` .

  For example, if you are using Artifactory standalone or as a local service, you would access your PyPI repositories using the following URL:

  `http://localhost:8081/artifactory/api/pypi/<repository key>/simple`

  Or, if you are using Artifactory Cloud, the URL would be:

  `https://<server name>.jfrog.io/artifactory/api/pypi/<repository key>/simple`
</Callout>

Once pip is installed, it can be used to specify the URL of the repository from which to resolve:

**Installing with full repository URL**

```
$ pip install frog-bar -i http://localhost:8081/artifactory/api/pypi/pypi-local/simple
```

<Callout icon="📘" theme="info">
  **Note**

  The default configuration snippet for Nginx and Apache using reverse proxy contains the `X-JFrog-Override-Base-Url` by default. If reverse proxy is not used in your environment, you need to add the header manually to the request, for example:

  ```
  -H "X-JFrog-Override-Base-Url: http://$ART_HOST"
  ```

  Instead of adding the header manually, you can also run the request on port 8081, or add a slash (/) at the end of the request:

  ```
  http://$ART_HOST/artifactory/api/pypi/pypi-virtual/simple/
  ```
</Callout>

#### Use PyPI Credentials

Due to its design, pip does not support reading credentials from a file. Credentials can be supplied as part of the URL, for example `http://<username>:<password>@localhost:8081/artifactory/api/pypi/pypi-local/simple`. The password can be omitted (with the preceding colon), and in this case, the user will be prompted to enter credentials interactively.

#### Use a Pip Configuration File

Aliases for different repositories can be specified through a pip configuration file, *\~/.pip/pip.conf* . The file contains configuration parameters per repository, for example:

**\~/.pip/pip.conf**

```
[global]
index-url = http://user:password@localhost:8081/artifactory/api/pypi/pypi-virtual/simple
```

For more information, please refer to <Anchor label="PIP User Guide" target="_blank" href="https://pip.pypa.io/en/stable/user_guide/#config-file">PIP User Guide</Anchor>.

#### Use a Pip Requirements File

A requirements file contains a list of packages to install. Usually, these are dependencies for the current package. It can be created manually or using the `pip freeze` command. The index URL can be specified in the first line of the file, For example:

**requirements.txt**

```
--index-url http://localhost:8081/artifactory/api/pypi/pypi-local/simple
PyYAML==3.11
argparse==1.2.1
frog-bar==0.2
frog-fu==0.2a
nltk==2.0.4
wsgiref==0.1.2
```

### Additional PyPI Publishing Tools

<Callout icon="📘" theme="info">
  **Limitation**

  Users should not deploy packages in Artifactory to repositories in the paths `pypi-repo/packages/**` or `pypi-repo/simple/**` , as these are saved namespaces used by Artifactory for internal logic. If you attempt to deploy to these paths, Artifactory returns a 400 error.
</Callout>

In addition to the [PyPI clients](#connect-your-pypi-client-to-artifactory) supported by Artifactory, there are several alternative methods for publishing PyPI packages to Artifactory:

* [Use disutils or setuptools](#use-pypi-distutils-or-setuptools)
* <Anchor label="Use .netrc" title="Use .netrc to Upload PyPI Packages" href="#use-netrc-to-upload-pypi-packages">Use .netrc</Anchor>
* [Upload Authenticated PyPI Packages to JFrog Artifactory](#upload-authenticated-pypi-packages-to-jfrog-artifactory)
* [Upload PyPI Egg and Wheel Packages](#upload-pypi-egg-and-wheel-packages)

#### Use PyPI distutils or setuptools

<Callout icon="📘" theme="info">
  **setuptools vs. distutils and python versions**

  Artifactory is agnostic to whether you use `setuptools` or `distutils`, and also to the version or implementation of Python your project uses.

  The following instruction were written for Python 2.7 and `setuptools` in mind. Using different version of Python, or different tools such `zest, distutils` and others may require minor modification to the instructions below.
</Callout>

Uploading to Artifactory using a `setup.py` script is supported in a similar way to uploading to PyPI. First, you need to add Artifactory as an index server for your user.

For instructions on using *setuptools* to package Python projects and create a `setup.py` script, please refer to the <Anchor label="setuptools documentation" target="_blank" href="https://pythonhosted.org/an_example_pypi_project/setuptools.html#setting-up-setup-py">setuptools documentation</Anchor> and <Anchor label="this tutorial project" target="_blank" href="https://pythonhosted.org/an_example_pypi_project/setuptools.html">this tutorial project</Anchor>.

##### Create the $HOME/.pypirc File

To upload to Artifactory, an entry for each repository needs to be made in `$HOME/.pypirc` as follows:

```
[distutils]
index-servers =
    local
    pypi

[pypi]
repository: https://pypi.org/pypi
username: mrBagthrope
password: notToBeSeen

[local]
repository: http://localhost:8081/artifactory/api/pypi/pypi-local
username: admin
password: password
```

Notice that the URL does not end with `/simple`.

<Callout icon="📘" theme="info">
  **The HOME environment variable**

  `setuptools` requires that the `.pypirc` file be found under `$HOME/.pypirc,` using the `HOME` environment variable.

  On unix-like systems this is usually set by your system to `/home/yourusername/` but in certain environments such as build servers you will have to set it manually.

  On Windows it must be set manually.
</Callout>

#### Use .netrc to Upload PyPI Packages

Uploading PyPI packages to Artifactory using a `.netrc` file credentials is supported. For more information on the `.netrc` file , see <Anchor label="The .netrc file" target="_blank" href="https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html">The .netrc file</Anchor> and <Anchor label="Purpose of the '.netrc' file" target="_blank" href="https://stackoverflow.com/questions/21828495/purpose-of-the-netrc-file">Purpose of the '.netrc' file</Anchor>.

<Callout icon="📘" theme="info">
  **Note**

  * For information on how to use a Keyring provider via PyPI repositories, see <Anchor label="How to use Keyring Provider via Pypi Repositories" target="_blank" href="https://jfrog.com/help/r/artifactory-how-to-use-keyring-provider-via-pypi-repositories/artifactory-how-to-use-keyring-provider-via-pypi-repositories">How to use Keyring Provider via Pypi Repositories</Anchor>.
  * The Twine client is not compatible with `.netrc` credentials.
</Callout>

To use the `.netrc` file:

1. To create a `.netrc` file in your root directory and set it with the minimum required permissions (Chmod 600), if you do not have one already, run the following command:

   ```
   touch ~/.netrc
   ```

2. Run the following command to populate the `.netrc` file with your Artifactory URL and credentials according to the `.netrc` file format:

<Callout icon="📘" theme="info">
  **Note**

  Make sure to replace the placeholders in **bold** with your own Artifactory URL, username, and password or identity token.
</Callout>

```
echo "machine <ARTIFACTORY_URL> login <USERNAME> password <PASSWORD/TOKEN>" > ~/.netrc
```

#### Upload Authenticated PyPI Packages to JFrog Artifactory

To upload authenticated PyPI packages to JFrog Artifactory:

1. Create the `.pypirc` file using the following code, and add your access token from JFrog Artifactory for the username `pypiadmin.`.

   ```
   [distutils]
   index-servers =
      private-repository
    
   [private-repository]
   repository = https://soleng.jfrog.io/artifactory/api/pypi/demo-pypi-local
   username = pypiadmin
   password = eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJsYkpadzNJUU13WXBBSWNRa01RRjN0dlA2Yml5M3dWcXdrQ0txUkxLaXhRIn0.eyJleHQiOiJ7XCJyZXZvY2FibGVcIjpcInRydWVcIn0iLCJzdWIiOiJqZmFjQDAxZTlycTMza3ljMHQxMWtwangybmcwemo1XC91c2Vyc1wvcHlwaWFkbWluIiwic2NwIjoiYXBwbGllZC1wZXJtaXNzaW9uc1wvYWRtaW4iLCJhdWQiOiIqQCoiLCJpc3MiOiJqZmZlQDAwMCIsImV4cCI6MTY4OTY5ODA5MywiaWF0IjoxNjU4MTYyMDkzLCJqdGkiOiJiZWY1YWY5Ni0zNTkyLTRiOTQtYWYyNS1kZmIxY2U1ZGU4YzIifQ.NI5OXpw0NHs7Asd3f_sY3tMyzM-2_07c3WyWEpbJrDPxO8eKoLRp10vGEF8Jo3HyRQ0H7Ybzf2-Cn8wf9yFMo4UGlgxGfm7_yc24xWVLCINjg0B2A5YRSvAetwdT2wgVPvEMUqCPSCU4_SGgGg606lIDxxImRfgZWwFn-wHfU8b8dCV7EV4dXGvH7iVb33W2JguE9KIQFP7lKkQlaErO6pGFNuPfOx1JbJllHh0oRpAPzvykda2i6Q2q3ZCObJZ9Rp8NqZYQfEm42YtIaOvAlE5fGepZgDjzHaaLcztJDHoR-BWjMiDfP0LRThHASo7F52t8p3vsZHW5NEov_trFrQ
   ```
2. Copy the `.pypirc` file to your Users folder.

   * For macOS users, create the file under `%USERPROFILE%`
   * For Windows users, create the file under `c:\users\<name>`
3. Validate that the `setup.py` file contains all of the following fields. It should be automatically created, but if it is not, add the file to your root folder with the following content.

   ```
   #!/usr/bin/env python
    
   from setuptools import setup
    
   setup(
       name='demo-python-example',
       version='1.0',
       description='Project example for building Python project with JFrog products',
       author='JFrog',
       author_email='jfrog@jfrog.com',
       packages=['helloworld'],
       install_requires=['PyYAML>3.11', 'nltk'],
   )
   ```
4. Create a PyPI package.

   ```
   py setup.py sdist bdist_wheel
   ```

   The following displays an example output.

   ```
   C:\Users\johnk\helloworld>py setup.py sdist bdist_wheel
   running sdist
   running egg_info
   writing demo_python_example.egg-info\PKG-INFO
   writing dependency_links to demo_python_example.egg-info\dependency_links.txt
   writing requirements to demo_python_example.egg-info\requires.txt
   writing top-level names to demo_python_example.egg-info\top_level.txt
   reading manifest file 'demo_python_example.egg-info\SOURCES.txt'
   writing manifest file 'demo_python_example.egg-info\SOURCES.txt'
   warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
   running check
   creating demo-python-example-1.0
   creating demo-python-example-1.0\demo_python_example.egg-info
   creating demo-python-example-1.0\helloworld
   copying files to demo-python-example-1.0...
   copying setup.py -> demo-python-example-1.0
   copying demo_python_example.egg-info\PKG-INFO -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\SOURCES.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\dependency_links.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\requires.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\top_level.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying helloworld\app.py -> demo-python-example-1.0\helloworld
   Writing demo-python-example-1.0\setup.cfg
   Creating tar archive
   removing 'demo-python-example-1.0' (and everything under it)
   running bdist_wheel
   running build
   running build_py
   C:\Users\johnk\installs\lib\site-packages\setuptools\command\install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
     warnings.warn(
   installing to build\bdist.win-amd64\wheel
   running install
   running install_lib
   creating build\bdist.win-amd64\wheel
   creating build\bdist.win-amd64\wheel\helloworld
   copying build\lib\helloworld\app.py -> build\bdist.win-amd64\wheel\.\helloworld
   running install_egg_info
   Copying demo_python_example.egg-info to build\bdist.win-amd64\wheel\.\demo_python_example-1.0-py3.10.egg-info
   running install_scripts
   creating build\bdist.win-amd64\wheel\demo_python_example-1.0.dist-info\WHEEL
   creating 'dist\demo_python_example-1.0-py3-none-any.whl' and adding 'build\bdist.win-amd64\wheel' to it
   adding 'helloworld/app.py'
   adding 'demo_python_example-1.0.dist-info/METADATA'
   adding 'demo_python_example-1.0.dist-info/WHEEL'
   adding 'demo_python_example-1.0.dist-info/top_level.txt'
   adding 'demo_python_example-1.0.dist-info/RECORD'
   removing build\bdist.win-amd64\wheel
   C:\Users\johnk\helloworld>
   ```
5. Upload the package to JFrog Artifactory.

   ```
   py setup.py sdist upload -r private-repository
   ```

   The following displays an example output.

   ```
   C:\Users\johnk\helloworld>py setup.py sdist bdist_wheel
   running sdist
   running egg_info
   writing demo_python_example.egg-info\PKG-INFO
   writing dependency_links to demo_python_example.egg-info\dependency_links.txt
   writing requirements to demo_python_example.egg-info\requires.txt
   writing top-level names to demo_python_example.egg-info\top_level.txt
   reading manifest file 'demo_python_example.egg-info\SOURCES.txt'
   writing manifest file 'demo_python_example.egg-info\SOURCES.txt'
   warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
   running check
   creating demo-python-example-1.0
   creating demo-python-example-1.0\demo_python_example.egg-info
   creating demo-python-example-1.0\helloworld
   copying files to demo-python-example-1.0...
   copying setup.py -> demo-python-example-1.0
   copying demo_python_example.egg-info\PKG-INFO -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\SOURCES.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\dependency_links.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\requires.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying demo_python_example.egg-info\top_level.txt -> demo-python-example-1.0\demo_python_example.egg-info
   copying helloworld\app.py -> demo-python-example-1.0\helloworld
   Writing demo-python-example-1.0\setup.cfg
   Creating tar archive
   removing 'demo-python-example-1.0' (and everything under it)
   running bdist_wheel
   running build
   running build_py
   C:\Users\johnk\installs\lib\site-packages\setuptools\command\install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
     warnings.warn(
   installing to build\bdist.win-amd64\wheel
   running install
   running install_lib
   creating build\bdist.win-amd64\wheel
   creating build\bdist.win-amd64\wheel\helloworld
   copying build\lib\helloworld\app.py -> build\bdist.win-amd64\wheel\.\helloworld
   running install_egg_info
   Copying demo_python_example.egg-info to build\bdist.win-amd64\wheel\.\demo_python_example-1.0-py3.10.egg-info
   running install_scripts
   creating build\bdist.win-amd64\wheel\demo_python_example-1.0.dist-info\WHEEL
   creating 'dist\demo_python_example-1.0-py3-none-any.whl' and adding 'build\bdist.win-amd64\wheel' to it
   adding 'helloworld/app.py'
   adding 'demo_python_example-1.0.dist-info/METADATA'
   adding 'demo_python_example-1.0.dist-info/WHEEL'
   adding 'demo_python_example-1.0.dist-info/top_level.txt'
   adding 'demo_python_example-1.0.dist-info/RECORD'
   removing build\bdist.win-amd64\wheel
   C:\Users\johnk\helloworld>
   ```
6. Your package was uploaded successfully to the JFrog Platform. Check it out by navigating to **Artifactory > Artifacts** in the Platform module.

#### Upload PyPI Egg and Wheel Packages

After creating a `.pypirc` file and a `setup.py` script at the root of your project, you can upload your egg (tar.gz) packages as follows:

```
~/python_project $ python setup.py sdist upload -r local
```

If you are using wheel (`whl`) you can upload your packaged as follows:

```
~/python_project $ python setup.py bdist_wheel upload -r local
```

Or if you wish to use both egg (`tar.gz`) and wheel (`whl`), you can upload them as follows:

```
~/python_project $ python setup.py sdist bdist_wheel upload -r local
```

Where **local** is the name of the section in your `.pypirc` file that points to your Artifactory PyPI repository.

<Callout icon="📘" theme="info">
  **Default upload**

  By default, both `setuptools` and `distutils` will upload to `https://pypi.org/pypi` if no repository is specified.
</Callout>

<Callout icon="📘" theme="info">
  **The 'register' command should be omitted**

  When uploading directly to `pypi.org` _,_ the documentation states that your package must first be registered by calling`python setup.py register.`

  When uploading to Artifactory this is neither required nor supported and **should be omitted**.
</Callout>

### Publish PyPI Packages Manually Using the Web UI or the REST API

PyPI packages can also be uploaded manually using the [Web UI](/docs/deploy-artifacts) or the [Artifactory REST API](/reference/deployartifact). For Artifactory to handle those packages correctly as PyPI packages, they must be uploaded with `pypi.name` and `pypi.version` properties.

<Callout icon="📘" theme="info">
  **Automatic extraction of properties**

  While indexing the newly uploaded packages Artifactory will automatically try to extract required properties from the package metadata saved in the file. Note that not all supported files can be extracted.

  Currently, only `zip` , `tar`, `tgz`, `tar.gz`, `tar.bz2`, `egg` and `whl` files can be extracted for metadata.

  In addition, indexing starts after a 60 second quiet period, counting from the last upload to the current repository.
</Callout>

### Enable JSON Indexing in PyPI Repositories

PyPI repositories in Artifactory support JSON indexing through the PyPI Simple JSON API. When JSON indexing is enabled, PyPI repositories in Artifactory return JSON-formatted indexes. JSON formatting is supported for local, remote, and virtual repositories, with local repositories continuing to index both in JSON and HTML.

**Prerequisites:** You must have Admin or Project Admin permissions to configure Artifactory settings.

**To enable JSON indexing:**

1. On the Administration module, navigate to **Artifactory Settings > Packages Settings**.
2. Under PyPI, select the **Enable simple json format** checkbox.
3. Click **Save**.

#### Limitations

The following items are limitations of the PyPI Simple JSON API in PyPI in Artifactory:

* **Fallback logic**: If JSON is requested but not available, the system falls back to HTML. If HTML is requested but not available, the system returns nothing.
* **Virtual repositories**: Virtual repositories only serve JSON if all included sub-repositories can provide it. If any sub-repository is restricted to HTML, the virtual repository responds with HTML to maintain consistency.
* **Offline availability risks**: If JSON indexing is disabled after caching indexes from a remote source, you may lose access to those indexes if that source is offline. Because Artifactory cannot fetch the required HTML equivalents from an offline repository, the packages remain unavailable until the connection is restored.