Repository: ccdc-opensource/csd-python-api-scripts
Pull request #80: Added filter for chirality NO_JIRA
Author: login: pmbulit
Created: 2025-05-01T14:18:38Z | Merged: 2025-05-02T09:48:00Z



Diff:
diff --git a/scripts/refcodes_with_properties/entry_property_calculator.py b/scripts/refcodes_with_properties/entry_property_calculator.py
index 588a17e..aa1ee9f 100644
--- a/scripts/refcodes_with_properties/entry_property_calculator.py
+++ b/scripts/refcodes_with_properties/entry_property_calculator.py
@@ -85,6 +85,23 @@ def __call__(self, theobject):
         return value >= self.minimum and value <= self.maximum
 
 
+class _ValueFilter(_Filter):
+    def __init__(self, args):
+        values = [p for p in args.split()]
+        #To do: add option for two values?
+        if values[0] == 'None':
+            self.expected_value = None
+        else:
+            self.expected_value = values[0]
+
+    def value(self, theobject):
+        raise NotImplementedError  # override this
+
+    def __call__(self, theobject):
+        value = self.value(theobject)
+        return value == self.expected_value
+
+
 class AllowedAtomicNumbersFilter(_Filter):
     def __init__(self, args):
         self.allowed_atomic_numbers = [int(atomic_number) for atomic_number in args.strip().split()]
@@ -200,6 +217,25 @@ def value(self, entry):
 register(AllHaveSitesFilter)
 
 
+class Has3DStructure(_ComparativeFilter):
+    def __init__(self, args):
+        super().__init__(args)
+
+    @staticmethod
+    def name():
+        return "has 3D structure"
+
+    @staticmethod
+    def helptext():
+        return "whether 3D coordinates have been determined for the structure"
+
+    def value(self, entry):
+        return entry.has_3d_structure
+
+
+register(Has3DStructure)
+
+
 class DisorderedFilter(_ComparativeFilter):
     def __init__(self, args):
         super().__init__(args)
@@ -413,6 +449,30 @@ def value(self, entry):
 register(SpacegroupNumberFilter)
 
 
+class ChiralityFilter(_ValueFilter):
+    def __init__(self, args):
+        super().__init__(args)
+
+    @staticmethod
+    def name():
+        return "chirality"
+
+    @staticmethod
+    def helptext():
+        return "specify the chirality value to be used as filter"
+
+    def value(self, entry):
+        try:
+            molecule = entry.crystal.molecule
+            chirality = next((atom.chirality for atom in molecule.atoms if atom.is_chiral), None)
+            return chirality
+        except TypeError:
+            return None
+
+
+register(ChiralityFilter)
+
+
 class FilterEvaluation(object):
     def __init__(self):
         self._methods = []
@@ -425,7 +485,7 @@ def evaluate(self, entry):
             try:
                 if not method(entry):
                     return False
-            except TypeError:
+            except (TypeError, RuntimeError):
                 return False
 
         return True
diff --git a/scripts/refcodes_with_properties/refcodes_with_properties.py b/scripts/refcodes_with_properties/refcodes_with_properties.py
index e98b7ea..474fc68 100644
--- a/scripts/refcodes_with_properties/refcodes_with_properties.py
+++ b/scripts/refcodes_with_properties/refcodes_with_properties.py
@@ -46,7 +46,7 @@
 
     outfile = sys.stdout
     if args.output_file is not None:
-        outfile = open(args.output_file, 'wb')
+        outfile = open(args.output_file, 'w', encoding='utf-8')
 
     filterer = entry_property_calculator.parse_control_file(open(control_file, "r").readlines())
 


Reviews:
user: login: github-actions[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T14:18:55Z
user: login: jasonccole
body: Looks fine.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T15:13:57Z

Review comments:
diff_hunk: @@ -85,6 +85,20 @@ def __call__(self, theobject):
         return value >= self.minimum and value <= self.maximum
 
 
+class _ValueFilter(_Filter):
+    def __init__(self, args):
+        values = [p for p in args.split()]
+        #To do: add option for two values?
path: scripts/refcodes_with_properties/entry_property_calculator.py
user: login: github-actions[bot]
body: 🚫 **[flake8]** <265> <sub>reported by [reviewdog](https://github.com/reviewdog/reviewdog) :dog:</sub><br>block comment should start with '# '
<!-- __reviewdog__:ChA2YTM5ZjQyYTY2MWE4MmQwEgZmbGFrZTg= -->

created_at: 2025-05-01T14:18:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -85,6 +85,20 @@ def __call__(self, theobject):
         return value >= self.minimum and value <= self.maximum
 
 
+class _ValueFilter(_Filter):
+    def __init__(self, args):
+        values = [p for p in args.split()]
+        #To do: add option for two values?
path: scripts/refcodes_with_properties/entry_property_calculator.py
user: login: github-actions[bot]
body: 🚫 **[flake8]** <265> <sub>reported by [reviewdog](https://github.com/reviewdog/reviewdog) :dog:</sub><br>block comment should start with '# '
<!-- __reviewdog__:ChBjNDY4ODBlYTgzMDA2Y2JiEgZmbGFrZTg= -->

created_at: 2025-05-01T14:18:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -413,6 +427,30 @@ def value(self, entry):
 register(SpacegroupNumberFilter)
 
 
+class ChiralityFilter(_ValueFilter):
+    def __init__(self, args):
+        super().__init__(args)
+
+    @staticmethod
+    def name():
+        return "chirality"
+
+    @staticmethod
+    def helptext():
+        return "specify the chirality value to be used as filter"
+
+    def value(self, entry):
+        try:
+            molecule = entry.crystal.molecule
+            chirality = next((atom.chirality for atom in molecule.atoms if atom.is_chiral), None)
+            return chirality
+        except TypeError:
+            return 0
path: scripts/refcodes_with_properties/entry_property_calculator.py
user: login: jasonccole
body: Should this return None to give a consistent return type?
created_at: 2025-05-01T15:08:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,7 +46,7 @@
 
     outfile = sys.stdout
     if args.output_file is not None:
-        outfile = open(args.output_file, 'wb')
+        outfile = open(args.output_file, 'w', encoding='utf-8')
path: scripts/refcodes_with_properties/refcodes_with_properties.py
user: login: jasonccole
body: I think this is needed due to changes from python2 to python3.
created_at: 2025-05-01T15:09:49Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-05-02T09:44:02Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=ccdc-opensource_csd-python-api-scripts&pullRequest=80)


author_association: NONE