You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: blog/create-a-package/handling-dependencies.qmd
+10-5Lines changed: 10 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ title: "Handling dependencies"
4
4
5
5
Dependencies are the external Python packages your code needs in order to work, such as `requests`, `numpy`, or `pandas`.
6
6
7
-
Here we'll focus on using [uv](https://docs.astral.sh/uv/){target="_blank"} to handle dependencies, as it's currently the best tool for this out there (it's fast and fairly easy to use, especially if you know `pip`).
7
+
Here we'll focus on using [uv](https://docs.astral.sh/uv/){target="_blank"} to handle dependencies, as it's currently the best tool for this out there (it's fast and fairly easy to use, especially if you know `pip` or other package manager like `Cargo`.).
8
8
9
9
## Specify dependencies
10
10
@@ -21,7 +21,7 @@ def normalize(array):
21
21
22
22
When people want to use our function, they **need** to have `numpy` installed for it to work, otherwise it will raise a `ModuleNotFoundError` on their machine.
23
23
24
-
So in order to ensure is `numpy`installed, we set `numpy` as a dependency of our package. This means that every time someone install our package, they will also install `numpy`.
24
+
So in order to ensure that this does not happen, we need to tell Python to also install `numpy`when installing our package. In practice, we say that we set `numpy` as a **dependency** of our package. This means that every time someone install our package, they will also install `numpy`.
25
25
26
26
The dependencies of a package are listed in the `pyproject.toml` file. If you don't know what that is, check out [organizing a package](./organize-a-package.html).
27
27
@@ -63,7 +63,7 @@ dependencies = [
63
63
64
64
:::
65
65
66
-
If we add other dependencies, they will be added to the `dependencies` list.
66
+
From now on, numpy will also be installed when users install our package. If we add other dependencies, they will be added to the "dependencies" list: we can have as many dependencies as we want, but we want to avoid that.
67
67
68
68
## Avoiding dependencies
69
69
@@ -125,7 +125,7 @@ uv pip install numpy
125
125
126
126
:::
127
127
128
-
Note that for each of those, the package resolver will always try to install the latest version it can depending on the other dependencies. If a package requires `numpy<=2.1.0`, other packages **must** include `numpy``2.1.0` for it to work.
128
+
Note that for each of those, the package manager will always try to install the latest version it can depending on the other dependencies. If a package requires `numpy<=2.1.0`, other packages **must** include `numpy``2.1.0` for it to work.
129
129
130
130
At this point, you might ask, **how do I know** which versions of each dependencies are required for my package? Well, as far as I know, there is no easy answer to this, but there are ways to ensure you don't get unexpected behaviors.
131
131
@@ -146,7 +146,7 @@ You have to test that your code works as expected on those versions. The best wa
146
146
147
147
### ... and be convenient
148
148
149
-
> Dependening on whether you're planning on distributing your package (e.g., put it on PyPI and allow other people to install it) or not, you might want to do different things here. We'll assume you want to distribute it at the end.
149
+
> Depending on whether you're planning on distributing your package (e.g., put it on PyPI and allow other people to install it) or not, you might want to do different things here. We'll assume you want to distribute it at the end.
150
150
151
151
When your package goaled is to be installed by other people, you want to be convenient. By that I mean **not being too restrictive**.
152
152
@@ -250,6 +250,10 @@ def read_file(filename):
250
250
)
251
251
```
252
252
253
+
::: {.callout-important}
254
+
It is **required** here to place `import` inside the function, because otherwise a `ModuleNotFoundError` error will be generated on the user's machine, even when importing a function with only optional dependencies..
255
+
:::
256
+
253
257
This will give your users a **clear and meaningful error message** that they can resolve very quickly. This kind of thing exist for the same reason we're talking about in this article: trying to minimize the number of dependencies (especially the unused ones!).
254
258
255
259
In order to add package to your optional dependencies, you can run:
@@ -319,3 +323,4 @@ uv sync --all-groups
319
323
```
320
324
321
325
326
+
The next section is about [code quality](../code-quality/) in your package.
Copy file name to clipboardExpand all lines: blog/create-a-package/introduction-to-packaging.qmd
+11-4Lines changed: 11 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -24,6 +24,8 @@ from my_package import something
24
24
25
25
Without it, Python treats the directory `my_package/` as a regular directory, **not something it can import from**.
26
26
27
+
> Note that this is not always true, but it does not matter here. See [namespace packages](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/){target="_blank"}.
28
+
27
29
28
30
29
31
## Package vs Module vs Library
@@ -34,7 +36,7 @@ These terms get thrown around a lot. Here's the quick breakdown:
34
36
-**Package**: A directory with an `__init__.py`, possibly containing multiple modules (e.g., multiple files)
35
37
-**Library**: A more general programming term and refers to a bundle of code that can be used ([source](https://www.reddit.com/r/Python/comments/weycrc/comment/iiqy6fi/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button){target="_blank"})
36
38
37
-
Library and package most of the time refer to the same thing. All packages are libraries, the opposite is not true. For the sake of simplicity, it's ok to consider them "equivalent", even though we're are mostly interested in packages in practice.
39
+
Library and package most of the time refer to the same thing. All packages are libraries, the opposite is not true. For the sake of simplicity, **it's ok to consider them "equivalent"**, even though we're are mostly interested in packages in practice.
38
40
39
41
Now, let's create the smallest Python package possible.
40
42
@@ -105,6 +107,8 @@ def say_hello(name):
105
107
print(message)
106
108
```
107
109
110
+
Here we define the main function of our package.
111
+
108
112
### `__init__.py`
109
113
110
114
```{.python filename="package_name/__init__.py"}
@@ -113,13 +117,14 @@ from .my_module import say_hello
113
117
__all__ = ["say_hello"]
114
118
```
115
119
120
+
Without the `__init__.py` file, we wouldn't be able to use `from my_package import say_hello` and would have to use `from my_package.my_module import say_hello`, which isn't the best syntax (but sometimes it can be!).
116
121
:::
117
122
118
123
## Use our package
119
124
120
-
Now, how do we use our package, from a user point of view?
125
+
Untile now, we were from the package developer side, but how do we use our package, from a user point of view?
121
126
122
-
For this, you'll need to have [uv](https://docs.astral.sh/uv/){target="_blank"} installed.
127
+
For this, you'll need to have [uv](https://docs.astral.sh/uv/){target="_blank"} installed (not mandatory, but it makes things much easier).
123
128
124
129
Then we'll need to run a command in our terminal at `Desktop/my_package/`:
125
130
@@ -144,4 +149,6 @@ say_hello("Julia")
144
149
> Hello Julia
145
150
146
151
147
-
And now we have a fully functional Python package! This is just the beginning, but this is an important fondation to have for what's coming next.
152
+
And now we have a **fully functional Python package**! This is just the beginning, but this is an important fondation to have for what's coming next.
153
+
154
+
Next, we need to [organize the package](./organize-a-package.html), particularly to get an overview of all the files we need (most of which are not Python files).
Next, we need to create a few essential files at the root of the project.
41
+
Next, we need to create a few essential files at the root of the project. As you can see, most of them are not Python files, but they are still very important.
42
42
43
43
::: {.panel-tabset}
44
44
45
45
### `pyproject.toml`
46
46
47
-
All the package metadata. It will contain a lot of useful information when we want to distribute this PyPI package so that everyone can install it easily. Don't worry too much about all of its content.
47
+
All the metadata for the package. This is essentially your package's identifier, which contains a lot of useful information when we want to distribute a package so that anyone can easily install it.
48
+
49
+
For example, it contains information about the license (what are users allowed to do with our package?), dependencies (what packages does our package need?), and lots of other metadata about the package (author(s), version, description, etc.).
48
50
49
51
Here is a simple version of this file:
50
52
@@ -207,7 +209,7 @@ sunflower/
207
209
208
210
## Add an internal function
209
211
210
-
When creating a package, it is very practical to create functions that we will use internally: inside the package itself.
212
+
When creating a package, it is very useful to create functions that we will use internally: within the package itself, but which are not intended for users of the package.
211
213
212
214
If we go back to our previous example, we might want to have a separate function that takes a string and cleans it up by removing non-text characters and putting it in lower case. Let's name this function `_clean_string()` and place it in a new file: `other_module.py`.
213
215
@@ -263,3 +265,7 @@ sunflower/
263
265
├── sandbox.py
264
266
└── pyproject.toml
265
267
```
268
+
269
+
We now have a basic but fairly robust file organization in our package. Now, if we want to continue improving our package, everything will happen directly in the `sunflower/sunflower` directory.
270
+
271
+
The next step is to [handle dependencies](./handling-dependencies.html), i.e., identify and specify the packages needed to use our package.
0 commit comments