Skip to content

Commit

Permalink
Improved handling of properties
Browse files Browse the repository at this point in the history
    * Added ability to get lists of systems or configurations filtered by name
    * Improved handling of properties on just a system, not configuration
    * Added ability to filter properties retrieved
    * Improved handling of properties when creating OpenBabel OB_MOL object
  • Loading branch information
paulsaxe committed Jul 30, 2023
1 parent afaa651 commit b8c4172
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 50 deletions.
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
History
=======

2023.7.30 -- Improved handling of properties
* Added ability to get lists of systems or configurations filtered by name
* Improved handling of properties on just a system, not configuration
* Added ability to filter properties retrieved
* Improved handling of properties when creating OpenBabel OB_MOL object

2023.7.26 -- Bugfix: error in QCSchema bonds; enhancement: RDKit
* Fixed bug in the bond indices in QCSchema
* Added ability to use RDKit for SMILES and InChI
Expand Down
10 changes: 8 additions & 2 deletions molsystem/configuration_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,26 @@ def exists(self, name):
"""A thin wrapper of the _Properties method."""
return self.properties.exists(name)

def get(self, _property="all"):
def get(self, _property="all", include_system_properties=False):
"""Get the given property value for this configuration.
Parameters
----------
_property : int or str
The id or name of the property.
include_system_properties : bool=False
Whether to include properties that are on the system, not any configuration
Returns
-------
int, float, or str
The value of the property.
"""
return self.properties.get(self._cid, _property)
return self.properties.get(
self._cid,
_property,
include_system_properties=include_system_properties,
)

