Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove all library requirements #626

Open
3 tasks
Corvince opened this issue Jan 21, 2019 · 25 comments · May be fixed by #2265
Open
3 tasks

Remove all library requirements #626

Corvince opened this issue Jan 21, 2019 · 25 comments · May be fixed by #2265
Labels
discuss maintenance Release notes label
Milestone

Comments

@Corvince
Copy link
Contributor

Mesa currently ships as a "batteries included" package with requirements for all possible functionality provided. While this is nice for new users, concerns have been raised that mesa is unsuitable for integration into larger projects due to its (possibly unused) dependencies. Upon further inspection all currently required packages are optional.

  • click, cookiecutter only used for mesa command
  • jupyter not used at all
  • networkx only implicitly used by NetworkGrid
  • numpy only used for ContinuousSpace
  • pandas only used for DataFrame output of the DataCollector
  • tornado only used for Visualization
  • tqdm only used for batch runner

Those requirements could be put under some extra_requires in the setup.py file and then users could still install mesa with pip install mesa[all] to have everything included.

Steps for this issue would include:

  • Update setup.py (decide on name for "all")
  • Lazy load all dependencies with helpful error messages if it fails
  • Update documentation

But before working on this issue we should decide whether this is a good idea or not

Credits to @rht for starting this discussion in #614

@rht
Copy link
Contributor

rht commented Jan 21, 2019

  • Small dependencies that do not affect the "closure size" and runtime much could be included by default. click, cookiecutter, tqdm are small and fast to load.
  • I'd argue that visualization is an essential component (MASON has it by default).

@rht
Copy link
Contributor

rht commented Jan 21, 2019

MASON also has continuous and network grid (defined from scratch) by default.

@rht
Copy link
Contributor

rht commented Jan 21, 2019

Tangent: maybe there should be a meta issue tracking feature parity with MASON (source: https://github.com/eclab/mason for easy access). This would be informative for people who are considering to migrate from MASON.

@dmasad
Copy link
Member

dmasad commented Feb 8, 2019

My sense is that the median Mesa user will want the 'batteries included' installation with all the dependencies. Instead of asking users to specify pip install mesa[all] to get that version, could we specify pip install mesa[min] (or similar) to install the dependency-free version?

@rht
Copy link
Contributor

rht commented Feb 8, 2019

The [] syntax is only for optional dependencies via extra_requires. The only way possible is to have a package mesa-core that mesa the suite inherits from.

@Corvince
Copy link
Contributor Author

Corvince commented Feb 8, 2019

Yes as rht says this is not possible. A sideways idea would be to create a conda package. I think a lot of new (and probably also more experienced) python users are now using Anaconda. And there we could deploy a 'batteries included' package and keep a minimal base version at pip. That is

conda install mesa
would equal to
pip install mesa[all]

  • Small dependencies that do not affect the "closure size" and runtime much could be included by default. click, cookiecutter, tqdm are small and fast to load.

That would put us in the place to decide what are "small" and "large" dependencies.

  • I'd argue that visualization is an essential component (MASON has it by default).

It's about making it optional, not removing it. There are a lot of other ways to visualize the results (especially if your doing research and want to create publication ready figures)

@rht
Copy link
Contributor

rht commented Feb 8, 2019

And there we could deploy a 'batteries included' package and keep a minimal base version at pip.

There would be confusing and non-standard since they are meant to be different installation methods of a package. Additionally, what if a conda package depends on the minimal version?

@Corvince
Copy link
Contributor Author

Corvince commented Feb 8, 2019

I don't know of a standard regarding this (if there is one, I agree we should comply), but its not unusual for the dependencies to differ. The goals of pip and conda are different. You can compare the dependencies for numpy or matplotlib for example (sorry I can't find a list for either of those, but confirmed it by testing locally).

