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

Resolve default imports for optional dependencies #3475

Merged
merged 54 commits into from
Nov 14, 2023

Conversation

arjxn-py
Copy link
Member

@arjxn-py arjxn-py commented Oct 26, 2023

Description

With this PR i'm trying to fix the error getting while importing pybamm without any extra dependencies for pybamm=23.9rc0

Fixes #3473

Type of change

Please add a line in the relevant section of CHANGELOG.md to document the change (include PR #) - note reverse order of PR #s. If necessary, also add to the list of breaking changes.

  • New feature (non-breaking change which adds functionality)
  • Optimization (back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)

Key checklist:

  • No style issues: $ pre-commit run (or $ nox -s pre-commit) (see CONTRIBUTING.md for how to set this up to run automatically when committing locally, in just two lines of code)
  • All tests pass: $ python run-tests.py --all (or $ nox -s tests)
  • The documentation builds: $ python run-tests.py --doctest (or $ nox -s doctests)

You can run integration tests, unit tests, and doctests together at once, using $ python run-tests.py --quick (or $ nox -s quick).

Further checks:

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

Copy link
Member

@Saransh-cpp Saransh-cpp left a comment

Choose a reason for hiding this comment

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

Thanks, @arjxn-py! Some comments below -

pybamm/expression_tree/functions.py Outdated Show resolved Hide resolved
pybamm/__init__.py Outdated Show resolved Hide resolved
@agriyakhetarpal
Copy link
Member

agriyakhetarpal commented Oct 28, 2023

https://github.com/pandas-dev/pandas/blob/984d75543fce5c68f0dcc4f0b3500256e4a9c0c9/pandas/io/pytables.py#L566

https://github.com/pandas-dev/pandas/blob/984d75543fce5c68f0dcc4f0b3500256e4a9c0c9/pandas/compat/_optional.py#L83-L165

This is how pandas does it, we could add a function with similar functionality in pybamm.util. These are design choices imo after all, but a write-once-use-anywhere paradigm would be useful in this scenario. For example, adding a decorator would be great such that it can be used on a class (or at its instantiation, not recommended however) which would automatically check if an optional dependency can be imported or not, and would apply to all subsequent functions defined inside it. I am not sure how one would go about implementing it, but something like

@pybamm._check_and_import_optional_dependency(name="pybtex")
class Citations:
   
   def print_citation(...):
    ...

This way, it would raise a warning plus a helpful message if pybtex cannot be found, but load it into the namespace if it can be found. We currently import the print_citations() method directly, which means the decorator would apply to the method only and not throw duplicate warnings. Python imports are cached very effectively which means there is negligible overhead if we import a dependency multiple times inside the same file or within a module.

Although these function-scoped imports are also a great idea btw. We already do it for matplotlib in the QuickPlot classes and methods; the good thing is that we don't add optional dependencies often, which means this is going to be a one-time thing and maintaining such imports would not be difficult (skfem for the SpatialMethod module, bpx for BPX, etc.)

TIL that importlib.metadata.distribution("pybamm").requires prints out a list of strings that contain all required and optional dependencies. The messy part is however about parsing these strings.

@codecov
Copy link

codecov bot commented Oct 28, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (bfddc83) 99.58% compared to head (d685c38) 99.58%.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #3475   +/-   ##
========================================
  Coverage    99.58%   99.58%           
========================================
  Files          256      256           
  Lines        20058    20116   +58     
========================================
+ Hits         19975    20033   +58     
  Misses          83       83           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@arjxn-py
Copy link
Member Author

I've finally managed to make a decorator function but there are complications with it :

  • If applied pybamm.util.have_optional_dependency will be executed whenever pybamm is imported. This behavior is expected since decorators are typically execute when the class is imported.
  • I am having trouble to make module available within the local scope of the method & i'm not sure if this is possible with a decorator function or not.

I'll also put in some efforts to do it with simple reusable function first.

@agriyakhetarpal
Copy link
Member

I've finally managed to make a decorator function but there are complications with it :

  • If applied pybamm.util.have_optional_dependency will be executed whenever pybamm is imported. This behavior is expected since decorators are typically execute when the class is imported.

I think this should be fine, the decorator should just execute "silently" and return nothing if a dependency is found. Is there a way to "lazy-load" an entire module at the time of import, e.g., to receive no warnings when doing import pybamm but to receive a warning about pybtex only if someone executes any of the functionality under pybamm.citations. or in other words tries to instantiate the Citations class? Doing that it would make import pybamm faster, even, I would say, since certain modules would be skipped.

@agriyakhetarpal
Copy link
Member

agriyakhetarpal commented Oct 30, 2023

I am having trouble to make module available within the local scope of the method & i'm not sure if this is possible with a decorator function or not.

In that case, it would be fine to do this for (inside) methods only and not for classes: this practice won't conform to DRY, but atleast it won't apply to private methods available under a class (we want to mark just those pieces of functionality which are available as a part of the public API)

@agriyakhetarpal
Copy link
Member

See also: https://scientific-python.org/specs/spec-0001/ (this demands a separate issue, I guess)

@Saransh-cpp
Copy link
Member

See also: https://scientific-python.org/specs/spec-0001/ (this demands a separate issue, I guess)

Yes, separate and important issue. Importing pybamm usually takes relatively more time than other libraries, and I think this should fix that.

@arjxn-py
Copy link
Member Author

See also: https://scientific-python.org/specs/spec-0001/ (this demands a separate issue, I guess)

Yes, happy to open one issue for it & also look into the same, @agriyakhetarpal do let me know if you want to open with some suggestion or simplifications.

@agriyakhetarpal
Copy link
Member

I see that there are some issues with building the documentation (there is a possibility it might break some of our internal Sphinx extensions that rely on autodoc), though I think we can discuss this further on a new issue thread. Some other simplications could be to reorganise top-level imports without an expense to the current API (i.e., no breaking changes).

Copy link
Member

@Saransh-cpp Saransh-cpp left a comment

Choose a reason for hiding this comment

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

Took over and made some changes. Probably the last change request (phew)

We should also be testing the "lite" pybamm in CI (as pointed out by @agriyakhetarpal), but I think we can do that after this release. The testing part will also tie up nicely with unittest to pytest migration (pytest.importorskip is quite intelligent and can be added module-wide).

pybamm/expression_tree/printing/sympy_overrides.py Outdated Show resolved Hide resolved
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Copy link
Member

@Saransh-cpp Saransh-cpp left a comment

Choose a reason for hiding this comment

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

Thanks a ton for the amazing work, @arjxn-py! 🙂

I'll wait for others to review this before merging.

Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

Looks good now, thank you @arjxn-py and @Saransh-cpp! Just needs a CHANGELOG entry and a documentation update to mark anytree as a required dependency in the installation guide.

I tested all example scripts with pybamm[plot] and everything worked as expected. I would also recommend re-running the failed integration tests and notebook tests just to be on the safer side of things.

@arjxn-py
Copy link
Member Author

Not sure why pre-commit.ci is failing now 😕

@Saransh-cpp
Copy link
Member

Not related to this PR, se #3519

Copy link
Sponsor Member

@brosaplanella brosaplanella left a comment

Choose a reason for hiding this comment

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

Looks good to me, thank you very much to all who contributed fixing this issue!

@Saransh-cpp Saransh-cpp merged commit 6fbd306 into pybamm-team:develop Nov 14, 2023
25 of 35 checks passed
Saransh-cpp added a commit that referenced this pull request Nov 14, 2023
Resolve default imports for optional dependencies
@arjxn-py arjxn-py deleted the fix-default-imports branch February 21, 2024 07:08
rtimms added a commit that referenced this pull request May 16, 2024
* Bump to v23.9rc0

* Merge pull request #3412 from agriyakhetarpal/drop-i686-manylinux2014-support

Drop support for i686 manylinux

* Merge pull request #3413 from Saransh-cpp/improve-release-workflow

Improve release workflow, add a note, bump version manually

* Merge pull request #3436 from Saransh-cpp/fortnightly-wheels

Build wheels on the 1st and 15th of every month

* Merge pull request #3445 from pybamm-team/issue-3428-rename-exchange

#3428 exchange-current density error

* Merge pull request #3449 from pybamm-team/i3431-windows-wheels

Fix failing windows wheel builds

* Merge pull request #3456 from abillscmu/issue-3224-initial_soc

make initial soc work with half cell models

* Merge pull request #3467 from abillscmu/bugfix/initial_soh

* Merge pull request #3423 from jsbrittain/jax_gpu

JaxSolver fails when using GPU support with no input parameters

* Fix changelog

* Merge pull request #3475 from arjxn-py/fix-default-imports

Resolve default imports for optional dependencies

* Bump - `v23.9rc1`

* Fix date in CHANGELOG

* Bump version to v23.9

* Fix docs about Jax solver compatibility with Python versions (#3702)

* Ensure correct Python versions for Jax solver compatibility

* Simplify array of Python versions

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

* Use different conjunction

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

---------

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

* Merge pull request #3706 from agriyakhetarpal/fix-pybamm-install-odes

Make `pybamm_install_odes` a bit more robust

* #3690 fix issue with skipped steps (#3708)

* #3690 fix issue with skipped steps

* #3690 changelog

* #3690 add test

* #3611 use actual cell volume for average total heating (#3707)

* #3611 use actual cell volume for average total heating

* #3611 changelog

* #3611 account for number of electrode pairs

* #3611 update variable names

* Improve the release workflow (#3737)

* Try fixing the release workflow

* Turn off safety

* Fix CHANGELOG

* Add OS

* Use regex for better matches

* Update instructions, add safety checks

* checkout to the version branch for the final release

* Bump to v24.1rc1

* #3630 fix interpolant shape error (#3761)

* #3630 fix interpolant shape error

* #3630 changelog

* Bump to v24.1rc2

* Bump to v24.1

* Fix doctests failures in scheduled tests (#3784)

Closes #3781

* Resolve broken `scikits.odes` installation on self-hosted M-series runner (#3785)

* Try fixing M-series runner tests

This is being done by adding SuiteSparse and SUNDIALS installations which might have been missing on the runner, which broke `scikits.odes`.

* Don't use Homebrew SUNDIALS, use LD_LIBRARY_PATH

* Don't use Homebrew to install SUNDIALS

* Force remove pip cache for `scikits.odes`

---------

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

* add temperature dependence to MSMR model

* changelog

* fix tests

* fix example

* rob comments

* update notebook

---------

Co-authored-by: Ferran Brosa Planella <Ferran.Brosa-Planella@warwick.ac.uk>
Co-authored-by: Saransh Chopra <saransh0701@gmail.com>
Co-authored-by: Martin Robinson <martinjrobins@gmail.com>
Co-authored-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>
Co-authored-by: Robert Timms <43040151+rtimms@users.noreply.github.com>
Co-authored-by: Saransh-cpp <Saransh-cpp@users.noreply.github.com>
js1tr3 pushed a commit to js1tr3/PyBaMM that referenced this pull request Aug 12, 2024
js1tr3 pushed a commit to js1tr3/PyBaMM that referenced this pull request Aug 12, 2024
* Bump to v23.9rc0

* Merge pull request pybamm-team#3412 from agriyakhetarpal/drop-i686-manylinux2014-support

Drop support for i686 manylinux

* Merge pull request pybamm-team#3413 from Saransh-cpp/improve-release-workflow

Improve release workflow, add a note, bump version manually

* Merge pull request pybamm-team#3436 from Saransh-cpp/fortnightly-wheels

Build wheels on the 1st and 15th of every month

* Merge pull request pybamm-team#3445 from pybamm-team/issue-3428-rename-exchange

pybamm-team#3428 exchange-current density error

* Merge pull request pybamm-team#3449 from pybamm-team/i3431-windows-wheels

Fix failing windows wheel builds

* Merge pull request pybamm-team#3456 from abillscmu/issue-3224-initial_soc

make initial soc work with half cell models

* Merge pull request pybamm-team#3467 from abillscmu/bugfix/initial_soh

* Merge pull request pybamm-team#3423 from jsbrittain/jax_gpu

JaxSolver fails when using GPU support with no input parameters

* Fix changelog

* Merge pull request pybamm-team#3475 from arjxn-py/fix-default-imports

Resolve default imports for optional dependencies

* Bump - `v23.9rc1`

* Fix date in CHANGELOG

* Bump version to v23.9

* Fix docs about Jax solver compatibility with Python versions (pybamm-team#3702)

* Ensure correct Python versions for Jax solver compatibility

* Simplify array of Python versions

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

* Use different conjunction

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

---------

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

* Merge pull request pybamm-team#3706 from agriyakhetarpal/fix-pybamm-install-odes

Make `pybamm_install_odes` a bit more robust

* pybamm-team#3690 fix issue with skipped steps (pybamm-team#3708)

* pybamm-team#3690 fix issue with skipped steps

* pybamm-team#3690 changelog

* pybamm-team#3690 add test

* pybamm-team#3611 use actual cell volume for average total heating (pybamm-team#3707)

* pybamm-team#3611 use actual cell volume for average total heating

* pybamm-team#3611 changelog

* pybamm-team#3611 account for number of electrode pairs

* pybamm-team#3611 update variable names

* Improve the release workflow (pybamm-team#3737)

* Try fixing the release workflow

* Turn off safety

* Fix CHANGELOG

* Add OS

* Use regex for better matches

* Update instructions, add safety checks

* checkout to the version branch for the final release

* Bump to v24.1rc1

* pybamm-team#3630 fix interpolant shape error (pybamm-team#3761)

* pybamm-team#3630 fix interpolant shape error

* pybamm-team#3630 changelog

* Bump to v24.1rc2

* Bump to v24.1

* Fix doctests failures in scheduled tests (pybamm-team#3784)

Closes pybamm-team#3781

* Resolve broken `scikits.odes` installation on self-hosted M-series runner (pybamm-team#3785)

* Try fixing M-series runner tests

This is being done by adding SuiteSparse and SUNDIALS installations which might have been missing on the runner, which broke `scikits.odes`.

* Don't use Homebrew SUNDIALS, use LD_LIBRARY_PATH

* Don't use Homebrew to install SUNDIALS

* Force remove pip cache for `scikits.odes`

---------

Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>

* add temperature dependence to MSMR model

* changelog

* fix tests

* fix example

* rob comments

* update notebook

---------

Co-authored-by: Ferran Brosa Planella <Ferran.Brosa-Planella@warwick.ac.uk>
Co-authored-by: Saransh Chopra <saransh0701@gmail.com>
Co-authored-by: Martin Robinson <martinjrobins@gmail.com>
Co-authored-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Co-authored-by: Eric G. Kratz <kratman@users.noreply.github.com>
Co-authored-by: Robert Timms <43040151+rtimms@users.noreply.github.com>
Co-authored-by: Saransh-cpp <Saransh-cpp@users.noreply.github.com>
js1tr3 pushed a commit to js1tr3/PyBaMM that referenced this pull request Aug 12, 2024
Resolve default imports for optional dependencies
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.

[Bug]: 23.9rc0 "optional dependencies" imported
4 participants