Adopt lazy imports from Terra#535
Conversation
19e0059 to
6c10c53
Compare
Pull Request Test Coverage Report for Build 1799728890
💛 - Coveralls |
mrossinek
left a comment
There was a problem hiding this comment.
In general this looks good to me 👍 I have some minor comments.
I did grep for ImportError on the repo and did find a few more occurrences though. Maybe those can be refactored, too?
qiskit_nature/drivers/second_quantization/gaussiand/gaussiandriver.py:257: except ImportError as mnfe:
test/drivers/second_quantization/fcidumpd/test_driver_fcidump_dumper.py:138: except ImportError:
test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py:320: except ImportError as ex:
test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py:408: except ImportError as ex:
test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py:434: except ImportError as ex:
test/algorithms/ground_state_solvers/test_groundstate_eigensolver.py:465: except ImportError as ex:
test/test_readme_sample.py:41: except ImportError as ex:
Grepping for MissingOptionalLibraryError gives the following:
qiskit_nature/problems/second_quantization/lattice/lattices/lattice.py:216: MissingOptionalLibraryError: Requires matplotlib.
qiskit_nature/drivers/second_quantization/vibrational_structure_molecule_driver.py:22:from qiskit.exceptions import MissingOptionalLibraryError
qiskit_nature/drivers/second_quantization/vibrational_structure_molecule_driver.py:54: MissingOptionalLibraryError: Driver not installed.
qiskit_nature/drivers/second_quantization/vibrational_structure_molecule_driver.py:64: except MissingOptionalLibraryError as ex:
qiskit_nature/drivers/second_quantization/vibrational_structure_molecule_driver.py:73: raise MissingOptionalLibraryError(
qiskit_nature/drivers/second_quantization/electronic_structure_molecule_driver.py:22:from qiskit.exceptions import MissingOptionalLibraryError
qiskit_nature/drivers/second_quantization/electronic_structure_molecule_driver.py:59: MissingOptionalLibraryError: Driver not installed.
qiskit_nature/drivers/second_quantization/electronic_structure_molecule_driver.py:72: except (MissingOptionalLibraryError, UnsupportMethodError) as ex:
qiskit_nature/drivers/second_quantization/electronic_structure_molecule_driver.py:81: raise MissingOptionalLibraryError(
test/drivers/second_quantization/test_molecule_driver.py:20:from qiskit.exceptions import MissingOptionalLibraryError
test/drivers/second_quantization/test_molecule_driver.py:73: except MissingOptionalLibraryError as ex:
test/drivers/second_quantization/test_molecule_driver.py:92: except MissingOptionalLibraryError as ex:
test/drivers/second_quantization/test_molecule_driver.py:156: except MissingOptionalLibraryError as ex:
| if PSI4PROG is None: | ||
| PSI4PROG = PSI4 |
There was a problem hiding this comment.
Why is this needed? If which cannot find the command how would we be able to use it?
There was a problem hiding this comment.
@mrossinek Just because the LazySubprocessTester from Terra won't accept a None or empty command in the constructor and I still wanted to use its capabilities of actually running the command to see if it is installed.
There was a problem hiding this comment.
Okay, then why is the same not being done in the gaussian case a few lines further up?
There was a problem hiding this comment.
Ahhh, because unfortunately Gaussian doesn't have a command line option like version or whatever that lets me just simply run it without side effect of actually running input data. For this I created my own Lazy class derived from Terra that just checks if the command is None. Effectively just what was being done before:
class NatureLazyCommandTester(LazyDependencyManager):
I didn't use it for PSI4 because in that case I could do a better check of actually running it because it has a version option.
There was a problem hiding this comment.
Oh I was not careful. The first time I read it, it looked like you used NatureLazyCommandTester for Gaussian and Psi4. But I see now that the latter actually uses the Terra-provided one 👍
There was a problem hiding this comment.
What functionality would you like in LazySubprocessTester? I made it reject "empty" commands as a way of catching bugs because I couldn't think of any use-cases, but if you've got a use-case for empty commands, we could add it.
Here, I would note that calling which on import isn't lazy - if you wanted it for your Gaussian one, perhaps your derived class could run shutil.which to define its _is_available? It depends how lazy you care about being, though.
@mrossinek I will review the ImportError to see if any can be refactored but the |
90dc2e2 to
b894525
Compare
mrossinek
left a comment
There was a problem hiding this comment.
Just one question otw this LGTM 🙂
d95369e to
0c6ea0b
Compare
jakelishman
left a comment
There was a problem hiding this comment.
I hope the tools are useful - let us/me know if there's anything about the existing Terra objects that might want expanding.
| _optionals.HAS_GAUSSIAN.require_now("GaussianForcesDriver __init__") | ||
|
|
||
| @staticmethod | ||
| @_optionals.HAS_GAUSSIAN.require_in_call("GaussianForcesDriver from_molecule") |
There was a problem hiding this comment.
If you don't supply an argument in the decorator form, it should use the qualified name of the method automatically. If you prefer, this line is equivalent to decorating with @_optionals.HAS_GAUSSIAN.require_in_call (i.e. without "calling" the decorator)
There was a problem hiding this comment.
Oh that is helpful. Thanks for the tip. I will change it.
| logger = logging.getLogger(__name__) | ||
|
|
||
| try: | ||
| if _optionals.HAS_PYQUANTE2: |
There was a problem hiding this comment.
I don't know if you mind, but this isn't a lazy test - the Boolean evaluation will be triggered as soon as this module is imported.
There was a problem hiding this comment.
Yes, I knew. We had those imports at the top because they are being used in different parts of the file and even in type annotations like:
self._mol: pyquante_molecule = None
self._bfs: basisset = None
I will see if it is possible to move them inside the methods.
| args = inspect.getfullargspec(PyQuanteDriver.__init__).args | ||
| args = inspect.signature(PyQuanteDriver.__init__).parameters.keys() |
There was a problem hiding this comment.
I put some effort into trying to make sure the wrappers would propagate through the signature and documentation (require_in_instance does a bit of magic to wrap the __init__ method). Let me know if something's broken about that.
(inspect.signature is the recommended way, though)
There was a problem hiding this comment.
Yes, the getfullargspec args started returning an empty array. I changed to signature which works.
| if PSI4PROG is None: | ||
| PSI4PROG = PSI4 |
There was a problem hiding this comment.
What functionality would you like in LazySubprocessTester? I made it reject "empty" commands as a way of catching bugs because I couldn't think of any use-cases, but if you've got a use-case for empty commands, we could add it.
Here, I would note that calling which on import isn't lazy - if you wanted it for your Gaussian one, perhaps your derived class could run shutil.which to define its _is_available? It depends how lazy you care about being, though.
| not empty. | ||
| """ | ||
|
|
||
| __slots__ = ("_command",) |
There was a problem hiding this comment.
Also, you don't need to do this if you don't want, especially if you'd like to attach data to the objects. To be honest, I probably shouldn't have done it in Terra to give you the choice of adding arbitrary data - from a Python perspective, it's a bad habit of mine that I over-use __slots__ (it comes from me preferring stricter typing, where you can't add attributes to stuff).
There's no real harm in it if you don't want to attach data to the objects, it's just a bit of overkill, and makes it harder if you later change your mind.
There was a problem hiding this comment.
Yes, since I was creating a lazy class I decided to stick to the idiom there but already had someone else asking me about it too :-) I will remove it.
|
@jakelishman About the Nature has two drivers, PSI4 and Gaussian, that have their own commands. We use A subprocess tester that would be useful would be one where I construct it with a command string, but inside I created a very simple subclass for Gaussian just to test None or not but I was thinking of doing what you suggested and put the |
mrossinek
left a comment
There was a problem hiding this comment.
LGTM! Thanks @manoelmarques!
* Adopt lazy imports from Terra * Migrate most ImportError to Lazy framework * Remove global optionals check from pyscf,pyquante * Create NatureLazySubprocessTester for Gaussian and PSI4
Summary
Adopt the API implemented in Qiskit/qiskit#7525
Details and comments