Getting Started with Trusted Publishing to PyPI

ActiveState stands as a Trusted Publisher on PyPI, offering developers an intuitive and streamlined package publishing process that encourages the exploration and adoption of ActiveState’s comprehensive development management abilities.

The initial Trusted Publisher Release offers:

  • Zero-configuration CI: Publish packages to PyPI without the setup hassle.
  • Cross-platform compatibility: Build wheels that work seamlessly across different environments.

The Trusted Publisher initiative does not just simplify the publishing process; it also lays the groundwork for a more collaborative, secure, and efficient Python development ecosystem through the ActiveState Platform. To effectively publish a package or wheel to PyPI, you’ll need an ActiveState account and the State Tool.

To publish a package to PyPI, follow the steps below. Existing ActiveState users who have the State Tool installed and are authenticated can begin at step 3.

  1. Download the State Tool
  2. Authenticate your account or Sign up for a new account
  3. Create a new Python project
  4. Publish your package to the ActiveState Platform
  5. Creating a PyPI project with a Trusted Publisher
  6. Build and download your Python wheel (optional)
  7. Publish to PyPI

For more information, and to find out what’s coming next see the Trusted Publisher Roadmap at the end of this article.


1. Download and install the State Tool

Linux or macOS

Open your command prompt and execute the following command