def id(self, name):
"""The id for a property
Expand Down
2 changes: 1 addition & 1 deletion molsystem/openbabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def to_OBMol(self, properties=None):
ob_mol.AssignSpinMultiplicity(True)

if properties == "all":
data = self.properties.get("all")
data = self.properties.get("all", include_system_properties=True)
pair = openbabel.OBPairData()
for key, value in data.items():
pair.SetAttribute(key)
Expand Down
182 changes: 137 additions & 45 deletions molsystem/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def exists(self, name):
self.cursor.execute("SELECT COUNT(*) FROM property WHERE name = ?", (name,))
return self.cursor.fetchone()[0] != 0

def get(self, configuration_id, _property="all"):
def get(self, configuration_id, _property="all", include_system_properties=False):
"""Get the given property value for the configuration.
Parameters
Expand All @@ -326,38 +326,85 @@ def get(self, configuration_id, _property="all"):
The id of the configuration.
_property : int or str, or "all"
The id or name of the property, or all properties if "all".
include_system_properties : bool=False
Whether to include properties that are on the system, not any configuration
Returns
-------
int, float, or str
The value of the property.
"""
if _property == "all":
sql = "SELECT name, type, value"
sql += " FROM property, float_data"
sql += " WHERE float_data.property = property.id AND configuration = ?"
sql += " UNION "
sql += "SELECT name, type, value"
sql += " FROM property, int_data"
sql += " WHERE int_data.property = property.id AND configuration = ?"
sql += " UNION "
sql += "SELECT name, type, value"
sql += " FROM property, str_data"
sql += " WHERE str_data.property = property.id AND configuration = ?"
sql += " UNION "
sql += "SELECT name, type, value"
sql += " FROM property, json_data"
sql += " WHERE json_data.property = property.id AND configuration = ?"

if include_system_properties:
self.cursor.execute(
sql,
(
configuration_id,
configuration_id,
configuration_id,
configuration_id,
),
"SELECT system FROM configuration WHERE id = ?", (configuration_id,)
)
system_id = self.cursor.fetchone()[0]

if _property == "all":
sql = (
"SELECT name, type, value\n"
" FROM property, float_data\n"
" WHERE float_data.property = property.id AND configuration = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, int_data\n"
" WHERE int_data.property = property.id AND configuration = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, str_data\n"
" WHERE str_data.property = property.id AND configuration = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, json_data\n"
" WHERE json_data.property = property.id AND configuration = ?"
)
if include_system_properties:
sql += (
"\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, float_data\n"
" WHERE float_data.property = property.id"
" AND configuration IS NULL AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, int_data\n"
" WHERE int_data.property = property.id"
" AND configuration IS NULL AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, str_data\n"
" WHERE str_data.property = property.id"
" AND configuration IS NULL AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, json_data\n"
" WHERE json_data.property = property.id"
" AND configuration IS NULL AND system = ? \n"
)
self.cursor.execute(
sql,
(
configuration_id,
configuration_id,
configuration_id,
configuration_id,
system_id,
system_id,
system_id,
system_id,
),
)
else:
self.cursor.execute(
sql,
(
configuration_id,
configuration_id,
configuration_id,
configuration_id,
),
)

result = {}
for row in self.cursor:
Expand All @@ -382,10 +429,19 @@ def get(self, configuration_id, _property="all"):

ptype = self.type(pid)
sql = (
f"SELECT value FROM {ptype}_data"
f"SELECT value FROM {ptype}_data\n"
" WHERE configuration = ? AND property = ?"
)
self.cursor.execute(sql, (configuration_id, pid))
if include_system_properties:
sql += (
"\n"
" UNION \n"
f"SELECT value FROM {ptype}_data\n"
" WHERE configuration IS NULL and system = ? AND property = ?"
)
self.cursor.execute(sql, (configuration_id, pid, system_id, pid))
else:
self.cursor.execute(sql, (configuration_id, pid))
result = self.cursor.fetchone()
if result is None:
raise ValueError(
Expand All @@ -397,7 +453,9 @@ def get(self, configuration_id, _property="all"):
else:
return result[0]

def get_for_system(self, system_id, _property="all"):
def get_for_system(
self, system_id, _property="all", include_configuration_properties=False
):
"""Get the given property value(s) for the system.
Parameters
Expand All @@ -406,29 +464,55 @@ def get_for_system(self, system_id, _property="all"):
The id of the system.
_property : int or str of "all"
The id or name of the property, or "all" for all properties.
include_configuration_properties : bool=False
Whether to include properties from any configuration in the system.
Returns
-------
[int, float, or str]
The value(s) of the property.
"""
if _property == "all":
sql = "SELECT name, type, value"
sql += " FROM property, float_data"
sql += " WHERE float_data.property = property.id AND system = ?"
sql += " UNION "
sql += "SELECT name, type, value"
sql += " FROM property, int_data"
sql += " WHERE int_data.property = property.id AND system = ?"
sql += " UNION "
sql += "SELECT name, type, value"
sql += " FROM property, str_data"
sql += " WHERE str_data.property = property.id AND system = ?"
sql += " UNION "
sql += "SELECT name, type, value"
sql += " FROM property, json_data"
sql += " WHERE json_data.property = property.id AND system = ?"

if include_configuration_properties:
sql = (
"SELECT name, type, value\n"
" FROM property, float_data\n"
" WHERE float_data.property = property.id AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, int_data\n"
" WHERE int_data.property = property.id AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, str_data\n"
" WHERE str_data.property = property.id AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, json_data\n"
" WHERE json_data.property = property.id AND system = ?\n"
)
else:
sql = (
"SELECT name, type, value\n"
" FROM property, float_data\n"
" WHERE float_data.property = property.id"
" AND configuration is NULL AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, int_data\n"
" WHERE int_data.property = property.id"
" AND configuration is NULL AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, str_data\n"
" WHERE str_data.property = property.id"
" AND configuration is NULL AND system = ?\n"
" UNION \n"
"SELECT name, type, value\n"
" FROM property, json_data\n"
" WHERE json_data.property = property.id"
" AND configuration is NULL AND system = ?\n"
)
self.cursor.execute(sql, (system_id, system_id, system_id, system_id))

result = {}
Expand All @@ -452,7 +536,15 @@ def get_for_system(self, system_id, _property="all"):
pid = _property
ptype = self.type(pid)

sql = f"SELECT value FROM {ptype}_data WHERE system = ? AND property = ?"
if include_configuration_properties:
sql = (
f"SELECT value FROM {ptype}_data WHERE system = ? AND property = ?"
)
else:
sql = (
f"SELECT value FROM {ptype}_data"
" WHERE configuration ISNULL AND system = ? AND property = ?"
)
result = []
for row in self.db.execute(sql, (system_id, pid)):
if ptype == "json":
Expand Down
Loading

0 comments on commit b8c4172

Please sign in to comment.