22
33:::{objectives}
44In this episode we will create a pip-installable Python package and learn how
5- to deploy it to PyPI. As example, we will use the star counting script which
6- we created in the previous episode .
5+ to deploy it to PyPI. As example, we can use one of the Python scripts from our
6+ example repository .
77:::
88
99
10- ## Creating a Python package with the help of flit
10+ ## Creating a Python package with the help of [ Flit ] ( https:// flit.pypa.io/ )
1111
1212There are unfortunately many ways to package a Python project:
1313- ` setuptools ` is the most common way to package a Python project. It is very
1414 powerful and flexible, but also can get complex.
15- - ` flit ` is a simpler alternative to ` setuptools ` . It is less powerful , but
15+ - ` flit ` is a simpler alternative to ` setuptools ` . It is less versatile , but
1616 also easier to use.
17- - ` poetry ` is a modern packaging tool which is more powerful than ` flit ` and
17+ - ` poetry ` is a modern packaging tool which is more versatile than ` flit ` and
1818 also easier to use than ` setuptools ` .
1919- ` twine ` is another tool to upload packages to PyPI.
2020- ...
@@ -26,33 +26,39 @@ There are unfortunately many ways to package a Python project:
2626 > Make the easy things easy and the hard things possible is an old motto from
2727 > the Perl community. Flit is entirely focused on the easy things part of that,
2828 > and leaves the hard things up to other tools.
29-
3029 :::
3130
3231
3332## Step 1: Initialize the package metadata and try a local install
3433
35- 1 . Our starting point is that we have a Python script called ` countstars .py`
34+ 1 . Our starting point is that we have a Python script called ` example .py`
3635 which we want to package.
3736
38372 . Now we follow the [ flit quick-start usage] ( https://flit.pypa.io/en/stable/#usage ) and add a docstring to the script and a ` __version__ ` .
3938
40393 . We then run ` flit init ` to create a ` pyproject.toml ` file and answer few questions. I obtained:
41- ``` toml
40+ ``` {code-block} toml
41+ ---
42+ emphasize-lines: 6, 13
43+ ---
4244 [build-system]
4345 requires = ["flit_core >=3.2,<4"]
4446 build-backend = "flit_core.buildapi"
4547
4648 [project]
47- name = " countstars "
48- authors = [{name = " Radovan Bast " , email = " radovan.bast@uit.no " }]
49+ name = "example "
50+ authors = [{name = "Firstname Lastname ", email = "first.last@example.org "}]
4951 license = {file = "LICENSE"}
50- classifiers = [" License :: OSI Approved :: MIT License " ]
52+ classifiers = ["License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2) "]
5153 dynamic = ["version", "description"]
5254
5355 [project.urls]
54- Home = " https://github.com/workshop-material/countstars "
56+ Home = "https://example.org "
5557 ```
58+ To have a more concrete example, if we package the ` generate_data.py ` script
59+ from the [ example
60+ repository] ( https://github.com/workshop-material/classification-task ) , then
61+ replace the name ` example ` with ` generate_data ` .
5662
57634 . We now add dependencies and also an entry point for the script:
5864 ``` {code-block} toml
@@ -64,22 +70,22 @@ There are unfortunately many ways to package a Python project:
6470 build-backend = "flit_core.buildapi"
6571
6672 [project]
67- name = "countstars "
68- authors = [{name = "Radovan Bast ", email = "radovan.bast@uit.no "}]
73+ name = "example "
74+ authors = [{name = "Firstname Lastname ", email = "first.last@example.org "}]
6975 license = {file = "LICENSE"}
70- classifiers = ["License :: OSI Approved :: MIT License "]
76+ classifiers = ["License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2) "]
7177 dynamic = ["version", "description"]
7278 dependencies = [
7379 "click",
74- "matplotlib ",
75- "scikit-image ",
80+ "numpy ",
81+ "pandas ",
7682 ]
7783
7884 [project.urls]
79- Home = "https://github.com/workshop-material/countstars "
85+ Home = "https://example.org "
8086
8187 [project.scripts]
82- count-stars = "countstars :main"
88+ example = "example :main"
8389 ```
8490
85915 . Before moving on, try a local install:
@@ -99,21 +105,23 @@ There are unfortunately many ways to package a Python project:
99105
100106If a local install worked, push the ` pyproject.toml ` to GitHub and try to install the package from GitHub.
101107
102- In a ` requirements.txt ` file, you can specify the GitHub repository and the branch:
108+ In a ` requirements.txt ` file, you can specify the GitHub repository and the
109+ branch (adapt the names):
103110```
104- git+https://github.com/workshop-material/countstars .git@main
111+ git+https://github.com/ORGANIZATION/REPOSITORY .git@main
105112```
106113
107- A corresponding ` envionment.yml ` file for conda would look like this:
114+ A corresponding ` envionment.yml ` file for conda would look like this (adapt the
115+ names):
108116``` yaml
109- name : countstars
117+ name : experiment
110118channels :
111119 - conda-forge
112120dependencies :
113- - python= 3.12
121+ - python <= 3.12
114122 - pip
115123 - pip :
116- - git+https://github.com/workshop-material/countstars .git@main
124+ - git+https://github.com/ORGANIZATION/REPOSITORY .git@main
117125` ` `
118126
119127Does it install and run? If yes, move on to the next step (test-PyPI and later
141149jobs:
142150 build:
143151 permissions: write-all
144- runs-on: ubuntu-latest
152+ runs-on: ubuntu-24.04
145153
146154 steps:
147155 - name: Switch branch
0 commit comments