sh <(curl -q https://platform.activestate.com/dl/cli/w19880m01/install.sh)

Once installed, we recommend closing and re-opening your command prompt to ensure your environment is properly updated.

Windows

After installing the State Tool .exe, you may be prompted to allow the State Tool executable access to your system before the installation can be completed.

You can also install the State Tool from the command line by running the following command

powershell -Command "& $([scriptblock]::Create((New-Object Net.WebClient).DownloadString('https://platform.activestate.com/dl/cli/install.ps1')))"

More information on working with the State Tool can be found here.


2. Sign up for an ActiveState account, or authenticate an existing account

Signing up for an ActiveState account lets you store the configuration for your projects, easily collaborate with contributors, and act as a “one-stop shop” for building, managing, and distributing Open Source language runtimes.

After downloading and installing the State Tool, open a command terminal and enter

state auth

If you are creating a new ActiveState account, follow the prompts given to create an organization for your project(s). Take note of the organization name as you’ll need it for the next step.

If you are working from an existing account, continue to the next step after authentication.


3. Create a new Python project using the State Tool

The ActiveState Platform bundles your dependencies into an easily consumable and deployable project runtime. Runtimes can be created for one user, or shared with other users who are members of the same organization.

To create a new Python project, open a command terminal and enter

state init <org/project> --language python@<language version>

Where “org” is the name of your ActiveState organization publishing the package and “project” is the name of the project where the package will be published. For example, to initialize an ActiveState project with the organization name “ExampleOrgName” and project name “NewPyPI” with Python version 3.10.13, enter state init ExampleOrgName/NewPyPI --language python@3.10.13

Note that the project name (“project”) can be selected by the user, but the organization name (“org”) MUST match the name of the ActiveState organization to which the project belongs.

For “language version”, enter the Python version for your project, for example “python@3.10.13”. Information on how to specify language version notation can be found here. This will create a new project on the ActiveState Platform.

To start a virtual environment and begin working with your project, enter

state shell <org/project>

Or, to set the project as your user default, enter

state use <org/project>

You have successfully created a new ActiveState project. This project is now available to any member of your organization, and on multiple platforms and operating systems. More information on supported platforms can be found here.

You can now publish your package to the ActiveState Platform.


4. Publish your package to the ActiveState Platform

Publishing your package to ActiveState’s catalog will allow ActiveState’s Platform to build it for you. The following steps will guide you through the publishing process.

  1. Open a command terminal and paste in the following command

state publish --namespace private/org --name PKG_NAME PKG_FILENAME --depend "builder/python-module-builder@>=0" --depend "language/python@>=3" --depend "language/python/setuptools@>=43.0.0" --depend "language/python/wheel@>=0"
 
  1. Replace the placeholder values in the block above with your ActiveState organization name–this will usually be “Username-org” (org), package name (PKG_NAME), and the filename of your SDIST or source tarball (PKG_FILENAME) and run the command. Take note of the TIMESTAMP in the output. Note that the namespace must start with private/ followed by your organization name. You can also append additional ‘folder’ names if desired.

  2. Run the command. This will publish your specified package to the ActiveState catalog and return a version of the following in your command line

Publishing ingredient...
Successfully published as:
Name: sample_activestate1
Namespace: <org>/language/python
Version: 1.0.0
Revision: 1
Timestamp: 2024-03-13T22:30:16Z

You can install this package by running `state install <org>/language/python/sample_activestate1 --ts now`.

Take note of the Timestamp: 2024-03-13T22:30:16Z value as you will need to use the value returned in your state publish command later in the publication process.

  1. After publishing your package to ActiveState, create a buildscript file (buildscript.as) to build the package into a wheel and publish it to PyPI. An example script is shown below.
  2. Paste the code below into the newly created buildscript.as file, substituting the placeholder values with those from your project

at_time = "PUBLISHED_TIMESTAMP"

        publish_receipt = pypi_publisher(
          attempt = 1,
          audience = "testpypi",
          pypi_uri = "test.pypi.org",
          src = wheels
        )
        runtime = state_tool_artifacts(
          build_flags = [
          ],
          src = sources
        )
        sources = solve(
          at_time = at_time,
          platforms = [
            "7c998ec2-7491-4e75-be4d-8885800ef5f2"
          ],
          requirements = [
            Req(namespace = "language", name = "python", version = Eq(value="3.10.13")),
            Req(namespace = "NAMESPACE", name = "PKG_NAME", version = Eq(value="VERSION"))
          ],
          solver_version = null
        )
        wheel_srcs = select_ingredient(
          namespace = "NAMESPACE",
          name = "PKG_NAME",
          src = sources
        )
        wheels = make_wheel(
          at_time = at_time,
          python_version = "3.10.13",
          src = wheel_srcs
        )

        main = runtime
  • The at_time value returned as your Timestamp value in the state publish step above
  • The strings after platforms = [ are the UUIDs of the supported platforms you want to build a wheel for. “7c998ec2-7491-4e75-be4d-8885800ef5f2” is shown as an example above. A list of all supported platforms can be found here. Select all applicable to your project from the list provided.
  • the name of the namespace (ie. folder where your published the ingredient, in this case, python) (<NAMESPACE>)
  • the name of your package (<PKG_NAME>).
  1. After successfully including the details of your project, save the changes to the file.
  2. “Commit” this file to the ActiveState system by running state commit in your terminal.

Your package is now available as a wheel on the ActiveState Platform.

Buildscript tips: You can leave pypi_uri and audience fields blank to publish directly to the main PyPI repository. If you experience a network timeout or another transient error, you can increment the attempt parameter to retry.


5. Creating a PyPI project with a Trusted Publisher or adding ActiveState as a Trusted Publisher to an existing PyPI project

To add ActiveState as a Trusted Publisher of a new PyPI project

  • Open your test PyPI account and go to the Publishing tab under Your account.
  • Click the ActiveState tab in the table (shown below)
  • Enter the requested information from your ActiveState account (note the PyPI project name and the ActiveState project name must be identical)
  • Click Add to complete

After clicking the Add button, your account will be updated with a new pending project name.

alt_text

To add ActiveState as a Trusted Publisher to an existing project login to your test.pypi.org account and select a project from the Your Projects tab.

  • Click the Manage button next to the project
  • Scroll down and click the ActiveState tab in the table (shown below)
  • Enter the requested information from your ActiveState account (note the PyPI project name and the ActiveState project name must be identical)
  • Click Add to complete

After clicking the Add button, ActiveState will be added as a Trusted Publisher to the existing PyPI project.

alt_text

After successfully adding ActiveState as a Trusted Publisher to a new or existing project, the following will be visible from the Publishing tab of your test.pypi.org account.

alt_text


6. Build a Python wheel (optional)

To test your wheel before publishing it to PyPI (covered in the next step)

  1. To build your wheel, run state eval wheels

  2. After building your wheel, run state builds --all to view all of the builds available. Take note of the HASH_ID value of your new wheel.

  3. Run state builds dl <HASH_ID> to download and test the wheel you’ve built.


7. Publish to PyPI

When you’re ready to publish your package (or wheel) to PyPI, enter the following into your command terminal

 state eval publish_receipt

And that’s it! Using the ActiveState Platform, you have successfully published a Python package or wheel to PyPI.


The ActiveState Trusted Publisher Roadmap

ActiveState is focused on collaboration and values your input. Developer feedback is crucial as we strive to create meaningful experiences that matter to Python users. We’re committed to transparency and want to involve you in our plans every step of the way. We want to hear from you on our forums<link>

  • NOW: Enhanced Initial Publishing
    • Get started quickly without the hassle of complex setup procedures.
    • Ensure your package works seamlessly across diverse platforms and environments.
    • Build and publish your packages in a secure, reliable environment, enhancing the credibility of your releases.
  • NEXT: Streamlined Publishing Process + Matrix Builds
    • Auto-generation and publishing of your SDIST directly from your source repo.
    • Simplified matrix building: build wheels for all operating systems and Python versions more easily.
  • LATER: Full Provenance Generation and Publishing
    • Provide detailed metadata about package origins and dependencies, strengthening security and transparency.
    • Build confidence among users and developers by ensuring a clear, traceable path from development to deployment.
    • Promote a higher standard of package integrity within the Python ecosystem.

With the Trusted Publisher initiative, we’re not just simplifying the publishing process; we’re also laying the groundwork for a more collaborative, secure, and efficient Python development ecosystem through the ActiveState Platform.