From 49cfc089887099735a20b924b4869f3ef643e743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ingvar=20Dahlgren?= Date: Tue, 23 Apr 2024 10:45:44 +0200 Subject: [PATCH 1/5] bump dev version --- chempy/_release.py | 2 +- postBuild | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100755 postBuild diff --git a/chempy/_release.py b/chempy/_release.py index 8a3e0698..d129b7f1 100644 --- a/chempy/_release.py +++ b/chempy/_release.py @@ -1 +1 @@ -__version__ = "0.8.1.dev0+git" +__version__ = "0.9.0.dev0+git" diff --git a/postBuild b/postBuild deleted file mode 100755 index d2713388..00000000 --- a/postBuild +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# See: http://mybinder.readthedocs.io/en/latest/using.html#postbuild -python setup.py develop --user - -# repo2docker does not use a conda environment, hence $CONDA_PREFIX is not -# set by default. Until there is a standard way of setting compiler variables -# we add the hardcoded conda-root path to the relevant environment variables: -PY_LIB_ROOT=$(compgen -G '/srv/conda/lib/python3.*') -cat <>$PY_LIB_ROOT/site-packages/usercustomize.py -import os -ld_lib_pth = os.environ.get('LD_LIBRARY_PATH', '') -lib_pth = os.environ.get('LIBRARY_PATH', '') -cpp_inc_pth = os.environ.get('CPLUS_INCLUDE_PATH', '') -os.environ['LD_LIBRARY_PATH'] = '/srv/conda/lib' + ((':%s' % ld_lib_pth) if ld_lib_pth else '') -os.environ['LIBRARY_PATH'] = '/srv/conda/lib' + ((':%s' % lib_pth) if lib_pth else '') -os.environ['CPLUS_INCLUDE_PATH'] = '/srv/conda/include' + ((':%s' % cpp_inc_pth) if cpp_inc_pth else '') -EOF From 3636f2a05e1a30fc6e5c736755b6b2ed1939f856 Mon Sep 17 00:00:00 2001 From: Jeremy A Gray Date: Sat, 23 Sep 2023 11:48:00 -0500 Subject: [PATCH 2/5] fix(parser): handle decimal subscripts Translate a Unicode decimal point in a subscript as a text decimal point. Use `.` as the decimal point operator and `..` as the hydrate operator. Add zinc nitrate example from bjodah/chempy#207. Signed-off-by: Jeremy A Gray --- chempy/util/parsing.py | 8 ++++--- chempy/util/tests/test_parsing.py | 38 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/chempy/util/parsing.py b/chempy/util/parsing.py index 0313545c..b4f89bb9 100644 --- a/chempy/util/parsing.py +++ b/chempy/util/parsing.py @@ -95,7 +95,7 @@ def _get_formula_parser(): | '{' formula '}' | '[' formula ']' ) count prime charge? formula :: term+ - hydrate :: '.' count? formula + hydrate :: '..' count? formula state :: '(' ( 's' | 'l' | 'g' | 'aq' | 'cr' ) ')' compound :: count formula hydrate? state? @@ -600,9 +600,11 @@ def formula_to_latex(formula, prefixes=None, infixes=None, **kwargs): ) -_unicode_sub = {} +_unicode_sub = { + ".": ".", +} -for k, v in enumerate("₀₁₂₃₄₅₆₇₈₉"): +for k, v in enumerate("₀₁₂₃₄₅₆₇₈₉."): _unicode_sub[str(k)] = v _unicode_sup = { diff --git a/chempy/util/tests/test_parsing.py b/chempy/util/tests/test_parsing.py index 67386278..12ebffa8 100644 --- a/chempy/util/tests/test_parsing.py +++ b/chempy/util/tests/test_parsing.py @@ -11,6 +11,7 @@ parsing_library, to_reaction, ) + from ..testing import requires @@ -625,6 +626,22 @@ def test_formula_to_latex_caged(species, latex): ("[Fe(H2O)6][Fe(CN)6]..19H2O(aq)", r"[Fe(H₂O)₆][Fe(CN)₆]·19H₂O(aq)"), ("[Fe(CN)6]-3", r"[Fe(CN)₆]³⁻"), ("[Fe(CN)6]-3(aq)", r"[Fe(CN)₆]³⁻(aq)"), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6", + r"Ca₂.₈₃₂Fe₀.₆₂₈₅Mg₅.₃₉₅(CO₃)₆", + ), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6(s)", + r"Ca₂.₈₃₂Fe₀.₆₂₈₅Mg₅.₃₉₅(CO₃)₆(s)", + ), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6..8H2O(s)", + r"Ca₂.₈₃₂Fe₀.₆₂₈₅Mg₅.₃₉₅(CO₃)₆·8H₂O(s)", + ), + ( + "Zn(NO3)2..6H2O", + r"Zn(NO₃)₂·6H₂O", + ), ], ) @requires(parsing_library) @@ -692,8 +709,29 @@ def test_formula_to_unicode_caged(species, unicode): ), ("[Fe(CN)6]-3", r"[Fe(CN)6]3-"), ("[Fe(CN)6]-3(aq)", r"[Fe(CN)6]3-(aq)"), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6", + r"Ca2.832Fe0.6285Mg5.395(CO3)6", + ), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6(s)", + r"Ca2.832Fe0.6285Mg5.395(CO3)6(s)", + ), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6..8H2O(s)", + r"Ca2.832Fe0.6285Mg5.395(CO3)6⋅8H2O(s)", + ), + ( + "Ca2.832Fe0.6285Mg5.395(CO3)6..8H2O(s)", + r"Ca2.832Fe0.6285Mg5.395(CO3)6⋅8H2O(s)", + ), + ( + "Zn(NO3)2..6H2O", + r"Zn(NO3)2⋅6H2O", + ), ], ) + @requires(parsing_library) def test_formula_to_html(species, html): assert formula_to_html(species) == html From 9fe07c99c5996a32162a7468d6d65e6429c7eec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ingvar=20Dahlgren?= Date: Tue, 23 Apr 2024 11:03:42 +0200 Subject: [PATCH 3/5] Allow \u00b7 to be parsed as complex/crystal water --- .woodpecker.yaml | 1 + README.rst | 2 +- chempy/util/parsing.py | 16 +++++++++++----- chempy/util/tests/test_parsing.py | 7 +++++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 3aca31ce..115497fb 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -27,6 +27,7 @@ steps: - export CPATH=$SUNDBASE/include:$CPATH - export LIBRARY_PATH=$SUNDBASE/lib - export LD_LIBRARY_PATH=$SUNDBASE/lib + - python3 -m pip install --cache-dir $CACHE_ROOT/pip_cache --user --upgrade-strategy=eager --upgrade cython - python3 -m pip install --cache-dir $CACHE_ROOT/pip_cache --user -e .[all] - python3 -c "import pycvodes; import pyodesys; import pygslodeiv2" # debug this CI config - git fetch -tq diff --git a/README.rst b/README.rst index 74294e81..a16c85af 100644 --- a/README.rst +++ b/README.rst @@ -385,7 +385,7 @@ If you make use of ChemPy in e.g. academic work you may cite the following peer- Depending on what underlying solver you are using you should also cite the appropriate paper (you can look at the list of references in the JOSS article). If you need to reference, in addition to the paper, a specific point version of ChemPy (for e.g. reproducibility) -you can get per-version DOIs from the zendodo archive: +you can get per-version DOIs from the zenodo archive: .. image:: https://zenodo.org/badge/8840/bjodah/chempy.svg :target: https://zenodo.org/badge/latestdoi/8840/bjodah/chempy diff --git a/chempy/util/parsing.py b/chempy/util/parsing.py index b4f89bb9..efffccc4 100644 --- a/chempy/util/parsing.py +++ b/chempy/util/parsing.py @@ -95,7 +95,7 @@ def _get_formula_parser(): | '{' formula '}' | '[' formula ']' ) count prime charge? formula :: term+ - hydrate :: '..' count? formula + hydrate :: ( '..' | '\u00B7' ) count? formula state :: '(' ( 's' | 'l' | 'g' | 'aq' | 'cr' ) ')' compound :: count formula hydrate? state? @@ -114,7 +114,7 @@ def _get_formula_parser(): | '{' formula '}' | '[' formula ']' ) count prime charge? formula :: term+ - hydrate :: '..' count? formula + hydrate :: ( '..' | '\u00B7' ) count? formula state :: '(' ( 's' | 'l' | 'g' | 'aq' | 'cr' ) ')' compound :: count formula hydrate? state? """ @@ -334,7 +334,7 @@ def _parse_stoich(stoich): _unicode_mapping = {k + "-": v + "-" for k, v in zip(_greek_letters, _greek_u)} _unicode_mapping["."] = "⋅" -_unicode_infix_mapping = {"..": "·"} +_unicode_infix_mapping = {"..": "\u00b7"} # 0x00b7: '·' _html_mapping = {k + "-": "&" + k + ";-" for k in _greek_letters} _html_mapping["."] = "⋅" @@ -386,7 +386,10 @@ def formula_to_composition( stoich_tok, chg_tok = _formula_to_parts(formula, prefixes, suffixes)[:2] tot_comp = {} - parts = stoich_tok.split("..") + if '\u00b7' in stoich_tok: + parts = stoich_tok.split('\u00b7') + else: + parts = stoich_tok.split("..") for idx, stoich in enumerate(parts): if idx == 0: @@ -532,7 +535,10 @@ def _formula_to_format( suffixes=("(s)", "(l)", "(g)", "(aq)"), ): parts = _formula_to_parts(formula, prefixes.keys(), suffixes) - stoichs = parts[0].split("..") + if '\u00b7' in parts[0]: + stoichs = parts[0].split('\u00b7') + else: + stoichs = parts[0].split("..") string = "" for idx, stoich in enumerate(stoichs): if idx == 0: diff --git a/chempy/util/tests/test_parsing.py b/chempy/util/tests/test_parsing.py index 12ebffa8..7819edcc 100644 --- a/chempy/util/tests/test_parsing.py +++ b/chempy/util/tests/test_parsing.py @@ -750,3 +750,10 @@ def test_formula_to_html(species, html): def test_formula_to_html_caged(species, html): """Should produce HTML for cage species.""" assert formula_to_html(species) == html + + + +def test_composition_dot_as_crystal_water_chempy08x(): + ref = {30: 1, 7: 2, 8: 12, 1: 12} + assert formula_to_composition('Zn(NO3)2{}6H2O'.format('\u00B7')) == ref + assert formula_to_composition('Zn(NO3)2..6H2O') == ref From 74e83f3eefa427f23e2f73b870a1dd63cde227b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ingvar=20Dahlgren?= Date: Tue, 23 Apr 2024 11:21:21 +0200 Subject: [PATCH 4/5] Add example in docs showing how fractional occupation is parsed --- chempy/util/parsing.py | 2 ++ chempy/util/tests/test_parsing.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/chempy/util/parsing.py b/chempy/util/parsing.py index efffccc4..9a532527 100644 --- a/chempy/util/parsing.py +++ b/chempy/util/parsing.py @@ -379,6 +379,8 @@ def formula_to_composition( True >>> formula_to_composition('Na2CO3..7H2O') == {11: 2, 6: 1, 8: 10, 1: 14} True + >>> formula_to_composition('UO2.3') == {92: 1, 8: 2.3} + True """ if prefixes is None: diff --git a/chempy/util/tests/test_parsing.py b/chempy/util/tests/test_parsing.py index 7819edcc..580e8079 100644 --- a/chempy/util/tests/test_parsing.py +++ b/chempy/util/tests/test_parsing.py @@ -752,7 +752,6 @@ def test_formula_to_html_caged(species, html): assert formula_to_html(species) == html - def test_composition_dot_as_crystal_water_chempy08x(): ref = {30: 1, 7: 2, 8: 12, 1: 12} assert formula_to_composition('Zn(NO3)2{}6H2O'.format('\u00B7')) == ref From 05c923f4fbd8dc1dff811d0edf712fdd6f9fba9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ingvar=20Dahlgren?= Date: Tue, 23 Apr 2024 12:02:09 +0200 Subject: [PATCH 5/5] fix lint --- .github/workflows/lint_python.yml | 4 ++-- chempy/util/tests/test_parsing.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 33a3b75c..1bc77f30 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -14,10 +14,10 @@ jobs: - run: bandit --recursive --skip B101,B102,B110,B112,B307,B404,B603,B607 . - run: black --check . || true - run: codespell --ignore-words-list="ans,claus,fith,nam,nd,ond,serie,te" - - run: flake8 . --count --max-complexity=66 --max-line-length=118 + - run: flake8 . --count --max-complexity=66 --max-line-length=129 --show-source --statistics - run: pip install flake8-bugbear flake8-comprehensions flake8-return flake8-simplify - - run: flake8 . --count --exit-zero --max-complexity=66 --max-line-length=118 + - run: flake8 . --count --exit-zero --max-complexity=66 --max-line-length=129 --show-source --statistics - run: isort --check-only --profile black . || true - run: pip install setuptools diff --git a/chempy/util/tests/test_parsing.py b/chempy/util/tests/test_parsing.py index 580e8079..b3cf0118 100644 --- a/chempy/util/tests/test_parsing.py +++ b/chempy/util/tests/test_parsing.py @@ -731,7 +731,6 @@ def test_formula_to_unicode_caged(species, unicode): ), ], ) - @requires(parsing_library) def test_formula_to_html(species, html): assert formula_to_html(species) == html