Run twine commands to publish Python packages to Artifactory with optional build-info collection.

When to Use

Use jf twine to publish Python packages (wheels, sdists) to Artifactory. This is the upload counterpart to jf pip (which installs packages).

Typical Python publish workflow:

# 1. Build the package
python -m build

# 2. Upload to Artifactory with build-info
jf twine upload dist/* --build-name=my-python-lib --build-number=$BUILD_NUMBER

# 3. Publish build info
jf rt build-publish my-python-lib $BUILD_NUMBER

Prerequisites

  • Twine must be installed separately (pip install twine).
  • Run jf pip-config or jf pipenv-config before using jf twine — twine uses the deployer repository from that configuration.
  • Configure a server with jf config add or jf c add.
  • Authentication to Artifactory is required.
  • Build your package (e.g., python -m build) before running jf twine upload.

Build: jf twine

Run twine commands to publish Python packages to Artifactory with optional build-info collection.

To publish Python packages with Twine:

Synopsis

jf twine <twine-arguments> [options]

Aliases: none

Arguments

ArgumentRequiredDescription
<twine-arguments>YesArguments and options for the twine command (for example, upload, check)

Build Options

FlagDefaultDescription
--build-nameBuild name for build-info. Requires --build-number.
--build-numberBuild number for build-info. Requires --build-name.
--moduleOptional module name for build-info. Requires --build-name and --build-number.
--projectJFrog Artifactory project key

Build Examples

Help

jf twine --help

Basic Usage

jf twine upload dist/* --build-name=<build-name> --build-number=<build-number>

Where:

  • <build-name>: A name for the build (for example, my-python-lib)
  • <build-number>: A number or identifier for the build run (for example, 1)

For example:

jf twine upload dist/* --build-name=my-python-lib --build-number=1

Upload with Build-Info

jf twine upload dist/*.whl dist/*.tar.gz --build-name=my-package --build-number=1

Check Package

jf twine check dist/*

Important Notes

  • pip-config or pipenv-config covers twine: The jf twine command reads its deployment repository from either a jf pip-config or jf pipenv-config configuration — whichever exists in your project. If both are present, the CLI checks for pip config first, then pipenv. You do not need a separate jf twine-config command. If neither config is found, you will see: no config file was found! Before running the 'jf twine' command on a project for the first time, the project should be configured with the 'jf pip-config OR pipenv-config' command.
  • Twine must be installed separately (pip install twine).
  • The check subcommand validates package metadata before upload — use it to catch issues early.

CI/CD Example (GitHub Actions)

# .github/workflows/build.yml
steps:
  - uses: actions/checkout@v4
  - name: Setup JFrog CLI
    uses: jfrog/setup-jfrog-cli@v4
    env:
      JF_URL: ${{ vars.JF_URL }}
      JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
  - name: Setup Python
    uses: actions/setup-python@v5
    with:
      python-version: '3.12'
  - name: Install build tools
    run: pip install build twine
  - name: Configure pip
    run: jf pip-config --server-id-resolve=setup-jfrog-cli-server --repo-resolve=pypi-virtual --server-id-deploy=setup-jfrog-cli-server --repo-deploy=pypi-local
  - name: Build package
    run: python -m build
  - name: Upload to Artifactory
    run: jf twine upload dist/* --build-name=my-python-lib --build-number=${{ github.run_number }}
  - name: Publish build info
    run: jf rt build-publish my-python-lib ${{ github.run_number }}

Troubleshooting

SymptomCauseFix
no config file was foundNeither jf pip-config nor jf pipenv-config was runRun jf pip-config (or jf pipenv-config) with --repo-deploy set
401 / 403 on uploadInvalid credentials or missing deploy permissionsRe-run jf config add; verify the user has deploy permissions on the target local repo
"file not found" on jf twine upload dist/*Package was not built firstRun python -m build before jf twine upload
Upload succeeds but package not visibleUploaded to wrong repositoryConfirm --repo-deploy in your pip/pipenv config points to a PyPI local repository
twine not foundTwine is not installedRun pip install twine

Enable debug logging: export JFROG_CLI_LOG_LEVEL=DEBUG


Related Topics