Skip to content

ewoks install: fresh env by default with the pip-venv package manager - #332

Open
woutdenolf wants to merge 3 commits into
mainfrom
331-ewoks-install-support-fresh-environments
Open

ewoks install: fresh env by default with the pip-venv package manager#332
woutdenolf wants to merge 3 commits into
mainfrom
331-ewoks-install-support-fresh-environments

Conversation

@woutdenolf

@woutdenolf woutdenolf commented Aug 10, 2026

Copy link
Copy Markdown
Member

In #65 we changed the graph attributes

"requirements": ["ewokscore==5.1.0", "networkx==3.4.2"]

to

"requirements": {
    "python": {"version": "3.12.11", "implementation": "CPython", "...": "..."},
    "system": {"system": "Linux", "machine": "x86_64", "...": "..."},
    "distributions": [
        {"name": "ewokscore", "version": "5.1.0", "installer": "pip"},
        {"name": "networkx", "version": "3.4.2", "installer": "pip"}
    ],
    "manager": {
        "name": "pip",   # Renamed in this PR to "pip-venv"
        "version": "25.0.1",
        "files": {"requirements.txt": "ewokscore==5.1.0\nnetworkx==3.4.2\n"}
    }
}

The final goal is to support more package managers than pip (uv, poetry, pixi and conda).

This PR is another step:

  • Refactor the Pip manager to support environment creation and use it by default (rename it to pip-venv).
  • In-place installation is opt-in.
  • Remove the non-Pip managers to be handled in follow-up PRs.

See docs on how this PR affects ewoks install and ewoks convert

  • doc/howtoguides/requirements.rst
  • doc/tutorials/install.rst
  • doc/tutorials/install/pip_venv.rst

This was cherry-picked from #330 to make the review easier. Still a large PR, sorry. The other PRs already adds uv, pixi, conda and poetry. This PR already lays the groundwork for those in terms of core, test and doc infrastructure.

FYI python -m ewoks._requirements.__init__ does a pip gathering in your current environment. Might be useful for the reviewing.

@woutdenolf woutdenolf linked an issue Aug 10, 2026 that may be closed by this pull request
@woutdenolf
woutdenolf marked this pull request as ready for review August 10, 2026 11:42
@woutdenolf
woutdenolf requested a review from a team August 10, 2026 11:48

@payno payno left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed documentation.

To be honest, it's hard for to be very critical about the PR. It would require a deeper knowledge of this system and/or package managers. And this would require quiet some time for me. I think Loïc will give a better review, but feel free to merge if needed.

My main concern is trying to reduce long-term maintenance. I'm very worried about the effort needed to handle all the use cases. IMO, forcing "reproducers" to use the same package manager isn't a big requirement, compared to the time/energy we'd need to spend making sure we don't end up with corner cases — and I'd advocate for this, at least.

Comment thread doc/tutorials/install/pip_venv.rst Outdated
Comment thread doc/tutorials/install/pip_venv.rst Outdated
"""Location of the environment with this name, inside a root directory of
the user or inside the root directory of this package manager.
"""
return Path(root or self.environments_root()).expanduser() / name

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to be very accurate at the moment because I don't know this part of the code yet.

But having this or in Path(root or self.environments_root()).expanduser() / name sounds a bit weird.

Makes me think that the environment location might not be static. From what I get from claude he/she says this will happen when user override the default location. But in this case I would expect environments_root to also be redefined.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function takes the root (optional coming from the user) or the environment root, expands ~ and return the child name. Not sure what the problem is.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a problem but more a concern. I'm afraid that having root as a parameter allowed from several functions can make things a bit complex.

Can we imagine having root as a parameter of the constructor and letting the 'overwrite' happen here? This would simplify the class IMO.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.environments_root() might be actually executing commands so not sure we want to do this in the constructor. But passing the root to the constructor should be ok.

@woutdenolf woutdenolf Aug 18, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok even that would make the code very awkward

def _managers() -> Dict[str, BaseManager]:
    return {
        name: manager_cls() for name, manager_cls in get_supported_managers().items()
    }

would become

def _managers(env_root=None) -> Dict[str, BaseManager]:
    return {
        name: manager_cls(env_root=env_root) for name, manager_cls in get_supported_managers().items()
    }

And we would provide an environment root suitable for only one manager to all managers.

Comment thread src/ewoks/_requirements/utils/base_manager.py
Comment on lines +68 to +74
managers = _managers()
scores = {name: (manager.PRIORITY,) for name, manager in managers.items()}
manager = _first_available(managers, scores)
if manager is None:
raise RuntimeError("No known package manager installed or available")

return manager

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not simple but should we consider this case ? the original manager not being here ?
To be honest I am a bit afraid that trying to bridge the gap between the different package manager is a pain we might want to avoid (at least to start. Because once we engage ourself this way we must continue).

@woutdenolf woutdenolf Aug 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requirements are always stored in two ways:

  • python's distribution info extracted from importlib.metadata
  • package manager specific (requirements.txt for pip for example)

We already need to fallback to importlib.metadata, especially for pip, since the result of pip freeze is not always installable (e.g. points to local paths).

Since we already need this fallback mechanism even when the producer and installer both use the same package manager, cross-manager support comes for free (using the importlib.metadata fallback).

Install any package that provides :term:`tasks <Task>` instead of
``ewoks`` for a real :term:`workflow`.

Re-producer side

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a corner case worth highlighting.

Right now, if I'm not mistaken, nothing prevents a user from converting a workflow and ending up with a Python environment that fully supports running it — which is very convenient.

However, if that user then shares it with a third party, the installation becomes useless.

@woutdenolf woutdenolf Aug 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, if that user then shares it with a third party, the installation becomes useless.

Don't get it. Shares what with a third party?

  • user1 generates a JSON file (ewoks convert) and share it with user2.
  • user2 receives an JSON file and installs (ewoks install) and executes (ewoks execute).

We are not sharing the environment, we are sharing the workflow (JSON or whatever).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is that what is shared through the JSON contains a list of requirements.
It comes directly from the user1 python environment.
But not makes sure this environment allows executing the workflow on itself.
User1 could have several environment and not activate the correct one when doing the ewoks convert.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually the JSON file comes from execute_graph(..., convert_destination=...) which calls ewoks_convert but also executes the workflow.

Of course I could imaging there are all kinds of reasons the reproducer can still not execution the workflow.

  • A task input point to a file that does not exist.
  • A task is implemented to us an environment variable
  • ...

I'm sure there are many. But it is worth mentioning in the docs as you said.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a section Limitations and caveats to the "Install and execute a workflow" tutorials.

@woutdenolf
woutdenolf requested a review from a team August 16, 2026 07:06
@woutdenolf
woutdenolf force-pushed the 331-ewoks-install-support-fresh-environments branch from 0b666ee to 1c35860 Compare August 18, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ewoks install: support fresh environments

2 participants