diff --git a/.coverage b/.coverage new file mode 100644 index 0000000..1bbc82a Binary files /dev/null and b/.coverage differ diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..c712d25 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = tests/* diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 941ce2d..bca6ae3 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -29,6 +29,7 @@ jobs: python -m pip install --upgrade pip python -m pip install -U wheel python -m pip install flake8 + python -m pip install pytest-cov coveralls python -m pip install --prefer-binary -r tests/requirements.txt python -m pip install --prefer-binary -e . - name: Lint with flake8 @@ -37,6 +38,13 @@ jobs: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest + - name: Test with pytest-cov run: | - pytest + pytest --cov-config=.coveragerc --cov=./ + coverage xml + - name: Upload coverage to Coveralls + if: ${{ matrix.python-version == 3.9 }} + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + file: coverage.xml diff --git a/README.md b/README.md index e30460c..02ef012 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# Business Prototyping Toolkit for Python +# Business Prototyping Toolkit for Python + +[![Coverage Status](https://coveralls.io/repos/github/transentis/bptk_py/badge.svg)](https://coveralls.io/github/transentis/bptk_py) __System Dynamics and Agent-based Modeling in Python__ @@ -9,7 +11,7 @@ Next to providing the necessary SD and ABM language constructs to build simulati This means you can build models in a XMILE-compatible visual modeling environment (such as [Stella](https://www.iseesystems.com) or [iThink](https://www.iseesystems.com)) and then use them _independently_ in an Python environment. The best way to get started with BPTK-Py is to read the [Quickstart](https://bptk.transentis.com/quickstart/quickstart.html) that is part ot the extensive [online documentation](https://bptk.transentis.com). The Quickstart provides a _single page_ overview of all the computational modeling techniques supported by BPTK. - + ## Main Features @@ -21,13 +23,13 @@ The best way to get started with BPTK-Py is to read the [Quickstart](https://bpt ## Getting Help -BPTK-Py is developed and maintained by [transentis labs](https://www.transentis.com/business-prototyping-toolki/en/). +BPTK-Py is developed and maintained by [transentis labs](https://www.transentis.com/business-prototyping-toolki/en/). -The first place to go to for help and installation instructions is the [online documentation](https://bptk.transentis.com). +The first place to go to for help and installation instructions is the [online documentation](https://bptk.transentis.com). -The [Quickstart](https://bptk.transentis.com/quickstart/quickstart.html) provides a _single page_ overview of all the modeling techniques supported by BPTK. +The [Quickstart](https://bptk.transentis.com/quickstart/quickstart.html) provides a _single page_ overview of all the modeling techniques supported by BPTK. -The online documentation is generated from an extensive set of Jupyter notebooks, the __BPTK Tutorial__. The tutorial is available as a [git repository](https://github.com/transentis/bptk_py_tutorial) on GitHub. +The online documentation is generated from an extensive set of Jupyter notebooks, the __BPTK Tutorial__. The tutorial is available as a [git repository](https://github.com/transentis/bptk_py_tutorial) on GitHub. Our [Business Prototyping Toolkit Meetup Group](https://www.transentis.com/business-prototyping-toolkit-meetup/en/) gathers online regularly. This is a good place to see BPTK in action, ask questions and suggest new features. We record every session and you can _view past recordings_ on the [meetup homepage](https://www.transentis.com/resources/business-prototyping-toolkit-meetup). @@ -121,7 +123,7 @@ For any questions our suggestions you have regarding BPTK, please contact us at: ### 1.5.1 * BPTK Server: Improvements to the new state externalisation feature -* BPTK Server: Improve cleanup of resources when an instance times out +* BPTK Server: Improve cleanup of resources when an instance times out ### 1.5.0 @@ -261,15 +263,15 @@ For any questions our suggestions you have regarding BPTK, please contact us at: ### 1.1.11 * SD-DSL: Added support for right-hand side addition and subtraction to support equations such as ``converter.equation = 1 - b`` -* Visualisation for SD-DSL elements now follows conventions to work properly with Matplotlib 3.3+ +* Visualisation for SD-DSL elements now follows conventions to work properly with Matplotlib 3.3+ ### 1.1.10 -* Visualisation using matplotlib now follows conventions to work properly with Matplotlib 3.3+ +* Visualisation using matplotlib now follows conventions to work properly with Matplotlib 3.3+ ### 1.1.9 * SD-DSL: System Dynamics element such as converters did not implement comparison operators (">", "<", ">=", "==", "!="). They have been added -### 1.1.8 +### 1.1.8 * Another bugfix for series renaming. Simplified the code for renaming by using Pandas' standard method ``rename`` ### 1.1.7 @@ -290,21 +292,21 @@ XMILE equations make use of double-quote enclosed identifiers in case it actuall Update BPTK-Py using the new update mechanism: [documentation](https://bptk.transentis.com/en/latest/docs/usage/installation.html#keeping-bptk-py-up-to-date) ### 1.1.3 -We figured that the update mechanisms via ``pip`` might be confusing sometimes, especially for non-programmers. This is +We figured that the update mechanisms via ``pip`` might be confusing sometimes, especially for non-programmers. This is why we decided to implement an update mechanism. Details are available in the [documentation](https://bptk.transentis.com/en/latest/docs/usage/installation.html#keeping-bptk-py-up-to-date) ### 1.1.2 * Bugfix to (XMILE) SD Compiler: Added support for array expressions within function calls. We had trouble with equations that contain another expression within a function call. E.g. ``DELAY(arrayedElement[1,2]*5, 1, 1)`` was not supported. * Improvement to (XMILE) SD Compiler: Removed replacement of currency symbols (``€``, ``$`` etc.) and percentage signs with abbreviations. We had implemented this in earlier releases but figured it leads to confusion with modellers. -### 1.1.1 +### 1.1.1 * The SD DSL now differentiates flows and biflows. Simply add a biflow using ```biflow = model.biflow()```. -* The SD DSL now supports: RANDOM, IF, NOT, AND, OR, NAN, SQRT, ROUND and all trigonometric and statistical builtins you know from XMILE. Furthermore the operators support Comparison Operators (>, <, >=, <=, ==, !=) and the modulo operator (x % y). +* The SD DSL now supports: RANDOM, IF, NOT, AND, OR, NAN, SQRT, ROUND and all trigonometric and statistical builtins you know from XMILE. Furthermore the operators support Comparison Operators (>, <, >=, <=, ==, !=) and the modulo operator (x % y). * RANDOM: ``converter.equation = sd.Random(, )`` draws a uniformly distributed float random number between and * ROUND: ``converter.equation = sd.Round(sd.random(0,1),2))`` rounds a random number between 0 and 1 to a 2 digit float - * IF: ```converter.equation = sd.If( , , ) ``` corresponds to ```IF THEN ELSE ```. Each term inside the IF clause can be a SD term again. Example for a valid If clause: ``equation = sd.If(sd.time()>10,sd.random(1,2), 100)`` + * IF: ```converter.equation = sd.If( , , ) ``` corresponds to ```IF THEN ELSE ```. Each term inside the IF clause can be a SD term again. Example for a valid If clause: ``equation = sd.If(sd.time()>10,sd.random(1,2), 100)`` * AND/OR: ```sd.Or(, )``` and ```sd.And(, )``` for multiple conditions - * NOT: Use ```sd.Not()``` for "not" conditions, e.g: ```sd.If(sd.Not(sd.time()>10), 1, 0 )``` + * NOT: Use ```sd.Not()``` for "not" conditions, e.g: ```sd.If(sd.Not(sd.time()>10), 1, 0 )``` * NAN / INF / PI: ``sd.nan()`` returns a NAN value, ``sd.Inf()`` gives you the infinity value, ```sd.pi()``` returns the number pi. * SQRT: ``sd.sqrt()`` computes the square root * SIN / TAN / COS: ``sd.sin(x) / sd.cos(x) / sd.tan(x)`` for sinus, cosinus or tangent of x (radians) and of course we also support ARCCOS, ARCSIN, ARCTAN with the same syntax @@ -322,7 +324,7 @@ why we decided to implement an update mechanism. Details are available in the [d ### 1.0.1 -* Bugfix release: Fixed an issue with plot_lookup +* Bugfix release: Fixed an issue with plot_lookup ### 1.0.0 diff --git a/tests/requirements.txt b/tests/requirements.txt index 55b033e..cffeec6 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1 +1,2 @@ -pytest \ No newline at end of file +pytest +pytest-cov \ No newline at end of file diff --git a/tests/test_bptk.py b/tests/test_bptk.py index d10b189..7937b5c 100644 --- a/tests/test_bptk.py +++ b/tests/test_bptk.py @@ -106,6 +106,7 @@ def test_sd_model_results_data_type(sd_model): results = sd_results(bptk) assert isinstance(results, pd.DataFrame) + def test_sd_model_results_col_names(sd_model): """ Testing the column names of the dataframe generated from the model. @@ -135,6 +136,7 @@ def test_sd_model_results_content(sd_model): assert_frame_equal(results, test_df) + def sd_run_scenarios_results(bptk): """ The function returns the dataframe results using the run_scenarios method, based on a simple system dynamics model. @@ -151,6 +153,7 @@ def sd_run_scenarios_results(bptk): ) return results + def test_sd_run_scenarios_df_results(sd_model): """ Testing the df return of run simulations in a simple system dynamics model. @@ -166,6 +169,7 @@ def test_sd_run_scenarios_df_results(sd_model): assert_frame_equal(results, test_df) + def test_sd_run_scenarios_json_results(sd_model): """ Testing the json return of run simulations in a simple system dynamics model. @@ -254,6 +258,7 @@ def abm_model(): """ from abm_model.abmModel import bptk yield bptk + bptk.destroy() def abm_results(bptk): @@ -292,6 +297,7 @@ def test_abm_results_data_type(abm_model): results = abm_results(abm_model) assert isinstance(results, pd.DataFrame) + def test_abm_results_col_names(abm_model): """ Testing the column names of the dataframe generated from the model. @@ -312,6 +318,7 @@ def test_abm_results_col_names(abm_model): assert all(col in expected_column_names for col in columns_names) # making sure that the column names exist + def test_abm_results_content(abm_model): """ Testng the content of the dataframe generated from the agent based model. @@ -362,6 +369,7 @@ def test_abm_run_scenarios_df_results(abm_model): assert_frame_equal(results, test_df) + def test_abm_run_scenarios_json_results(abm_model): """ Testing the json return of run simulations in a simple agent-based model. @@ -413,6 +421,7 @@ def test_abm_run_scenarios_json_results(abm_model): expected_json = json.dumps(expected_json, indent=2) assert results==expected_json + def test_abm_delete_agent(abm_model): model = abm_model.get_scenario(scenario_manager="testAbmManager",scenario="testScenario2")