├── betse
├── py.typed
├── lib
│ ├── __init__.py
│ ├── numpy
│ │ ├── __init__.py
│ │ └── npscalar.py
│ ├── pickle
│ │ └── __init__.py
│ ├── pil
│ │ ├── __init__.py
│ │ └── pils.py
│ ├── yaml
│ │ ├── __init__.py
│ │ └── abc
│ │ │ └── __init__.py
│ ├── matplotlib
│ │ ├── __init__.py
│ │ ├── writer
│ │ │ └── __init__.py
│ │ ├── mplutil.py
│ │ └── mplzorder.py
│ └── setuptools
│ │ └── __init__.py
├── cli
│ ├── __init__.py
│ └── __main__.py
├── gui
│ ├── __init__.py
│ └── interact.py
├── util
│ ├── app
│ │ ├── __init__.py
│ │ └── meta
│ │ │ └── __init__.py
│ ├── cli
│ │ ├── __init__.py
│ │ └── repl
│ │ │ ├── __init__.py
│ │ │ └── replenv.py
│ ├── io
│ │ ├── __init__.py
│ │ ├── error
│ │ │ ├── __init__.py
│ │ │ ├── errhaiku.py
│ │ │ └── errfault.py
│ │ ├── log
│ │ │ ├── __init__.py
│ │ │ ├── conf
│ │ │ │ ├── __init__.py
│ │ │ │ └── logconfformat.py
│ │ │ └── logfilter.py
│ │ ├── stdouts.py
│ │ └── stderrs.py
│ ├── math
│ │ ├── __init__.py
│ │ └── geometry
│ │ │ ├── __init__.py
│ │ │ └── polygon
│ │ │ └── __init__.py
│ ├── os
│ │ ├── __init__.py
│ │ ├── brand
│ │ │ ├── __init__.py
│ │ │ └── posix.py
│ │ ├── command
│ │ │ └── __init__.py
│ │ ├── process
│ │ │ └── __init__.py
│ │ └── shell
│ │ │ └── __init__.py
│ ├── path
│ │ └── __init__.py
│ ├── py
│ │ ├── __init__.py
│ │ ├── module
│ │ │ └── __init__.py
│ │ ├── pyfreeze.py
│ │ └── pyimpl.py
│ ├── test
│ │ ├── __init__.py
│ │ └── pytest
│ │ │ ├── __init__.py
│ │ │ ├── fixture
│ │ │ ├── __init__.py
│ │ │ └── pytfixture.py
│ │ │ ├── mark
│ │ │ ├── __init__.py
│ │ │ ├── pytmark.py
│ │ │ └── pytfail.py
│ │ │ └── pytabc.py
│ ├── type
│ │ ├── __init__.py
│ │ ├── call
│ │ │ └── __init__.py
│ │ ├── cls
│ │ │ └── __init__.py
│ │ ├── obj
│ │ │ ├── __init__.py
│ │ │ └── sentinels.py
│ │ ├── text
│ │ │ ├── __init__.py
│ │ │ ├── string
│ │ │ │ └── __init__.py
│ │ │ └── chars.py
│ │ ├── decorator
│ │ │ └── __init__.py
│ │ ├── descriptor
│ │ │ └── __init__.py
│ │ ├── iterable
│ │ │ ├── __init__.py
│ │ │ ├── set
│ │ │ │ ├── __init__.py
│ │ │ │ └── sets.py
│ │ │ ├── mapping
│ │ │ │ └── __init__.py
│ │ │ ├── iterators.py
│ │ │ ├── queues.py
│ │ │ └── generators.py
│ │ ├── numeric
│ │ │ ├── __init__.py
│ │ │ └── bits.py
│ │ ├── contexts.py
│ │ └── typehints.py
│ └── __init__.py
├── science
│ ├── compat
│ │ ├── __init__.py
│ │ └── compatgrnconf.py
│ ├── config
│ │ ├── __init__.py
│ │ ├── grn
│ │ │ ├── __init__.py
│ │ │ └── confgrn.py
│ │ ├── model
│ │ │ ├── __init__.py
│ │ │ └── confphase.py
│ │ └── export
│ │ │ ├── __init__.py
│ │ │ ├── visual
│ │ │ ├── __init__.py
│ │ │ └── confexpvisual.py
│ │ │ └── confexpabc.py
│ ├── enum
│ │ ├── __init__.py
│ │ ├── enumphase.py
│ │ └── enumion.py
│ ├── math
│ │ ├── __init__.py
│ │ ├── cache
│ │ │ ├── __init__.py
│ │ │ └── cachelyrvec.py
│ │ └── vector
│ │ │ └── __init__.py
│ ├── phase
│ │ ├── __init__.py
│ │ └── require
│ │ │ ├── __init__.py
│ │ │ └── abc
│ │ │ └── __init__.py
│ ├── physics
│ │ └── __init__.py
│ ├── pipe
│ │ ├── __init__.py
│ │ └── export
│ │ │ ├── __init__.py
│ │ │ ├── plot
│ │ │ └── __init__.py
│ │ │ ├── pipeexpabc.py
│ │ │ └── pipeexpenum.py
│ ├── visual
│ │ ├── __init__.py
│ │ ├── anim
│ │ │ └── __init__.py
│ │ ├── layer
│ │ │ ├── __init__.py
│ │ │ ├── vector
│ │ │ │ └── __init__.py
│ │ │ ├── vectorfield
│ │ │ │ └── __init__.py
│ │ │ └── lyrtext.py
│ │ └── plot
│ │ │ ├── __init__.py
│ │ │ └── plotabc.py
│ ├── channels
│ │ ├── __init__.py
│ │ └── channelsabc.py
│ ├── chemistry
│ │ └── __init__.py
│ ├── organelles
│ │ └── __init__.py
│ ├── tissue
│ │ ├── event
│ │ │ ├── __init__.py
│ │ │ └── tisevecut.py
│ │ ├── picker
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ └── channels_o.py
│ └── __init__.py
├── data
│ └── yaml
│ │ ├── geo
│ │ ├── square
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ ├── 3.png
│ │ │ ├── 4.png
│ │ │ ├── 5.png
│ │ │ ├── 6.png
│ │ │ ├── 7.png
│ │ │ ├── 8.png
│ │ │ ├── 9.png
│ │ │ ├── 10.png
│ │ │ ├── 11.png
│ │ │ ├── 12.png
│ │ │ ├── 13.png
│ │ │ ├── 14.png
│ │ │ ├── 15.png
│ │ │ ├── 16.png
│ │ │ └── base.png
│ │ ├── circle
│ │ │ ├── ring.png
│ │ │ ├── spot.png
│ │ │ ├── poles.png
│ │ │ ├── spot_1.png
│ │ │ ├── spot_2.png
│ │ │ ├── spot_3.png
│ │ │ ├── wedge.png
│ │ │ ├── amputate.png
│ │ │ ├── mini_spot.png
│ │ │ ├── tissue_A.png
│ │ │ ├── tissue_B.png
│ │ │ ├── top_pole.png
│ │ │ ├── bottom_pole.png
│ │ │ ├── circle_base.png
│ │ │ ├── mini_wedge.png
│ │ │ └── circle_base_2.png
│ │ ├── cyst
│ │ │ ├── ring.png
│ │ │ ├── wedge.png
│ │ │ ├── blastula.png
│ │ │ ├── blastula2.png
│ │ │ └── thick_side_ring.png
│ │ ├── snake
│ │ │ ├── body.png
│ │ │ ├── brain.png
│ │ │ ├── cuts.png
│ │ │ ├── head.png
│ │ │ ├── nose.png
│ │ │ ├── tail.png
│ │ │ ├── cuts_sym1.png
│ │ │ ├── cuts_asymH1.png
│ │ │ └── cuts_asymT1.png
│ │ ├── worm
│ │ │ ├── 2Cuts.png
│ │ │ ├── 2CutsB.png
│ │ │ ├── 3Cuts.png
│ │ │ ├── 3CutsB.png
│ │ │ ├── Body.png
│ │ │ ├── Spot.png
│ │ │ ├── 1CutEvenB.png
│ │ │ ├── 1CutUnevenB.png
│ │ │ ├── 1H_Gradient.png
│ │ │ ├── 2H_Gradient.png
│ │ │ ├── 2H_Gradient_Asym.png
│ │ │ ├── Werner_Gradient.png
│ │ │ ├── 1H_Gradient_Linear.png
│ │ │ ├── 1H_Gradient_Neural.png
│ │ │ ├── 2H_Gradient_Linear.png
│ │ │ ├── 2H_Gradient_Neural.png
│ │ │ └── 2H_Gradient_FlatMid.png
│ │ ├── worm_o
│ │ │ ├── body.png
│ │ │ ├── gut.png
│ │ │ ├── brain.png
│ │ │ ├── cuts_0.png
│ │ │ ├── cuts_1.png
│ │ │ ├── cuts_2.png
│ │ │ ├── nerves.png
│ │ │ ├── wedge.png
│ │ │ ├── amp_head.png
│ │ │ ├── amp_tail.png
│ │ │ ├── ellipse.png
│ │ │ ├── endpoints.png
│ │ │ ├── somatic.png
│ │ │ ├── thought.png
│ │ │ ├── amputation.png
│ │ │ └── amputation_o.png
│ │ ├── ellipse
│ │ │ ├── body.png
│ │ │ ├── front.png
│ │ │ ├── poles.png
│ │ │ ├── rear.png
│ │ │ ├── cuts_a.png
│ │ │ ├── cuts_b.png
│ │ │ ├── 1Hgradient.png
│ │ │ ├── 1worm_base.png
│ │ │ ├── 1worm_cuts.png
│ │ │ ├── 1worm_head.png
│ │ │ ├── 1worm_tail.png
│ │ │ ├── 2Hgradient.png
│ │ │ ├── 1worm_5cuts.png
│ │ │ ├── 1worm_cuts2.png
│ │ │ ├── CRYgradient.png
│ │ │ ├── 1worm_1cut_high.png
│ │ │ ├── 1worm_1cut_mid.png
│ │ │ ├── 2Hgradient_new.png
│ │ │ ├── 1worm_2cuts_asym.png
│ │ │ └── 1worm_2cuts_even.png
│ │ ├── embryo2
│ │ │ ├── folds.png
│ │ │ ├── plate.png
│ │ │ ├── clipping.png
│ │ │ └── placode.png
│ │ ├── lattice
│ │ │ ├── holes.png
│ │ │ ├── clipping.png
│ │ │ └── lattice.png
│ │ ├── planaria_o
│ │ │ ├── Wound.png
│ │ │ ├── GutMask.png
│ │ │ ├── Thought.png
│ │ │ ├── CutLines.png
│ │ │ ├── GutCavity.png
│ │ │ ├── NervesMask.png
│ │ │ ├── BoundaryMask.png
│ │ │ ├── ClippingMask.png
│ │ │ └── NervesCircuitMask.png
│ │ ├── root
│ │ │ └── root_demo.png
│ │ └── embryo
│ │ │ ├── neurula_base.png
│ │ │ ├── neurula_hole.png
│ │ │ ├── neurula_peaks.png
│ │ │ ├── neurula_plate.png
│ │ │ ├── neurula_tips.png
│ │ │ ├── neurula_valley.png
│ │ │ ├── neurula_endoderm.png
│ │ │ ├── neurula_mesoderm.png
│ │ │ ├── neurula_notocord.png
│ │ │ ├── neurula_connected.png
│ │ │ └── neurula_epidermis.png
│ │ ├── SIMS
│ │ └── .gitignore
│ │ ├── INITS
│ │ └── .gitignore
│ │ ├── RESULTS
│ │ ├── .gitignore
│ │ ├── init_1
│ │ │ └── .gitignore
│ │ └── sim_1
│ │ │ └── .gitignore
│ │ └── extra_configs
│ │ └── expression_data.yaml
├── __init__.py
└── __main__.py
├── betse_test
├── __init__.py
├── _fixture
│ ├── __init__.py
│ └── simconf
│ │ └── __init__.py
├── a00_unit
│ ├── __init__.py
│ ├── app
│ │ ├── __init__.py
│ │ └── meta
│ │ │ └── __init__.py
│ ├── lib
│ │ └── __init__.py
│ ├── math
│ │ ├── __init__.py
│ │ ├── geometry
│ │ │ ├── __init__.py
│ │ │ └── test_geopoly.py
│ │ └── test_mathoper.py
│ ├── path
│ │ └── __init__.py
│ ├── py
│ │ ├── __init__.py
│ │ └── test_c.py
│ ├── type
│ │ ├── __init__.py
│ │ ├── text
│ │ │ ├── __init__.py
│ │ │ └── test_mls.py
│ │ ├── descriptor
│ │ │ └── __init__.py
│ │ ├── iterable
│ │ │ ├── __init__.py
│ │ │ ├── mapping
│ │ │ │ └── __init__.py
│ │ │ ├── test_iterables.py
│ │ │ └── test_iterget.py
│ │ └── numeric
│ │ │ ├── __init__.py
│ │ │ ├── test_floats.py
│ │ │ └── test_versions.py
│ ├── fixture
│ │ └── __init__.py
│ ├── conftest.py
│ ├── test_import.py
│ └── README.md
├── a90_func
│ ├── __init__.py
│ ├── _fixture
│ │ └── __init__.py
│ ├── a90_sim_cli
│ │ ├── __init__.py
│ │ ├── fixture
│ │ │ └── __init__.py
│ │ ├── solve
│ │ │ ├── __init__.py
│ │ │ ├── test_sim_fast.py
│ │ │ └── test_sim_full.py
│ │ └── conftest.py
│ ├── a00_sim_wrapper
│ │ ├── __init__.py
│ │ └── test_wrapper.py
│ ├── conftest.py
│ └── README.md
├── _data
│ └── v0.5.0
│ │ └── yaml
│ │ └── geo
│ │ └── circle
│ │ ├── wedge.png
│ │ ├── circle_base.png
│ │ └── mini_spot.png
└── README.md
├── doc
├── ipynb
│ └── tutorial
│ │ └── developer
│ │ └── geo
│ │ └── circle
│ │ ├── poles.png
│ │ ├── ring.png
│ │ ├── spot.png
│ │ ├── spot_1.png
│ │ ├── spot_2.png
│ │ ├── spot_3.png
│ │ ├── wedge.png
│ │ ├── amputate.png
│ │ ├── tissue_A.png
│ │ ├── tissue_B.png
│ │ ├── top_pole.png
│ │ ├── bottom_pole.png
│ │ ├── circle_base.png
│ │ ├── mini_spot.png
│ │ ├── mini_wedge.png
│ │ └── circle_base_2.png
├── yaml
│ └── paper
│ │ ├── 2018_PBMB
│ │ ├── Patterns
│ │ │ └── geo
│ │ │ │ └── 1H2
│ │ │ │ ├── Body.png
│ │ │ │ ├── Spot.png
│ │ │ │ ├── 3Cuts.png
│ │ │ │ └── 1H_Gradient.png
│ │ └── Physiology
│ │ │ └── geo
│ │ │ └── circle
│ │ │ ├── spot_3.png
│ │ │ ├── wedge.png
│ │ │ └── circle_base.png
│ │ └── 2016_Frontiers
│ │ └── Attractors
│ │ └── geo
│ │ └── circle
│ │ ├── wedge.png
│ │ ├── tissue_A.png
│ │ ├── tissue_B.png
│ │ └── circle_base.png
└── md
│ ├── DEV_DEMO.md
│ ├── AUTHORS.md
│ ├── TEST.md
│ ├── USAGE.md
│ └── DEVELOP.md
├── freeze
└── hooks
│ └── hook-scipy.special.py
├── LICENSE
├── .gitignore
└── requirements-conda.txt
/betse/py.typed:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/cli/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/betse/gui/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/betse/lib/numpy/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/pickle/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/pil/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/yaml/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/app/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/cli/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/io/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/math/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/os/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/path/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/py/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/matplotlib/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/setuptools/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/yaml/abc/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/compat/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/config/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/enum/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/math/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/phase/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/physics/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/pipe/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/visual/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/app/meta/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/io/error/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/io/log/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/os/brand/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/os/command/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/os/process/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/os/shell/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/py/module/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/call/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/cls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/obj/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/text/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/_fixture/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a90_func/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/channels/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/chemistry/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/config/grn/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/config/model/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/math/cache/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/math/vector/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/organelles/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/pipe/export/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/tissue/event/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/visual/anim/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/visual/layer/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/visual/plot/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/io/log/conf/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/math/geometry/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/decorator/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/descriptor/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/numeric/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/app/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/lib/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/math/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/path/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/py/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/lib/matplotlib/writer/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/config/export/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/phase/require/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/phase/require/abc/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/pipe/export/plot/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/tissue/picker/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/fixture/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/mark/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/set/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/text/string/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/_fixture/simconf/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/app/meta/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/fixture/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/text/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a90_func/_fixture/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a90_sim_cli/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/config/export/visual/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/visual/layer/vector/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/math/geometry/polygon/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/mapping/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/math/geometry/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/descriptor/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/iterable/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/numeric/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a00_sim_wrapper/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/science/visual/layer/vectorfield/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/iterable/mapping/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a90_sim_cli/fixture/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a90_sim_cli/solve/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/1.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/2.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/3.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/4.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/5.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/6.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/7.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/8.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/9.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/ring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/ring.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/spot.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/cyst/ring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/cyst/ring.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/cyst/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/cyst/wedge.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/body.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/brain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/brain.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/cuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/cuts.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/head.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/nose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/nose.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/tail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/tail.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/10.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/11.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/12.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/13.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/14.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/15.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/16.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/square/base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/square/base.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2Cuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2Cuts.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2CutsB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2CutsB.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/3Cuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/3Cuts.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/3CutsB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/3CutsB.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/Body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/Body.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/Spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/Spot.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/body.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/gut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/gut.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/poles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/poles.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/spot_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/spot_1.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/spot_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/spot_2.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/spot_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/spot_3.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/wedge.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/cyst/blastula.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/cyst/blastula.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/body.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/front.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/poles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/poles.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/rear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/rear.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo2/folds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo2/folds.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo2/plate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo2/plate.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/lattice/holes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/lattice/holes.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/brain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/brain.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/cuts_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/cuts_0.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/cuts_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/cuts_1.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/cuts_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/cuts_2.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/nerves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/nerves.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/wedge.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/amputate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/amputate.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/mini_spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/mini_spot.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/tissue_A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/tissue_A.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/tissue_B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/tissue_B.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/top_pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/top_pole.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/cyst/blastula2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/cyst/blastula2.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/cuts_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/cuts_a.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/cuts_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/cuts_b.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo2/clipping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo2/clipping.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo2/placode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo2/placode.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/lattice/clipping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/lattice/clipping.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/lattice/lattice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/lattice/lattice.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/Wound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/Wound.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/root/root_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/root/root_demo.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/cuts_sym1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/cuts_sym1.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/1CutEvenB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/1CutEvenB.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/1CutUnevenB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/1CutUnevenB.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/1H_Gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/1H_Gradient.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2H_Gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2H_Gradient.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/amp_head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/amp_head.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/amp_tail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/amp_tail.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/ellipse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/ellipse.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/endpoints.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/endpoints.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/somatic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/somatic.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/thought.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/thought.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/bottom_pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/bottom_pole.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/circle_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/circle_base.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/mini_wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/mini_wedge.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1Hgradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1Hgradient.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_base.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_cuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_cuts.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_head.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_tail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_tail.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/2Hgradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/2Hgradient.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/GutMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/GutMask.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/Thought.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/Thought.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/cuts_asymH1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/cuts_asymH1.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/snake/cuts_asymT1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/snake/cuts_asymT1.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/amputation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/amputation.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/circle/circle_base_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/circle/circle_base_2.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/cyst/thick_side_ring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/cyst/thick_side_ring.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_5cuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_5cuts.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_cuts2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_cuts2.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/CRYgradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/CRYgradient.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_base.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_hole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_hole.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_peaks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_peaks.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_plate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_plate.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_tips.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_tips.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_valley.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_valley.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/CutLines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/CutLines.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/GutCavity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/GutCavity.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/NervesMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/NervesMask.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2H_Gradient_Asym.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2H_Gradient_Asym.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/Werner_Gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/Werner_Gradient.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm_o/amputation_o.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm_o/amputation_o.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_1cut_high.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_1cut_high.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_1cut_mid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_1cut_mid.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/2Hgradient_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/2Hgradient_new.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_endoderm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_endoderm.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_mesoderm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_mesoderm.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_notocord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_notocord.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/BoundaryMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/BoundaryMask.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/ClippingMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/ClippingMask.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/1H_Gradient_Linear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/1H_Gradient_Linear.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/1H_Gradient_Neural.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/1H_Gradient_Neural.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2H_Gradient_Linear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2H_Gradient_Linear.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2H_Gradient_Neural.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2H_Gradient_Neural.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_2cuts_asym.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_2cuts_asym.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/ellipse/1worm_2cuts_even.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/ellipse/1worm_2cuts_even.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_connected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_connected.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/embryo/neurula_epidermis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/embryo/neurula_epidermis.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/worm/2H_Gradient_FlatMid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/worm/2H_Gradient_FlatMid.png
--------------------------------------------------------------------------------
/betse_test/_data/v0.5.0/yaml/geo/circle/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse_test/_data/v0.5.0/yaml/geo/circle/wedge.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/poles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/poles.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/ring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/ring.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/spot.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/spot_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/spot_1.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/spot_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/spot_2.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/spot_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/spot_3.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/wedge.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/Body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/Body.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/Spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/Spot.png
--------------------------------------------------------------------------------
/betse/data/yaml/geo/planaria_o/NervesCircuitMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse/data/yaml/geo/planaria_o/NervesCircuitMask.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/amputate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/amputate.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/tissue_A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/tissue_A.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/tissue_B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/tissue_B.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/top_pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/top_pole.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/3Cuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/3Cuts.png
--------------------------------------------------------------------------------
/betse/science/tissue/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
--------------------------------------------------------------------------------
/betse_test/_data/v0.5.0/yaml/geo/circle/circle_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse_test/_data/v0.5.0/yaml/geo/circle/circle_base.png
--------------------------------------------------------------------------------
/betse_test/_data/v0.5.0/yaml/geo/circle/mini_spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/betse_test/_data/v0.5.0/yaml/geo/circle/mini_spot.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/bottom_pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/bottom_pole.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/circle_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/circle_base.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/mini_spot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/mini_spot.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/mini_wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/mini_wedge.png
--------------------------------------------------------------------------------
/doc/ipynb/tutorial/developer/geo/circle/circle_base_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/ipynb/tutorial/developer/geo/circle/circle_base_2.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/1H_Gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Patterns/geo/1H2/1H_Gradient.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Physiology/geo/circle/spot_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Physiology/geo/circle/spot_3.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Physiology/geo/circle/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Physiology/geo/circle/wedge.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/wedge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/wedge.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2018_PBMB/Physiology/geo/circle/circle_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2018_PBMB/Physiology/geo/circle/circle_base.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/tissue_A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/tissue_A.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/tissue_B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/tissue_B.png
--------------------------------------------------------------------------------
/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/circle_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betsee/betse/HEAD/doc/yaml/paper/2016_Frontiers/Attractors/geo/circle/circle_base.png
--------------------------------------------------------------------------------
/freeze/hooks/hook-scipy.special.py:
--------------------------------------------------------------------------------
1 | #FIXME: Contribute back. When doing so, note that this appears to be required
2 | #*ONLY* for scipy >= 0.15.0.
3 | hiddenimports = ['scipy.integrate']
4 |
--------------------------------------------------------------------------------
/betse/util/cli/repl/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
--------------------------------------------------------------------------------
/betse/science/compat/compatgrnconf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Facilities guaranteeing backward compatibility with prior file formats for
8 | gene regulatory networks (GRNs).
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.io.log import logs
13 | from betse.util.type.types import type_check, MappingType
14 |
--------------------------------------------------------------------------------
/betse/data/yaml/SIMS/.gitignore:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # Empty ".gitignore" forcing Git to track this otherwise empty directory.
7 | #
8 | # --------------------( SEE ALSO )--------------------
9 | # For further details, see the following StackOverflow discussion:
10 | # https://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository
11 |
--------------------------------------------------------------------------------
/betse/data/yaml/INITS/.gitignore:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # Empty ".gitignore" forcing Git to track this otherwise empty directory.
7 | #
8 | # --------------------( SEE ALSO )--------------------
9 | # For further details, see the following StackOverflow discussion:
10 | # https://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository
11 |
--------------------------------------------------------------------------------
/betse/data/yaml/RESULTS/.gitignore:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # Empty ".gitignore" forcing Git to track this otherwise empty directory.
7 | #
8 | # --------------------( SEE ALSO )--------------------
9 | # For further details, see the following StackOverflow discussion:
10 | # https://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository
11 |
--------------------------------------------------------------------------------
/betse/data/yaml/RESULTS/init_1/.gitignore:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # Empty ".gitignore" forcing Git to track this otherwise empty directory.
7 | #
8 | # --------------------( SEE ALSO )--------------------
9 | # For further details, see the following StackOverflow discussion:
10 | # https://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository
11 |
--------------------------------------------------------------------------------
/betse/data/yaml/RESULTS/sim_1/.gitignore:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # Empty ".gitignore" forcing Git to track this otherwise empty directory.
7 | #
8 | # --------------------( SEE ALSO )--------------------
9 | # For further details, see the following StackOverflow discussion:
10 | # https://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository
11 |
--------------------------------------------------------------------------------
/betse/util/type/contexts.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **context manager** (i.e., classes implementing the context manager
8 | protocol and hence the ``__enter__`` and ``__exit__`` special methods)
9 | facilities.
10 | '''
11 |
12 | # ....................{ IMPORTS }....................
13 | from beartype.typing import Iterator
14 | from contextlib import contextmanager
15 |
16 | # ....................{ MANAGERS }....................
17 | @contextmanager
18 | def noop_context() -> Iterator[None]:
19 | '''
20 | Empty context manager exiting immediately after being entered.
21 | '''
22 |
23 | yield
24 |
--------------------------------------------------------------------------------
/betse_test/a90_func/conftest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | # ....................{ IMPORTS ~ fixture }....................
7 | '''
8 | Global functional test configuration for BETSE's command-line interface (CLI).
9 |
10 | ``py.test`` implicitly imports all functionality defined by this module into
11 | all CLI-specific functional test modules. Since this functionality now includes
12 | all publicly declared functional fixtures in this ``fixture`` subpackage, these
13 | tests may reference these fixtures without explicit imports.
14 | '''
15 |
16 | # ....................{ IMPORTS ~ fixture }....................
17 | from betse_test.a90_func._fixture.clier import betse_cli
18 |
--------------------------------------------------------------------------------
/betse/cli/__main__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Subsidiary entry point of this application's command line interface (CLI),
8 | preserving backward compatibility with prior versions.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.__main__ import main
13 | from betse.util.os.command import cmdexit
14 |
15 | # ....................{ MAIN }....................
16 | # If this module is imported from the command line, run this application's CLI;
17 | # else, noop. For POSIX compliance, the exit status returned by this function
18 | # is propagated to the caller as this script's exit status.
19 | if __name__ == '__main__':
20 | cmdexit.exit_with_status(main())
21 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/iterators.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **iterator** (i.e., objects satisfying the standard iterator API)
8 | facilities.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.type.types import IterableTypes
13 |
14 | # ....................{ GENERATORS }....................
15 | def empty_iterator() -> IterableTypes:
16 | '''
17 | Empty iterator iterating over... absolutely nothing.
18 |
19 | See Also
20 | ----------
21 | https://stackoverflow.com/a/10621647/2809027
22 | StackOverflow answer strongly inspiring this implementation.
23 | '''
24 |
25 | # It is clever. It is Python.
26 | return iter(())
27 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/conftest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Global unit test configuration for BETSE.
8 |
9 | :mod:`pytest` implicitly imports all functionality defined by this module into
10 | all unit test modules. As this functionality includes all publicly declared
11 | functional fixtures in this fixture subpackage, these tests may reference these
12 | fixtures without explicit imports.
13 | '''
14 |
15 | # ....................{ IMPORTS ~ fixture : autouse }....................
16 | # Import fixtures automatically run at the start of the current test session,
17 | # typically *NOT* manually required by specific tests, *AFTER* importing all
18 | # non-autouse fixtures possibly required by these autouse fixtures above.
19 |
20 | from betse_test._fixture.initter import betse_init_package
21 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/text/test_mls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests exercising *ML (e.g., HTML, SGML, XML) functionality.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | # import pytest
12 |
13 | # ....................{ TESTS }....................
14 | def test_is_ml() -> None:
15 | '''
16 | Unit test the :func:`betse.util.type.text.mls.is_ml` tester.
17 | '''
18 |
19 | # Defer heavyweight imports.
20 | from betse.util.type.text import mls
21 |
22 | # Assert this tester to behave as expected.
23 | assert mls.is_ml(
24 | 'And that one shall come to you')
25 | assert not mls.is_ml(
26 | '...')
27 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a90_sim_cli/conftest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | # ....................{ IMPORTS ~ fixture }....................
7 | '''
8 | Global functional test configuration for the simulation-specific portion of
9 | BETSE's command-line interface (CLI).
10 |
11 | ``py.test`` implicitly imports all functionality defined by this module into
12 | all CLI-specific functional test modules. Since this functionality now includes
13 | all publicly declared functional fixtures in this ``fixture`` subpackage, these
14 | tests may reference these fixtures without explicit imports.
15 | '''
16 |
17 | # ....................{ IMPORTS ~ fixture }....................
18 | from betse_test.a90_func.a90_sim_cli.fixture.clisimer import (
19 | betse_cli_sim,
20 | betse_cli_sim_default,
21 | betse_cli_sim_compat,
22 | )
23 |
--------------------------------------------------------------------------------
/betse/lib/matplotlib/mplutil.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level matplotlib-specific functionality for which no better home exists.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from betse.util.io.error.errwarning import ignoring_warnings
12 | from beartype.typing import ContextManager
13 | from matplotlib import MatplotlibDeprecationWarning
14 |
15 | # ....................{ WARNINGS }....................
16 | def ignoring_deprecations_mpl() -> ContextManager:
17 | '''
18 | Single-shot context manager temporarily ignoring all matplotlib-specific
19 | deprecation warnings emitted by the :mod:`warnings` module for the duration
20 | of this context.
21 |
22 | See Also
23 | -----------
24 | :class:`ignoring_warnings`
25 | Further details.
26 | '''
27 |
28 | return ignoring_warnings(MatplotlibDeprecationWarning)
29 |
--------------------------------------------------------------------------------
/betse/data/yaml/extra_configs/expression_data.yaml:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # This expression_data.yaml file allows for specific expression levels of any biomolecule, reaction,
4 | # channel, or transporter to be set across all tissue profiles of the model. Expression levels
5 | # are relative to the maximum:
6 | # production rate (for biomolecules)
7 | # reaction rate (for reactions)
8 | # conductivity (for channels)
9 | # rate (for transporters)
10 | # Use the expression data
11 |
12 | K_Leak: # Name of the biomolecule, pump, channel, reaction, or transporter in your main config file
13 | spot: 2.5 # Expression level on tissue profile 'spot'
14 | zone: 1.0 # Expression level on tissue profile 'zone'
15 |
16 | Kv: # Name of the biomolecule, pump, channel, reaction, or transporter in your main config file
17 | spot: 2.5
18 | zone: 1.0
19 |
20 | Nav: # Name of the biomolecule, pump, channel, reaction, or transporter in your main config file
21 | spot: 2.5
22 | zone: 1.0
23 |
24 | X: # Name of the biomolecule, pump, channel, reaction, or transporter in your main config file
25 | spot: 2.5
26 | zone: 1.0
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/doc/md/DEV_DEMO.md:
--------------------------------------------------------------------------------
1 | BETSE Developer's Tutorial
2 | ===========
3 | BETSE is a self-contained software package, but it is also possible to use
4 | modules and methods from BETSE as tools in your own projects. The BETSE Developer's
5 | Tutorial is a Jupyter Notebook script that allows you to import BETSE modules,
6 | run a sim in the Jupyter Notebook, and gives some pointers on how to access
7 | and plot simulation data and data structures of the BETSE sim.
8 |
9 | **How to Use the Developer's Tutorial Script**
10 |
11 | To use these simulations, first install BETSE (if you haven't done so already):
12 |
13 | https://gitlab.com/betse/betse#simple
14 |
15 | Note that using Anaconda to install BETSE will also install [Jupyter Notebooks](https://jupyter.org/).
16 |
17 | Download the Developers Tutorial and unzip it into a
18 | directory of your choice on your computer (e.g. 'BETSE_Sims'):
19 |
20 | [Developer's Tutorial](https://www.dropbox.com/s/f4ilizqnbmn2of5/developer.zip?dl=0)
21 |
22 | Open the Jupyter Notebook 'Dev_Demo_BETSEv1.0.ipynb' and follow instructions
23 | therein. Features of the BETSE simulation that the Developer's Tutorial runs
24 | can be edited by making changes to the 'sim_config.yaml' file included with
25 | the Developer's Tutorial package.
26 |
27 |
--------------------------------------------------------------------------------
/betse/science/config/model/confphase.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
5 | '''
6 | YAML-backed simulation phase subconfigurations.
7 | '''
8 |
9 | # ....................{ IMPORTS }....................
10 | from betse.lib.yaml.yamlalias import yaml_alias
11 | from betse.lib.yaml.abc.yamlabc import YamlABC
12 | # from betse.util.type.types import type_check, NumericSimpleTypes
13 |
14 | # ....................{ SUBCLASSES }....................
15 | #FIXME: Implement us up.
16 | #FIXME: Refactor the Parameters.set_time_profile() method to leverage this.
17 | class SimConfPhase(YamlABC):
18 | '''
19 | YAML-backed simulation phase subconfiguration, encapsulating the
20 | configuration of a single phase (e.g., seed, initialization, simulation)
21 | parsed from the current YAML-formatted simulation configuration file.
22 |
23 | Attributes (Path)
24 | ----------
25 | . : .
26 | .
27 |
28 | Attributes (Time)
29 | ----------
30 | . : .
31 | .
32 | '''
33 |
34 | # ..................{ ALIASES ~ wut }..................
35 | wut = yaml_alias("['wut']['wut']", int)
36 |
--------------------------------------------------------------------------------
/betse/science/pipe/export/pipeexpabc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Simulation export pipeline** (i.e., container of related, albeit isolated,
8 | simulation export actions to be run iteratively) hierarchy.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.science.pipe.pipeabc import SimPipeABC
13 | from betse.util.type.descriptor.descs import classproperty_readonly
14 |
15 | # ....................{ SUPERCLASSES }....................
16 | class SimPipeExportABC(SimPipeABC):
17 | '''
18 | Abstract base class of all **simulation export pipeline** (i.e., object
19 | iteratively exporting *all* variations on a single type of simulation
20 | export) subclasses.
21 | '''
22 |
23 | # ..................{ SUPERCLASS }..................
24 | @classproperty_readonly
25 | def _RUNNER_METHOD_NAME_PREFIX(self) -> str:
26 | return 'export_'
27 |
28 |
29 | @classproperty_readonly
30 | def _VERB_CONTINUOUS(cls) -> str:
31 | return 'Exporting'
32 |
--------------------------------------------------------------------------------
/betse/util/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Blast-proof utilities.
8 | '''
9 |
10 | #FIXME: Consider offshoring this entire subpackage into a new independent
11 | #Python project codenamed "Blast-proof utilities." PiPI project and package
12 | #names deriving from this codename include:
13 | #
14 | #* "blapu". No existing PyPI packages. No prominent Google hits. Sorta ideal? My
15 | # own quandry is... well, let's face it: "Blapu." Really? That's awful.
16 | #* "blaut". No existing PyPI packages. Many prominent Google hits. Less ideal?
17 | #* "blauti". No existing PyPI packages. No prominent Google hits. *MOST IDEAL?*
18 | #* "blapru". No existing PyPI packages. No prominent Google hits. Less ideal?
19 | #* "blastu". No existing PyPI packages. Extremely prominent Google hits
20 | # pertaining to a technology festival hosted in Bravil, however. Non-ideal?
21 | #
22 | #I'm partial to "blauti," as of this writing. It just works. Only 5,000 Google
23 | #hits effectively guarantees uniqueness. It also reads and sounds apropos.
24 | #FIXME: Oh, yeah. We got this:
25 | #
26 | #* "brutil". Speaks for itself in waves of languid ludicrousness, doesn't it?
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright notice,
10 | this list of conditions and the following disclaimer in the documentation
11 | and/or other materials provided with the distribution.
12 |
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/mark/pytmark.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level :mod:`pymod`-based general-purpose decorators marking tests.
8 |
9 | This submodule aggregates general-purpose decorators *not* conditionally
10 | marking their decorated tests as either failed, parametrized, or skipped.
11 | '''
12 |
13 | # ....................{ IMPORTS }....................
14 | import pytest
15 |
16 | # ....................{ MARKS }....................
17 | noop = pytest.mark.noop
18 | '''
19 | Preserve the decorated test or test parameter as is with *no* modification.
20 |
21 | Caveats
22 | ----------
23 | This decorator has the unintended side effect of also marking all tests and
24 | test parameters decorated by this decorated with the ``noop`` tag. This
25 | harmless albeit unfortunate side effect is the result of the :mod:`pytest.mark`
26 | API, which strictly requires that *all* decorators passed to the ``marks``
27 | parameter of the :mod:`pytest.param` function be strictly generated by the
28 | :mod:`pytest.mark` API, which then imposes this seemingly arbitrary constraint.
29 |
30 | In other words, there's absolutely nothing to see here, folks.
31 | '''
32 |
--------------------------------------------------------------------------------
/doc/md/AUTHORS.md:
--------------------------------------------------------------------------------
1 | Authors and Contributors
2 | ===========
3 |
4 | BETSE is principally authored by [Alexis
5 | Pietak](https://www.researchgate.net/profile/Alexis_Pietak) and [Cecil
6 | Curry](https://gitlab.com/u/leycec) with **much-appreciated contributions**
7 | from (_in chronological order of first merge request_):
8 |
9 | * [**Douglas Moore**](https://gitlab.com/u/dglmoore) for:
10 | * [REPL and scripting support](https://gitlab.com/betse/betse/merge_requests/2).
11 | * [Windows integration](https://gitlab.com/betse/betse/merge_requests/1).
12 |
13 | A rousing thanks to these illustrious contributors, without whom BETSE would
14 | only be a dim glimmer in the undocumented shallows of GitLab. **You are
15 | uniformly awesome. ***
16 |
17 | * _As evidenced by this footnote, we really mean it._
18 |
19 | ## GitLab
20 |
21 | For an HTML5-driven topology of all contributors, see our [Contributors
22 | Graph](https://gitlab.com/betse/betse/graphs/master/contributors).
23 |
24 | ## Git
25 |
26 | For a CLI-driven list of all contributions to filename `${filename}` by:
27 |
28 | * High-level **commits** (tracked across file renames), run the following command in
29 | local copies of BETSE's Git repository:
30 |
31 | git log --follow ${filename}
32 |
33 | * Low-level **line numbers**, run the following command in the same:
34 |
35 | git blame ${filename}
36 |
--------------------------------------------------------------------------------
/betse/science/config/export/confexpabc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Simulation export subconfiguration** (i.e., YAML-backed list item configuring
8 | the exportation of one or more external files from the ``plot`` subcommand when
9 | passed the simulation configuration file containing this item) superclasses.
10 | '''
11 |
12 | # ....................{ IMPORTS }....................
13 | from betse.lib.yaml.abc.yamllistabc import YamlListItemABC
14 | from betse.lib.yaml.abc.yamlmixin import (
15 | YamlBooledMixin, YamlNamedMixin, YamlTypedMixin)
16 | # from betse.util.type.types import type_check
17 |
18 | # ....................{ SUPERCLASSES }....................
19 | class SimConfExportABC(
20 | YamlBooledMixin,
21 | YamlNamedMixin,
22 | YamlTypedMixin,
23 | YamlListItemABC,
24 | ):
25 | '''
26 | Abstract base class of all **simulation export subconfiguration** (i.e.,
27 | YAML-backed list item configuring the exportation of one or more external
28 | files from the ``plot`` subcommand when passed the simulation configuration
29 | file containing this item) subclasses.
30 | '''
31 |
32 | # That's all she wrote.
33 | pass
34 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a90_sim_cli/solve/test_sim_fast.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | CLI-specific functional tests exercising the equivalent circuit-based
8 | simulation solver.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | # from betse.util.test.pytest.mark.pytfail import xfail
13 |
14 | # ....................{ TESTS }....................
15 | def test_cli_sim_fast(betse_cli_sim: 'CLISimTester') -> None:
16 | '''
17 | Functional test exporting all available exports (e.g., CSVs, plots,
18 | animations) with all simulation features required by these exports,
19 | including the equivalent circuit-based solver but excluding extracellular
20 | spaces (which are only partially supported by this solver).
21 |
22 | Parameters
23 | ----------
24 | betse_cli_sim : CLISimTester
25 | Object running BETSE CLI simulation subcommands.
26 | '''
27 |
28 | # Enable all exports and features required by these exports.
29 | betse_cli_sim.sim_state.config.enable_solver_fast_exports()
30 |
31 | # Test all default simulation-specific subcommands with this configuration.
32 | betse_cli_sim.run_subcommands_try()
33 |
--------------------------------------------------------------------------------
/betse/util/type/obj/sentinels.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Sentinel** (i.e., objects of arbitrary unique value, typically used to
8 | distinguish edge-case results from the standard ``None`` singleton) facilities.
9 | '''
10 |
11 | # ....................{ CLASSES }....................
12 | class Sentinel(object):
13 | '''
14 | Class encapsulating sentinel objects of arbitrary (albeit unique) value.
15 |
16 | Instances of this class are intended to be used as placeholder objects in
17 | iterables, typically to identify erroneous or edge-case algorithm input.
18 | '''
19 |
20 | def __repr__(self) -> str:
21 | '''
22 | Human- and machine-readable representation of this sentinel.
23 |
24 | This method has been overridden purely to improve the debuggability of
25 | algorithms requiring instances of this class.
26 | '''
27 |
28 | return 'Sentinel()'
29 |
30 | # ....................{ CONSTANTS }....................
31 | SENTINEL = Sentinel()
32 | '''
33 | Sentinel object of arbitrary value.
34 |
35 | This object is internally leveraged by various utility functions (e.g.,
36 | :func:`betse.util.type.iterable.iterables.zip_isometric`) to identify erroneous
37 | and edge-case input (e.g., iterables of insufficient length).
38 | '''
39 |
--------------------------------------------------------------------------------
/betse/science/tissue/event/tisevecut.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level classes aggregating all parameters pertaining to simulation events.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from betse.science.tissue.event.tiseveabc import SimEventSpikeABC
12 | # from betse.util.io.log import logs
13 | from betse.util.type.types import type_check #, SequenceTypes
14 |
15 | # ....................{ SUBCLASSES }....................
16 | #FIXME: Refactor the TissueHandler.removeCells() method into a new
17 | #fire() method of this subclass.
18 | class SimEventCut(SimEventSpikeABC):
19 | '''
20 | **Cutting event** (i.e., event removing one or more cells of the current
21 | cell cluster at some time step during the simulation phase).
22 | '''
23 |
24 | # ..................{ INITIALIZERS }..................
25 | @type_check
26 | def __init__(self, p: 'betse.science.parameters.Parameters') -> None:
27 | '''
28 | Initialize this cutting event for the passed simulation configuration.
29 |
30 | Attributes
31 | ----------
32 | p : betse.science.parameters.Parameters
33 | Current simulation configuration.
34 | '''
35 |
36 | # Initialize our superclass.
37 | super().__init__(p=p, time_step=p.event_cut_time)
38 |
--------------------------------------------------------------------------------
/betse/science/tissue/channels_o.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
5 | #FIXME: Consider moving this submodule into the channel-specific
6 | #"betse.science.tissue.channels" subpackage, for disambiguity.
7 |
8 | import numpy as np
9 |
10 | # calcium (and voltage) gated K+ channel-------------------------------------------------------------------------------
11 | def cagPotassium(dyna,sim,cells,p):
12 | """
13 | Model of a high-conductance calcium activated potassium channel (SK channel), obtained from
14 | the allosteric model of Cox DH, Cui J, Aldrich RW. J Gen Physiology. 1997. 110: 257-281.
15 | """
16 |
17 | # get data on cytosolic calcium levels in target cells:
18 |
19 | ca = sim.cc_cells[sim.iCa][cells.mem_to_cells][dyna.targets_cagK]
20 |
21 | # calculate different terms:
22 | t1 = 1 + ((ca*1e6)/10.22)
23 | t2 = 1 + ((ca*1e6)/0.89)
24 |
25 | # calculate probability of channel being open or closed:
26 | P = 1/(1+((t1/t2)**4)*6182*np.exp(-(1.64*p.F*sim.vm)/(p.R*sim.T)))
27 |
28 | # print(P.min(), P.mean(), P.max())
29 |
30 | # # ensure proper probability behaviour:
31 | # inds_P_over = (P > 1.0).nonzero()
32 | # P[inds_P_over] = 1.0
33 | #
34 | # inds_P_under = (P < 0.0).nonzero()
35 | # P[inds_P_under] = 0.0
36 |
37 | # calculate conductance of this potassium channel:
38 | # print(P.mean())
39 |
40 | # delta_Q = - (dyna.maxDmKcag * P * (sim.vm - self.vrev))
41 | sim.Dm_cag[sim.iK] = dyna.maxDmKcag*P
42 |
--------------------------------------------------------------------------------
/betse/science/math/cache/cachelyrvec.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level vector subcache functionality.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from betse.science.math.cache.cacheabc import SimPhaseCacheABC
12 | from betse.science.visual.layer.vector import lyrvecabc
13 | from betse.science.visual.layer.vector.lyrvecabc import (
14 | LayerCellsVectorColorfulABC)
15 | from betse.util.type.decorator.decmemo import property_cached
16 |
17 | # ....................{ SUBCLASSES }....................
18 | class SimPhaseCacheLayerCellsVector(SimPhaseCacheABC):
19 | '''
20 | Simulation phase-specific **vector layer** (i.e., vector-based layer
21 | layering a one-dimensional Numpy array onto exported visuals) subcache,
22 | persisting all previously constructed vector-based layers for a single
23 | simulation phase.
24 | '''
25 |
26 | # ..................{ PROPERTIES ~ currents }..................
27 | @property_cached
28 | def voltage_membrane(self) -> LayerCellsVectorColorfulABC:
29 | '''
30 | Vector layer layering all transmembrane voltages (Vmem) for the cell
31 | cluster over all time steps onto caller-provided visuals.
32 | '''
33 |
34 | return lyrvecabc.make_layer(
35 | phase=self._phase, vector=self._phase.cache.vector.voltage_membrane)
36 |
--------------------------------------------------------------------------------
/doc/md/TEST.md:
--------------------------------------------------------------------------------
1 | Testing
2 | ===========
3 |
4 | BETSE is rigorously tested with a [comprehensive test
5 | suite](https://gitlab.com/betse/betse/tree/master/betse_test) comprising both
6 | [functional](https://en.wikipedia.org/wiki/Functional_testing) and [unit
7 | tests](https://en.wikipedia.org/wiki/Unit_testing).
8 |
9 | ## Manual Testing
10 |
11 | BETSE is manually testable by [**py.test**](http://pytest.org) at the command
12 | line. Either:
13 |
14 | * Run all available tests. Either:
15 | * Run `test`, the provided Bash shell script wrapper. For convenience, this
16 | script is runnable from any directory (including the top-level BETSE
17 | directory) _and_ accepts all arguments accepted by the `test` subcommand
18 | (detailed below):
19 |
20 | $ ./test
21 |
22 | * Run the `setuptools`-driven `test` subcommand. Due to `setuptools`
23 | constraints, this subcommand is runnable _only_ from the top-level BETSE
24 | directory:
25 |
26 | $ cd "${BETSE_DIR}"
27 | $ python3 setup.py test
28 |
29 | * Run all tests matching a passed Python-evaluatable expression. For example, to
30 | run all test functions and classes whose names contain either `test_tartarus`
31 | _or_ `test_thalassa`:
32 |
33 | $ cd "${BETSE_DIR}"
34 | $ python3 setup.py test -k 'test_tartarus or test_thalassa'
35 |
36 | ## Continuous Integration (CI)
37 |
38 | BETSE is continuously integrated by
39 | [**GitLab-CI**](https://about.gitlab.com/gitlab-ci) on each commit pushed to
40 | each branch of BETSE's [GitLab](https://gitlab.com)-hosted [Git
41 | repository](https://gitlab.com/betse/betse/tree/master).
42 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/math/geometry/test_geopoly.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests for the :mod:`betse.util.math.geometry.geopoly` submodule.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 |
12 | # ....................{ TESTS }....................
13 | def test_orient_counterclockwise() -> None:
14 | '''
15 | Unit test the
16 | :func:`betse.util.math.geometry.geopoly.orient_counterclockwise`
17 | function.
18 | '''
19 |
20 | # Defer heavyweight imports.
21 | from betse.util.math.geometry.polygon import geopoly
22 |
23 | # Rectangle oriented randomly rather than counter-clockwise. Due to trivial
24 | # limitations of the betse.lib.numpy.nparray.to_iterable() function, this
25 | # rectangle is defined as a list of lists rather than tuple of tuples.
26 | rectangle_unoriented = [[2, 2], [2, -1], [-1, -1], [-1, 2],]
27 |
28 | # Rectangle oriented counter-clockwise.
29 | rectangle_oriented = geopoly.orient_counterclockwise(rectangle_unoriented)
30 |
31 | # Assert this rectangle to be oriented counter-clockwise.
32 | assert rectangle_oriented == [[-1, -1], [2, -1], [2, 2], [-1, 2],]
33 |
34 | # Assert that attempting to reorient this rectangle counter-clockwise is a
35 | # noop (i.e., produces the same rectangle).
36 | assert geopoly.orient_counterclockwise(rectangle_oriented) == (
37 | rectangle_oriented)
38 |
--------------------------------------------------------------------------------
/betse/util/io/stdouts.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level standard output facilities.
8 | '''
9 |
10 | #FIXME: Copy setup.util.get_command_output() here after completion.
11 |
12 | # ....................{ IMPORTS }....................
13 |
14 | # ....................{ OUTPUTTERS }....................
15 | def output(*objs) -> None:
16 | '''
17 | Print all passed objects as is to standard output *without* logging these
18 | objects.
19 |
20 | This function is provided only for orthogonality with the function of the
21 | same name defined by the :mod:`betse.util.io.stderrs` module.
22 |
23 | This function is intentionally *not* named ``print()`` to avoid conflict
24 | with the builtin function of the same name.
25 | '''
26 |
27 | print(*objs)
28 |
29 |
30 | def output_lines(*objs) -> None:
31 | '''
32 | Print all passed objects as is to standard output *without* logging these
33 | objects, delimiting each such object by a newline.
34 | '''
35 |
36 | print('\n'.join(objs))
37 |
38 |
39 | def output_traceback() -> None:
40 | '''
41 | Print the current call stack to standard output.
42 | '''
43 |
44 | # Avoid circular import dependencies.
45 | from betse.util.type.call import callers
46 |
47 | # Print this call stack, excluding the calls to both this and the
48 | # callers.get_traceback() functions.
49 | output(callers.get_traceback(-2))
50 |
--------------------------------------------------------------------------------
/betse/science/pipe/export/pipeexpenum.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Export-specific enumeration types** (i.e., :class:`enum.Enum` subclasses
8 | expressing mutually exclusive choices specific to post-simulation exports).
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.type.enums import make_enum
13 |
14 | # ....................{ ENUMS }....................
15 | SimExportType = make_enum(
16 | class_name='SimExportType',
17 | member_names=('ANIM', 'CSV', 'PLOT',),
18 | doc='''
19 | Enumeration of all supported types of **post-simulation exports** (e.g.,
20 | plots, animations, comma-separated value (CSV) files).
21 |
22 | Attributes
23 | ----------
24 | ANIM : enum
25 | Post-simulation animations, visualizing the cell cluster across one or
26 | more sampled time steps of an initialization or simulation phase as the
27 | same number of frames of an animated video.
28 | CSV : enum
29 | Post-simulation comma-separated value (CSV) files, aggregating raw data
30 | for the cell cluster across one or more sampled time steps of an
31 | initialization or simulation phase.
32 | PLOT : enum
33 | Post-simulation plots, visualizing the cell cluster across one or more
34 | sampled time steps of an initialization or simulation phase as a single
35 | non-animated image.
36 | ''',
37 | )
38 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/math/test_mathoper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests for the :mod:`betse.util.math.mathoper` submodule.
8 | '''
9 |
10 | # ....................{ TESTS }....................
11 | def test_det1d() -> None:
12 | '''
13 | Unit test the :func:`betse.util.math.mathoper.det1d` function.
14 | '''
15 |
16 | # Defer heavyweight imports.
17 | from betse.util.math.mathoper import det1d
18 | from numpy import asarray
19 | from numpy.testing import assert_equal
20 |
21 | # Two-dimensional input arrays.
22 | arr1 = asarray([1, 2])
23 | arr2 = asarray([4, 5])
24 |
25 | # One-dimensional cross product of these arrays.
26 | determinant = det1d(arr1, arr2)
27 |
28 | # Assert this cross product is as expected.
29 | assert_equal(determinant, -3, strict=True)
30 |
31 |
32 | def test_cross2d() -> None:
33 | '''
34 | Unit test the :func:`betse.util.math.mathoper.cross2d` function.
35 | '''
36 |
37 | # Defer heavyweight imports.
38 | from betse.util.math.mathoper import cross2d
39 | from numpy import asarray
40 | from numpy.testing import assert_equal
41 |
42 | # Two-dimensional input arrays.
43 | arr1 = asarray([[1, 2], [6, 5]])
44 | arr2 = asarray([[7, 8], [3, 4]])
45 |
46 | # One-dimensional cross product of these arrays.
47 | cross_product = cross2d(arr1, arr2)
48 |
49 | # Assert this cross product is as expected.
50 | assert_equal(cross_product, asarray([-6, 9]), strict=True)
51 |
--------------------------------------------------------------------------------
/betse/science/visual/layer/lyrtext.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
5 | '''
6 | Layer subclasses printing text over the current cell cluster.
7 | '''
8 |
9 | # ....................{ IMPORTS }....................
10 | from betse.science.math import mathunit
11 | from betse.science.visual.layer.lyrabc import LayerCellsABC
12 |
13 | # ....................{ CLASSES }....................
14 | class LayerCellsIndex(LayerCellsABC):
15 | '''
16 | Layer printing the 0-based index of each cell in the cell cluster as a text
17 | label centered on that cell.
18 | '''
19 |
20 | # ..................{ SUPERCLASS }..................
21 | def _layer_first(self) -> None:
22 |
23 | # For the 0-based index and 2-tuple of X and Y coordinates of the center
24 | # of each cell, display this index centered at these coordinates.
25 | for cell_index, cell_center in enumerate(
26 | self._phase.cells.cell_centres):
27 | self._visual.axes.text(
28 | # Text to be displayed.
29 | s=cell_index,
30 |
31 | # X and Y coordinates to display this text at.
32 | x=mathunit.upscale_coordinates(cell_center[0]),
33 | y=mathunit.upscale_coordinates(cell_center[1]),
34 |
35 | # Alignment of this text at these coordinates.
36 | horizontalalignment='center',
37 | verticalalignment='center',
38 |
39 | # Z-order of this text with respect to other artists.
40 | zorder=self._zorder,
41 | )
42 |
--------------------------------------------------------------------------------
/betse/util/type/typehints.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Project-wide **type hints** (i.e., PEP-compliant annotations of general-purpose
8 | interest throughout the codebase).
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from beartype.typing import (
13 | Annotated,
14 | ContextManager,
15 | Generator,
16 | )
17 | from beartype.vale import (
18 | IsAttr,
19 | IsEqual,
20 | )
21 | from numpy import ndarray
22 |
23 | # ....................{ HINTS }....................
24 | ContextManagerOrGenerator = ContextManager | Generator
25 | '''
26 | PEP-compliant type hint matching either a context manager *or* generator.
27 | '''
28 |
29 | # ....................{ HINTS ~ lib : numpy : 1d }....................
30 | NDArrayNdim1 = Annotated[ndarray, IsAttr['ndim', IsEqual[1]]]
31 | '''
32 | PEP-compliant type hint matching a 1-dimensional NumPy array.
33 | '''
34 |
35 |
36 | NDArrayNdim1Size2 = Annotated[
37 | ndarray,
38 | IsAttr['ndim', IsEqual[1]],
39 | IsAttr['size', IsEqual[2]],
40 | ]
41 | '''
42 | PEP-compliant type hint matching a 1-dimensional NumPy **2-array** (i.e., array
43 | containing exactly two numbers, typically comprising the X and Y coordinates of
44 | some 2-dimensional point).
45 | '''
46 |
47 | # ....................{ HINTS ~ lib : numpy : 2d }....................
48 | NDArrayNdim2 = Annotated[ndarray, IsAttr['ndim', IsEqual[2]]]
49 | '''
50 | PEP-compliant type hint matching a 2-dimensional NumPy array.
51 | '''
52 |
--------------------------------------------------------------------------------
/betse/util/type/numeric/bits.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **bitwise** (i.e., callables operating on one or more individual bits
8 | of integer-based bit fields) facilities.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.type.types import type_check
13 |
14 | # ....................{ TESTERS }....................
15 | @type_check
16 | def is_bit_on(bit_field: int, bit_mask: int) -> bool:
17 | '''
18 | ``True`` only if the bit in the passed bit field uniquely identified by the
19 | passed bit mask is **on** (i.e., one rather than zero).
20 |
21 | Parameters
22 | ----------
23 | bit_field : int
24 | **Bit field** (i.e., integer whose individual bits collectively
25 | comprise a rudimentary array of boolean flags) to be tested.
26 | bit_mask : int
27 | **Bit mask** (i.e., integer containing exactly one non-zero bit at the
28 | position uniquely identifying the desired bit) of the bit to be tested.
29 |
30 | Returns
31 | ----------
32 | bool
33 | ``True`` only if this bit in this bit field is on.
34 | '''
35 |
36 | # Return true only if this bit in this bit field is on. Dismantled, this
37 | # is:
38 | #
39 | # * "bit_field & bit_mask", either:
40 | # * If this bit is on in this bit field, "bit_mask" and hence non-zero.
41 | # * If this bit is off in this bit field, zero.
42 | # * "bool(...)", reducing this integer to a boolean.
43 | return bool(bit_field & bit_mask)
44 |
--------------------------------------------------------------------------------
/betse/util/cli/repl/replenv.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Environmental context for the BETSE REPL.
8 |
9 | Each function and variable in this module is loaded into the global
10 | :data:`repl_env` dictionary via a call to :func:`locals`. For safety, this
11 | dictionary is the only attribute that should be imported from this module.
12 | '''
13 |
14 | # ....................{ IMPORTS }....................
15 | # from betse.util.type.types import type_check
16 |
17 | # ....................{ GLOBALS }....................
18 | __betse_repl__ = True
19 | '''
20 | `True` only if the current environment is an active REPL.
21 |
22 | It is important that scripts be able to tell that they are running in a REPL
23 | as opposed to standalone mode. For example, if the script's author opts to
24 | follow the "if main" convention, then the script will only run in standalone
25 | mode as `__name__ == "betse.repl.environment"` within the REPL. This boolean
26 | simplifies matters by allowing logic resembling:
27 |
28 | if __name__ == '__main__' or __betse_repl__:
29 | ...
30 |
31 | or if behavior should differ between hosted and standalone modes:
32 |
33 | if __name__ == '__main__':
34 | ...
35 | elif __betse_repl__:
36 | ...
37 | '''
38 |
39 | # ....................{ GLOBALS ~ env }....................
40 | REPL_ENV = locals()
41 | '''
42 | Dictionary mapping from the names to values of all attributes defined by this
43 | submodule, including those defined by the :mod:`betse.script` subpackage.
44 | '''
45 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/queues.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **queue** (i.e., First-In, First-Out (FIFO) data structure, typically
8 | backed by the standard :class:`collections.deque` type) functionality.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | import itertools
13 | from betse.util.type.types import type_check, QueueType
14 |
15 | # ....................{ POPPERS }....................
16 | @type_check
17 | def pop_left(queue: QueueType, count: int) -> None:
18 | '''
19 | Pop (i.e., remove) the passed number of items from the head of the passed
20 | queue in a modestly efficient manner in-place (i.e., modifying the passed
21 | queue itself).
22 |
23 | Parameters
24 | ----------
25 | queue : QueueType
26 | Queue to pop this number of items from the head of.
27 | count : int
28 | Number of items to pop from the head of this queue.
29 |
30 | See Also
31 | ----------
32 | https://stackoverflow.com/questions/9507636/how-can-i-pop-lots-of-elements-from-a-deque#comment12041956_9507840
33 | StackOverflow comment strongly inspiring this implementation.
34 | '''
35 |
36 | # The following implementation is assumed but has yet to be profiled to be
37 | # the optimally efficient solution. Alternatives include a map()-based
38 | # solution, which commonly profiles slower than comparable starmap()-based
39 | # solutions in the general case:
40 | # map(apply, repeat(queue.popleft, count))
41 | list(itertools.starmap(queue.popleft, itertools.repeat((), count)))
42 |
--------------------------------------------------------------------------------
/betse/util/type/text/chars.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **character** (i.e., string of length 1) facilities.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from betse.exceptions import BetseCharException
12 | from betse.util.type.types import type_check
13 |
14 | # ....................{ EXCEPTIONS }....................
15 | @type_check
16 | def die_unless_char(text: str) -> None:
17 | '''
18 | Raise an exception unless the passed string is a **character** (i.e., of
19 | length 1).
20 |
21 | Parameters
22 | ----------
23 | text : str
24 | String to be validated.
25 |
26 | Raises
27 | ----------
28 | BetseCharException
29 | If this string is either:
30 | * The empty string.
31 | * Of length greater than 1.
32 | '''
33 |
34 | # If this string is *NOT* a character, raise an exception.
35 | if not is_char(text):
36 | raise BetseCharException(
37 | 'String "{}" not a character '
38 | '(i.e., either empty or of length >= 2).'.format(text))
39 |
40 | # ....................{ TESTERS ~ case }....................
41 | @type_check
42 | def is_char(text: str) -> bool:
43 | '''
44 | ``True`` only if the passed string is a **character** (i.e., of length 1).
45 |
46 | Parameters
47 | ----------
48 | text : str
49 | String to be tested.
50 |
51 | Returns
52 | ----------
53 | bool
54 | ``True`` only if this string is a character.
55 | '''
56 |
57 | # Don't judge us.
58 | return len(text) == 1
59 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/test_import.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests for BETSE's Python API testing the importability of fragile public
8 | modules and packages (e.g., containing cyclic import statements subject to
9 | breaking by brute-force PyCharm refactorings).
10 | '''
11 |
12 | # ....................{ IMPORTS }....................
13 | from betse.util.test.pytest.mark.pytfail import xfail
14 | # from betse_test.mark.skip import skip_unless_plugin_xdist
15 |
16 | # ....................{ TESTS }....................
17 | #FIXME: Ugh! Ideally, this test should *NOT* require xdist support. This test
18 | #must be isolated to a subprocess. To do so, the simplest means is the xdist
19 | #"--boxed" CLI option. However, we'd only want *THIS* test to be isolated in
20 | #that manner -- not *EVERY* test! To do so, we'll probably want to examine the
21 | #xdist codebase, ascertain how "--boxed" is implemented, and provide a new
22 | #utility test function or decorator performing the equivalent. Alternately,
23 | #PyInstaller's testing framework already supports test isolation (probably using
24 | #the "subprocess" module), suggesting we could also examine that as a fallback.
25 |
26 | # @skip_unless_plugin_xdist
27 | @xfail(reason='Test isolation unsupported.')
28 | def test_import_logs() -> None:
29 | '''
30 | Test the importability of BETSE's logging API.
31 |
32 | This API contains cyclic import statements commonly broken by PyCharm's
33 | brute-force refactorings.
34 | '''
35 |
36 | # Import this API and call all functionality containing these statements.
37 | from betse.util.io.log import logs
38 | logs.get_logger()
39 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/mark/pytfail.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level :mod:`pymod`-based decorators failing tests.
8 |
9 | These decorators conditionally mark their decorated tests as failing depending
10 | on whether the conditions signified by the passed parameters are satisfied
11 | (e.g., the importability of the passed module name).
12 | '''
13 |
14 | # ....................{ IMPORTS }....................
15 | import pytest
16 | from betse.util.type.types import type_check
17 |
18 | # ....................{ FAIL ~ alias }....................
19 | xfail_if = pytest.mark.xfail
20 | '''
21 | Conditionally mark the decorated test as ignorably known to fail with the
22 | passed human-readable justification if the passed boolean is ``False``.
23 |
24 | Parameters
25 | ----------
26 | boolean : bool
27 | Boolean to be tested.
28 | reason : str
29 | Human-readable message justifying the failure of this test.
30 |
31 | See Also
32 | ----------
33 | :func:`pytest.mark.xfail`
34 | Further details on the ``XFAIL`` test state.
35 | '''
36 |
37 |
38 | @type_check
39 | def xfail(reason: str):
40 | '''
41 | Unconditionally mark the decorated test as ignorably known to fail with the
42 | passed human-readable justification.
43 |
44 | :mod:`pytest` will neither run this test nor accumulate this failure. While
45 | superficially similar to tests unconditionally skipped via the ``@skip()``
46 | decorator, this failure will be collected as an `XFAIL` by py.test
47 | reporting.
48 |
49 | Parameters
50 | ----------
51 | reason : str
52 | Human-readable message justifying the failure of this test.
53 | '''
54 |
55 | return xfail_if(True, reason=reason)
56 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/iterable/test_iterables.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests exercising the :mod:`betse.util.type.iterable.iterables` submodule.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 |
12 | # ....................{ TESTS ~ default }....................
13 | #FIXME: Exercise all remaining edge cases... of which there are many. See the
14 | #iterables.to_iterable() docstring for further details.
15 | def test_to_iterable() -> None:
16 | '''
17 | Unit test the
18 | :func:`betse.util.type.iterable.iterables.to_iterable` function.
19 | '''
20 |
21 | # Defer heavyweight imports.
22 | from betse.util.type.iterable import iterables
23 |
24 | # Input tuple to be converted from.
25 | howl_tuple = (
26 | 'incomparable blind streets of shuddering cloud',
27 | 'and lightning in the mind leaping toward poles',
28 | 'of Canada & Paterson,',
29 | 'illuminating all the motionless world',
30 | 'of Time between,',
31 | )
32 |
33 | # Input generator to be converted from.
34 | howl_generator = (stanza for stanza in howl_tuple)
35 |
36 | # Test whether this conversion preserves this input tuple as is.
37 | assert iterables.to_iterable(iterable=howl_tuple) is howl_tuple
38 |
39 | # Test whether this conversion converts this input tuple into an output
40 | # iterable of differing type.
41 | assert iterables.to_iterable(iterable=howl_tuple, cls=set) == set(
42 | howl_tuple)
43 |
44 | # Test whether this conversion converts this input generator into an output
45 | # tuple identical to this input tuple.
46 | assert iterables.to_iterable(iterable=howl_generator) == howl_tuple
47 |
--------------------------------------------------------------------------------
/betse/science/visual/plot/plotabc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
5 | '''
6 | Abstract base classes of all post-simulation plot subclasses.
7 | '''
8 |
9 | # ....................{ IMPORTS }....................
10 | from betse.science.phase.phasecls import SimPhase
11 | from betse.science.visual.visabc import VisualCellsABC
12 | from betse.util.type.types import type_check
13 |
14 | # ....................{ CLASSES }....................
15 | class PlotCellsAfterSolving(VisualCellsABC):
16 | '''
17 | Abstract base class of all post-simulation cell plot subclasses, plotting
18 | simulation data over the cell cluster _after_ rather than _during_
19 | simulation modelling.
20 | '''
21 |
22 | @type_check
23 | def __init__(
24 | self,
25 | phase: SimPhase,
26 | *args, **kwargs
27 | ) -> None:
28 | '''
29 | Initialize this post-simulation plot.
30 |
31 | Parameters
32 | ----------
33 | phase: SimPhase
34 | Current simulation phase.
35 |
36 | See the superclass `__init__()` method for all remaining parameters.
37 | '''
38 |
39 | # Initialize our superclass.
40 | super().__init__(
41 | *args,
42 |
43 | # Pass this simulation phase as is to our superclass.
44 | phase=phase,
45 |
46 | # Save and show this post-simulation plot only if this configuration
47 | # enables doing so.
48 | is_save=phase.p.plot.is_after_sim_save,
49 | is_show=phase.p.plot.is_after_sim_show,
50 |
51 | # Save all post-simulation plots to the same parent directory.
52 | save_dir_parent_basename='plot',
53 |
54 | # Pass all remaining arguments as is to our superclass.
55 | **kwargs
56 | )
57 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/README.md:
--------------------------------------------------------------------------------
1 | Unit Tests
2 | ===========
3 |
4 | [`py.test`](http://pytest.org)-driven [unit
5 | tests](https://en.wikipedia.org/wiki/Functional_testing) exercising BETSE's
6 | programmatic Python API.
7 |
8 | ## Structure
9 |
10 | For collective sanity, tests are rigorously structured as follows:
11 |
12 | ### Unit Tests
13 |
14 | Each unit test should be:
15 |
16 | * Defined as a function named `test_unit_{test_name}` (e.g.,
17 | `test_unit_mpl_import`, a unit test exercising the importability of BETSE's
18 | Matplotlib API), where `{test_name}` is this test's unique name.
19 | * In a module with basename `test_{tests_name}.py` (e.g., `test_mpl.py`, a suite
20 | of unit tests exercising BETSE's Matplotlib API), where `{tests_name}` is any
21 | arbitrary non-empty string.
22 |
23 | ### Unit Test Fixtures
24 |
25 | Each **unit test fixture** (i.e., callable depended upon by one or more unit
26 | tests, typically preparing the external environment or filesystem for subsequent
27 | test execution) should be:
28 |
29 | * Defined as a function named `betse_{fixture_name}` (e.g., `betse_sim_context`,
30 | a fixture establishing a simulation configuration for subsequent reuse by
31 | several functional tests), where `{fixture_name}` is any arbitrary non-empty
32 | string. The `betse_` prefix future-proofs testing by preventing collisions
33 | between BETSE-specific fixtures and existing or future fixtures provided by
34 | either `py.test` itself or a third-party `py.test` plugin.
35 | * In a module with any basename residing in the `fixture` subpackage.
36 | * Imported by this package's `conftest` module, effectively
37 | implicitly this fixture in all unit test modules. While this fixture is
38 | explicitly importable in these modules, there are no tangible benefits to
39 | doing so and several tangible detriments -- including:
40 | * **Refactorability.** Since `py.test` silently adds this directory to
41 | Python's `sys.path` when testing, refactoring tools and IDEs have no means
42 | of automatically parsing and thus refactoring test and fixture imports.
43 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/fixture/pytfixture.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level :mod:`pytest` fixtures.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from pytest import fixture
12 |
13 | # ....................{ FIXTURES }....................
14 | @fixture(scope='session')
15 | def monkeypatch_session():
16 | '''
17 | Session-scoped ``monkeypatch`` fixture.
18 |
19 | Caveats
20 | -------
21 | **The ``monkeypatch`` fixture should never be referenced from session-scoped
22 | fixtures.** Doing so raises the following fatal error on session startup:
23 |
24 | ScopeMismatch: You tried to access the 'function' scoped fixture
25 | 'monkeypatch' with a 'session' scoped request object, involved
26 | factories
27 |
28 | This equivalent fixture suffers no such deficits and hence should be
29 | referenced from session-scoped fixtures instead.
30 |
31 | Returns
32 | -------
33 | _pytest.monkeypatch.MonkeyPatch
34 | Object returned by the `monkeypatch` fixture keeping a record of
35 | :func:`setattr`, item, environment, and :attr:`sys.path` changes.
36 |
37 | See Also
38 | --------
39 | https://github.com/pytest-dev/pytest/issues/363#issuecomment-406536200
40 | GitHub comment strongly inspiring this implementation.
41 | '''
42 |
43 | # Defer violations of privacy encapsulation for safety. Tragically, this
44 | # class is inaccessible via any other means.
45 | from _pytest.monkeypatch import MonkeyPatch
46 |
47 | # Create and yield to the calling session-scoped fixture a new
48 | # monkey-patcher instance.
49 | monkey_patch = MonkeyPatch()
50 | yield monkey_patch
51 |
52 | # Revert all temporary changes applied to this instance by the calling
53 | # session-scoped fixture.
54 | monkey_patch.undo()
55 |
--------------------------------------------------------------------------------
/betse/science/config/export/visual/confexpvisual.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Visual export subconfiguration** (i.e., YAML-backed wrapper exposing settings
8 | globally applicable to all visual exports) functionality.
9 | '''
10 |
11 | #FIXME: Refactor all remaining visual export-centric settings currently defined
12 | #as "Parameters" instance variables into data descriptors defined below.
13 |
14 | # ....................{ IMPORTS }....................
15 | from betse.lib.yaml.yamlalias import yaml_alias
16 | from betse.lib.yaml.abc.yamlabc import YamlABC
17 | # from betse.util.type.types import type_check
18 |
19 | # ....................{ SUBCLASSES }....................
20 | class SimConfExportVisual(YamlABC):
21 | '''
22 | **Visual export subconfiguration** (i.e., YAML-backed wrapper exposing
23 | settings globally applicable to all visual exports).
24 |
25 | Attributes (Cell: Indices)
26 | ----------
27 | is_show_cell_indices : bool
28 | ``True`` only if the 0-based indices of all cells are to be displayed
29 | over all cell cluster visuals (e.g., as integers situated at cell
30 | centres).
31 | single_cell_index : int
32 | 0-based index of the cell to be visualized for all single cell visuals.
33 | Defaults to 0, the index assigned to the first cell guaranteed to
34 | exist. Note that cell indices are seed-specific and may be visualized
35 | by enabling the :attr:`is_show_cell_indices` boolean.
36 | '''
37 |
38 | # ..................{ ALIASES ~ cell : index }..................
39 | is_show_cell_indices = yaml_alias(
40 | "['results options']['visuals']['cell indices']['show']", bool)
41 |
42 | #FIXME, Consider generalizing this into a list.
43 | single_cell_index = yaml_alias(
44 | "['results options']['visuals']['cell indices']['single cell']", int)
45 |
--------------------------------------------------------------------------------
/betse/science/enum/enumphase.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Simulation modelling enumerations** (i.e., :class:`enum.Enum` subclasses
8 | internally required by simulation modelling phases).
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.type import enums
13 |
14 | # ....................{ ENUMS }....................
15 | SimPhaseKind = enums.make_enum(
16 | class_name='SimPhaseKind',
17 | member_names=('SEED', 'INIT', 'SIM',),
18 | is_ordered=True,
19 | doc='''
20 | Ordered enumeration of all supported types of **simulation phases** (i.e.,
21 | consecutive steps for the process of simulating simulation configurations).
22 |
23 | Each member of this enumeration is arbitrarily comparable to each other member.
24 | Each member's value is less than that of another member's value if and only if
25 | the former simulation phase is performed _before_ the latter. Specifically,
26 | this enumeration is a total ordering such that:
27 |
28 | >>> SimPhaseKind.SEED < SimPhaseKind.INIT < SimPhaseKind.SIM
29 | True
30 |
31 | Attributes
32 | ----------
33 | SEED : enum
34 | Seed simulation phase, as implemented by the
35 | :meth:`betse.science.simrunner.SimRunner.seed` method. This phase creates
36 | the cell cluster and caches this cluster to an output file.
37 | INIT : enum
38 | Initialization simulation phase, as implemented by the
39 | :meth:`betse.science.simrunner.SimRunner.init` method. This phase
40 | initializes the previously created cell cluster from a cached input file
41 | and caches this initialization to an output file.
42 | SIM : enum
43 | Proper simulation phase, as implemented by the
44 | :meth:`betse.science.simrunner.SimRunner.sim` method. This phase simulates
45 | the previously initialized cell cluster from a cached input file and caches
46 | this simulation to an output file.
47 | ''')
--------------------------------------------------------------------------------
/betse/science/enum/enumion.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Ionic enumerations** (i.e., :class:`enum.Enum` subclasses required to
8 | differentiate between various types of ions).
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.type import enums
13 | from betse.util.type.types import GeneratorType
14 |
15 | # ....................{ ITERATORS }....................
16 | def iter_ion_names() -> GeneratorType:
17 | '''
18 | Generator yielding the unmodified name of each supported type of ion
19 | specified by the :class:`IonType` enumeration (in lexicographic order).
20 |
21 | Returns
22 | ----------
23 | GeneratorType
24 | Generator yielding each such name.
25 | '''
26 |
27 | # Let there be ion.
28 | yield from enums.iter_names(IonType)
29 |
30 | # ....................{ ENUMS }....................
31 | IonType = enums.make_enum(
32 | class_name='IonType',
33 | member_names=('Na', 'K', 'Ca', 'Cl', 'M', 'P',),
34 | is_ordered=True,
35 | doc='''
36 | Ordered enumeration of all supported types of **ions** (i.e., atoms or
37 | molecules having lost or gained electrons and hence net electric charge).
38 |
39 | For brevity, the names of these types are intentionally condensed to their
40 | standard abbreviations rather than elongated to their human-readable nouns
41 | (e.g., ``Na`` rather than ``SODIUM``). Doing so also improves interoperability
42 | with the remainder of the codebase, which first invented this nomenclature.
43 |
44 | Attributes
45 | ----------
46 | Na : enum
47 | Sodium cation Na+.
48 | K : enum
49 | Potassium cation K+.
50 | Ca : enum
51 | Calcium cation Ca2+.
52 | Cl : enum
53 | Chloride anion Cl-.
54 | M : enum
55 | Unidentified anion M-, synthetically manufactured to enforce
56 | charge-balancing across the environmental matrix for both simulation
57 | stability and correctness.
58 | P : enum
59 | Anionic protein P-.
60 | ''')
61 |
--------------------------------------------------------------------------------
/betse/gui/interact.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
5 |
6 | import matplotlib.pyplot as plt
7 |
8 | class PolyPicker(object):
9 | """
10 | Allows the user to interactively select cell polygons from a graph.
11 | Once selected, polygons turn bright blue.
12 | The process is complete when the figure window is closed.
13 | Returns a list of indices to cells, which will have properties
14 | changed (e.g. ion channels added) depending on how the polypicker
15 | is used in the main script.
16 |
17 | """
18 |
19 | def __init__(self,cells,p,resume_after_picking):
20 |
21 | self.resume_after_picking = resume_after_picking
22 | self.picked_indices = []
23 | self.plotPatch(cells,p)
24 | # self.fig.canvas.mpl_connect('pick_event', self.get_inds)
25 | self.cidpick = self.fig.canvas.mpl_connect('pick_event', self)
26 | self.cidclose = self.fig.canvas.mpl_connect('close_event', self.on_close)
27 |
28 | def plotPatch(self,cells,p):
29 |
30 | self.fig = plt.figure()
31 | self.ax = plt.subplot(111)
32 |
33 | for i, poly in enumerate(cells.cell_verts):
34 | plygn = plt.Polygon(p.um*poly,facecolor='b')
35 | plygn.set_picker(True)
36 | plygn.set_alpha(0.25)
37 | plygn.ind = i
38 | self.ax.add_patch(plygn)
39 | self.ax.set_xlabel('Spatial distance x [um]')
40 | self.ax.set_ylabel('Spatial distance y [um]')
41 | self.ax.set_title('Select Cells with Mouse Click')
42 |
43 | self.ax.axis('equal')
44 | self.ax.autoscale_view()
45 |
46 | plt.show(block=False)
47 |
48 | def on_pick(self,event):
49 |
50 | patch = event.artist
51 | patch.set_alpha(1.0)
52 | self.index = patch.ind
53 | self.fig.canvas.draw()
54 | self.picked_indices.append(self.index)
55 |
56 | def on_close(self, event):
57 | self.fig.canvas.mpl_disconnect(self.cidclose)
58 | self.fig.canvas.mpl_disconnect(self.cidpick)
59 | self.resume_after_picking(self)
60 |
61 | def __call__(self, event):
62 | self.on_pick(event)
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/betse_test/a90_func/README.md:
--------------------------------------------------------------------------------
1 | Functional Tests
2 | ===========
3 |
4 | [`py.test`](http://pytest.org)-driven [functional
5 | tests](https://en.wikipedia.org/wiki/Functional_testing) exercising the
6 | currently installed versions of BETSE's external CLI and GUI commands.
7 |
8 | ## Structure
9 |
10 | For collective sanity, tests are rigorously structured as follows:
11 |
12 | ### Functional Tests
13 |
14 | Each functional test should be:
15 |
16 | * Defined as a function named `test_{ui_type}_{test_name}` (e.g.,
17 | `test_cli_betse_info`, a functional test exercising the `betse info`
18 | subcommand of BETSE's CLI), where:
19 | * `{ui_type}` is either:
20 | * `cli`, for functional tests exercising the BETSE CLI.
21 | * `gui`, for functional tests exercising the BETSE GUI.
22 | * `{test_name}` is this test's unique name.
23 | * In a module with basename `test_{tests_name}.py` (e.g., `test_cli.py`, a suite
24 | of functional tests exercising BETSE's CLI), where `{tests_name}` is any
25 | arbitrary non-empty string, residing in either the `cli` or `gui` subpackages.
26 |
27 | ### Functional Test Fixtures
28 |
29 | Each **functional test fixture** (i.e., callable depended upon by one or more
30 | functional tests, typically preparing the external environment or filesystem for
31 | subsequent test execution) should be:
32 |
33 | * Defined as a function named `betse_{fixture_name}` (e.g., `betse_sim_context`,
34 | a fixture establishing a simulation configuration for subsequent reuse by
35 | several functional tests), where `{fixture_name}` is any arbitrary non-empty
36 | string. The `betse_` prefix future-proofs testing by preventing collisions
37 | between BETSE-specific fixtures and existing or future fixtures provided by
38 | either `py.test` itself or a third-party `py.test` plugin.
39 | * In a module with any basename residing in the `fixture` subpackage.
40 | * Imported by the topmost `conftest` module of this package, effectively
41 | implicitly this fixture in all functional test modules. While this fixture is
42 | explicitly importable in these modules, there are no tangible benefits to
43 | doing so and several tangible detriments -- including:
44 | * **Refactorability.** Since `py.test` silently adds this directory to
45 | Python's `sys.path` when testing, refactoring tools and IDEs have no means
46 | of automatically parsing and thus refactoring test and fixture imports.
47 |
--------------------------------------------------------------------------------
/betse/science/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | :mod:`betse.science` initialization functionality.
8 |
9 | Motivation
10 | ----------
11 | This submodule guarantees that, on the first importation of the
12 | :mod:`betse.science` subpackage, both the current application *and* all
13 | mandatory third-party dependencies of this application have been initialized
14 | with sane defaults.
15 |
16 | This submodule is effectively syntactic sugar. While technically unnecessary,
17 | this submodule streamlines interactive use (e.g., from web-based Jupyter
18 | notebooks or CLI-based iPython consoles) by implicitly guaranteeing this
19 | application to be fully usable *without* manual intervention by end users.
20 |
21 | This submodule silently reduces to a noop when this application has already
22 | been initialized, as is the common case.
23 | '''
24 |
25 | #FIXME: Enforce BETSE initialization on the first import of any BETSE submodule
26 | #by shifting the entirety of this submodule to "betse.__init__" *AFTER*
27 | #stripping out the "betse.lib" and "betse.util" subpackages into a new
28 | #third-party "brutil" package. Why after? Because shifting this submodule now
29 | #would prevent downstream consumers (e.g., BETSEE) from setting the application
30 | #metadata singleton to a downstream preference, which would be bad. Indeed,
31 | #this is the best justification for "brutil" we've stumbled over yet.
32 |
33 | # ....................{ IMPORTS }....................
34 | from betse.util.app.meta import appmetaone as _appmetaone
35 |
36 | # ....................{ MAIN }....................
37 | # Instantiate and set a BETSE-specific application metadata singleton if the
38 | # appmetaone.set_app_meta() function has yet to be called elsewhere.
39 | _app_meta = _appmetaone.set_app_meta_betse_if_unset()
40 |
41 | # Initialize all mandatory third-party dependencies if the
42 | # _app_meta.init_libs() method has yet to be called elsewhere.
43 | _app_meta.init_libs_if_needed()
44 |
45 | # ....................{ CLEANUP }....................
46 | # Delete *ALL* attributes (including callables) defined above, preventing the
47 | # package namespace from being polluted with these attributes.
48 | del _appmetaone, _app_meta
49 |
--------------------------------------------------------------------------------
/betse/science/channels/channelsabc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 |
5 | '''
6 | Abstract base classes of all channel classes.
7 | '''
8 |
9 | # ....................{ IMPORTS }....................
10 | from abc import ABCMeta, abstractmethod
11 | import numpy as np
12 | from betse.science import sim_toolbox as stb
13 | from betse.science.math import toolbox as tb
14 |
15 | # ....................{ BASE }....................
16 | class ChannelsABC(object, metaclass=ABCMeta):
17 | '''
18 | Abstract base class of all channel classes.
19 |
20 | Attributes
21 | ----------
22 | '''
23 | @abstractmethod
24 | def init(self, vm, cells, p, targets = None):
25 | '''
26 | Runs the initialization sequence for a voltage gated ion channel.
27 | '''
28 |
29 | pass
30 |
31 |
32 |
33 | @abstractmethod
34 | def run(self, vm, p):
35 | '''
36 | Runs the voltage gated ion channel.
37 | '''
38 | pass
39 |
40 | def update_mh(self, p, time_unit = 1e3):
41 | """
42 | Updates the 'm' and 'h' gating functions of the channel model for
43 | standard Hodgkin-Huxley formalism channel models.
44 |
45 | """
46 |
47 | # Update channel state using RK4:------------------------------------
48 | # dm = tb.RK4(lambda m: (self._mInf - self.m) / (self._mTau))
49 | # dh = tb.RK4(lambda h: (self._hInf - self.h) / (self._hTau))
50 | #
51 | # self.m += dm(self.m, p.dt)
52 | # self.h += dh(self.h, p.dt)
53 |
54 | # Update channel state using semi-Implicit Euler method:-------------------
55 | dt = p.dt*self.time_unit
56 |
57 | self.m = (self._mTau*self.m + dt*self._mInf)/(self._mTau + dt)
58 | self.h = (self._hTau*self.h + dt*self._hInf)/(self._hTau + dt)
59 |
60 | def update_ml(self, p, time_unit = 1e3):
61 | """
62 | An iterative time-step updating method for the
63 | time-dependent Morris-Lecar formalism of voltage-gated
64 | ion channels (a variant of Hodgkin-Huxley)
65 | :param p: Parameters
66 | :param time_unit:
67 | :return:
68 | """
69 |
70 | dt = p.dt * self.time_unit
71 | self.m = (self.m + (dt * self.Phi * self._mInf / self._mTau)) / (1 + ((dt * self.Phi) / self._mTau))
72 |
--------------------------------------------------------------------------------
/betse/util/io/stderrs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level standard error facilities.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | import sys, traceback
12 | from betse.util.type.types import type_check, StrOrNoneTypes
13 |
14 | # ....................{ OUTPUTTERS }....................
15 | @type_check
16 | def output(*texts: str) -> None:
17 | '''
18 | Print all passed strings to stderr *without* logging these strings.
19 |
20 | This function is intentionally *not* named :func:`print`, as doing so would
21 | invite conflicts with the standard :func:`print` function.
22 | '''
23 |
24 | print(*texts, file=sys.stderr)
25 |
26 |
27 | @type_check
28 | def output_warning(*warnings: str) -> None:
29 | '''
30 | Print all passed strings (prefixed by a suitable human-readable warning
31 | label) to stderr *without* logging these strings.
32 | '''
33 |
34 | # ...that was easier than expected.
35 | output('WARNING: ', *warnings)
36 |
37 | # ....................{ OUTPUTTERS ~ exception }....................
38 | @type_check
39 | def output_exception(heading: StrOrNoneTypes = None) -> None:
40 | '''
41 | Print the currently caught exception to stderr *without* logging this
42 | exception optionally preceded by the passed human-readable heading if any.
43 |
44 | Parameters
45 | ----------
46 | heading : optional[str]
47 | Optional human-readable heading to be printed before this exception if
48 | any *or* ``None`` if no heading is to be printed.
49 | '''
50 |
51 | #FIXME: Assert that an exception has actually been raised here.
52 |
53 | # If a heanding is passed, print this heading to stderr.
54 | if heading is not None:
55 | output(heading)
56 |
57 | # Print this exception to stderr.
58 | traceback.print_exc(file=sys.stderr)
59 |
60 |
61 | def output_traceback() -> None:
62 | '''
63 | Print the current call stack to stderr *without* logging this call stack.
64 | '''
65 |
66 | # Avoid circular import dependencies.
67 | from betse.util.type.call import callers
68 |
69 | # Print this call stack, excluding the calls to both this and the
70 | # callers.get_traceback() functions.
71 | output(callers.get_traceback(-2))
72 |
--------------------------------------------------------------------------------
/betse/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Top-level application namespace.
8 |
9 | For PEP 8 compliance, this namespace exposes a subset of the metadata constants
10 | provided by the :mod:`betse.metadata` module commonly inspected by external
11 | automation.
12 | '''
13 |
14 | # ....................{ IMPORTS }....................
15 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16 | # WARNING: To avoid race conditions during setuptools-based installation, this
17 | # module may import *ONLY* from modules guaranteed to exist at the start of
18 | # installation. This includes all standard Python and application modules but
19 | # *NOT* third-party dependencies, which if currently uninstalled will only be
20 | # installed at some later time in the installation. Likewise, to avoid circular
21 | # import dependencies, the top-level of this module should avoid importing
22 | # application modules where feasible.
23 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
24 |
25 | # ....................{ IMPORTS }....................
26 | # Subject all subsequent imports to @beartype-based hybrid runtime-static
27 | # type-checking *BEFORE* importing anything further.
28 | # from beartype import BeartypeConf
29 | from beartype.claw import beartype_this_package
30 | beartype_this_package()
31 |
32 | # For PEP 8 compliance, versions constants expected by external automation are
33 | # imported under their PEP 8-mandated names.
34 | from betse.metadata import VERSION as __version__
35 | from betse.metadata import VERSION_PARTS as __version_info__
36 |
37 | # ....................{ GLOBALS }....................
38 | # Document all global variables imported into this namespace above.
39 |
40 | __version__
41 | '''
42 | Human-readable application version as a ``.``-delimited string.
43 |
44 | For PEP 8 compliance, this specifier has the canonical name ``__version__``
45 | rather than that of a typical global (e.g., ``VERSION_STR``).
46 | '''
47 |
48 |
49 | __version_info__
50 | '''
51 | Machine-readable application version as a tuple of integers.
52 |
53 | For PEP 8 compliance, this specifier has the canonical name
54 | ``__version_info__`` rather than that of a typical global (e.g.,
55 | ``VERSION_PARTS``).
56 | '''
57 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/numeric/test_floats.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests exercising the :mod`betse.util.type.numeric.floats` submodule.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | # import pytest
12 |
13 | # ....................{ TESTS ~ base 10 }....................
14 | def test_float_get_base_10_exponent() -> None:
15 | '''
16 | Unit test the :func:`betse.util.type.numeric.floats.get_base_10_exponent`
17 | getter.
18 | '''
19 |
20 | # Defer heavyweight imports.
21 | from betse.util.type.numeric import floats
22 |
23 | # Assert this getter to behave as expected on common edge cases.
24 | assert floats.get_base_10_exponent(7.77e+66) == 66
25 | assert floats.get_base_10_exponent(6.66e-77) == -77
26 | assert floats.get_base_10_exponent(0.000123456789) == -4
27 | assert floats.get_base_10_exponent(100001234567.9) == 11
28 |
29 |
30 | def test_float_get_base_10_precision() -> None:
31 | '''
32 | Unit test the :func:`betse.util.type.numeric.floats.get_base_10_precision`
33 | getter.
34 | '''
35 |
36 | # Defer heavyweight imports.
37 | from betse.util.type.numeric import floats
38 |
39 | # Assert this getter to behave as expected on common edge cases, including:
40 | #
41 | # * A large float formatted in scientific notation by the str() builtin.
42 | # * A small float formatted in scientific notation by the str() builtin.
43 | # * A small float with a leading digit formatted in decimal notation by the
44 | # str() builtin.
45 | # * A small float with no leading digit formatted in decimal notation by the
46 | # str() builtin.
47 | #
48 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
49 | # CAUTION: Python implicitly reformats all floating point numbers smaller
50 | # than 0.0001 when converted to strings in scientific rather than decimal
51 | # notation. Hence, small floats should be no smaller than 0.0001.
52 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
53 | assert floats.get_base_10_precision(7.77e+66) == 66
54 | assert floats.get_base_10_precision(6.66e-77) == 77
55 | assert floats.get_base_10_precision(0.000123456789) == 12
56 | assert floats.get_base_10_precision( .000123456789) == 12
57 |
--------------------------------------------------------------------------------
/betse/science/config/grn/confgrn.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | YAML-backed gene regulatory network (GRN) subconfigurations.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from betse.lib.yaml.yamlalias import yaml_alias
12 | from betse.lib.yaml.abc.yamlfileabc import YamlFileABC
13 | # from betse.science.config.grn.confgrnyadda import SimConfGrnYadda
14 | from betse.util.type.types import type_check #, MappingType, SequenceTypes
15 |
16 | # ....................{ SUBCLASSES }....................
17 | class SimConfGrnFile(YamlFileABC):
18 | '''
19 | YAML-backed in-memory and on-disk gene regulatory network (GRN)
20 | subconfiguration, encapsulating a low-level container of *all* GRN-related
21 | configuration settings both loaded from and saved back to a YAML-formatted
22 | configuration file.
23 |
24 | Attributes (General)
25 | ----------
26 | '''
27 |
28 | # ..................{ ALIASES }..................
29 | # is_overlay_current = yaml_alias(
30 | # "['results options']['overlay currents']", bool)
31 |
32 | # ..................{ INITIALIZERS }..................
33 | def __init__(self, *args, **kwargs) -> None:
34 |
35 | # Initialize our superclass with all passed parameters.
36 | super().__init__(*args, **kwargs)
37 |
38 | # Encapsulate low-level dictionaries with high-level wrappers.
39 | # self.anim_while_sim = SimConfExportAnimCellsEmbedded()
40 |
41 | # Encapsulate low-level lists of dictionaries with high-level wrappers.
42 | # self.anims_after_sim = SimConfExportVisualCells.make_list()
43 |
44 | # ..................{ LOADERS }..................
45 | def load(self, *args, **kwargs) -> None:
46 |
47 | # Load our superclass with all passed arguments.
48 | super().load(*args, **kwargs)
49 |
50 | # Load all subconfigurations of this configuration.
51 | # self.anim_while_sim.load(conf=self._conf[
52 | # 'results options']['while solving']['animations'])
53 |
54 |
55 | def unload(self) -> None:
56 |
57 | # Unload our superclass.
58 | super().unload()
59 |
60 | # Unload all subconfigurations of this configuration.
61 | # self.anim_while_sim.unload()
62 |
--------------------------------------------------------------------------------
/betse/lib/numpy/npscalar.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **Numpy-specific scalar** (i.e., primitive non-standard data types
8 | specific to the Numpy API) facilities.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | # import numpy as np
13 | # from betse.util.io.log import logs
14 | from betse.util.type.types import type_check, NumpyScalarType, ScalarTypes
15 |
16 | # ....................{ CONVERTERS }....................
17 | @type_check
18 | def to_python(scalar: NumpyScalarType) -> ScalarTypes:
19 | '''
20 | Standard Numpy-agnostic scalar (e.g., :class:`bool`) losslessly coerced
21 | from the passed non-standard Numpy-specific scalar (e.g.,
22 | :class:`np.bool_`).
23 |
24 | This function converts the passed Numpy scalar to the corresponding Python
25 | scalar such that the latter is guaranteed to be a **lossless copy** (i.e.,
26 | copy with *no* appreciable loss in numerical precision) of the former.
27 |
28 | Parameters
29 | ----------
30 | scalar : NumpyScalarType
31 | Numpy-specific scalar to be converted into the corresponding
32 | Numpy-agnostic scalar.
33 |
34 | Returns
35 | ----------
36 | ScalarTypes
37 | Numpy-agnostic scalar converted from this Numpy-specific scalar.
38 |
39 | See Also
40 | ----------
41 | https://stackoverflow.com/a/11389998/2809027
42 | StackOverflow answer strongly inspiring this implementation.
43 |
44 | Examples
45 | ----------
46 | >>> from betse.lib.numpy import npscalar
47 | >>> import numpy as np
48 | >>> python_bool = True
49 | >>> numpy_bool = np.bool_(python_bool)
50 | >>> numpy_bool
51 | True
52 | >>> numpy_bool is True
53 | False
54 | >>> numpy_bool == True
55 | False
56 | >>> python_numpy_bool = npscalar.to_python(numpy_bool)
57 | >>> python_numpy_bool
58 | True
59 | >>> python_numpy_bool is True
60 | True
61 | >>> python_numpy_bool == True
62 | True
63 | '''
64 |
65 | # This is insanity. This is Numpy. For further details, see the official
66 | # documentation for the numpy.ndarray.item() method at:
67 | # https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.item.html
68 | return scalar.item()
69 |
--------------------------------------------------------------------------------
/doc/md/USAGE.md:
--------------------------------------------------------------------------------
1 | Usage
2 | ===========
3 |
4 | > **NOTE:** This synopsis is _painfully_ inadequate. For detailed usage
5 | > instructions complete with explanatory examples, plots, and screenshots, see
6 | > our [77-page
7 | > PDF](https://www.dropbox.com/s/fsxhjpipbiog0ru/BETSE_Documentation_Nov1st2015.pdf?dl=0)
8 | > instead.
9 |
10 | BETSE is usable as follows.
11 |
12 | ## CLI
13 |
14 | BETSE is currently _only_ available as a low-level command-line interface (CLI)
15 | named `betse`, a Python wrapper script installed to the current `${PATH}` on
16 | [BETSE installation](INSTALL.md).
17 |
18 | ## GUI
19 |
20 | A high-level graphical user interface (GUI) named `betse-qt` implemented via
21 | non-[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License) Python
22 | bindings (e.g., [PySide](https://wiki.qt.io/PySide),
23 | [PySide2](https://wiki.qt.io/PySide2)) to the cross-platform
24 | non-[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License) [Qt]
25 | (https://www.qt.io) windowing toolkit is planned **but currently
26 | unimplemented.**
27 |
28 | Consider submitting a [feature request](https://gitlab.com/betse/betse/issues)
29 | if you would prefer to see this process prioritized.
30 |
31 | ## Python
32 |
33 | BETSE is intended to be used as a front-facing interactive application rather
34 | than as a backend non-interactive library.
35 |
36 | The **BETSE API** comprises the top-level
37 | [`betse` Python package](https://gitlab.com/betse/betse/tree/master/betse) and
38 | all subpackages and submodules of that package installed with BETSE. While the
39 | BETSE API _is_ externally importable by other Python packages, doing so is
40 | currently unsupported. The BETSE API is intended to be imported and used _only_
41 | by the first-party interfaces listed above.
42 |
43 | **The BETSE API is _not_ intended to be imported or used by third parties** –
44 | not because we don't like third parties,_We do!_ but because we lack
45 | sufficient resources (both grant funding _and_ developer time) to stabilize the
46 | BETSE API for public consumption. Until resources arrive, breaking API changes
47 | are likely to be a permanent fixture of the BETSE landscape.
48 |
49 | No [backward](https://en.wikipedia.org/wiki/Backward_compatibility) or
50 | [forward compatibility](https://en.wikipedia.org/wiki/Forward_compatibility)
51 | guarantees are currently provided. Third-party Python scripts (e.g., [IPython
52 | notebooks](http://jupyter.org)), frameworks, and applications attempting to
53 | leverage BETSE for internal use are likely to be disappointed.
54 |
55 | Consider submitting a [feature request](https://gitlab.com/betse/betse/issues)
56 | if you would prefer to see the BETSE API stabilized.
57 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a90_sim_cli/solve/test_sim_full.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | CLI-specific functional tests exercising the full simulation solver.
8 | '''
9 |
10 | # ....................{ TESTS }....................
11 | def test_cli_sim_full_noecm(betse_cli_sim: 'CLISimTester') -> None:
12 | '''
13 | Functional test exporting all available exports (e.g., CSVs, plots,
14 | animations) with all simulation features required by these exports,
15 | including the full solver but excluding extracellular spaces.
16 |
17 | Parameters
18 | ----------
19 | betse_cli_sim : CLISimTester
20 | Object running BETSE CLI simulation subcommands.
21 | '''
22 |
23 | # Enable all exports and features required by these exports, excluding ECM.
24 | betse_cli_sim.sim_state.config.enable_solver_full_exports_noecm()
25 |
26 | # Test all default simulation-specific subcommands with this configuration.
27 | betse_cli_sim.run_subcommands_try()
28 |
29 |
30 | def test_cli_sim_full_ecm(betse_cli_sim: 'CLISimTester') -> None:
31 | '''
32 | Functional test exporting all available exports (e.g., CSVs, plots,
33 | animations) with all simulation features required by these exports,
34 | including both the full solver and extracellular spaces.
35 |
36 | Parameters
37 | ----------
38 | betse_cli_sim : CLISimTester
39 | Object running BETSE CLI simulation subcommands.
40 | '''
41 |
42 | # Enable all exports and features required by these exports, including ECM.
43 | betse_cli_sim.sim_state.config.enable_solver_full_exports_ecm()
44 |
45 | # Test all default simulation-specific subcommands with this configuration.
46 | betse_cli_sim.run_subcommands_try()
47 |
48 |
49 | def test_cli_sim_full_vg_ions(betse_cli_sim: 'CLISimTester') -> None:
50 | '''
51 | Functional test simulating all voltage-gated ion channels (e.g., sodium,
52 | potassium) *and* simulation features required by these channels, including
53 | the full solver.
54 |
55 | Parameters
56 | ----------
57 | betse_cli_sim : CLISimTester
58 | Object running BETSE CLI simulation subcommands.
59 | '''
60 |
61 | # Enable all voltage-gated ion channels and features required by these
62 | # channels.
63 | betse_cli_sim.sim_state.config.enable_solver_full_vg_ions()
64 |
65 | # Test all simulation-specific subcommands *EXCLUDING* plotting subcommands
66 | # (which other tests already exercise) with this configuration.
67 | betse_cli_sim.run_subcommands_sim()
68 |
--------------------------------------------------------------------------------
/betse/__main__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Main entry point of this application's command line interface (CLI).
8 |
9 | This submodule is a thin wrapper intended to be:
10 |
11 | * Indirectly imported and run from external entry point scripts installed by
12 | setuptools (e.g., the ``betse`` command).
13 | * Directly imported and run from the command line (e.g., via
14 | ``python -m betse.cli``).
15 | '''
16 |
17 | # ....................{ IMPORTS }....................
18 | from beartype.typing import Collection
19 | from betse.util.os.command import cmdexit
20 |
21 | # ....................{ MAIN }....................
22 | def main(arg_list: Collection[str] = None) -> int:
23 | '''
24 | Run this application's command-line interface (CLI) with the passed
25 | arguments if non-``None`` *or* with the arguments passed on the command
26 | line (i.e., :attr:`sys.argv`) otherwise.
27 |
28 | This function is provided as a convenience to callers requiring procedural
29 | functions rather than conventional methods (e.g., :mod:`setuptools`).
30 |
31 | Parameters
32 | ----------
33 | arg_list : Collection[str]
34 | Collection of zero or more string arguments to pass to this interface.
35 | Defaults to :data:`None`, in which case arguments passed on the command
36 | line (i.e., :attr:`sys.argv`) will be used instead.
37 |
38 | Returns
39 | -------
40 | int
41 | Exit status of this interface and hence this process as an unsigned
42 | byte (i.e., integer in the range ``[0, 255]``).
43 | '''
44 |
45 | # Defer function-specific imports.
46 | from betse.appmeta import BetseAppMeta
47 | from betse.cli.climain import BetseCLI
48 |
49 | # Initialize this application (excluding mandatory dependencies of this
50 | # application, which will be initialized later in the startup process) by
51 | # instantiating the BETSE-specific application metadata singleton.
52 | BetseAppMeta()
53 |
54 | # Implement this application by instantiating and running the
55 | # BETSE-specific command-line interface (CLI).
56 | return BetseCLI().run(arg_list)
57 |
58 | # ....................{ MAIN }....................
59 | # If this module is imported from the command line, run this application's CLI;
60 | # else, noop. For POSIX compliance, the exit status returned by this function
61 | # is propagated to the caller as this script's exit status.
62 | if __name__ == '__main__':
63 | cmdexit.exit_with_status(main())
64 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/numeric/test_versions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests exercising the :mod`betse.util.type.numeric.versions` submodule.
8 |
9 | Unit testing this submodule as critical, both because of its centrality to
10 | sane dependency resolution *and* because of the inability of the
11 | :mod:`setuptools`-bundled :mod:`pkg_resources` package underlying this
12 | submodule to maintain adequate (or, *any*) backward compatibility guarantees.
13 | '''
14 |
15 | # ....................{ TESTS }....................
16 | def test_version_comparators() -> None:
17 | '''
18 | Unit test the family of ``betse.util.type.numeric.version.is_*_than*``
19 | comparators (e.g.,
20 | :func:`betse.util.type.numeric.version.is_less_than_or_equal_to`).
21 | '''
22 |
23 | # Defer heavyweight imports.
24 | from betse.util.type.numeric import versions
25 |
26 | # Assert each comparator to behave as expected on common edge cases.
27 | assert versions.is_greater_than('0.6.43.410', (0, 6, 43, 409))
28 | assert versions.is_greater_than_or_equal_to(('3', '300', '33'), '3.300.33')
29 | assert versions.is_less_than(('0', '412', '454'), (0, 412, 455))
30 | assert versions.is_less_than_or_equal_to('23.140.692.63', '23.140.692.63')
31 |
32 |
33 | def test_version_converters() -> None:
34 | '''
35 | Unit test the :func:`betse.util.type.numeric.version.to_comparable`
36 | function.
37 | '''
38 |
39 | # Defer heavyweight imports.
40 | from betse.util.type.numeric import versions
41 |
42 | # Assert this converter to behave as expected on common edge cases --
43 | # notably, pre-release (i.e., "alpha candidate") version numbers for the
44 | # PySide2 dependency required by the BETSEE downstream consumer. For
45 | # unknown reasons:
46 | # * These numbers are suffixed by "~"-prefixed labels violating PEP 440
47 | # compliance. The pkg_resources package underlying this converter creates
48 | # and returns a unique class of objects to represent such versions.
49 | # * These objects are sorted incorrectly. Versions containing tilde
50 | # characters are incorrectly sorted as strictly less than versions *NOT*
51 | # containing tilde characters (e.g., "5.9.0~a1" < "5.7.0").
52 | version_bad_new = versions.to_comparable('5.9.0~a1')
53 | version_bad_old = versions.to_comparable('5.6.0~a1')
54 |
55 | # Assert these uncompliant versions to be sorted in the correct manner.
56 | assert not versions.is_less_than(version_bad_new, '5.7.0')
57 | assert versions.is_less_than(version_bad_old, '5.7.0')
58 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/py/test_c.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests for the :func:`betse.util.py.pymodule.is_c` function.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 |
12 | # ....................{ TESTS }....................
13 | def test_is_c_unmonkeypatched() -> None:
14 | '''
15 | Unit test the :func:`betse.util.py.module.pymodule.is_c` function *without*
16 | monkeypatching the special PEP 302-specific ``__loader__`` attribute of
17 | tested modules.
18 | '''
19 |
20 | # Defer heavyweight imports.
21 | from betse.lib.numpy import numpys
22 | from betse.util.py.module import pymodule
23 |
24 | # Arbitrary Numpy submodule guaranteed to be implemented as a C extension.
25 | # Note that testing this particular C module is critical, as the core
26 | # codebase explicitly performs the same call at application startup.
27 | numpy_c_extension = numpys.get_c_extension()
28 |
29 | # Ensure that a C module is correctly detected as such.
30 | assert pymodule.is_c(numpy_c_extension) is True
31 |
32 | # Ensure that a pure-Python submodule is *NOT* detected to be a C
33 | # extension.
34 | assert pymodule.is_c(pymodule) is False
35 |
36 |
37 | def test_is_c_monkeypatched(monkeypatch) -> None:
38 | '''
39 | Test all calls of the :func:`betse.util.py.module.pymodule.is_c` function
40 | by monkeypatching the special PEP 302-specific ``__loader__`` attribute of
41 | tested modules.
42 |
43 | This monkeypatch improves code coverage by exercising an infrequently used
44 | fallback codepath in this function.
45 |
46 | Parameters
47 | ----------
48 | monkeypatch : MonkeyPatch
49 | Builtin fixture object permitting object attributes to be safely
50 | modified for the duration of this unit test.
51 | '''
52 |
53 | # Imports deferred for safety.
54 | from betse.lib.numpy import numpys
55 | from betse.util.py.module import pymodule
56 |
57 | # Arbitrary Numpy submodule guaranteed to be implemented as a C extension.
58 | numpy_c_extension = numpys.get_c_extension()
59 |
60 | # Remove the PEP 302-specific "__loader__" attribute of each such module
61 | # before performing testing. Since this attribute need *NOT* exist, prevent
62 | # exceptions from being raised if this attribute does *NOT* exist.
63 | for module_object in (pymodule, numpy_c_extension):
64 | monkeypatch.delattr(module_object, name='__loader__', raising=False)
65 |
66 | # Defer to the existing base unit test.
67 | test_is_c_unmonkeypatched()
68 |
--------------------------------------------------------------------------------
/doc/md/DEVELOP.md:
--------------------------------------------------------------------------------
1 | Development
2 | ===========
3 |
4 | For development purposes, BETSE is _editably installable_ (i.e., as a symbolic
5 | link rather than physical copy). As the name implies, editable installations are
6 | modifiable at runtime and hence suitable for development. By the magic of
7 | setuptools eggs and symbolic links, modifications to the copy of BETSE from
8 | which an editable installation originated are propagated back to that
9 | installation implicitly.
10 |
11 | ## System-wide
12 |
13 | BETSE is installable into a system-wide directory as follows:
14 |
15 | * **_(Optional)._** Set the current umask to `002`.
16 |
17 | $ umask 002
18 |
19 | * Editably install BETSE.
20 |
21 | $ cd "${BETSE_DIR}"
22 | $ sudo python3 setup.py symlink
23 |
24 | The `symlink` command is a BETSE-specific `setuptools` command inspired by the
25 | IPython `setuptools` command of the same name, generalizing the behaviour of the
26 | default `develop` command to system-wide editable installations.
27 |
28 | Why? Because the `develop` command is suitable _only_ for user-specific
29 | editable installations. While both `pip` and `setuptools` provide commands for
30 | performing editable installations (e.g., `sudo pip3 install --no-deps
31 | --editable .` and `sudo python3 setup.py develop --no-deps`, respectively),
32 | executable scripts installed by these commands raise fatal exceptions on
33 | failing to find `setuptools`-installed dependencies regardless of whether these
34 | dependencies have already been installed in a system-wide manner. To quote
35 | [IPython developer
36 | MinRK](http://mail.scipy.org/pipermail/ipython-dev/2014-February/013209.html):
37 |
38 | So much hate for setuptools right now. I can't believe `--no-deps` skips
39 | dependency installation, but still adds a redundant check to entry points.
40 |
41 | ## User-specific
42 |
43 | BETSE is editably installable into a user-specific venv via either `pip` or
44 | `setuptools` **from within such venv.** While there appears to be no particular
45 | advantage to using one over the other, it remains helpful to note that both
46 | apply. In either case, external executables (e.g., `betse`, `betse-qt`) will
47 | also be installed and usable in the expected manner.
48 |
49 | ### pip
50 |
51 | BETSE is editably installable into a user-specific venv via `pip` as follows:
52 |
53 | $ cd "${BETSE_DIR}"
54 | $ pip3 install --no-deps --editable .
55 |
56 | This installation is uninstallable as follows:
57 |
58 | $ pip3 uninstall betse
59 |
60 | ### setuptools
61 |
62 | BETSE is editably installable into a user-specific venv via `setuptools` as
63 | follows:
64 |
65 | $ cd "${BETSE_DIR}"
66 | $ ./setup.py develop --no-deps
67 |
68 | This installation is uninstallable as follows:
69 |
70 | $ cd "${BETSE_DIR}"
71 | $ ./setup.py develop --uninstall
72 |
--------------------------------------------------------------------------------
/betse/lib/matplotlib/mplzorder.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Matplotlib-specific **z-order** (i.e., positive integers ordering artist
8 | drawing, such that artists with larger z-orders are drawn over artists with
9 | smaller z-orders) facilities.
10 |
11 | See Also
12 | ----------
13 | http://matplotlib.org/examples/pylab_examples/zorder_demo.html
14 | Canonical z-order example from which most constants defined by this
15 | submodule were derived.
16 | '''
17 |
18 | # ....................{ CONSTANTS }....................
19 | ZORDER_PATCH = 1
20 | '''
21 | Default **z-order** (i.e., positive integer ordering artist drawing, such that
22 | artists with larger z-orders are drawn over artists with smaller z-orders) for
23 | patch artists (e.g., :class:`Patch`, :class:`PatchCollection`).
24 |
25 | This is the lowest default z-order, thus drawing patch artists under all other
26 | artists by default.
27 | '''
28 |
29 |
30 | ZORDER_LINE = 2
31 | '''
32 | Default **z-order** (i.e., positive integer ordering artist drawing, such that
33 | artists with larger z-orders are drawn over artists with smaller z-orders) for
34 | line artists (e.g., `Line2D`, `LineCollection`, `StreamplotSet`).
35 |
36 | This is the middle default z-order, thus drawing line artists over all patch
37 | artists but under all text artists by default.
38 | '''
39 |
40 |
41 | ZORDER_TEXT = 3
42 | '''
43 | Default **z-order** (i.e., positive integer ordering artist drawing, such that
44 | artists with larger z-orders are drawn over artists with smaller z-orders) for
45 | text artists (e.g., `Text`).
46 |
47 | This is the highest default z-order, thus drawing text artists over all other
48 | artists by default.
49 | '''
50 |
51 |
52 | ZORDER_STREAM = (ZORDER_LINE + ZORDER_TEXT) / 2
53 | '''
54 | BETSE-specific **z-order** (i.e., positive integer ordering artist drawing,
55 | such that artists with larger z-orders are drawn over artists with smaller
56 | z-orders) for streamplots (e.g., `StreamplotSet`).
57 |
58 | This magic number has been chosen such that streamplots with this z-order will
59 | be drawn over all line and patch artists but under all text artists by default.
60 | Streamplots are technically a variant of line artists but sufficiently non-
61 | linear (and visually busy) to warrant separate handling.
62 |
63 | It may also be pertinent to note that recent Matplotlib releases as of this
64 | writing (1.40) accidentally broke backward compatibility with respect to
65 | default streamplot z-order. Specifically, streamplots were assigned a default
66 | z-order of `ZORDER_PATCH` rather than `ZORDER_LINE`:
67 |
68 | https://github.com/matplotlib/matplotlib/pull/5567
69 | '''
70 |
--------------------------------------------------------------------------------
/betse/util/io/log/logfilter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level logging filter subclasses.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12 | # WARNING: To avoid circular import dependencies, avoid importing from *ANY*
13 | # application-specific modules at the top-level -- excluding those explicitly
14 | # known *NOT* to import from this module. Since all application-specific modules
15 | # must *ALWAYS* be able to safely import from this module at any level, these
16 | # circularities are best avoided here rather than elsewhere.
17 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
18 | from betse import metadata
19 | from betse.util.io.log.logenum import LogLevel
20 | from betse.util.type.types import type_check
21 | from logging import Filter, LogRecord
22 |
23 | # ....................{ CLASSES }....................
24 | class LogFilterThirdPartyDebug(Filter):
25 | '''
26 | Log filter ignoring all log records with logging levels less than or equal
27 | to :attr:`LogLevel.DEBUG` *and* names not prefixed by ``betse``.
28 |
29 | Equivalently, this log filter *only* retains log records with either:
30 |
31 | * Logging levels greater than :attr:`LogLevel.DEBUG`.
32 | * Names prefixed by ``betse``, including both:
33 | * ``betse``, the top-level package for BETSE.
34 | * ``betsee``, the top-level package for BETSEE.
35 |
36 | This log filter prevents ignorable debug messages logged by third-party
37 | frameworks (e.g., Pillow) from polluting this application's debug output.
38 | '''
39 |
40 | @type_check
41 | def filter(self, log_record: LogRecord) -> bool:
42 | '''
43 | ``True`` only if the passed log record is to be retained.
44 | '''
45 |
46 | # print('log record name: {}'.format(log_record.name))
47 | return (
48 | log_record.levelno > LogLevel.DEBUG or
49 | log_record.name.startswith(metadata.PACKAGE_NAME))
50 |
51 |
52 | class LogFilterMoreThanInfo(Filter):
53 | '''
54 | Log filter ignoring all log records with logging levels greater than
55 | :attr:`LogLevel.INFO``.
56 |
57 | Equivalently, this log filter *only* retains log records with logging levels
58 | less than or equal to :attr:`LogLevel.INFO``.
59 | '''
60 |
61 | @type_check
62 | def filter(self, log_record: LogRecord) -> bool:
63 | '''
64 | ``True`` only if the passed log record is to be retained.
65 | '''
66 |
67 | return log_record.levelno <= LogLevel.INFO
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # Git-specific dotfile instructing git to avoid tracking repository paths
7 | # matching one or more glob expressions listed below by default.
8 | #
9 | # --------------------( SEE ALSO )--------------------
10 | # For further details, see:
11 | #
12 | # * "man gitignore" for high-level commentary.
13 | # * "man 7 glob" for low-level commentary on glob syntax. Note, in particular,
14 | # that glob() and hence ".gitignore" files support only a proper subset of
15 | # full glob syntax supported by POSIX-compatible shells (e.g., bash, zsh).
16 |
17 | # ....................{ DIRECTORIES ~ top-level }....................
18 | # Ignore all top-level BETSE-specific temporary directories.
19 | /output/
20 | /sample_sim/
21 |
22 | # Ignore all top-level PyInstaller-specific temporary directories.
23 | /freeze/build/
24 | /freeze/dist/
25 |
26 | # Ignore all top-level pip-specific temporary directories.
27 | /pip-wheel-metadata/
28 |
29 | # Ignore all top-level py.test-specific temporary directories.
30 | /.cache/
31 | /.pytest_cache/
32 |
33 | # Ignore all top-level setuptools-specific temporary directories.
34 | /build/
35 | /dist/
36 | /.eggs/
37 | /*.egg-info/
38 |
39 | # Ignore all top-level tox-specific temporary directories.
40 | /.tox/
41 |
42 | # ....................{ DIRECTORIES ~ general }....................
43 | # Ignore all Python-specific cache directories.
44 | __pycache__/
45 |
46 | # Ignore all PyCharm-specific subdirectories.
47 | .idea/
48 |
49 | # Ignore all Rope-specific subdirectories.
50 | .ropeproject/
51 |
52 | # ....................{ FILES ~ top-level }....................
53 | # Ignore all top-level Coverage.py-specific output files.
54 | /.coverage
55 | /.coverage.*
56 | /coverage.xml
57 |
58 | # Ignore all top-level Nose-specific output files.
59 | /nosetests.xml
60 |
61 | # Ignore all top-level setuptools-specific output files.
62 | /MANIFEST
63 |
64 | # Ignore top-level PyInstaller-specific output files *NOT* intended to be
65 | # modified. ".spec"-suffixed files *ARE* intended to be modified and hence
66 | # excluded.
67 | /*.manifest
68 |
69 | # Ignore top-level symbolic links to BETSE-dependent projects (e.g., BETSEE).
70 | /betsee_link
71 |
72 | # ....................{ FILES ~ general }....................
73 | # Ignore all BETSE-specific output files.
74 | *.btse
75 |
76 | # Ignore all audio and video files.
77 | *.mp4
78 |
79 | # Ignore all macOS-specific cache files.
80 | .DS_Store
81 |
82 | # Ignore all Python-specific cache files.
83 | *.py[cod]
84 |
85 | # Ignore all temporary files.
86 | *~
87 | *.log
88 | *.sw?
89 |
--------------------------------------------------------------------------------
/betse/util/py/pyfreeze.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level **frozen application** (i.e., cross-platform Python application
8 | converted into one or more platform-specific executable binaries) facilities.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | import sys
13 | from betse.exceptions import BetsePyFrozenException
14 | # from betse.util.type.types import type_check, SequenceTypes
15 |
16 | # ....................{ TESTERS }....................
17 | def is_frozen() -> bool:
18 | '''
19 | ``True`` only if the active Python interpreter is **frozen** (i.e., embedded
20 | in a platform-specific compressed executable archiving this application and
21 | all transitive dependencies thereof).
22 | '''
23 |
24 | # If the "sys" module has an attribute:
25 | #
26 | # * "_MEIPASS", this is a binary frozen by PyInstaller.
27 | # * "frozen", this is a binary frozen by a non-PyInstaller freezer (e.g.,
28 | # "py2app", "py2exe").
29 | return is_frozen_pyinstaller() or hasattr(sys, 'frozen')
30 |
31 |
32 | def is_frozen_pyinstaller() -> bool:
33 | '''
34 | ``True`` only if the active Python interpreter is frozen with PyInstaller.
35 |
36 | This function returns ``True`` only if the PyInstaller-specific private
37 | attribute ``_MEIPASS`` added to the canonical :mod:`sys` module by the
38 | PyInstaller bootloader embedded in this frozen executable (if any) exists.
39 | '''
40 |
41 | # Hear no evil, code no evil, comment no evil.
42 | return hasattr(sys, '_MEIPASS')
43 |
44 | # ....................{ GETTERS }....................
45 | def get_app_dirname_pyinstaller() -> str:
46 | '''
47 | Absolute path of the temporary directory extracted by the PyInstaller
48 | bootloader from the platform-specific executable binary frozen by
49 | PyInstaller for this this application.
50 |
51 | This directory contains all files and directories required to run this
52 | application, including both Python modules, packages, and C extensions _and_
53 | non-Python resources.
54 |
55 | Returns
56 | ----------
57 | str
58 | Absolute path of this directory.
59 |
60 | Raises
61 | ----------
62 | :exc:`betse.exceptions.BetsePyFrozenException`
63 | If this application is _not_ frozen with PyInstaller.
64 | '''
65 |
66 | # If this application is *NOT* frozen with PyInstaller, raise an exception.
67 | if not is_frozen_pyinstaller():
68 | raise BetsePyFrozenException('Application not frozen with PyInstaller.')
69 |
70 | # That is not buggy which can eternal lie.
71 | return sys._MEIPASS
72 |
--------------------------------------------------------------------------------
/betse/lib/pil/pils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level support facilities for Pillow, the Python Image Library
8 | (PIL)-compatible fork implementing most image I/O performed by this
9 | application.
10 | '''
11 |
12 | #FIXME: Revisit imageio when the following feature request is resolved in full:
13 | # https://github.com/imageio/imageio/issues/289
14 |
15 | # ....................{ IMPORTS }....................
16 | from PIL import Image
17 | from betse.util.io.log import logs
18 | from betse.util.path import pathnames
19 | from betse.util.type.decorator.decmemo import func_cached
20 | from betse.util.type.types import SetType # type_check,
21 |
22 | # ....................{ GETTERS }....................
23 | @func_cached
24 | def get_filetypes() -> SetType:
25 | '''
26 | Set of all image filetypes supported by the current version of Pillow.
27 |
28 | For generality, these filetypes are *not* prefixed by a ``.`` delimiter.
29 |
30 | Examples
31 | ----------
32 | >>> from betse.lib.pil import pils
33 | >>> pils.get_filetypes()
34 | {'flc', 'bmp', 'ppm', 'webp', 'j2k', 'jpf', 'jpe', 'pcd'}
35 | '''
36 |
37 | # Initialize Pillow if uninitialized.
38 | #
39 | # If Pillow is uninitialized, the "Image.EXTENSION" dictionary is empty.
40 | # Since the betse.util.app.meta.appmetaabc.AppMetaABC.init_libs() function
41 | # already initializes Pillow, explicitly doing so here should typically
42 | # *NOT* be necessary. Since this getter could technically be called from
43 | # global scope prior to the initialization performed by "betse.ignition"
44 | # *AND* since this initialization efficiently reduces to a noop if
45 | # unnecessary, manually initializing Pillow here is cost-free... and
46 | # cost-free is the way to be.
47 | init()
48 |
49 | # Return a set of...
50 | return set(
51 | # This filetype stripped of this prefixing "."...
52 | pathnames.undot_filetype(filetype_dotted)
53 | # For each "."-prefixed filetype supported by Pillow.
54 | for filetype_dotted in Image.EXTENSION.keys()
55 | )
56 |
57 | # ....................{ ENUMERATIONS }....................
58 | def init() -> None:
59 | '''
60 | Initialize Pillow if uninitialized *or* reduce to a noop otherwise (i.e.,
61 | if Pillow is already initialized).
62 | '''
63 |
64 | # Log this initialization.
65 | logs.log_debug('Initializing Pillow...')
66 |
67 | # If Pillow is already initialized, this function internally reduces to an
68 | # efficient noop in the expected manner (e.g., by accessing a private
69 | # boolean global).
70 | Image.init()
71 |
--------------------------------------------------------------------------------
/betse/util/py/pyimpl.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **Python implementation** (i.e., Python interpreter conforming to the
8 | established Python syntax and semantics of the CPython reference
9 | implementation) facilities.
10 |
11 | Caveats
12 | ----------
13 | Implementation-specific functions are generally considered poor form. Call
14 | these functions *only* where necessary.
15 | '''
16 |
17 | # ....................{ IMPORTS }....................
18 | import platform
19 | from betse.util.type.decorator.decmemo import func_cached
20 | from betse.util.type.iterable.mapping.mapcls import OrderedArgsDict
21 |
22 | # ....................{ TESTERS }....................
23 | @func_cached
24 | def is_cpython() -> bool:
25 | '''
26 | ``True`` only if the active Python interpreter is an instance of the
27 | official CPython implementation.
28 | '''
29 |
30 | # Depressingly, this actually appears to be the most efficacious test.
31 | return get_name() == 'CPython'
32 |
33 |
34 | @func_cached
35 | def is_pypy() -> bool:
36 | '''
37 | ``True`` only if the active Python interpreter is an instance of the
38 | third-party PyPy implementation.
39 | '''
40 |
41 | # Depressingly, this actually appears to be the most efficacious test.
42 | return get_name() == 'PyPy'
43 |
44 | # ....................{ GETTERS }....................
45 | @func_cached
46 | def get_name() -> str:
47 | '''
48 | Human-readable name of the active Python interpreter's implementation
49 | (e.g., ``CPython``, ``IronPython``, ``Jython``, ``PyPy``).
50 | '''
51 |
52 | return platform.python_implementation()
53 |
54 | # ....................{ GETTERS ~ metadata }....................
55 | def get_metadata() -> OrderedArgsDict:
56 | '''
57 | Ordered dictionary synopsizing the active Python interpreter's
58 | implementation.
59 |
60 | This function aggregates the metadata reported by the reasonably
61 | cross-platform module `platform` into a simple dictionary.
62 | '''
63 |
64 | # This dictionary.
65 | metadata = OrderedArgsDict(
66 | 'name', get_name(),
67 | 'vcs revision', platform.python_revision() or 'none',
68 | 'vcs branch', platform.python_branch() or 'none',
69 | 'compiler', platform.python_compiler(),
70 | )
71 |
72 | # 2-tuple providing this interpreter's build number and date as strings.
73 | python_build = platform.python_build()
74 |
75 | # Append this metadata.
76 | metadata['build number'] = python_build[0]
77 | metadata['build data'] = python_build[1]
78 |
79 | # Return this dictionary.
80 | return metadata
81 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/set/sets.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **set** (i.e., :class:`set`-like types or instances) functionality.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from betse.util.type.types import type_check, IterableTypes, SetType
12 |
13 | # ....................{ MAKERS }....................
14 | @type_check
15 | def make_union(*iterables: IterableTypes) -> SetType:
16 | '''
17 | **Union** (i.e., set of all objects contained in all passed iterables) of
18 | all passed iterables.
19 |
20 | This function generalizes the :meth:`set.union` method, which implicitly
21 | requires the first iterable to be a set, to arbitrary iterables, none of
22 | which (including the first iterable) are required to be a set.
23 |
24 | Parameters
25 | ----------
26 | iterables : Tuple[IterableTypes]
27 | Tuple of all iterables to be united.
28 |
29 | Raises
30 | ----------
31 | BetseSequenceException
32 | If less than two iterables are passed.
33 | '''
34 |
35 | # Avoid circular import dependencies.
36 | from betse.util.type.iterable import generators, sequences
37 |
38 | # If passed no iterables, raise an exception.
39 | sequences.die_if_empty(sequence=iterables)
40 | # Else, at least one iterable is passed.
41 |
42 | # If passed only one generator, implicitly expand this generator into the
43 | # sequence of all items yielded by this generator.
44 | if len(iterables) == 1 and generators.is_generator(iterables[0]):
45 | iterables = tuple(iterables[0])
46 |
47 | # First iterable.
48 | iterable_first = iterables[0]
49 |
50 | # First iterable coerced into a set if nor already a set *OR* preserved as
51 | # is otherwise.
52 | #
53 | # Note that testing whether this iterable is a "SetType" does *NOT*
54 | # suffice, as that abstract base class sadly fails to require that
55 | # subclasses adhere to the public API of the "set" builtin (e.g., by
56 | # defining a union() method).
57 | iterable_first_set = (
58 | iterable_first if isinstance(iterable_first, set) else
59 | set(iterable_first))
60 |
61 | # If passed only one iterable, simply return this set.
62 | if len(iterables) == 1:
63 | return iterable_first_set
64 | # Else, two or more iterables are passed.
65 |
66 | # Generator comprehension yielding each subsequent iterable.
67 | iterables_rest = (iterable for iterable in iterables[1:])
68 |
69 | # Union of all passed iterables.
70 | iterables_united = iterable_first_set.union(*iterables_rest)
71 |
72 | # Return this union.
73 | return iterables_united
74 |
--------------------------------------------------------------------------------
/betse/util/io/error/errhaiku.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Error haiku** (i.e., pseudo-random human-readable general-purpose error
8 | message formatted as a haiku) facilities.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | import random, sys, traceback
13 |
14 | # ....................{ CONSTANTS }....................
15 | ERROR_HAIKU = (
16 | (
17 | 'Chaos reigns within.',
18 | 'Reflect, repent, and reboot.',
19 | 'Order shall return.',
20 | ), (
21 | 'ABORTED effort:',
22 | 'Close all that you have.',
23 | 'You ask way too much.',
24 | ), (
25 | 'First snow, then silence.',
26 | 'This thousand dollar screen dies',
27 | 'so beautifully.',
28 | ), (
29 | 'A crash reduces',
30 | 'your expensive computer',
31 | 'to a simple stone.',
32 | ), (
33 | 'Error messages',
34 | 'cannot completely convey.',
35 | 'We now know shared loss.',
36 | ), (
37 | 'The code was willing.',
38 | 'It considered your request',
39 | 'but the chips were weak.',
40 | ), (
41 | 'There is a chasm',
42 | 'of carbon and silicon',
43 | "this software can't bridge.",
44 | ), (
45 | 'To have no errors',
46 | 'would be life without meaning.',
47 | 'No struggle, no joy.',
48 | ), (
49 | 'many fingers clicking',
50 | 'screens are full of letters',
51 | 'what is their meaning?',
52 | ), (
53 | 'Water spills downwards.',
54 | 'Electric stream cascades sparks.',
55 | 'Data flow ceases.',
56 | ), (
57 | 'Technical support',
58 | 'would be a flowing source of',
59 | 'sweet commiseration.',
60 | ), (
61 | 'Fatal exception.',
62 | 'Code has looped upon itself',
63 | 'like the coiled serpent.',
64 | ), (
65 | 'An old CPU.',
66 | 'A new program is loaded.',
67 | 'The sound of crashing.',
68 | ),
69 | )
70 | '''
71 | List of haikus to be printed in the event of fatal errors.
72 |
73 | This is serious business, folks.
74 |
75 | See Also
76 | ----------
77 | http://baetzler.de/humor/haiku_error.var
78 | https://www.gnu.org/fun/jokes/error-haiku.html
79 | To quote: "IMAGINE IF INSTEAD OF CRYPTIC TEXT STRINGS, YOUR COMPUTER
80 | PRODUCED ERROR MESSAGES IN HAIKU..." We need no longer imagine.
81 | '''
82 |
83 | # ....................{ GETTERS }....................
84 | def get_random() -> str:
85 | '''
86 | Pseudo-random human-readable general-purpose error message formatted as a
87 | haiku, commonly printed and/or logged in the event of fatal errors.
88 | '''
89 |
90 | return '\n'.join(random.choice(ERROR_HAIKU))
91 |
--------------------------------------------------------------------------------
/betse/util/io/error/errfault.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | **Segmentation fault** (i.e., memory access violation by the active Python
8 | process, caused by attempting to access an inaccessible, illegal, or otherwise
9 | invalid memory location) facilities.
10 | '''
11 |
12 | # ....................{ IMPORTS }....................
13 | import faulthandler
14 |
15 | # ....................{ HANDLERS }....................
16 | def handle_faults() -> None:
17 | '''
18 | Enable Python's standard handler for **segmentation faults** (i.e., memory
19 | access violations by the active Python process, caused by attempting to
20 | access inaccessible, illegal, or otherwise invalid memory locations).
21 |
22 | On the first segmentation fault, this handler prints a detailed traceback
23 | of the current call stack for the current thread to standard error before
24 | abruptly terminating this process.
25 |
26 | Caveats
27 | ----------
28 | Technically, the :func:`faulthandler.enable` function internally called by
29 | this function supports redirection to an open file handle (e.g., referring
30 | to a user-specific log file) rather than to standard error. However, that
31 | handle is required to remain open for the lifetime of the fault handler and
32 | hence the active Python process. Since guaranteeing this is infeasible in
33 | practice, this function defers to the default fault handler for safety.
34 |
35 | Note that there are *no* performance penalties associated with enabling
36 | this handler. Ergo, *all* Python applications are advised to do so. For
37 | further details, see `this authoritative StackOverflow answer`_ by the
38 | author of the standard :mod:`faulthandler` module.
39 |
40 | .. _authoritative StackOverflow answer:
41 | https://stackoverflow.com/a/29246977/2809027
42 |
43 | See Also
44 | ----------
45 | :func:`ignore_faults`
46 | Function disabling this handler, thus reverting to Python's default
47 | behavior with respect to segmentation faults.
48 | '''
49 |
50 | faulthandler.enable()
51 |
52 |
53 | def ignore_faults() -> None:
54 | '''
55 | Disable Python's standard handler for **segmentation faults** (i.e., memory
56 | access violations by the active Python process, caused by attempting to
57 | access inaccessible, illegal, or otherwise invalid memory locations).
58 |
59 | This function reverts to Python's default behavior with respect to
60 | segmentation faults. On the first segmentation fault, Python will abruptly
61 | terminate this process with *no* traceback or advance notice.
62 |
63 | See Also
64 | ----------
65 | :func:`handle_faults`
66 | Function re-enabling this handler.
67 | '''
68 |
69 | faulthandler.disable()
70 |
--------------------------------------------------------------------------------
/betse/util/test/pytest/pytabc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | High-level :mod:`pytest`-specific abstract base class (ABC) hierarchies.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | from abc import ABCMeta
12 |
13 | # ....................{ CLASSES }....................
14 | # FIXME: The "_first_failure_method_name" attribute documented below is
15 | # dynamically set on the py.test object encapsulating this class instance
16 | # rather than this actual class instance. This may or may not be a bad thing.
17 | class SerialTestABC(metaclass=ABCMeta):
18 | '''
19 | Abstract base class running all test methods defined by this concrete
20 | subclass **serially** (i.e., in the order in which this subclass declares
21 | these test such that subsequently declared tests depend on the success of
22 | all previously declared tests).
23 |
24 | On the first failure of such a test, all subsequent such tests will be
25 | automaticaly marked as xfailing (i.e., failing *without* being run).
26 |
27 | The majority of the black magic required by this class is implemented as
28 | low-level py.test hooks in the top-level :mod:`betse_func.conftest` plugin.
29 |
30 | Attributes
31 | ----------
32 | _first_failure_method_name : str
33 | Unqualified name of the first failing test method (i.e., method whose
34 | execution raised an exception) declared by this subclass for the
35 | current test session if any such method failed *or* ``None`` otherwise
36 | (i.e., if no such methods have yet to fail).
37 | '''
38 |
39 | # ..................{ INITIALIZERS }..................
40 | @staticmethod
41 | def is_test_serial(item) -> bool:
42 | '''
43 | ``True`` only if the passed test callable is **serial** (i.e., a method
44 | of a subclass of this class).
45 |
46 | Serial methods are intended to be run in test method declaration order,
47 | such that subsequently declared test methods depend on the success of
48 | all previously declared test methods.
49 |
50 | Parameters
51 | ----------
52 | item : pytest.main.Item
53 | Metadata encapsulating this test callable (e.g., function, method).
54 |
55 | Returns
56 | -------
57 | bool
58 | ``True`` only if this test is serial.
59 | '''
60 |
61 | # Class of this test callable if this callable is a method *OR* "None".
62 | test_class = item.parent.cls
63 |
64 | # This callable is intended to be run serially only if the test
65 | # subclass to which this callable is bound subclasses this abstract
66 | # base class.
67 | return test_class is not None and issubclass(test_class, SerialTestABC)
68 |
--------------------------------------------------------------------------------
/betse/util/type/iterable/generators.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level **generator** (i.e., objects satisfying the standard generator API)
8 | facilities.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse.util.type.types import type_check, GeneratorType, IterableTypes
13 |
14 | # ....................{ GENERATORS }....................
15 | def empty_generator() -> GeneratorType:
16 | '''
17 | Empty generator yielding... absolutely nothing.
18 |
19 | See Also
20 | ----------
21 | https://stackoverflow.com/a/36658865/2809027
22 | StackOverflow answer strongly inspiring this implementation.
23 | '''
24 |
25 | yield from ()
26 |
27 | # ....................{ TESTERS }....................
28 | def is_generator(obj: object) -> bool:
29 | '''
30 | ``True`` only if the passed object is a generator.
31 | '''
32 |
33 | # Best things in life are free.
34 | return isinstance(obj, GeneratorType)
35 |
36 | # ....................{ GETTERS }....................
37 | @type_check
38 | def get_length(generator: GeneratorType) -> int:
39 | '''
40 | Length of the passed **finite generator** (i.e., generator guaranteed to
41 | yield only a finite number of values).
42 |
43 | Caveats
44 | ----------
45 | **This function consumes the passed generator,** as a harmful (albeit
46 | unavoidable) side effect of calculating the length of this generator.
47 |
48 | **This function fails to halt if the passed generator is infinite,** as a
49 | harmful (albeit unavoidable) side effect of needing to entirely consume
50 | this generator in order to calculate its length.
51 |
52 | See Also
53 | ----------
54 | https://stackoverflow.com/a/31350424
55 | StackOverflow answer strongly inspiring this implementation.
56 | '''
57 |
58 | # Convert this generator into a list and return the length of this list.
59 | #
60 | # While clearly non-ideal, this approach is well-known to be the most
61 | # time-efficient solution. The most space-efficient solution is quite
62 | # different, but also approximately four times slower. Since time is scarce
63 | # and space is cheap in the general case, we prefer the sane approach.
64 | return len(list(generator))
65 |
66 | # ....................{ CONVERTERS }....................
67 | @type_check
68 | def to_tuple_if_generator(iterable: IterableTypes) -> IterableTypes:
69 | '''
70 | Tuple of all items iteratively yielded by the passed iterable if this
71 | iterable is a generator *or* this iterable as is otherwise (i.e., if this
72 | iterable is *not* a generator).
73 | '''
74 |
75 | return tuple(iterable) if is_generator(iterable) else iterable
76 |
--------------------------------------------------------------------------------
/betse_test/README.md:
--------------------------------------------------------------------------------
1 | Tests
2 | ===========
3 |
4 | [`py.test`](http://pytest.org)-driven
5 | [functional](https://en.wikipedia.org/wiki/Functional_testing) and [unit
6 | tests](https://en.wikipedia.org/wiki/Unit_testing).
7 |
8 | ## Structure
9 |
10 | For collective sanity, tests are rigorously structured as follows:
11 |
12 | * All functional test reside in the `betse_test_func` subdirectory of this
13 | directory.
14 | * All unit tests reside in the `betse_test_unit` subdirectory of this directory.
15 | * This directory should directly contain _no_ files except this otherwise
16 | ignorable file. In particular, this directory should _not_ contain an
17 | `__init__.py` file.
18 | * This directory should directly contain _no_ subdirectories except the
19 | aforementioned subdirectories.
20 |
21 | ### Nomenclature
22 |
23 | The somewhat obscure choice of subdirectory names is intentional, ensuring:
24 |
25 | * Functional tests may import other functional tests or fixtures via the topmost
26 | `betse_test_func` package name, which `py.test` dynamically injects at test
27 | discovery time into Python's current `sys.path`.
28 | * Unit tests may import other unit tests or fixtures via the topmost
29 | `betse_test_unit` package name, which `py.test` dynamically injects at test
30 | discovery time into Python's current `sys.path`.
31 | * No import collision between functional and unit tests and fixtures. Functional
32 | tests and fixtures reside in one Python namespace; unit tests and fixtures
33 | reside in another.
34 | * No import collision between tests and fixtures and the remainder of the Python
35 | ecosystem (e.g., the first-party stdlib or third-party packages). Tests and
36 | fixtures reside in `betse_test_` namespaces. All other packages presumably do
37 | _not_.
38 |
39 | ### Importability
40 |
41 | To permit any test or fixture to import any other test or fixture, this
42 | directory and all subdirectories of this directory _must_ contain `__init__.py`
43 | files. As no parent directories of this directory contain these files, `py.test`
44 | [assigns](https://pytest.org/latest/goodpractices.html) this directory a topmost
45 | package with the same basename in Python's import namespace. All submodules
46 | (i.e., `.py`-suffixed files in subpackages) and subpackages (i.e., subdirectories
47 | with `__init__.py` files) of this package may then be imported from any test or
48 | fixture via this package name.
49 |
50 | For example, any test or fixture may explicitly import both the test-specific
51 | `betse_test/util/metafixture.py` module _and_ the test-agnostic
52 | `betse/metadata.py` module defined in the main codebase as follows:
53 |
54 | ```
55 | # This imports "betse_test/util/metafixture.py", thanks to magic.
56 | from betse_test.util import metafixture
57 |
58 | # This imports "betse/metadata.py", thanks to magic.
59 | from betse import metadata
60 | ```
61 |
62 | ## See Also
63 |
64 | For further details on test discovery, see the
65 | [paragraph](https://pytest.org/latest/goodpractices.html) beginning _"If pytest
66 | finds a “a/b/test_module.py” test file..."_.
67 |
--------------------------------------------------------------------------------
/betse/util/io/log/conf/logconfformat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Low-level logging formatter subclasses.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12 | # WARNING: To avoid circular import dependencies, avoid importing from *ANY*
13 | # application-specific modules at the top-level -- excluding those explicitly
14 | # known *NOT* to import from this module. Since all application-specific
15 | # modules must *ALWAYS* be able to safely import from this module at any level,
16 | # these circularities are best avoided here rather than elsewhere.
17 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
18 |
19 | # from betse.util.type.types import type_check
20 | from logging import Formatter
21 |
22 | # ....................{ CLASSES }....................
23 | #FIXME: Unfortunately, this fundamentally fails to work. The reason why? The
24 | #"TextWrapper" class inserts spurious newlines *EVEN WHEN YOU EXPLICITLY TELL
25 | #IT NOT TO*. This is crazy, but noted in the documentation:
26 | #
27 | # "If replace_whitespace is False, newlines may appear in the middle of a
28 | # line and cause strange output. For this reason, text should be split into
29 | # paragraphs (using str.splitlines() or similar) which are wrapped
30 | # separately."
31 | #
32 | #Until this is resolved, the only remaining means of wrapping log messages will
33 | #be to define new top-level module functions suffixed by "_wrapped" ensuring
34 | #that the appropriate formatter is used (e.g., a new log_info_wrapped()
35 | #function). For now, let's just avoid the topic entirely. It's all a bit
36 | #cumbersome and we're rather weary of it.
37 |
38 | class LogFormatterWrap(Formatter):
39 | '''
40 | Log formatter wrapping all lines in handled log records to a sane line
41 | length (e.g., 80 characters).
42 |
43 | Attributes
44 | ----------
45 | _text_wrapper : TextWrapper
46 | Object with which to wrap log messages, cached for efficiency.
47 | '''
48 |
49 | pass
50 | # def __init__(self, *args, **kwargs):
51 | # super().__init__(*args, **kwargs)
52 | # self._text_wrapper = TextWrapper(
53 | # drop_whitespace = False,
54 | # replace_whitespace = False,
55 | # )
56 |
57 | # def format(self, log_record: LogRecord) -> str:
58 | # # Avoid circular import dependencies.
59 | # from betse.util.type import strs
60 | #
61 | # # Get such message by (in order):
62 | # #
63 | # # * Formatting such message according to our superclass.
64 | # # * Wrapping such formatted message.
65 | # return strs.wrap(
66 | # text = super().format(log_record),
67 | # text_wrapper = self._text_wrapper,
68 | # )
69 |
--------------------------------------------------------------------------------
/betse_test/a90_func/a00_sim_wrapper/test_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Integration tests exercising the public API of the public
8 | :mod:`betse.science.wrapper` subpackage.
9 | '''
10 |
11 | # ....................{ IMPORTS }....................
12 | from betse_test._fixture.simconf.simconfclser import SimConfTestInternal
13 |
14 | # ....................{ TESTS }....................
15 | def test_wrapper_default(betse_sim_conf: SimConfTestInternal) -> None:
16 | '''
17 | Integration test exercising default parameters accepted by the
18 | :meth:`betse.science.wrapper.BetseWrapper.__init__` method.
19 |
20 | Parameters
21 | ----------
22 | betse_sim_conf : SimConfTestInternal
23 | Object encapsulating a temporary simulation configuration file.
24 | '''
25 |
26 | # Defer test-specific imports.
27 | from betse.science.wrapper import BetseWrapper
28 |
29 | # # Save these changes back to the same file.
30 | # p.save_inplace()
31 |
32 | # BETSE wrapper configured by this file *AND* no other passed parameters,
33 | # intentionally exercising defaults set for those parameters.
34 | wrapper = BetseWrapper(config_filename=betse_sim_conf.p.conf_filename)
35 |
36 | # Run the default pipeline performing *ONLY* the initialization phase.
37 | wrapper.run_pipeline()
38 |
39 |
40 | def test_wrapper_logging(
41 | betse_sim_conf: SimConfTestInternal,
42 | betse_temp_dir: 'py._path.local.LocalPath',
43 | ) -> None:
44 | '''
45 | Integration test exercising logging parameters accepted by the
46 | :meth:`betse.science.wrapper.BetseWrapper.__init__` method.
47 |
48 | Parameters
49 | ----------
50 | betse_sim_conf : SimConfTestInternal
51 | Object encapsulating a temporary simulation configuration file.
52 | betse_temp_dir : py._path.local.LocalPath
53 | Object encapsulating a temporary directory isolated to this test.
54 | '''
55 |
56 | # Defer test-specific imports.
57 | from betse.science.wrapper import BetseWrapper
58 |
59 | # Absolute filename of a logfile with arbitrary basename in this temporary
60 | # directory.
61 | log_file = betse_temp_dir.join('betse.log')
62 |
63 | # BETSE wrapper... *AND* no other passed parameters,
64 | # intentionally exercising defaults set for those parameters.
65 | wrapper = BetseWrapper(
66 | # Configured by this file.
67 | config_filename=betse_sim_conf.p.conf_filename,
68 | # Logging to another file.
69 | log_filename=str(log_file),
70 | # Logging *ALL* messages.
71 | log_level='ALL',
72 | )
73 |
74 | # Run the default pipeline performing *ONLY* the initialization phase.
75 | wrapper.run_pipeline()
76 |
77 | # Assert this logfile to have been created.
78 | assert log_file.check(file=1)
79 |
80 | # Assert this logfile to be non-empty.
81 | assert log_file.size() > 100
82 |
--------------------------------------------------------------------------------
/requirements-conda.txt:
--------------------------------------------------------------------------------
1 | # --------------------( LICENSE )--------------------
2 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
3 | # See "LICENSE" for further details.
4 | #
5 | # --------------------( SYNOPSIS )--------------------
6 | # List of all mandatory or optional runtime dependencies of this application
7 | # installed by the "conda" package manager bundled with both the default
8 | # Anaconda distribution and minimal Miniconda distribution.
9 | #
10 | # This file conforms to the "conda" rather than "setuptools" or "pip" file
11 | # format for listing dependencies. The existing dependencies listed by the
12 | # top-level "setup.py" script *CANNOT* be reused here by merely specifying ".".
13 | #
14 | # --------------------( USAGE )--------------------
15 | # This file is principally intended for use in continuous integration (CI)
16 | # pipelines exercising our test suite on each commit to this codebase.
17 | # Prominent references to this file include:
18 | #
19 | # * "appveyor.yml", configuring Windows-specific AppVeyor CI pipelines.
20 | # * ".gitlab-ci.yml", configuring Linux-specific GitLab Runner CI pipelines.
21 | #
22 | # --------------------( EXAMPLES )--------------------
23 | # To generate a sample file in this format describing all currently installed
24 | # "conda" packages, run the following command:
25 | #
26 | # $ conda list -e
27 |
28 | # ....................{ DEPENDENCIES ~ run : mandatory }....................
29 | # All mandatory and optional runtime dependencies of this application for which
30 | # Anaconda packages are published by either the conda-forge channel (ideally)
31 | # *OR* any of the official default channels.
32 | #
33 | # For simplicity, this list is a partial duplicate of the canonical
34 | # conda-specific dependency list for this application specified by the
35 | # YAML-formatted "requirements:/run:" list in the recipe at our official
36 | # conda-forge feedstock: e.g.,
37 | #
38 | # https://github.com/leycec/betse-feedstock/blob/master/recipe/meta.yaml
39 | #
40 | # Ideally, these two lists should be manually synchronized as much as feasible.
41 | # This list should be revised where necessary to reflect changes between the
42 | # live and most recent stable versions of this application.
43 | setuptools >=3.3
44 | dill >=0.2.3
45 | matplotlib >=1.5.0
46 | numpy >=1.13.0
47 | pillow >=2.3.0
48 | ruamel.yaml >=0.15.24
49 | scipy >=0.12.0
50 | six >=1.5.2
51 |
52 | # ....................{ DEPENDENCIES ~ run : optional }....................
53 | # All optional runtime dependencies of this application for which Anaconda
54 | # packages are published by either the conda-forge channel (ideally) *OR* any
55 | # of the official default channels.
56 | #
57 | # This list intentionally omits the following dependencies:
58 | #
59 | # * The optional "pyside2" dependency, which applies *ONLY* to interactive
60 | # environments.
61 | graphviz >=2.38.0
62 | networkx >=2.0
63 | pydot >=1.0.28
64 | ffmpeg
65 |
66 | # ....................{ DEPENDENCIES ~ test : mandatory }....................
67 | # All mandatory testing dependencies of this application.
68 | pytest >=3.1.0
69 |
--------------------------------------------------------------------------------
/betse/util/os/brand/posix.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | POSIX (Portable Operating System Interface)-specific facilities.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 | import os
12 | from betse.exceptions import BetseOSException
13 | # from betse.util.io.log import logs
14 | from betse.util.type.decorator.decmemo import func_cached
15 |
16 | # ....................{ EXCEPTIONS }....................
17 | def die_unless_posix() -> None:
18 | '''
19 | Raise an exception unless the current platform is POSIX-compatible.
20 |
21 | See Also
22 | ----------
23 | :func:`is_posix`
24 | Further details.
25 | '''
26 |
27 | # Avoid circular import dependencies.
28 | from betse.util.os import oses
29 |
30 | # If the current platform is POSIX-incompatible, raise an exception.
31 | if not is_posix():
32 | raise BetseOSException(
33 | '{} not POSIX-compatible.'.format(oses.get_name()))
34 |
35 | # ....................{ TESTERS }....................
36 | @func_cached
37 | def is_posix() -> bool:
38 | '''
39 | ``True`` only if the current platform is **POSIX-compatible** (i.e.,
40 | complies with the POSIX (Portable Operating System Interface) standard).
41 |
42 | Typically, this implies this system to *not* be vanilla Microsoft Windows
43 | and hence to be either:
44 |
45 | * A genuinely POSIX-compliant system.
46 | * A Cygwin-based Windows application (e.g., CLI terminal, GUI application).
47 | '''
48 |
49 | return os.name == 'posix'
50 |
51 |
52 | @func_cached
53 | def is_x11() -> bool:
54 | '''
55 | ``True`` only if the active Python interpreter is running under the X
56 | Window System (hereafter X11), implying this process to be headfull and
57 | hence support both CLIs and GUIs.
58 |
59 | Caveats
60 | ----------
61 | This function returning ``True`` does *not* necessarily imply the current
62 | platform to be a Linux distribution. Unlike most Linux-centric protocols,
63 | support for the X11 protocol is sufficiently widespread across non-Linux
64 | POSIX-compatible platforms as to be effectively cross-platform. Unlike the
65 | Linux-specific :func:`is_mir` and :func:`is_wayland` testers, this
66 | Linux-agnostic tester detects X11 by generically detecting the X11-specific
67 | ``${DISPLAY}`` environment variable rather than the Linux-specific
68 | ``${XDG_SESSION_TYPE}`` environment variable if any.
69 | '''
70 |
71 | # Avoid circular import dependencies.
72 | from betse.util.os.shell import shellenv
73 |
74 | # If the current platform is *NOT* POSIX-compatible, return false.
75 | if not is_posix():
76 | return False
77 | # Else, the current platform is POSIX-compatible.
78 |
79 | # Return true only if the active Python interpreter inherited the
80 | # X11-specific ${DISPLAY} variable from its parent shell environment.
81 | return shellenv.is_var('DISPLAY')
82 |
--------------------------------------------------------------------------------
/betse_test/a00_unit/type/iterable/test_iterget.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # --------------------( LICENSE )--------------------
3 | # Copyright 2014-2025 by Alexis Pietak & Cecil Curry.
4 | # See "LICENSE" for further details.
5 |
6 | '''
7 | Unit tests exercising the :mod:`betse.util.type.iterable.iterget` submodule.
8 | '''
9 |
10 | # ....................{ IMPORTS }....................
11 |
12 | # ....................{ CLASSES }....................
13 | class BellType(object):
14 | '''
15 | Type of each item of the iterable to be tested by the
16 | :func:`test_get_item_var_uniquified_str` unit test.
17 |
18 | Attributes
19 | ----------
20 | name : str
21 | Name of this item, guaranteed to be unique across all such items.
22 | stanza : str
23 | Arbitrary string associated with this item.
24 | '''
25 |
26 | # ..................{ INITIALIZERS }..................
27 | def __init__(self, name: str, stanza: str) -> None:
28 |
29 | self.name = name
30 | self.stanza = stanza
31 |
32 | # ....................{ TESTS ~ default }....................
33 | def test_get_item_var_uniquified_str() -> None:
34 | '''
35 | Unit test the
36 | :func:`betse.util.type.iterable.iterget.get_item_str_uniquified`
37 | function.
38 | '''
39 |
40 | # Defer heavyweight imports.
41 | from betse.util.type.iterable import iterget
42 |
43 | # Iterable to be tested.
44 | the_bells = [
45 | BellType(
46 | name='Silver bells !',
47 | stanza='What a world of merriment their melody foretells !'),
48 | BellType(
49 | name='Golden bells!',
50 | stanza='What a world of happiness their harmony foretells !'),
51 | BellType(
52 | name='Brazen bells !',
53 | stanza='What tale of terror, now, their turbulency tells !'),
54 | BellType(
55 | name='Iron bells !',
56 | stanza='What a world of solemn thought their monody compels !'),
57 | ]
58 |
59 | # Exercise the edge case when this iterable contains no item whose "name"
60 | # variable matches the passed format specifier.
61 | the_fifth_bell = iterget.get_item_str_uniquified(
62 | iterable=the_bells,
63 | item_attr_name='name',
64 | item_str_format='Runic bells ! ({})',
65 | )
66 |
67 | # Assert this getter function to have synthesized the expected string.
68 | assert the_fifth_bell == 'Runic bells ! (5)'
69 |
70 | # Add a new item whose "name" variable is this string to this iterable.
71 | the_bells.append(BellType(
72 | name=the_fifth_bell,
73 | stanza='In a clamorous appealing to the mercy of the fire,'))
74 |
75 | # Exercise the edge case when this iterable contains one item whose "name"
76 | # variable matches the passed format specifier.
77 | the_sixth_bell = iterget.get_item_str_uniquified(
78 | iterable=the_bells,
79 | item_attr_name='name',
80 | item_str_format='Runic bells ! ({})',
81 | )
82 |
83 | # Assert this getter function to have synthesized the expected string.
84 | assert the_sixth_bell == 'Runic bells ! (6)'
85 |
--------------------------------------------------------------------------------