forked from com-lihaoyi/mill
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythonlib: improved dependency management and examples (com-lihaoyi#3998
) Make the dependency management more flexible: - [x] allow users to re-use `requirements.txt` files (inspired by [the same pants feature](https://www.pantsbuild.org/dev/docs/python/overview/third-party-dependencies#requirementstxt)) - [x] separate library and tool requirements - library deps are transitive, and will in the future be included as requirements in distributions - tool requirements are not transitive and won't be included in distributions. They're used for things like type checkers and bundlers (which can all be extracted into separated traits later on if we want to). - [x] support referencing wheel files directly - [x] allow user-defined PYTHONPATH - [x] custom package repos - ~lockfile support~ Removing this from this pull request, since it's likely a bit more complex than I initially thought. Pants delegates this behavior to PEX, but we should see if this can be done with more basic tools, or we decide to rely on pex for everything. - [x] examples for all the above Part of com-lihaoyi#3928
- Loading branch information
Showing
25 changed files
with
328 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
= Python Library Dependencies | ||
|
||
include::partial$gtag-config.adoc[] | ||
|
||
|
||
This page goes into more detail about configuring third party dependencies | ||
for `PythonModule`s. | ||
|
||
== Adding Dependencies | ||
|
||
include::partial$example/pythonlib/dependencies/1-pip-deps.adoc[] | ||
|
||
=== Adding Dependencies via requirements.txt files | ||
|
||
include::partial$example/pythonlib/dependencies/2-pip-requirements.adoc[] | ||
|
||
== Unmanaged Wheels | ||
|
||
include::partial$example/pythonlib/dependencies/3-unmanaged-wheels.adoc[] | ||
|
||
== Downloading Unmanaged Wheels | ||
|
||
include::partial$example/pythonlib/dependencies/4-downloading-unmanaged-wheels.adoc[] | ||
|
||
== Using Custom Package Indexes | ||
|
||
include::partial$example/pythonlib/dependencies/5-repository-config.adoc[] | ||
|
||
== Debugging | ||
|
||
include::partial$example/pythonlib/dependencies/6-debugging.adoc[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
//// SNIPPET:BUILD | ||
package build | ||
import mill._, pythonlib._ | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package build | ||
import mill._, pythonlib._ | ||
|
||
object `package` extends RootModule with PythonModule { | ||
def pythonDeps = Seq( | ||
"numpy==2.1.2", | ||
"pandas~=2.2.3", | ||
"jinja2 @ https://github.com/pallets/jinja/releases/download/3.1.4/jinja2-3.1.4-py3-none-any.whl" | ||
) | ||
} | ||
|
||
// You can define the `pythonDeps` field to add dependencies to your module, which will be installed | ||
// via https://pip.pypa.io/en/stable/[pip]. Dependencies can include | ||
// https://peps.python.org/pep-0440/[anything that pip understands], such as `<package>==<version>` | ||
// constraints, or even direct references to wheels. | ||
|
||
/** Usage | ||
|
||
> ./mill run | ||
[10 20 30 40 50] | ||
|
||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import numpy as np | ||
|
||
data = np.array([10, 20, 30, 40, 50]) | ||
print(data) |
18 changes: 18 additions & 0 deletions
18
example/pythonlib/dependencies/2-pip-requirements/build.mill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// You can also read dependencies from `requirements.txt` files. This can be | ||
// useful if you're migrating an existing project to mill. | ||
|
||
package build | ||
import mill._, pythonlib._ | ||
|
||
object `package` extends RootModule with PythonModule { | ||
def pythonRequirementFiles = Task.Sources { | ||
millSourcePath / "requirements.txt" | ||
} | ||
} | ||
|
||
/** Usage | ||
|
||
> ./mill run | ||
[10 20 30 40 50] | ||
|
||
*/ |
1 change: 1 addition & 0 deletions
1
example/pythonlib/dependencies/2-pip-requirements/requirements.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
numpy==2.1.2 |
4 changes: 4 additions & 0 deletions
4
example/pythonlib/dependencies/2-pip-requirements/src/main.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import numpy as np | ||
|
||
data = np.array([10, 20, 30, 40, 50]) | ||
print(data) |
25 changes: 25 additions & 0 deletions
25
example/pythonlib/dependencies/3-unmanaged-wheels/build.mill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// In most scenarios you should rely on `pythonDeps`/`moduleDeps` and let Mill | ||
// manage the downloading and caching of wheels for you. But in the rare case | ||
// you receive a wheel or folder-full-of-wheels from somewhere and need to | ||
// include it in your project, `unmanagedWheels` is the way to do it. | ||
|
||
package build | ||
import mill._, pythonlib._ | ||
|
||
object `package` extends RootModule with PythonModule { | ||
def unmanagedWheels: T[Seq[PathRef]] = Task.Input { | ||
Seq.from(os.list(millSourcePath / "lib").map(PathRef(_))) | ||
} | ||
} | ||
|
||
// You can override `unmanagedWheels` to point it at a wheel (.whl file) or | ||
// source distribution (.tar.gz with a pyproject.toml file) you place on the | ||
// filesystem, e.g. in the above snippet any files that happen to live in the | ||
// `lib/` folder. | ||
|
||
/** Usage | ||
|
||
> ./mill run | ||
b'"Hello, world!"' | ||
|
||
*/ |
Binary file added
BIN
+130 KB
example/pythonlib/dependencies/3-unmanaged-wheels/lib/jinja2-3.1.4-py3-none-any.whl
Binary file not shown.
Binary file added
BIN
+5.19 MB
example/pythonlib/dependencies/3-unmanaged-wheels/lib/orjson-3.10.12.tar.gz
Binary file not shown.
9 changes: 9 additions & 0 deletions
9
example/pythonlib/dependencies/3-unmanaged-wheels/src/main.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# this comes from a wheel | ||
import jinja2 | ||
|
||
# this comes from an sdist | ||
import orjson as oj | ||
|
||
environment = jinja2.Environment() | ||
template = environment.from_string("Hello, {{ name }}!") | ||
print(oj.dumps(template.render(name="world"))) |
37 changes: 37 additions & 0 deletions
37
example/pythonlib/dependencies/4-downloading-unmanaged-wheels/build.mill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// You can also override `unmanagedWheels` to point it at wheels that you want to | ||
// download from arbitrary URLs. | ||
// `requests.get` comes from the https://github.com/com-lihaoyi/requests-scala[Requests-Scala] | ||
// library, one of Mill's xref:fundamentals/bundled-libraries.adoc[Bundled Libraries]. | ||
// | ||
package build | ||
import mill._, pythonlib._ | ||
|
||
object `package` extends RootModule with PythonModule { | ||
def unmanagedWheels = Task { | ||
val name = "jinja2-3.1.4-py3-none-any.whl" | ||
val url = s"https://github.com/pallets/jinja/releases/download/3.1.4/$name" | ||
os.write(Task.dest / name, requests.get.stream(url)) | ||
Seq(PathRef(Task.dest / name)) | ||
} | ||
} | ||
|
||
/** Usage | ||
|
||
> ./mill run | ||
Hello, world! | ||
|
||
*/ | ||
|
||
// Tasks like `unmanagedWheels` and `pythonDeps` are cached, so your wheel is downloaded only | ||
// once and re-used indefinitely after that. This is usually not a problem, because usually URLs | ||
// follow the rule that https://www.w3.org/Provider/Style/URI[Cool URIs don't change], and so files | ||
// downloaded from the same URL will always contain the same contents. | ||
// | ||
// NOTE: An unmanaged wheel downloaded via `requests.get` is still unmanaged: even though you | ||
// downloaded it from somewhere, `requests.get` does not know how to pull in third party | ||
// dependencies or de-duplicate different versions on the classpath. All the same caveats you need | ||
// to worry about when dealing with xref:#_unmanaged_wheels[unmanaged wheels] apply here as well. In | ||
// case you **do** want mill to take care of managing dependencies of a package which is not | ||
// available on PyPI, you shouldn't get that package in `unmanagedWheels` (like we did in the | ||
// example above). Instead, you can declare the dependency as a regular `pythonDep` | ||
// https://peps.python.org/pep-0440/#direct-references[as a direct URL that pip understands]. |
4 changes: 4 additions & 0 deletions
4
example/pythonlib/dependencies/4-downloading-unmanaged-wheels/src/main.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import jinja2 | ||
environment = jinja2.Environment() | ||
template = environment.from_string("Hello, {{ name }}!") | ||
print(template.render(name="world")) |
44 changes: 44 additions & 0 deletions
44
example/pythonlib/dependencies/5-repository-config/build.mill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// By default, dependencies are resolved from https://pypi.org/[the Python | ||
// Package Index (PyPI)], the standard package index for python projects. You | ||
// can also add your own package indexes by overriding the `indexes` task in | ||
// the module: | ||
|
||
package build | ||
import mill._, pythonlib._ | ||
|
||
object foo extends PythonModule { | ||
|
||
def pythonDeps = Seq( | ||
"testpkg-jodersky==0.0.1" // a test package, only available on test.pypi.org | ||
) | ||
|
||
// override this task to add or replace the package indexes | ||
def indexes = super.indexes() ++ Seq("https://test.pypi.org/simple/") | ||
} | ||
|
||
// Mill uses https://pip.pypa.io/en/stable/[pip] to find and install dependencies. | ||
// | ||
// You can configure pip through its | ||
// https://pip.pypa.io/en/stable/topics/configuration/#location[normal configuration files.] | ||
// | ||
// === Private indexes | ||
// | ||
// You can read up in more detail on https://pip.pypa.io/en/stable/topics/authentication/[how to | ||
// configure pip to authenticate to private indexes]. Here is an example which reads a package from | ||
// an environment variable: | ||
|
||
object bar extends PythonModule { | ||
def indexPassword = Task.Input { Task.env.apply("COMPANY_PASSWORD") } | ||
def indexes = Task { | ||
Seq(s"https://username:${indexPassword()}@pypi.company.com/simple") | ||
} | ||
} | ||
|
||
// More advanced authentication techniques are available by configuring pip directly. | ||
|
||
/** Usage | ||
|
||
> ./mill foo.run | ||
2 | ||
|
||
*/ |
3 changes: 3 additions & 0 deletions
3
example/pythonlib/dependencies/5-repository-config/foo/src/main.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from testpkg_jodersky import example | ||
|
||
print(example.add_one(1)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// In case anything goes wrong, or if you're just curious, you can see what | ||
// arguments mill passes to `pip install` by looking at the output of the | ||
// `pipInstallArgs` task. | ||
|
||
package build | ||
import mill._, pythonlib._ | ||
|
||
object `package` extends RootModule with PythonModule { | ||
def pythonDeps = Seq( | ||
"numpy==2.1.2", | ||
"pandas~=2.2.3", | ||
"jinja2 @ https://github.com/pallets/jinja/releases/download/3.1.4/jinja2-3.1.4-py3-none-any.whl" | ||
) | ||
|
||
def indexes = Seq("invalid_index") | ||
} | ||
|
||
/** Usage | ||
|
||
> ./mill show pipInstallArgs | ||
{ | ||
"args": [ | ||
"--index-url", | ||
"invalid_index", | ||
"mypy==1.13.0", | ||
"pex==2.24.1", | ||
"numpy==2.1.2", | ||
"pandas~=2.2.3", | ||
"jinja2 @ https://github.com/pallets/jinja/releases/download/3.1.4/jinja2-3.1.4-py3-none-any.whl" | ||
], | ||
"sig": ... | ||
} | ||
|
||
*/ |
Oops, something went wrong.