Skip to content
New issue

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

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

Already on GitHub? # to your account

Support pathlib.Path in place of path strings #740

Open
mattwthompson opened this issue Oct 7, 2020 · 2 comments
Open

Support pathlib.Path in place of path strings #740

mattwthompson opened this issue Oct 7, 2020 · 2 comments

Comments

@mattwthompson
Copy link
Member

Is your feature request related to a problem? Please describe.
Some, likely many, I/O operations work on path strings but not pathlib.Path objects.

>>> from openforcefield.topology import Molecule
>>> from pathlib import Path
>>> Molecule.from_file('mol.sdf', file_format='sdf')
Molecule with name '' and SMILES '[H]C([H])([H])C([H])([H])O[H]'
>>> Molecule.from_file(Path('mol.sdf'), file_format='sdf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mwt/software/openforcefield/openforcefield/topology/molecule.py", line 3797, in from_file
    raise Exception("Unable to read molecule from file: {}".format(file_path))
Exception: Unable to read molecule from file: mol.sdf

Most Python APIs treat them the same, allowing for a largely painless transition from os.path to pathlib.Path.

Describe the solution you'd like
Long-term, it would be nice for all methods that expect str to also work on Path objects. Many probably already work, I have not looked into this deeply.

Describe alternatives you've considered
There are decent enough workarounds

>>> Molecule.from_file(Path('mol.sdf').as_posix(), file_format='sdf')
Molecule with name '' and SMILES '[H]C([H])([H])C([H])([H])O[H]'
>>> Molecule.from_file(str(Path('mol.sdf')), file_format='sdf')
Molecule with name '' and SMILES '[H]C([H])([H])C([H])([H])O[H]'

Additional context
This may be blocked by upstream dependencies (i.e. rdkit/rdkit#2923). Also looks like a Pydantic refactor may handle this for free (in the domains we control).

pathlib is in the standard library as of Python 3.4 or so.

@mattwthompson
Copy link
Member Author

Adding the good first issue label as implementing this shouldn't require much/any chemistry expertise

@mattwthompson
Copy link
Member Author

In [1]: import pathlib

In [2]: from openff.toolkit import Molecule, ForceField

In [3]: ForceField("openff-2.1.0.offxml").to_file(pathlib.Path("x.offxml"))

In [4]: !head x.offxml
<?xml version="1.0" encoding="utf-8"?>
<SMIRNOFF version="0.3" aromaticity_model="OEAroModel_MDL">
    <Author>The Open Force Field Initiative</Author>
    <Date>2023-05-02</Date>
    <Constraints version="0.3">
        <Constraint smirks="[#1:1]-[*:2]" id="c1"></Constraint>
        <Constraint smirks="[#1:1]-[#8X2H2+0:2]-[#1]" id="c-tip3p-H-O" distance="0.9572 * angstrom ** 1"></Constraint>
        <Constraint smirks="[#1:1]-[#8X2H2+0]-[#1:2]" id="c-tip3p-H-O-H" distance="1.5139006545247014 * angstrom ** 1"></Constraint>
    </Constraints>
    <Bonds version="0.4" potential="harmonic" fractional_bondorder_method="AM1-Wiberg" fractional_bondorder_interpolation="linear">

In [5]: Molecule.from_smiles("CCO").to_file(pathlib.Path("molecule.sdf"), file_format="sdf")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[5], line 1
----> 1 Molecule.from_smiles("CCO").to_file(pathlib.Path("molecule.sdf"), file_format="sdf")

File ~/software/openff-toolkit/openff/toolkit/topology/molecule.py:4162, in FrozenMolecule.to_file(self, file_path, file_format, toolkit_registry)
   4160     toolkit.to_file(self, file_path, file_format)
   4161 else:
-> 4162     toolkit.to_file_obj(self, file_path, file_format)

File ~/software/openff-toolkit/openff/toolkit/utils/openeye_wrapper.py:554, in OpenEyeToolkitWrapper.to_file_obj(self, molecule, file_obj, file_format)
    552 # This function requires a text-mode file_obj.
    553 try:
--> 554     file_obj.write("")
    555 except TypeError:
    556     # Switch to a ValueError and use a more informative exception
    557     # message to match RDKit.
    558     raise ValueError(
    559         "Need a text mode file object like StringIO or a file opened with mode 't'"
    560     ) from None

AttributeError: 'PosixPath' object has no attribute 'write'

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

1 participant