diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76b29352..b57940b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,12 +55,16 @@ jobs: run: python -m pip install pytest-github-actions-annotate-failures - name: Test package - run: python -m pytest ./tests --doctest-modules --cov=src/decaylanguage --cov-report=xml + run: python -m pytest ./tests --cov=src/decaylanguage --cov-report=xml - name: Test coverage with Codecov if: "runner.os != 'Windows' && matrix.python-version != 3.7" uses: codecov/codecov-action@v3 + - name: Test docstrings with doctest + if: "runner.os == 'Linux' && matrix.python-version == 3.11" + run: python -m pytest --doctest-modules src/decaylanguage + notebooks: runs-on: ubuntu-latest diff --git a/src/decaylanguage/dec/dec.py b/src/decaylanguage/dec/dec.py index 94c4ff18..6a4879be 100644 --- a/src/decaylanguage/dec/dec.py +++ b/src/decaylanguage/dec/dec.py @@ -74,8 +74,8 @@ class DecFileParser: Example ------- - >>> dfp = DecFileParser('my-decay-file.dec') - >>> dfp.parse() + >>> dfp = DecFileParser('my-decay-file.dec') # doctest: +SKIP + >>> dfp.parse() # doctest: +SKIP """ __slots__ = ( @@ -693,10 +693,11 @@ def list_decay_modes(self, mother: str, pdg_name: bool = False) -> list[list[str Example ------- - >>> parser = DecFileParser('my-decay-file.dec') - >>> parser.parse() - >>> parser.list_decay_mother_names() # Inspect what decays are defined - >>> parser.list_decay_modes('pi0') + >>> parser = DecFileParser('my-decay-file.dec') # doctest: +SKIP + >>> parser.parse() # doctest: +SKIP + >>> # Inspect what decays are defined + >>> parser.list_decay_mother_names() # doctest: +SKIP + >>> parser.list_decay_modes('pi0') # doctest: +SKIP """ if pdg_name: mother = PDG2EvtGenNameMap[mother] @@ -928,9 +929,9 @@ def build_decay_chains( Examples -------- - >>> parser = DecFileParser('a-Dplus-decay-file.dec') - >>> parser.parse() - >>> parser.build_decay_chains('D+') + >>> parser = DecFileParser('a-Dplus-decay-file.dec') # doctest: +SKIP + >>> parser.parse() # doctest: +SKIP + >>> parser.build_decay_chains('D+') # doctest: +SKIP {'D+': [{'bf': 1.0, 'fs': ['K-', 'pi+', @@ -950,7 +951,7 @@ def build_decay_chains( {'bf': 6.5e-08, 'fs': ['e+', 'e-'], 'model': 'PHSP', 'model_params': ''}]}], 'model': 'PHSP', 'model_params': ''}]} - >>> p.build_decay_chains('D+', stable_particles=['pi0']) + >>> p.build_decay_chains('D+', stable_particles=['pi0']) # doctest: +SKIP {'D+': [{'bf': 1.0, 'fs': ['K-', 'pi+', 'pi+', 'pi0'], 'model': 'PHSP', 'model_params': ''}]} """ keys = ("bf", "fs", "model", "model_params") @@ -1067,7 +1068,7 @@ class DecayModelParamValueReplacement(Visitor): # type: ignore[misc] Examples -------- >>> from lark import Tree, Token - >>> ... + >>> ... # doctest: +SKIP >>> t = Tree('decay', [Tree('particle', [Token('LABEL', 'Upsilon(4S)')]), ... Tree('decayline', [Tree('value', [Token('SIGNED_NUMBER', '1.0')]), ... Tree('particle', [Token('LABEL', 'B0')]), @@ -1075,11 +1076,13 @@ class DecayModelParamValueReplacement(Visitor): # type: ignore[misc] ... Tree('model', [Token('MODEL_NAME', 'VSS_BMIX'), ... Tree('model_options', [Token('LABEL', 'dm')])])])]) >>> dict_define_defs = {'dm': 0.507e12} - >>> DecayModelParamValueReplacement(define_defs=dict_define_defs).visit(t) - Tree(decay, [Tree(particle, [Token(LABEL, 'Upsilon(4S)')]), Tree(decayline, - [Tree(value, [Token(SIGNED_NUMBER, '1.0')]), Tree(particle, [Token(LABEL, 'B0')]), - Tree(particle, [Token(LABEL, 'anti-B0')]), Tree(model, [Token(MODEL_NAME, 'VSS_BMIX'), - Tree(model_options, [Token(LABEL, 507000000000.0)])])])]) + >>> DecayModelParamValueReplacement(define_defs=dict_define_defs).visit(t) # doctest: +NORMALIZE_WHITESPACE + Tree('decay', [Tree('particle', [Token('LABEL', 'Upsilon(4S)')]), + Tree('decayline', [Tree('value', [Token('SIGNED_NUMBER', '1.0')]), + Tree('particle', [Token('LABEL', 'B0')]), + Tree('particle', [Token('LABEL', 'anti-B0')]), + Tree('model', [Token('MODEL_NAME', 'VSS_BMIX'), + Tree('model_options', [Token('LABEL', 507000000000.0)])])])]) """ def __init__(self, define_defs: dict[str, Any] | None = None) -> None: @@ -1126,15 +1129,16 @@ class ChargeConjugateReplacement(Visitor): # type: ignore[misc] Examples -------- >>> from lark import Tree, Token - >>> ... + >>> ... # doctest: +SKIP >>> t = Tree('decay', [Tree('particle', [Token('LABEL', 'D0')]), Tree('decayline', [Tree - ... ('value', [Token('SIGNED_NUMBER', '1.0')]), Tree('particle', [Token('LABEL', 'K-')]) - ... , Tree('particle', [Token('LABEL', 'pi+')]), Tree('model', [Token('MODEL_NAME', 'PHS - ... P')])])]) - >>> ChargeConjugateReplacement().visit(t) - Tree(decay, [Tree(particle, [Token(LABEL, 'D~0')]), Tree(decayline, - [Tree(value, [Token(SIGNED_NUMBER, '1.0')]), Tree(particle, [Token(LABEL, 'K+')]), - Tree(particle, [Token(LABEL, 'pi-')]), Tree(model, [Token(MODEL_NAME, 'PHSP')])])]) + ... ('value', [Token('SIGNED_NUMBER', '1.0')]), Tree('particle', [Token('LABEL', 'K-')]), + ... Tree('particle', [Token('LABEL', 'pi+')]), Tree('model', [Token('MODEL_NAME', 'PHSP')])])]) + >>> ChargeConjugateReplacement().visit(t) # doctest: +NORMALIZE_WHITESPACE + Tree('decay', [Tree('particle', [Token('LABEL', 'anti-D0')]), + Tree('decayline', [Tree('value', [Token('SIGNED_NUMBER', '1.0')]), + Tree('particle', [Token('LABEL', 'K+')]), + Tree('particle', [Token('LABEL', 'pi-')]), + Tree('model', [Token('MODEL_NAME', 'PHSP')])])]) """ def __init__(self, charge_conj_defs: dict[str, str] | None = None) -> None: diff --git a/src/decaylanguage/decay/decay.py b/src/decaylanguage/decay/decay.py index f6add18a..e949a125 100644 --- a/src/decaylanguage/decay/decay.py +++ b/src/decaylanguage/decay/decay.py @@ -236,8 +236,8 @@ def __init__( >>> # Decay mode with decay model information >>> dd = DaughtersDict('pi- pi0 nu_tau') >>> dm = DecayMode(0.2551, dd, - model='TAUHADNU', - model_params=[-0.108, 0.775, 0.149, 1.364, 0.400]) + ... model='TAUHADNU', + ... model_params=[-0.108, 0.775, 0.149, 1.364, 0.400]) >>> # Decay mode with user metadata >>> dd = DaughtersDict('K+ K-') @@ -246,6 +246,7 @@ def __init__( >>> # Decay mode with metadata for generators such as zfit's phasespace >>> dm = DecayMode(0.5, "K+ K-", zfit={"B0": "gauss"}) >>> dm.metadata['zfit'] == {'B0': 'gauss'} + True """ self.bf = bf self.daughters = DaughtersDict(daughters) @@ -273,16 +274,15 @@ def from_dict( Examples -------- - >>> Simplest construction - >>> DecayMode.from_dict({'bf': 0.98823, - 'fs': ['gamma', 'gamma']}) + >>> # Simplest construction + >>> DecayMode.from_dict({'bf': 0.98823, 'fs': ['gamma', 'gamma']}) >>> # Decay mode with decay model details >>> DecayMode.from_dict({'bf': 0.98823, - 'fs': ['gamma', 'gamma'], - 'model': 'PHSP', - 'model_params': ''}) + ... 'fs': ['gamma', 'gamma'], + ... 'model': 'PHSP', + ... 'model_params': ''}) >>> # Decay mode with metadata for generators such as zfit's phasespace @@ -384,9 +384,8 @@ def to_dict(self) -> dict[str, int | float | str | list[str]]: Examples -------- - >>> dm = DecayMode(0.5, 'K+ K- K- pi- pi0 nu_tau', - model='PHSP', study='toy', year=2019) - >>> dm.to_dict() + >>> dm = DecayMode(0.5, 'K+ K- K- pi- pi0 nu_tau', model='PHSP', study='toy', year=2019) + >>> dm.to_dict() # doctest: +NORMALIZE_WHITESPACE {'bf': 0.5, 'fs': ['K+', 'K-', 'K-', 'nu_tau', 'pi-', 'pi0'], 'model': 'PHSP', @@ -693,7 +692,7 @@ def to_dict(self) -> dict[str, list[dict[str, float | str | list[Any]]]]: >>> dm1 = DecayMode(0.028, 'K_S0 pi+ pi-') >>> dm2 = DecayMode(0.692, 'pi+ pi-') >>> dc = DecayChain('D0', {'D0':dm1, 'K_S0':dm2}) - >>> dc.to_dict() + >>> dc.to_dict() # doctest: +NORMALIZE_WHITESPACE {'D0': [{'bf': 0.028, 'fs': [{'K_S0': [{'bf': 0.692, 'fs': ['pi+', 'pi-'], @@ -750,7 +749,7 @@ def flatten( >>> >>> dc.flatten() gamma gamma pi+ pi- (0 sub-decays), BF=0.008479803984> - >>> dc.flatten().to_dict() + >>> dc.flatten().to_dict() # doctest: +NORMALIZE_WHITESPACE {'D0': [{'bf': 0.008479803984, 'fs': ['gamma', 'gamma', 'pi+', 'pi-'], 'model': 'PHSP', diff --git a/src/decaylanguage/decay/viewer.py b/src/decaylanguage/decay/viewer.py index cb410b1e..162ae70e 100644 --- a/src/decaylanguage/decay/viewer.py +++ b/src/decaylanguage/decay/viewer.py @@ -34,15 +34,16 @@ class DecayChainViewer: Examples -------- - >>> dfp = DecFileParser('my-Dst-decay-file.dec') - >>> dfp.parse() - >>> chain = dfp.build_decay_chains('D*+') - >>> dcv = DecayChainViewer(chain) - >>> dcv # display the SVG figure in a notebook + >>> dfp = DecFileParser('my-Dst-decay-file.dec') # doctest: +SKIP + >>> dfp.parse() # doctest: +SKIP + >>> chain = dfp.build_decay_chains('D*+') # doctest: +SKIP + >>> dcv = DecayChainViewer(chain) # doctest: +SKIP + >>> # display the SVG figure in a notebook + >>> dcv # doctest: +SKIP When not in notebooks the graph can easily be visualized with the `graphviz.Digraph.render` or `graphviz.Digraph.view` functions, e.g.: - >>> dcv.graph.render(filename="test", format="pdf", view=True, cleanup=True) + >>> dcv.graph.render(filename="test", format="pdf", view=True, cleanup=True) # doctest: +SKIP """ __slots__ = ("_chain", "_graph", "_graph_attributes")