├── 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 | --------------------------------------------------------------------------------