How to release Python code on GitHub

I have created a Python script and I want to create a release on GitHub. However, this is a script and not a Python package, so I cannot create a .whl file and then attach it to GitHub to create a release. The script is within a src directory.

Not attaching the link to the GitHub repo since I am new to the forum and it might look like a promotion, let me know if it’s needed and I would be happy to share the link.

I think you can just make a git tag, push it, then in the web UI, create a release.

If you needed to upload things besides the source code with the release, you can do it all while making the release in the web UI

See: Managing releases in a repository - GitHub Docs

Is there any tool to package the script like we do in case we want to publish our modules to PyPi?

Depends on what you mean by packaging. If you mean to make a standalone script, have a look into PyInstaller or PyOxidizer. They’re capable of bundling the interpreter plus any dependencies you use into a standalone application.

2 Likes

Thanks, this is what I was looking for.

You may find this to be overkill, but you can in fact build a wheel which can then be used in all the normal ways (uploaded to PyPI, published as a release on GitHub etc.) You can do it all with built-in tools (except the uploads) following standards, and you can get a nice custom wrapper executable (on Windows, it will be an actual compiled .exe file, although it still depends on the Python for which the wheel was installed).

Suppose we have a directory structure

camelot/
    pyproject.toml
    src/
        camelot.py

with pyproject.toml something like

[project]
name = "camelot"
version = "1.0.0"
scripts = { "holy-grail-camelot-scene" = "camelot:camelot" }
description = "It's a very silly place."
license = { text = "You must bring us a shrubbery!" }

[[project.authors]]
name = "Arthur, King of the Britons"
email = "king_arthur@royalty.co.uk"

(Disclaimer: please use a real license. Normally you would put license = { file = "LICENSE.txt" } or similar, and include that file with the license.)

and src/camelot.py

def camelot():
    print("It's only a model...")

if __name__ == '__main__':
    camelot()

Now we can run (output redacted):

$ pip wheel .
Processing /path/to/camelot
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: camelot
  Building wheel for camelot (pyproject.toml) ... done
  Created wheel for camelot: filename=camelot-1.0.0-py3-none-any.whl size=1524 sha256=...
  Stored in directory: /tmp/...
Successfully built camelot

Which we can test by making a local venv, activating it, and installing that wheel file into it:

$ python -m venv .venv
$ source .venv/bin/activate
(.venv) $ pip install camelot-1.0.0-py3-none-any.whl 
Processing ./camelot-1.0.0-py3-none-any.whl
Installing collected packages: camelot
Successfully installed camelot-1.0.0

and try the wrapper:

(.venv) $ holy-grail-camelot-scene 
It's only a model...

(The wrapper imports the code, so that __name__ will be 'camelot', and not '__main__'. However, it then explicitly calls the camelot function itself - that’s what the :camelot part is for in pyproject.toml. Use .s normally for the package/module “path”, and : optionally to mark something inside the module to call. No arguments are passed; you’ll have to access and parse sys.args yourself if you care about command-line arguments.)

This of course also allows library use:

(.venv) $ python
Python 3.8.10 (default, May 26 2023, 14:05:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import camelot
>>> camelot.camelot()
It's only a model...

and running as a module:

(.venv) $ python -m camelot
It's only a model...

and running as a script (if you can find it):

(.venv) $ python .venv/lib/python3.8/site-packages/camelot.py 
It's only a model...

(Is this worth putting up as a guide somewhere?)

3 Likes

Holly smokes! This is amazing! I would do this, definitely, would write the whole process in the README.md and would give you the credits. Hope you wouldn’t mind me linking your profile on my README.md file. BTW here’s the link to my repo, any feedback/comments/constructive criticism is highly appreciated!