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

Ensure that qchem is imported lazily #1962

Merged
merged 16 commits into from
Dec 2, 2021
Merged

Ensure that qchem is imported lazily #1962

merged 16 commits into from
Dec 2, 2021

Conversation

josh146
Copy link
Member

@josh146 josh146 commented Dec 1, 2021

Context: pennylane.qchem is currently imported when PennyLane is imported, if it is available. If not, pennylane.qchem instead points to a dummy NestedAttributeError class, which raises an import error if or when the user attempts to access qml.qchem.

Description of the Change: With Python 3.7, module level __getattr__ and __dir__ special methods can now be defined. This allows us to modify this system, to ensure qchem is only imported when accessed.

Benefits: Potential speed up in import time.

For example:

>>> import pennylane as qml
>>> import sys
>>> "pennylane_qchem" in sys.modules
False
>>> qml.qchem
<module 'pennylane_qchem.qchem' from '/home/josh/xanadu/pennylane/qchem/pennylane_qchem/qchem/__init__.py'>
>>> "pennylane_qchem" in sys.modules
True

Possible Drawbacks: n/a

Related GitHub Issues: Closes #1961

@josh146 josh146 linked an issue Dec 1, 2021 that may be closed by this pull request
@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2021

Hello. You may have forgotten to update the changelog!
Please edit doc/releases/changelog-dev.md with:

  • A one-to-two sentence description of the change. You may include a small working example for new features.
  • A link back to this PR.
  • Your name (or GitHub username) in the contributors section.

@josh146 josh146 added the review-ready 👌 PRs which are ready for review by someone from the core team. label Dec 1, 2021
Comment on lines +287 to +288
f"The {name} plugin requires PennyLane versions {plugin_device_class.pennylane_requires}, "
f"however PennyLane version {__version__} is installed."
Copy link
Member Author

Choose a reason for hiding this comment

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

This is because pylint was complaining

@cvjjm
Copy link
Contributor

cvjjm commented Dec 1, 2021

Thumbs up!

@codecov
Copy link

codecov bot commented Dec 1, 2021

Codecov Report

Merging #1962 (8c4386c) into master (3b51f48) will increase coverage by 1.91%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1962      +/-   ##
==========================================
+ Coverage   96.90%   98.81%   +1.91%     
==========================================
  Files         226      226              
  Lines       17346    17348       +2     
==========================================
+ Hits        16809    17143     +334     
+ Misses        537      205     -332     
Impacted Files Coverage Δ
pennylane/__init__.py 100.00% <100.00%> (ø)
pennylane/interfaces/batch/__init__.py 100.00% <0.00%> (+0.90%) ⬆️
pennylane/interfaces/batch/tensorflow_autograph.py 100.00% <0.00%> (+1.17%) ⬆️
pennylane/beta/devices/default_tensor.py 96.94% <0.00%> (+1.69%) ⬆️
pennylane/interfaces/batch/tensorflow.py 100.00% <0.00%> (+2.04%) ⬆️
pennylane/beta/devices/default_tensor_tf.py 90.62% <0.00%> (+3.12%) ⬆️
pennylane/interfaces/batch/torch.py 100.00% <0.00%> (+3.27%) ⬆️
pennylane/devices/default_qubit_tf.py 90.00% <0.00%> (+3.33%) ⬆️
pennylane/collections/qnode_collection.py 100.00% <0.00%> (+3.50%) ⬆️
pennylane/qnode_old.py 95.61% <0.00%> (+4.38%) ⬆️
... and 14 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3b51f48...8c4386c. Read the comment docs.

_qchem = None


def __getattr__(name):
Copy link
Contributor

@soranjh soranjh Dec 1, 2021

Choose a reason for hiding this comment

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

I performed VQE calculations in the following cases, everything seems to work as expected.
A. PennyLane-QChem is installed,

  1. `from pennylane import qchem` works fine
    
  2. `qml.qchem.excitations(2, 4)` without importing qchem works fine
    

B. PennyLane-QChem is not installed

  1. `from pennylane import qchem`: does not complain
    
  2. `qml.qchem.excitations(2, 4)` with/without importing qchem: asks for installing qchem
    

@josh146
Copy link
Member Author

josh146 commented Dec 2, 2021

Thanks Soran for checking!

Copy link
Contributor

@soranjh soranjh 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, that is a nice addition.

@cvjjm
Copy link
Contributor

cvjjm commented Dec 2, 2021

By the way: Are you aware of https://github.com/mnmelo/lazy_import ? Just stumbled across it and it looks pretty amazing.

@josh146
Copy link
Member Author

josh146 commented Dec 2, 2021

Nice! I actually wasn't aware. Although it seems to be unmaintained for 4 years now... I imagine the ability to set module level __getattr__ from Python 3.7+ removed its main need.

(Although, its testing module looks quite nice)

Copy link
Contributor

@antalszava antalszava 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! 🎉 :) Just had some questions.



# add everything as long as it's not a module and not prefixed with _
_all = sorted(
Copy link
Contributor

Choose a reason for hiding this comment

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

How come we're sorting here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question @antalszava.. I do not remember why I am sorting this.

Comment on lines +333 to +337
if entry.name == "OpenFermion":
_qchem = entry.load()

if _qchem is None:
raise ImportError(
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to check if OpenFermion was found as an entry. What if we have PennyLane-QChem installed, but OpenFermion uninstalled (e.g., first Qchem was installed, but then OpenFermion got manually uninstalled)? We'd get the ImportError, however, it refers to QChem not Openfermion, correct?

Copy link
Member Author

Choose a reason for hiding this comment

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

oh this is an historical accident 😆 The entry point for qchem is named "OpenFermion", since we initially envisioned qchem as an openfermion plugin.

def __getattr__(name):
"""Ensure that the qchem module is imported lazily"""
if name == "qchem":
global _qchem # pylint: disable=global-statement
Copy link
Contributor

Choose a reason for hiding this comment

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

For my understanding: how come we have to define _qchem as global here and not on line 322?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, _qchem is an existing module level variable, but the way Python scope works is as follows:

a = 5

def f():
    # No assignment; Python assumes
    # a refers to the global variable a above.
    print(a)

def g():
    # a is assigned to within the function;
    # Python assigns it with a scope *local*
    # to the function, independent of the global
    # a above.
    a = 7
    print(a)

If we wish g() to assign value to the global variable a above, we need to then explicitly state this using the global keyword.

@antalszava antalszava merged commit dba8147 into master Dec 2, 2021
@antalszava antalszava deleted the lazy-qchem branch December 2, 2021 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
review-ready 👌 PRs which are ready for review by someone from the core team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Speed up PennyLane load time
4 participants