Can I retrieve the path for an entry point, using importlib.metadata?

I’m documenting a workflow with a jupyter notebook, and I wanted to embed shell commands when that makes sense. Something like this, where some_command is a script they’ve installed with this package:

# here's the data
data_path = Path("/where/the/data/is")

# then we run this command
! some_command {data_path}

An issue I’ve hit is that the notebook is running in a different environment from jupyterlab, so some_command is not on the path. I can get this to work with a full path, e.g. ! /path/to/env/bin/some_command ... but I don’t want to hard-code the path because the user’s environment can be set up differently.

With importlib.metadata I can retrieve the entry point command directly, which is pretty slick:

import importlib.metadata

ep, = importlib.metadata.entry_points(name="some_command")

ep_cmd = ep.load()
ep_cmd(data_path)   # look ma, no shell!

Sadly this has a pretty nasty UX interaction with jupyter if the command calls sys.exit, and I want to avoid that. In any case I’d prefer to write shell command there because it’s much less esoteric.

One way to achieve this is to infer the location of the entry point from sys.executable (some_command should be sitting next to python, as I understand it). But I was curious if there’s a nice way to use importlib.metadata to tell me the path to the executable for a given tool.

Any tips?

My knowlege might be incomplete, but AFAIK no, because importlib.metadata only refers to the static metadata that is part of the wheel unpacking. The location of entrypoint scripts is not defined in there and instead depends on the installer, which does not/is not required to write this information anywhere the runtime can access it.

According to the spec installers are supposed to put them into the scripts folder, wherever that is for the python runtime - not sure if this is a findable location and if you want to go through the effort of doing that.

However, I would also suggest other solutions to the issue described:

  • Catching SystemExit. As long as the script is reasoanbly well behaved outside of calling sys.exit, this should be fine.
  • Running sys.executable with a script that imports importlibe.metadata and calls the relevant entry point. This should fit into a single-line arguemnt script, so this should not be that much effort. The expected behavior around calling the entry point is described in the spec.
1 Like