DEV Community

Cover image for How to Create and Publish a Python Package on PyPI ๐Ÿ
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

How to Create and Publish a Python Package on PyPI ๐Ÿ

Publishing your first Python package on PyPI (Python Package Index) feels like sending your code off to collegeโ€”itโ€™s out there in the world, ready to make you proud (and maybe help someone too).

In my case, I was working on my own version of mkdocs-material.

Initially, I was all about the UIโ€”just trying to get it to look good and work as intended. After some effort, I had something usable and thought, "Alright, let's figure out the deployment."

The original mkdocs uses a Python package for its installer, so you can just pip install mkdocs, mkdocs new ., and then mkdocs build to convert markdown files into HTML.

Itโ€™s simple, elegant, and works like a charm.

I wanted the same experience for my projectโ€”an easy pip install setup to make deploying my version of mkdocs-material.

So, it was my time to learn how to build my own Python package and publish it. And thatโ€™s exactly what weโ€™ll do here, step by step.

Donโ€™t worryโ€”itโ€™s easier than debugging a Friday night code bug XD

Step 1: Structure ๐Ÿ“‚

A well-structured project is like a clean kitchenโ€”you can find your tools (or code) easily and avoid unnecessary messes.

Here's what our project layout will look like:

โ”œโ”€โ”€ dev_to/
โ”‚   โ”œโ”€โ”€ __init__.py        
โ”‚   โ”œโ”€โ”€ say_hello.py       # Your module code
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_say_hello.py  
โ”œโ”€โ”€ README.md              
โ”œโ”€โ”€ setup.py               # Package metadata
โ”œโ”€โ”€ pyproject.toml         # Build system config
โ”œโ”€โ”€ LICENSE                
Enter fullscreen mode Exit fullscreen mode

Step 2: Code ๐Ÿ“

This is the heart of your packageโ€”what it does and why it exists.

  • dev_to/say_hello.py A simple function that greets users:
  def say_hello(name):
      return f"Hello dev.to, from {name}!"
Enter fullscreen mode Exit fullscreen mode
  • dev_to/__init__.py Makes your function accessible at the package level:
  from .say_hello import say_hello
Enter fullscreen mode Exit fullscreen mode

Image description

Step 3: Tests โœ…

Tests ensure your code behaves as expected and helps you avoid embarrassing bugs. Trust me, your future self will thank you.

  • tests/test_say_hello.py A basic test script:
  from dev_to import say_hello

  def test_say_hello():
      result = say_hello("World")
      assert result == "Hello dev.to, from World!"
      print("Test passed!")

  if __name__ == "__main__":
      test_say_hello()
Enter fullscreen mode Exit fullscreen mode
$ p tests/test_say_hello.py 
Test passed!
Enter fullscreen mode Exit fullscreen mode

Step 4: Metadata

Metadata describes your package what it is, who made it, and how others can use it.

  • setup.py Configure your package:
  from setuptools import setup, find_packages

  setup(
      name="dev_to",
      version="0.1.0",
      author="lovestaco",
      description="A simple example package",
      long_description=open("README.md").read(),
      long_description_content_type="text/markdown",
      url="https://github.com/lovestaco/dev_to",
      packages=find_packages(),
      classifiers=[
          "Programming Language :: Python :: 3",
          "License :: OSI Approved :: MIT License",
          "Operating System :: OS Independent",
      ],
      python_requires=">=3.6",
  )
Enter fullscreen mode Exit fullscreen mode
  • pyproject.toml Declare the build system:
  [build-system]
  requires = ["setuptools", "wheel"]
  build-backend = "setuptools.build_meta"
Enter fullscreen mode Exit fullscreen mode

Step 5: Build the Package

Building generates the distributable files required for publishing.

Install the tools:

pip install build
Enter fullscreen mode Exit fullscreen mode

Build your package:

python -m build
Enter fullscreen mode Exit fullscreen mode

This creates a dist/ folder containing .tar.gz and .whl files.

$ python -m build
* Creating isolated environment: virtualenv+pip...
* Installing packages in isolated environment:
  - setuptools
  - wheel
.
.
.
adding 'dev_to-0.1.0.dist-info/RECORD'
removing build/bdist.linux-x86_64/wheel
Successfully built dev_to-0.1.0.tar.gz and dev_to-0.1.0-py3-none-any.whl
Enter fullscreen mode Exit fullscreen mode

Image description

Step 6: Moment of Truth

Install the package locally:

pip install dist/dev_to-0.1.0-py3-none-any.whl
Enter fullscreen mode Exit fullscreen mode

Try it out:

Image description

Step 7: Publish to PyPI ๐Ÿš€

Install Twine:

pip install twine
Enter fullscreen mode Exit fullscreen mode

Upload your package:

python -m twine upload dist/*
Enter fullscreen mode Exit fullscreen mode

You'll need your PyPI credentials. Once uploaded, your package is live! ๐ŸŽ‰

Install it like this:

pip install dev-to
Enter fullscreen mode Exit fullscreen mode

Image description

Iโ€™ve been working on a super-convenient tool called LiveAPI.

LiveAPI helps you get all your backend APIs documented in a few minutes

With LiveAPI, you can quickly generate interactive API documentation that allows users to execute APIs directly from the browser.

Image description

If youโ€™re tired of manually creating docs for your APIs, this tool might just make your life easier.

Top comments (0)