Wyatt Baldwin

🐘

PDM vs Poetry

A few years back, I started using poetry to manage dependencies for all my Python projects. I ran into some minor issues early on but haven’t had any problems recently and prefer it to any of the other dependency management / packaging solutions I’ve tried so far.

Recently, I’ve started hearing about pdm and how it’s the bee’s knees. I did a search for “pdm vs poetry” and didn’t find much, so I thought I’d play around with pdm a bit and write something myself.

Creating a new project

Both tools have an init command. Create a new directory, cd into it, run <tool> init, and follow the prompts.

One difference here is that poetry will prompt for more package metadata and allow you to define your dependencies at this stage.

The pyproject.toml generated by pdm is pretty bare, so you’ll have to fill in a bunch of stuff like the project name, version, etc.

pdm will also ask if you want to create a virtualenv at this stage. If you choose y, it will create a virtualenv in ./venv. If you choose n, it will use PEP 582 mode (more on PEP 582 below).

Converting an existing project from poetry to pdm

pdm has an import command that you can run on an existing pyproject.toml. It will keep all of your existing config, except it will overwrite the [build-system] section.

If you’re using the [tool.poetry.group.dev.dependencies] section to define your dev dependencies, pdm won’t recognize it, so I’d advise changing it back to [tool.poetry.dev-dependencies] to avoid issues with that.

pdm also didn’t import local develop dependencies correctly. It converted poetry dependencies like this:

some-package = { path = "../some-local-package", develop = true }

to:

[tool.poetry.dev-dependencies]
dev = [
    "some-local-package @ ",
]

This causes pdm install to throw a cryptic TypeError. To fix it, you have to remove the @ and change the spec to:

"-e file:///abs/path/to/some-local-package"

Differences

Dependency resolution

I didn’t notice a huge difference in the speed of dependency resolution or initial installation (pre-cache).

PEP 582

Using PEP 582 mode with pdm requires a bit of setup since Python doesn’t support it out of the box, but it’s not too bad (and isn’t specific to pdm). There’s a PEP 582 page on the pdm site that tells you how to do this.

It’s pretty straightforward, but I did run into one issue when running pdm --pep582 in fish. It outputs some lines that export environment variables using set -x, but I had to change them to set -gx to get everything to work.

The other thing you might want to do is put __pypackages__/3.x/bin in your $PATH when you cd into a project directory. I wrote some fish scripts to do this, but you could just use direnv.

Conclusion

I’ll probably keep an eye on pdm, but poetry seems a bit more polished currently. If you’re already using poetry, I don’t see any reason to switch. If you haven’t gone down this particular rabbit hole yet, I’d probably recommend poetry at this point.

The most interesting thing about pdm to me is the PEP 582 / __pypackages__ support. After playing with it a bit, I do think it would be a good addition to Python.

Comments, Corrections, Suggestions

This blog doesn’t have a comment system, but you can send feedback via the contact form on the home page.

NOTE: I originally published this on 23 December, but there were a couple of errors. This version removes/corrects those errors and does more of an actual comparison.