And conda packages can only depend on other conda packages. Even if, how could that be a problem in that direction? The only source of error I can imagine is install the minimal version with pip and then install a conda package depending on the maximal/conda version of mesa. But then the worst case scenario is receiving an error message that tells users they have to install a dependency.

@Corvince
Copy link
Contributor Author

Corvince commented Feb 8, 2019

The [] syntax is only for optional dependencies via extra_requires. The only way possible is to have a package mesa-core that mesa the suite inherits from.

Which probably would be the cleanest solution and would also answer #134 . But I don't see the resources for this split nor the immediate need. I think there would be hardly anyone to only use the core components. And for those use cases it is easy enough to fork the repo and adapt

@rht
Copy link
Contributor

rht commented Feb 8, 2019

The difference between scipy in conda and pip is that the former has openblas and cython as requirements (https://github.com/conda-forge/scipy-feedstock/blob/master/recipe/meta.yaml), and in pip, openblas is optional. The pip version also has a mechanism not to update numpy if possible (https://github.com/scipy/scipy/blob/master/setup.py#L419-L428). Anyone would have the exact same functioning scipy regardless of the installation method, with performance being the only difference.

One use case of the minimal version is abcEconomics (https://github.com/ab-ce/abce) -- we are planning to reshape the scheduler, the agent verbs, etc (maybe later logging as well but this is too complicated) to be consistent with Mesa / to use Mesa as a basis (cc: @DavoudTaghawiNejad). One plus point of this is that I will port abcE's multi-core scheduling (via multiprocessing) to Mesa. I'm sure there are other projects that may benefit from this deduplication of the ABM layer / API.

@DavoudTaghawiNejad
Copy link

there is always the pip mesa --no-dependency option if you don't want to install it without dependencies.

@rht
Copy link
Contributor

rht commented Feb 8, 2019

there is always the pip mesa --no-dependency option if you don't want to install it without dependencies.

That's for manual install, but there is no such option when being specified in requirements.txt. Nor in Pipfile, toml file (I forgot the filename for this) or other requirements.txt successors.

@jakobaxelsson
Copy link

I think I have a clear use case for this. I am running mesa in the browser using pyscript (which in turn relies on pyodide). In pyscript, it is possible to import pure Python packages from PyPI without any problems. However, mesa does not import, and this appears to be due to the tornado dependency. To solve this, I needed to make a local copy of mesa and remove the things I didn’t need. However, this is of course not a desirable solution.

My problem would be solved if the tornado based visualization was an extra. As far as I understand, the mesa version 2+ is anyway moving away from that visualization style, so maybe it would be quite acceptable for most users to specify mesa[tornado] if they wanted that visualization?

@rht
Copy link
Contributor

rht commented Aug 19, 2023

My problem would be solved if the tornado based visualization was an extra. As far as I understand, the mesa version 2+ is anyway moving away from that visualization style, so maybe it would be quite acceptable for most users to specify mesa[tornado] if they wanted that visualization?

Looking at your repo, it seems that you don't require the visualization component at all, even for the new Solara-based one.
I think you could do fine with pip install --no-deps mesa separately from pip install -r requirements.txt, because there is no way to specify --no-deps for 1 package in requirements.txt

@rht
Copy link
Contributor

rht commented Aug 19, 2023

Since import mesa will by default perform imports from the Tornado stuff, so I think a workaround would be to from mesa.space import xinstead.

@Corvince
Copy link
Contributor Author

Since import mesa will by default perform imports from the Tornado stuff, so I think a workaround would be to from mesa.space import xinstead.

Interesting observation, maybe we could wrap the visualization import in a try...except block so it only gets imported when the package is installed.

@rht
Copy link
Contributor

rht commented Aug 19, 2023

Speaking of which, @jakobaxelsson, your project reminds me of https://github.com/mlc-ai/web-llm, recently featured in latent.space, where you could use it to run 70B Llama 2 in the web browser.

@jakobaxelsson
Copy link

Thank you so much for your advice. The suggested workaround helped me solve the problem. Although it makes my code slightly less clear in a few places, it is still far, far better than having to maintain a local copy of mesa.

In the end, what I needed to do was the following. Since pyscript does not seem to have an option to install packages without dependencies, I had to fall back on the underlying pyodide package install, using micropip.install(...). This function handles that:

async def import_mesa():
    import micropip
    await micropip.install("mesa", deps = False)
    try:
        import mesa
    except:
        pass

Initially, I did not have the try: … except: …. However, this leads to exceptions when trying to do e.g. from mesa.agent import agent as MesaAgent. After adding the try-clause, it works (but I cannot explain why this was needed, and it was only by accident that I discovered that this would work.)

Although I can certainly live with this workaround, I still think it might be a good idea to provide optional extras when installing mesa, to be able to have more flexibility for users who only need a smaller part of this large library. It is also not a very intrusive change. For existing users, they would need to do a one time change in their requirements.txt changing mesa to mesa[all] the next time they upgrade to a new version. For new users, it doesn’t make a difference. Probably, it would be possible to give reasonable error messages if a user tries to use a part of the library that has not been installed. (But again, my issue is solved, so this is just my humble opinion about a useful future extension to mesa.)

@rht
Copy link
Contributor

rht commented Aug 21, 2023

from mesa.agent import agent as MesaAgent shouldn't error. What was the error message you encountered?

Regarding with mesa[all], I'd say it is much more common for people to install the whole thing. I'd consider mesa-core/mesa-minimal instead.

@jakobaxelsson
Copy link

I get ModuleNotFoundError: No module named 'tornado'. You can easily replicate this if you go to https://pyodide.org/en/stable/console.html and type in the following lines:

>>> import micropip
>>> await micropip.install("mesa", deps = False)
>>> await micropip.install("pandas", deps = False)
>>> await micropip.install("networkx", deps = False)
>>> from mesa.model import Model as MesaModel

However, if you then evaluate the last line once more, there is no error.

@rht
Copy link
Contributor

rht commented Aug 21, 2023

It could be that https://github.com/projectmesa/mesa/blob/main/mesa/__init__.py is executed even when you do from mesa.model import Model as MesaModel.

According to https://discuss.python.org/t/help-packaging-optional-application-features-using-extras/14074/4, it is not possible to remove requirements from default requirements. As such, mesa[minimal] can't be done.

A short term solution would be, as @Corvince said, to wrap imports inside a try-except.

@rht
Copy link
Contributor

rht commented Aug 21, 2023

As such, mesa[minimal] can't be done.

But a separate mesa-core/mesa-minimal should do.

@jakobaxelsson
Copy link

Would it be an option to change https://github.com/projectmesa/mesa/blob/main/mesa/__init__.py so that each separate import statement is wrapped in a try-except clause? In that way, mesa would initiate whatever it can, and there could be a warning message for those imports that fail? (Just a quick thought, there may be consequences that I don't fully understand...)

@Corvince
Copy link
Contributor Author

Would it be an option to change https://github.com/projectmesa/mesa/blob/main/mesa/__init__.py so that each separate import statement is wrapped in a try-except clause? In that way, mesa would initiate whatever it can, and there could be a warning message for those imports that fail? (Just a quick thought, there may be consequences that I don't fully understand...)

Yes this is what I was thinking as well. Only that right now we only have to do this for the visualization, the rest is part of this repo so should be available.

Maybe you want to submit a PR with the change?

@EwoutH
Copy link
Member

EwoutH commented Sep 3, 2024

It's nice that you can't do anything in Mesa that's not already thought of. Really shows the bottleneck is engineering capacity.

Coincidentally started working on this two days ago:

@EwoutH EwoutH added the maintenance Release notes label label Sep 3, 2024
@EwoutH EwoutH added this to the v3.0 milestone Sep 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss maintenance Release notes label
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants