├── .circleci └── config.yml ├── .dockerignore ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── CODE_OF_CONDUCT.rst ├── CONTRIBUTING.rst ├── Dockerfile ├── LICENSE ├── README.rst ├── cicm2021paper ├── bib.bib ├── example.tex ├── llncs.cls └── main.tex ├── cicm2022paper ├── Makefile ├── README ├── bib.bib ├── example.tex ├── llncs.cls └── main.tex ├── cicm2022talk ├── README ├── architecture.drawio.svg ├── bit.ly_3RnIm7v.png ├── isabelle-server.png ├── isabelle_jedit.png ├── still-ugly.png └── talk.tex ├── doc ├── Makefile ├── _static │ └── tty.gif ├── auto_examples │ ├── images │ │ └── thumb │ │ │ └── sphx_glr_plot_example_thumb.png │ ├── index.rst │ ├── plot_example.ipynb │ ├── plot_example.py │ ├── plot_example.rst │ ├── plot_example.zip │ └── sg_execution_times.rst ├── code-of-conduct.rst ├── conf.py ├── contributing.rst ├── index.rst ├── package-documentation.rst └── requirements.txt ├── examples ├── Example.thy ├── README.rst ├── ROOT ├── cicm2022_example.ipynb ├── document │ └── root.tex ├── example.ipynb └── plot_example.py ├── isabelle_client ├── __init__.py ├── conftest.py ├── isabelle__client.py ├── isabelle_connector.py ├── py.typed ├── resources │ ├── Cygwin-Isabelle.bat │ ├── example.txt │ ├── isabelle │ └── isabelle-responses │ │ ├── cancel │ │ ├── help │ │ ├── purge_theories │ │ ├── session_build │ │ ├── session_start │ │ ├── session_stop │ │ ├── shutdown │ │ ├── unknown │ │ ├── use_theories │ │ ├── use_theories.Fail │ │ └── use_theories.Sledgehammer ├── sledgehammer_connector.py ├── socket_communication.py └── utils.py ├── local-build.sh ├── poetry.lock ├── poetry.toml ├── pyproject.toml └── unpublished-pre-print ├── architecture.pdf ├── cicm2022.bib ├── cicm2022.tex ├── llncs.cls └── splncs04.bst /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | build-and-test: 4 | docker: 5 | - image: inpefess/multipython:3.13 6 | steps: 7 | - checkout 8 | - run: 9 | name: use tox 10 | command: | 11 | pip install tox 12 | pyenv local 3.9.21 3.10.16 3.11.11 3.12.9 3.13.2 13 | tox 14 | - run: 15 | name: upload data to codecov 16 | command: | 17 | bash <(curl -s https://codecov.io/bash) -X gcov -X coveragepy 18 | - store_artifacts: 19 | path: build 20 | - store_test_results: 21 | path: test-results 22 | workflows: 23 | main: 24 | jobs: 25 | - build-and-test 26 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | CONTRIBUTING.rst 3 | CODE_OF_CONDUCT.rst 4 | README.rst 5 | LICENSE 6 | pyproject.toml 7 | poetry.lock 8 | test-results/ 9 | spelling.dict 10 | isabelle_client/ 11 | .venv/ 12 | dist/ 13 | doc/ 14 | ./**/.* 15 | ./**/__pycache__/ 16 | ./**/*.gif 17 | examples/video_example/ 18 | examples/output/ 19 | ./**/*.log 20 | ./**/*.pdf 21 | ./**/*.*~ 22 | ./**/*~ 23 | local-build.sh 24 | ./**/.ini 25 | ./**/.yml 26 | ./**/.toml 27 | cicm2021paper/ 28 | LICENSE 29 | tests/ 30 | coverage.xml 31 | cicm2022paper/ 32 | cicm2022talk/ 33 | unpublished-pre-print/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | dist/ 3 | test-results/ 4 | .venv/ 5 | __pycache__/ 6 | .*~ 7 | *~ 8 | doc/_build/ 9 | .idea/ 10 | *.bbl 11 | *.blg 12 | *.log 13 | *.pdf 14 | *.out 15 | *.aux 16 | *.cicmauthinsts 17 | .ipynb_checkpoints/ 18 | flycheck_*.* 19 | .dir-locals.el 20 | examples/output/ 21 | coverage.xml 22 | *.nav 23 | *.snm 24 | *.toc 25 | _minted-*/ 26 | \#*.*\# 27 | *.pickle 28 | *.md5 29 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: mypy 5 | name: mypy 6 | entry: mypy 7 | language: system 8 | types: [python] 9 | - id: ruff check 10 | name: ruff check 11 | entry: ruff check 12 | language: system 13 | types: [python] 14 | - id: ruff format 15 | name: ruff format 16 | entry: ruff format 17 | language: system 18 | types: [python] 19 | - id: pydoclint 20 | name: pydoclint 21 | entry: pydoclint 22 | language: system 23 | types: [python] 24 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | version: 2 5 | 6 | build: 7 | os: ubuntu-22.04 8 | tools: 9 | python: "3.10" 10 | 11 | sphinx: 12 | configuration: doc/conf.py 13 | fail_on_warning: true 14 | 15 | python: 16 | install: 17 | - requirements: doc/requirements.txt 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.rst: -------------------------------------------------------------------------------- 1 | Contributor Covenant Code of Conduct 2 | ==================================== 3 | 4 | Our Pledge 5 | ---------- 6 | 7 | We as members, contributors, and leaders pledge to make participation in 8 | our community a harassment-free experience for everyone, regardless of 9 | age, body size, visible or invisible disability, ethnicity, sex 10 | characteristics, gender identity and expression, level of experience, 11 | education, socio-economic status, nationality, personal appearance, 12 | race, caste, color, religion, or sexual identity and orientation. 13 | 14 | We pledge to act and interact in ways that contribute to an open, 15 | welcoming, diverse, inclusive, and healthy community. 16 | 17 | Our Standards 18 | ------------- 19 | 20 | Examples of behavior that contributes to a positive environment for our 21 | community include: 22 | 23 | - Demonstrating empathy and kindness toward other people 24 | - Being respectful of differing opinions, viewpoints, and experiences 25 | - Giving and gracefully accepting constructive feedback 26 | - Accepting responsibility and apologizing to those affected by our 27 | mistakes, and learning from the experience 28 | - Focusing on what is best not just for us as individuals, but for the 29 | overall community 30 | 31 | Examples of unacceptable behavior include: 32 | 33 | - The use of sexualized language or imagery, and sexual attention or 34 | advances of any kind 35 | - Trolling, insulting or derogatory comments, and personal or political 36 | attacks 37 | - Public or private harassment 38 | - Publishing others’ private information, such as a physical or email 39 | address, without their explicit permission 40 | - Other conduct which could reasonably be considered inappropriate in a 41 | professional setting 42 | 43 | Enforcement Responsibilities 44 | ---------------------------- 45 | 46 | Community leaders are responsible for clarifying and enforcing our 47 | standards of acceptable behavior and will take appropriate and fair 48 | corrective action in response to any behavior that they deem 49 | inappropriate, threatening, offensive, or harmful. 50 | 51 | Community leaders have the right and responsibility to remove, edit, or 52 | reject comments, commits, code, wiki edits, issues, and other 53 | contributions that are not aligned to this Code of Conduct, and will 54 | communicate reasons for moderation decisions when appropriate. 55 | 56 | Scope 57 | ----- 58 | 59 | This Code of Conduct applies within all community spaces, and also 60 | applies when an individual is officially representing the community in 61 | public spaces. Examples of representing our community include using an 62 | official e-mail address, posting via an official social media account, 63 | or acting as an appointed representative at an online or offline event. 64 | 65 | Enforcement 66 | ----------- 67 | 68 | Instances of abusive, harassing, or otherwise unacceptable behavior may 69 | be reported to the community leaders responsible for enforcement at `the 70 | following email `__. All complaints will be 71 | reviewed and investigated promptly and fairly. 72 | 73 | All community leaders are obligated to respect the privacy and security 74 | of the reporter of any incident. 75 | 76 | Enforcement Guidelines 77 | ---------------------- 78 | 79 | Community leaders will follow these Community Impact Guidelines in 80 | determining the consequences for any action they deem in violation of 81 | this Code of Conduct: 82 | 83 | 1. Correction 84 | ~~~~~~~~~~~~~ 85 | 86 | **Community Impact**: Use of inappropriate language or other behavior 87 | deemed unprofessional or unwelcome in the community. 88 | 89 | **Consequence**: A private, written warning from community leaders, 90 | providing clarity around the nature of the violation and an explanation 91 | of why the behavior was inappropriate. A public apology may be 92 | requested. 93 | 94 | 2. Warning 95 | ~~~~~~~~~~ 96 | 97 | **Community Impact**: A violation through a single incident or series of 98 | actions. 99 | 100 | **Consequence**: A warning with consequences for continued behavior. No 101 | interaction with the people involved, including unsolicited interaction 102 | with those enforcing the Code of Conduct, for a specified period of 103 | time. This includes avoiding interactions in community spaces as well as 104 | external channels like social media. Violating these terms may lead to a 105 | temporary or permanent ban. 106 | 107 | 3. Temporary Ban 108 | ~~~~~~~~~~~~~~~~ 109 | 110 | **Community Impact**: A serious violation of community standards, 111 | including sustained inappropriate behavior. 112 | 113 | **Consequence**: A temporary ban from any sort of interaction or public 114 | communication with the community for a specified period of time. No 115 | public or private interaction with the people involved, including 116 | unsolicited interaction with those enforcing the Code of Conduct, is 117 | allowed during this period. Violating these terms may lead to a 118 | permanent ban. 119 | 120 | 4. Permanent Ban 121 | ~~~~~~~~~~~~~~~~ 122 | 123 | **Community Impact**: Demonstrating a pattern of violation of community 124 | standards, including sustained inappropriate behavior, harassment of an 125 | individual, or aggression toward or disparagement of classes of 126 | individuals. 127 | 128 | **Consequence**: A permanent ban from any sort of public interaction 129 | within the community. 130 | 131 | Attribution 132 | ----------- 133 | 134 | This Code of Conduct is adapted from the `Contributor 135 | Covenant `__, version 2.1, 136 | available at 137 | https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. 138 | 139 | Community Impact Guidelines were inspired by `Mozilla’s code of conduct 140 | enforcement ladder `__. 141 | 142 | For answers to common questions about this code of conduct, see the FAQ 143 | at https://www.contributor-covenant.org/faq. Translations are available 144 | at https://www.contributor-covenant.org/translations. 145 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/inpefess/isabelle-client/issues 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in 22 | troubleshooting. 23 | * Detailed steps to reproduce the bug. 24 | 25 | Fix Bugs 26 | ~~~~~~~~ 27 | 28 | Look through the GitHub issues for bugs. Anything tagged with "bug" 29 | and "help wanted" is open to whoever wants to implement a fix for it. 30 | 31 | Implement Features 32 | ~~~~~~~~~~~~~~~~~~ 33 | 34 | Look through the GitHub issues for features. Anything tagged with 35 | "enhancement" and "help wanted" is open to whoever wants to implement 36 | it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | Python client for Isabelle server could always use more 42 | documentation, whether as part of the official docs, in docstrings, 43 | or even on the web in blog posts, articles, and such. 44 | 45 | Submit Feedback 46 | ~~~~~~~~~~~~~~~ 47 | 48 | The best way to send feedback is to file an issue at 49 | https://github.com/inpefess/isabelle-client/issues. 50 | 51 | If you are proposing a new feature: 52 | 53 | * Explain in detail how it would work. 54 | * Keep the scope as narrow as possible, to make it easier to 55 | implement. 56 | * Remember that this is a volunteer-driven project, and that 57 | contributions are welcome :) 58 | 59 | Get Started! 60 | ------------ 61 | 62 | Ready to contribute? Here's how to set up `isabelle-client` for local 63 | development. Please note this documentation assumes you already have 64 | `Git 65 | `__ 66 | installed and ready to go. 67 | 68 | 1. `Fork `__ the 69 | `isabelle-client` repo on GitHub. 70 | 71 | 1. Clone your fork locally: 72 | 73 | .. code:: sh 74 | 75 | cd path_for_the_repo 76 | git clone git@github.com:YOUR_NAME/isabelle-client.git 77 | 78 | 1. Install 79 | [poetry](https://python-poetry.org/docs/#installing-with-the-official-installer). 80 | 81 | 1. Now you can install all the things you need for development (this 82 | command will also create a virtual environment in `.venv` 83 | subfolder): 84 | 85 | .. code:: bash 86 | 87 | poetry install --all-groups 88 | source .venv/bin/activate 89 | # recommended but not necessary 90 | pre-commit install 91 | 92 | 1. Create a branch for local development: 93 | 94 | .. code:: bash 95 | 96 | git checkout -b name-of-your-bugfix-or-feature 97 | 98 | Now you can make your changes locally. 99 | 100 | 1. When you're done making changes, check that your changes pass code 101 | quality checks. 102 | 103 | .. code:: bash 104 | 105 | ruff format 106 | ruff check 107 | pydoclint isabelle_client 108 | mypy isabelle_client 109 | 110 | 1. The next step would be to run the test cases. `isabelle-client` 111 | uses pytest and all the existing tests are `doctests 112 | `__. 113 | 114 | .. code:: bash 115 | 116 | pytest 117 | 118 | 7. If your contribution is a bug fix or new feature, you may want to 119 | add a test to the existing test suite. If possible, do it by 120 | doctest, not a dedicates test case file. 121 | 122 | 1. Commit your changes and push your branch to GitHub: 123 | 124 | .. code:: bash 125 | 126 | git add . 127 | git commit -m "Your detailed description of your changes." 128 | git push origin name-of-your-bugfix-or-feature 129 | 130 | 1. Submit a pull request through the GitHub website. 131 | 132 | 133 | Pull Request Guidelines 134 | ----------------------- 135 | 136 | Before you submit a pull request, check that it meets these 137 | guidelines: 138 | 139 | 1. The pull request should include tests. 140 | 141 | 2. If the pull request adds functionality, the docs should be 142 | updated. Put your new functionality into a function with a 143 | docstring, and add the feature to the list in README.rst. 144 | 145 | 3. The pull request should work for Python 3.9, 3.10, 3.11, 3.12 and 146 | 3.13. Check https://github.com/inpefess/isabelle-client/pulls and 147 | make sure that the tests pass for all supported Python versions. 148 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM makarius/isabelle:Isabelle2024_X11_Latex 2 | ARG NB_USER=jovyan 3 | ARG NB_UID=1000 4 | ENV USER ${NB_USER} 5 | ENV NB_UID ${NB_UID} 6 | USER root 7 | RUN groupmod -g 9999 isabelle 8 | RUN usermod -u 9999 -g 9999 isabelle 9 | RUN adduser --disabled-password \ 10 | --gecos "Default user" \ 11 | --uid ${NB_UID} \ 12 | ${NB_USER} 13 | RUN apt-get update 14 | RUN apt-get install -y python3-pip 15 | ENV HOME /home/${NB_USER} 16 | ENV ISABELLE_BIN /home/isabelle/Isabelle/bin/ 17 | ENV PATH=${HOME}/.local/bin/:${ISABELLE_BIN}:${PATH} 18 | COPY examples/ ${HOME}/isabelle-client-examples/ 19 | RUN chown -R ${NB_USER}:${NB_USER} ${HOME}/isabelle-client-examples/ 20 | RUN chown -R ${NB_USER}:${NB_USER} ${ISABELLE_BIN} 21 | USER ${NB_USER} 22 | WORKDIR ${HOME} 23 | RUN python3 -m pip install --no-cache-dir notebook jupyterlab isabelle-client 24 | ENTRYPOINT [] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | |Binder|\ |PyPI version|\ |Anaconda version|\ |CircleCI|\ |Documentation Status|\ |codecov|\ |DOI| 2 | 3 | Python client for Isabelle server 4 | ================================= 5 | 6 | ``isabelle-client`` is a TCP client for 7 | `Isabelle `__ server. For more information 8 | about the server see Chapter 4 of `the Isabelle system 9 | manual `__. 10 | 11 | How to Install 12 | ============== 13 | 14 | The best way to install this package is to use ``pip``: 15 | 16 | .. code:: sh 17 | 18 | pip install isabelle-client 19 | 20 | 21 | Another option is to use Anaconda: 22 | 23 | .. code:: sh 24 | 25 | conda install -c conda-forge isabelle-client 26 | 27 | One can also download and run the client together with Isabelle in a 28 | Docker contanier: 29 | 30 | .. code:: sh 31 | 32 | docker build -t isabelle-client https://github.com/inpefess/isabelle-client.git 33 | docker run -it --rm -p 8888:8888 isabelle-client jupyter-lab --ip=0.0.0.0 --port=8888 34 | 35 | How to use 36 | ========== 37 | 38 | .. code:: python 39 | 40 | from isabelle_client import get_isabelle_client, start_isabelle_server 41 | 42 | # start Isabelle server 43 | server_info, _ = start_isabelle_server() 44 | # create a client object 45 | isabelle = get_isabelle_client(server_info) 46 | # send a theory file from the current directory to the server 47 | response = isabelle.use_theories( 48 | theories=["Example"], master_dir=".", watchdog_timeout=0 49 | ) 50 | # shut the server down 51 | isabelle.shutdown() 52 | 53 | 54 | For more details, follow the `usage 55 | example `__ 56 | from documentation, run the 57 | `script `__, 58 | or use ``isabelle-client`` from a 59 | `notebook `__. 60 | 61 | More documentation 62 | ================== 63 | 64 | More documentation can be found 65 | `here `__. 66 | 67 | Similar Software 68 | ================ 69 | 70 | There are Python clients to other interactive theorem provers, for 71 | example: 72 | 73 | * `for Lean 74 | `__ 75 | * `for Coq `__ 76 | * `another one for Coq `__ 77 | 78 | Modules helping to inetract with Isabelle server from Python are 79 | parts of the `Proving for Fun 80 | `__ project. 81 | 82 | There are also clients to Isabelle server in other programming 83 | languages, e.g. `this one in Rust 84 | `__. 85 | 86 | How to cite 87 | =========== 88 | 89 | If you’re writing a research paper, you can cite the Isabelle client 90 | using the `following DOI 91 | `__. You can also cite 92 | Isabelle 2021 (and the earlier version of the client) with `this DOI 93 | `__. There also is a 94 | somewhat more complete (but unpublished) `pre-print 95 | `__. 96 | 97 | How to Contribute 98 | ================= 99 | 100 | Please follow `the contribution guide `__ while adhering to `the code of conduct `__. 101 | 102 | 103 | .. |PyPI version| image:: https://badge.fury.io/py/isabelle-client.svg 104 | :target: https://badge.fury.io/py/isabelle-client 105 | .. |Anaconda version| image:: https://anaconda.org/conda-forge/isabelle-client/badges/version.svg 106 | :target: https://anaconda.org/conda-forge/isabelle-client 107 | .. |CircleCI| image:: https://circleci.com/gh/inpefess/isabelle-client.svg?style=svg 108 | :target: https://circleci.com/gh/inpefess/isabelle-client 109 | .. |Documentation Status| image:: https://readthedocs.org/projects/isabelle-client/badge/?version=latest 110 | :target: https://isabelle-client.readthedocs.io/en/latest/?badge=latest 111 | .. |codecov| image:: https://codecov.io/gh/inpefess/isabelle-client/branch/master/graph/badge.svg 112 | :target: https://codecov.io/gh/inpefess/isabelle-client 113 | .. |Binder| image:: https://mybinder.org/badge_logo.svg 114 | :target: https://mybinder.org/v2/gh/inpefess/isabelle-client/HEAD?labpath=isabelle-client-examples/example.ipynb 115 | .. |DOI| image:: https://img.shields.io/badge/DOI-10.1007%2F978--3--031--16681--5__24-blue 116 | :target: https://doi.org/10.1007/978-3-031-16681-5_24 117 | -------------------------------------------------------------------------------- /cicm2021paper/bib.bib: -------------------------------------------------------------------------------- 1 | @article{DBLP:journals/sttt/DragomirPT20, 2 | author = {Iulia Dragomir and 3 | Viorel Preoteasa and 4 | Stavros Tripakis}, 5 | title = {The Refinement Calculus of Reactive Systems Toolset}, 6 | journal = {Int. J. Softw. Tools Technol. Transf.}, 7 | volume = {22}, 8 | number = {6}, 9 | pages = {689--708}, 10 | year = {2020}, 11 | url = {https://doi.org/10.1007/s10009-020-00561-4}, 12 | doi = {10.1007/s10009-020-00561-4}, 13 | timestamp = {Tue, 17 Nov 2020 11:22:15 +0100}, 14 | biburl = {https://dblp.org/rec/journals/sttt/DragomirPT20.bib}, 15 | bibsource = {dblp computer science bibliography, https://dblp.org} 16 | } 17 | 18 | @misc{Kaggle2020MLSurvey, 19 | author = {Kaggle}, 20 | title = {State of Data Science and Machine Learning}, 21 | year = {2020}, 22 | publisher = {Kaggle}, 23 | note = {\url{https://www.kaggle.com/kaggle-survey-2020}} 24 | } 25 | 26 | @misc{ProvingContestBackends, 27 | author = {Maximilian P.L. Haslbeck, Simon Wimmer}, 28 | title = {Platform for interactive theorem proving competitions}, 29 | publisher = {GitHub}, 30 | note = {\url{https://github.com/maxhaslbeck/proving-contest-backends}} 31 | } 32 | 33 | @manual{isabelle-system, 34 | author = {Makarius Wenzel}, 35 | title = {The {Isabelle} System Manual}, 36 | note = {\url{https://isabelle.in.tum.de/doc/system.pdf}}} -------------------------------------------------------------------------------- /cicm2021paper/example.tex: -------------------------------------------------------------------------------- 1 | % This is an example of contribution. 2 | % 3 | % The TOOL, VERSION, PROGRAMMINGLANGUAGE, LICENSE AND URL fields are 4 | % mandatory, as well as a list of CICMauthor. 5 | % 6 | % After the \maketool command you can put a number of subsubsections. 7 | % Suggested ones are: ``Description'', ``Applications'', 8 | % ``Changes from previous version'' (when applicable) 9 | % 10 | % The contribution should exactly fit one page. 11 | % 12 | % You can provide a bib.bib file for the bibliography. The bibliography 13 | % will be consolidated at the end of the consolidated paper. 14 | 15 | \TOOL{Python client for Isabelle server} 16 | \VERSION{0.2.0} 17 | \PROGRAMMINGLANGUAGE{Python} 18 | \LICENSE{Apache 2.0} 19 | \URL{https://pypi.org/project/isabelle-client} 20 | \CICMauthor{Boris Shminke}{Université Côte d’Azur, CNRS, LJAD, France} 21 | 22 | \maketool 23 | 24 | \subsubsection{Description} 25 | Python client for Isabelle server gives researchers using Python as their primary programming language an opportunity to communicate with Isabelle server through TCP directly from a Python script. Since Python-based tools continue to dominate the machine learning (ML) frameworks~\cite{Kaggle2020MLSurvey}, this package, installable from The Python Package Index, can help researchers from the ML community to use the power of Isabelle proof assistant in their studies. Also, in other research domains where Isabelle can be helpful, Python as scripting languages remains preferable~\cite{DBLP:journals/sttt/DragomirPT20}. Some pieces of software written in Python and related to Isabelle (e.g.~\cite{ProvingContestBackends}) can include code for communication with the server, but they are hard to find, not easily reusable and well-documented. 26 | 27 | The client relies on a standard Python package \texttt{asyncio} for low-level communication with the server. It implements wrapper methods for all commands of Isabelle server listed in its manual~\cite{isabelle-system}. The package also includes a function for starting Isabelle server from Python script. 28 | 29 | \subsubsection{Applications} At the moment, the package is being used by its author for research in AI for algebra. It helps to check hundreds of working hypotheses, auto-generated by other Python scripts. 30 | 31 | \subsubsection{Acknowledgements} This work has been supported by the French government, through the 3IA Côte d’Azur Investments in the Future project managed by the National Research Agency (ANR) with the reference number ANR-19-P3IA-0002. 32 | -------------------------------------------------------------------------------- /cicm2021paper/main.tex: -------------------------------------------------------------------------------- 1 | %\documentclass[preprint]{llncs} 2 | \documentclass{llncs} 3 | \usepackage{hyperref} 4 | %\usepackage{floatflt} 5 | %\begin{floatingtable}[r]{ 6 | %}\end{floatingtable} 7 | 8 | %%%% Macro to append all authors 9 | \makeatletter 10 | % CICMauthor 11 | %\newcommand{\CICMauthors}{\@starttoc{cicmauthors}} 12 | %\newcommand{\l@CICMauthors}[2]{#1\par} 13 | \newcommand{\CICMauthor}[2]{ 14 | % \addtocontents{cicmauthors}{#1} 15 | % \addtocontents{cicinstitutes}{#2} 16 | \addtocontents{cicmauthinsts}{\textbf{#1}, #2\newline} 17 | } 18 | 19 | % CICMinstitute 20 | %\newcommand{\CICMinstitutes}{\@starttoc{cicinstitutes}} 21 | %\newcommand{\l@CICMinstitutes}[2]{#1\par} 22 | 23 | % CICMauthinsts 24 | \newcommand{\CICMauthinsts}{\@starttoc{cicmauthinsts}} 25 | 26 | \newcommand{\TOOL}[1]{\def\@TOOL{#1}} 27 | \newcommand{\VERSION}[1]{\def\@VERSION{#1}} 28 | \newcommand{\PROGRAMMINGLANGUAGE}[1]{\def\@PROGRAMMINGLANGUAGE{#1}} 29 | \newcommand{\LICENSE}[1]{\def\@LICENSE{#1}} 30 | \newcommand{\URL}[1]{\def\@URL{\url{#1}}} 31 | 32 | \newcommand{\maketool}{ 33 | \noindent 34 | \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}@{}lr} 35 | \begin{tabular}[t]{@{}p{5cm}} 36 | {\Large\textbf{\@TOOL}}\\\\ 37 | \CICMauthinsts\\ 38 | \end{tabular} 39 | & 40 | \begin{tabular}[t]{@{}|ll|} 41 | \hline 42 | \textbf{Tool:} & \@TOOL{} (v\@VERSION)\\ 43 | \textbf{Impl. in:} & \@PROGRAMMINGLANGUAGE\\ 44 | \textbf{License:} & \@LICENSE\\ 45 | \textbf{Download:} & \\ 46 | \multicolumn{2}{l}{\@URL}\\ 47 | \hline 48 | \end{tabular} 49 | \end{tabular*} 50 | } 51 | 52 | \makeatother 53 | 54 | \title{CICM'21 Systems Entry} 55 | 56 | \author{Here we will put the consoldated list of authors} 57 | 58 | \institute{And here the consolidated list of institutes} 59 | 60 | \begin{document} 61 | \maketitle 62 | 63 | %Authors: \CICMauthors 64 | 65 | %Institutes: \CICMinstitutes 66 | 67 | \begin{abstract} 68 | This paper gives an overview of new tools and improvements of existing tools in the CICM domain. 69 | \end{abstract} 70 | 71 | \newpage 72 | 73 | \input{example.tex} 74 | 75 | \newpage 76 | 77 | \bibliographystyle{plain} 78 | \bibliography{bib.bib} 79 | 80 | \end{document} 81 | -------------------------------------------------------------------------------- /cicm2022paper/Makefile: -------------------------------------------------------------------------------- 1 | filename=main 2 | fullname=${filename}.tex 3 | default: pdf 4 | pdf: 5 | pdflatex ${fullname} 6 | bibtex ${filename} 7 | pdflatex ${fullname} 8 | bibtex ${filename} 9 | pdflatex ${fullname} 10 | clean: 11 | rm -f ${filename}.pdf 12 | rm -f ${filename}.aux 13 | rm -f ${filename}.bbl 14 | rm -f ${filename}.blg 15 | rm -f ${filename}.log 16 | rm -f ${filename}.out 17 | rm -f ${filename}.cicmauthinsts 18 | -------------------------------------------------------------------------------- /cicm2022paper/README: -------------------------------------------------------------------------------- 1 | Build with `make` or `make clean pdf` -------------------------------------------------------------------------------- /cicm2022paper/bib.bib: -------------------------------------------------------------------------------- 1 | @inproceedings{IsabelleServer, 2 | author = {Makarius Wenzel}, 3 | title = {{Isabelle/PIDE after 10 years of development}}, 4 | booktitle = {13th International Workshop on User Interfaces for Theorem Provers (UITP 2018)}, 5 | series = {Federated Logic Conference 2018}, 6 | year = 2018, 7 | url = {https://sketis.net/wp-content/uploads/2018/08/isabelle-pide-uitp2018.pdf} 8 | } 9 | @article{FussnerShminke, 10 | doi = {10.48550/ARXIV.2109.05264}, 11 | url = {https://arxiv.org/abs/2109.05264}, 12 | author = {Fussner, Wesley and Shminke, Boris}, 13 | keywords = {Logic in Computer Science (cs.LO), FOS: Computer and information sciences, FOS: Computer and information sciences}, 14 | title = {{Mining counterexamples for wide-signature algebras with an Isabelle server}}, 15 | journal = {arXiv:2109.05264 [cs.LO]}, 16 | publisher = {arXiv}, 17 | year = {2021}, 18 | copyright = {Creative Commons Attribution 4.0 International} 19 | } 20 | @article{haslbeck2019competitive, 21 | title={{Competitive Proving for Fun}}, 22 | author={Haslbeck, Maximilian PL and Wimmer, Simon}, 23 | journal={Kalpa Publications in Computing}, 24 | volume={10}, 25 | pages={9--14}, 26 | year={2019}, 27 | publisher={EasyChair} 28 | } 29 | @inproceedings{DBLP:conf/mkm/LiskaLNRSSSW21, 30 | author = {Martin L{\'{\i}}ska and 31 | D{\'{a}}vid Lupt{\'{a}}k and 32 | V{\'{\i}}t Novotn{\'{y}} and 33 | Michal Ruzicka and 34 | Boris Shminke and 35 | Petr Sojka and 36 | Michal Stef{\'{a}}nik and 37 | Makarius Wenzel}, 38 | editor = {Fairouz Kamareddine and 39 | Claudio Sacerdoti Coen}, 40 | title = {{CICM'21 Systems Entries}}, 41 | booktitle = {Intelligent Computer Mathematics - 14th International Conference, 42 | {CICM} 2021, Timisoara, Romania, July 26-31, 2021, Proceedings}, 43 | series = {Lecture Notes in Computer Science}, 44 | volume = {12833}, 45 | pages = {245--248}, 46 | publisher = {Springer}, 47 | year = {2021}, 48 | url = {https://doi.org/10.1007/978-3-030-81097-9\_20}, 49 | doi = {10.1007/978-3-030-81097-9\_20}, 50 | timestamp = {Mon, 03 Jan 2022 22:24:40 +0100}, 51 | biburl = {https://dblp.org/rec/conf/mkm/LiskaLNRSSSW21.bib}, 52 | bibsource = {dblp computer science bibliography, https://dblp.org} 53 | } 54 | @article{conda_forge_community_2015_4774216, 55 | author = {conda-forge community}, 56 | title = {{The conda-forge Project: Community-based Software 57 | Distribution Built on the conda Package Format and 58 | Ecosystem}}, 59 | month = jul, 60 | year = 2015, 61 | publisher = {Zenodo}, 62 | journal = {Zenodo}, 63 | doi = {10.5281/zenodo.4774216}, 64 | url = {https://doi.org/10.5281/zenodo.4774216}, 65 | volume = {https://doi.org/10.5281/zenodo.4774216} 66 | } 67 | @InProceedings{ project_jupyter-proc-scipy-2018, 68 | author = { {P}roject {J}upyter and {M}atthias {B}ussonnier and {J}essica {F}orde and {J}eremy {F}reeman and {B}rian {G}ranger and {T}im {H}ead and {C}hris {H}oldgraf and {K}yle {K}elley and {G}ladys {N}alvarte and {A}ndrew {O}sheroff and {M} {P}acer and {Y}uvi {P}anda and {F}ernando {P}erez and {B}enjamin {R}agan-{K}elley and {C}arol {W}illing }, 69 | title = { {B}inder 2.0 - {R}eproducible, interactive, sharable environments for science at scale }, 70 | booktitle = { {P}roceedings of the 17th {P}ython in {S}cience {C}onference }, 71 | pages = { 113 - 120 }, 72 | year = { 2018 }, 73 | editor = { {F}atih {A}kici and {D}avid {L}ippa and {D}illon {N}iederhut and {M} {P}acer }, 74 | doi = { 10.25080/Majora-4af1f417-011 } 75 | } 76 | @article{boris_shminke_2022_6490275, 77 | author = {Boris Shminke}, 78 | title = {{Python client for Isabelle server (0.3.5)}}, 79 | month = apr, 80 | year = 2022, 81 | publisher = {Zenodo}, 82 | journal = {Zenodo}, 83 | doi = {10.5281/zenodo.6490275}, 84 | url = {https://doi.org/10.5281/zenodo.6490275}, 85 | volume = {https://doi.org/10.5281/zenodo.6490275} 86 | } 87 | @article{isabelle_system_manual, 88 | author = {Makarius Wenzel}, 89 | title = {{The Isabelle System Manual}}, 90 | month = dec, 91 | year = 2021, 92 | url = {https://isabelle.in.tum.de/dist/Isabelle2021-1/doc/system.pdf}, 93 | volume = {https://isabelle.in.tum.de/dist/Isabelle2021-1/doc/system.pdf}, 94 | } -------------------------------------------------------------------------------- /cicm2022paper/example.tex: -------------------------------------------------------------------------------- 1 | %% Copyright 2022 Boris Shminke 2 | %% 3 | %% Licensed under the Apache License, Version 2.0 (the "License"); 4 | %% you may not use this file except in compliance with the License. 5 | %% You may obtain a copy of the License at 6 | %% 7 | %% https://www.apache.org/licenses/LICENSE-2.0 8 | %% 9 | %% Unless required by applicable law or agreed to in writing, software 10 | %% distributed under the License is distributed on an "AS IS" BASIS, 11 | %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | %% See the License for the specific language governing permissions and 13 | %% limitations under the License. 14 | 15 | \TOOL{Python client for Isabell\-e server} 16 | \VERSION{0.3.5} 17 | \PROGRAMMINGLANGUAGE{Python} 18 | \LICENSE{Apache-2.0} 19 | \URL{https://pypi.org/project/isabelle-client} 20 | \CICMauthor{Boris Shminke}{Laboratoire J.A. Dieudonné, CNRS and Université Côte d'Azur, France 21 | \email{boris.shminke@cnrs.fr}} 22 | 23 | \maketool 24 | 25 | \subsubsection{Description}~ 26 | 27 | Python client to Isabelle server~\cite{IsabelleServer} gives researchers and students using Python as their primary programming language an opportunity to communicate with the Isabelle server through TCP directly from a Python script. 28 | 29 | Such an approach helps avoid the complexities of integrating the existing Python script with languages used for Isabelle development (ML and Scala). \texttt{isabelle-client} relies on \texttt{asyncio}, a Python package providing a high-level interface for TCP communications. 30 | 31 | The client supports relaying all the Isabelle server commands described in its manual (see Chapter 4 of~\cite{isabelle_system_manual}) and parses the responses back to Python objects. 32 | 33 | The client's distributive package also provides a utility function for starting an instance of the Isabelle server in the background directly from a Python script. 34 | 35 | The digital artefact of the current version is available on Zenodo~\cite{boris_shminke_2022_6490275}. Interested potential users of the client can also follow an interactive example~\footnote{ \href{https://mybinder.org/v2/gh/inpefess/isabelle-client/HEAD?labpath=isabelle-client-examples/example.ipynb}{https://bit.ly/isabelle-client}} and the package documentation~\footnote{\href{https://isabelle-client.rtfd.io}{https://isabelle-client.rtfd.io}} for more detailed information. 36 | 37 | \subsubsection{Applications} 38 | \begin{itemize} 39 | \item A discovery of a proof~\cite{FussnerShminke} for an algebraic problem which stood open for two years despite the efforts of specialists in the field. 40 | \item The \texttt{isabelle-client} running in a Docker container on Binder was used during the practical sessions of the Advanced Logic course taught at the Université Côte d'Azur in the autumn of the 2021-2022 academic year. This use case helped the author to realise the need for ease of the installation procedure on different operating systems and programming environments. 41 | \item Also, Fabian Huch used the \texttt{isabelle-client} for debugging the ``Proving for Fun'' backend~\cite{haslbeck2019competitive}. Thanks to this use case, the importance of supporting different (and even outdated) versions of Python became known. 42 | \end{itemize} 43 | \subsubsection{Changes from previous version}~ 44 | 45 | The first public version (0.2.0) of this client~\cite{DBLP:conf/mkm/LiskaLNRSSSW21} worked only for Python 3.7 on GNU/Linux and was supposed to be installed only with the \texttt{pip} package manager. 46 | \begin{itemize} 47 | \item The current version is available for any Python 3.6+ on GNU/Linux and Windows. Every new build is tested in a continuous integration workflow against each supported Python version. 48 | \item The package is hosted now not only on the Python Package Index (PyPI), but also on Conda Forge~\cite{conda_forge_community_2015_4774216}, which enables its installation with both \texttt{pip} and \texttt{conda} package managers. 49 | \item In addition, one can run the client inside a Docker container, for example, in a cloud using Binder~\cite{project_jupyter-proc-scipy-2018}. 50 | \item The current version of the client is tested to work with the latest Isabelle 2021-1 (released in December 2021). 51 | \item The last client version returns all server replies as a Python list, not only the last one as it was in the previous version giving more flexibility to the end-user. 52 | \item Last but not least, the current version arrives with detailed documentation pages and is nearly 100\% covered with unit tests using fixtures for emulating a working Isabelle server behaviour. 53 | \end{itemize} 54 | \subsubsection{Acknowledgements} 55 | This work has been supported by the French government, through the 3IA Côte d'Azur Investments in the Future project managed by the National Research Agency (ANR) with the reference number ANR-19-P3IA-0002. 56 | -------------------------------------------------------------------------------- /cicm2022paper/main.tex: -------------------------------------------------------------------------------- 1 | %\documentclass[preprint]{llncs} 2 | \documentclass{llncs} 3 | \usepackage{hyperref} 4 | %\usepackage{floatflt} 5 | %\begin{floatingtable}[r]{ 6 | %}\end{floatingtable} 7 | 8 | %%%% Macro to append all authors 9 | \makeatletter 10 | % CICMauthor 11 | %\newcommand{\CICMauthors}{\@starttoc{cicmauthors}} 12 | %\newcommand{\l@CICMauthors}[2]{#1\par} 13 | \newcommand{\CICMauthor}[2]{ 14 | % \addtocontents{cicmauthors}{#1} 15 | % \addtocontents{cicinstitutes}{#2} 16 | \addtocontents{cicmauthinsts}{\textbf{#1}, #2\newline} 17 | } 18 | 19 | % CICMinstitute 20 | %\newcommand{\CICMinstitutes}{\@starttoc{cicinstitutes}} 21 | %\newcommand{\l@CICMinstitutes}[2]{#1\par} 22 | 23 | % CICMauthinsts 24 | \newcommand{\CICMauthinsts}{\@starttoc{cicmauthinsts}} 25 | 26 | \newcommand{\TOOL}[1]{\def\@TOOL{#1}} 27 | \newcommand{\VERSION}[1]{\def\@VERSION{#1}} 28 | \newcommand{\PROGRAMMINGLANGUAGE}[1]{\def\@PROGRAMMINGLANGUAGE{#1}} 29 | \newcommand{\LICENSE}[1]{\def\@LICENSE{#1}} 30 | \newcommand{\URL}[1]{\def\@URL{\url{#1}}} 31 | 32 | \newcommand{\maketool}{ 33 | \noindent 34 | \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}@{}lr} 35 | \begin{tabular}[t]{@{}p{5cm}} 36 | {\Large\textbf{\@TOOL}}\\\\ 37 | \CICMauthinsts\\ 38 | \end{tabular} 39 | & 40 | \begin{tabular}[t]{@{}|ll|} 41 | \hline 42 | \textbf{Tool:} & \@TOOL{} (v\@VERSION)\\ 43 | \textbf{Impl. in:} & \@PROGRAMMINGLANGUAGE\\ 44 | \textbf{License:} & \@LICENSE\\ 45 | \textbf{Download:} & \\ 46 | \multicolumn{2}{l}{\@URL}\\ 47 | \hline 48 | \end{tabular} 49 | \end{tabular*} 50 | } 51 | 52 | \makeatother 53 | 54 | \title{CICM'2022 System Entries} 55 | 56 | \author{Here we will put the consoldated list of authors} 57 | 58 | \institute{And here the consolidated list of institutes} 59 | 60 | \begin{document} 61 | \maketitle 62 | 63 | %Authors: \CICMauthors 64 | 65 | %Institutes: \CICMinstitutes 66 | 67 | \begin{abstract} 68 | This paper gives an overview of new tools and improvements of existing tools in the CICM domain. 69 | \end{abstract} 70 | 71 | \newpage 72 | 73 | \input{example.tex} 74 | 75 | \newpage 76 | 77 | \bibliographystyle{plain} 78 | \bibliography{bib.bib} 79 | 80 | \end{document} 81 | -------------------------------------------------------------------------------- /cicm2022talk/README: -------------------------------------------------------------------------------- 1 | Build with `pdflatex talk.tex` -------------------------------------------------------------------------------- /cicm2022talk/architecture.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
isabelle-client package









isabelle-client package...

theory file
theory...
Isabelle Server
Isabelle Server
an instance of IsabelleClient class
an instance of Isabell...
start_isabelle_server
function
start_isabelle_server...
init params
init params
server info
server info
server info
server info
requests
requests
replies
replies
other Python scripts
other Python scripts
as arguments
as arguments

theory file
theory...
generate
generate
theories' processing
results
theories' processing...

theory file
theory...
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /cicm2022talk/bit.ly_3RnIm7v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/cicm2022talk/bit.ly_3RnIm7v.png -------------------------------------------------------------------------------- /cicm2022talk/isabelle-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/cicm2022talk/isabelle-server.png -------------------------------------------------------------------------------- /cicm2022talk/isabelle_jedit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/cicm2022talk/isabelle_jedit.png -------------------------------------------------------------------------------- /cicm2022talk/still-ugly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/cicm2022talk/still-ugly.png -------------------------------------------------------------------------------- /cicm2022talk/talk.tex: -------------------------------------------------------------------------------- 1 | %% Copyright 2022 Boris Shminke 2 | %% 3 | %% Licensed under the Apache License, Version 2.0 (the "License"); 4 | %% you may not use this file except in compliance with the License. 5 | %% You may obtain a copy of the License at 6 | %% 7 | %% https://www.apache.org/licenses/LICENSE-2.0 8 | %% 9 | %% Unless required by applicable law or agreed to in writing, software 10 | %% distributed under the License is distributed on an "AS IS" BASIS, 11 | %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | %% See the License for the specific language governing permissions and 13 | %% limitations under the License. 14 | \documentclass{beamer} 15 | \usetheme{Antibes} 16 | \usepackage{hyperref} 17 | \usepackage{caption} 18 | \title{Python client for Isabelle server} 19 | \author{Boris Shminke} 20 | \institute{Université Côte d’Azur, CNRS, LJAD, France} 21 | \date{21 Sep 2022} 22 | \begin{document} 23 | \begin{frame} 24 | \titlepage 25 | \end{frame} 26 | \begin{frame} 27 | \frametitle{Motivation: Isabelle GUI is great, but} 28 | \begin{columns}[T] 29 | \begin{column}{0.3\textwidth} 30 | \begin{itemize} 31 | \item manual input 32 | \item interactive 33 | \item no other programming language needed 34 | \end{itemize} 35 | \end{column} 36 | \begin{column}{0.7\textwidth} 37 | \includegraphics[width=\paperwidth,height=\paperheight]{isabelle_jedit} 38 | \end{column} 39 | \end{columns} 40 | \end{frame} 41 | \begin{frame} 42 | \frametitle{Motivation: hacking Isabelle is demanding} 43 | \begin{columns}[T] 44 | \begin{column}{0.45\textwidth} 45 | \begin{itemize} 46 | \item input: files, streams, etc 47 | \item one can program (nearly) anything 48 | \item \texttt{Scala} and/or \texttt{Poly/ML} 49 | \end{itemize} 50 | \end{column} 51 | \begin{column}{0.55\textwidth} 52 | \includegraphics[width=\paperwidth,height=\paperheight]{still-ugly} 53 | \end{column} 54 | \end{columns} 55 | \end{frame} 56 | \begin{frame}[t] 57 | \frametitle{Motivation: Isabelle server - in between} 58 | \begin{itemize} 59 | \item a ready solution (since 2018) 60 | \item working with theory files (in bulk) 61 | \item any language (through TCP) 62 | \end{itemize} 63 | \end{frame} 64 | \begin{frame} 65 | \frametitle{Demo: Isabelle server from Python} 66 | \begin{figure} 67 | \caption*{\url{https://bit.ly/3RnIm7v}} 68 | \includegraphics[scale=0.25]{bit.ly_3RnIm7v.png} 69 | \end{figure} 70 | \end{frame} 71 | \begin{frame}[t] 72 | \frametitle{Demo: main takeaways} 73 | \begin{itemize} 74 | \item we worked with Isabelle theories as texts 75 | \item we haven't use any language except Python 76 | \item Isabelle did for us what it does best 77 | \end{itemize} 78 | \end{frame} 79 | \begin{frame}[t] 80 | \frametitle{What else I can do with Python client: research} 81 | \begin{itemize} 82 | \item generate hundreds of theories to check 83 | \item parse \texttt{Nitpick} replies to get finite models 84 | \item crack a research problem which stood open for two years! 85 | \item \url{https://github.com/inpefess/residuated-binars} 86 | \item \url{https://arxiv.org/abs/2109.05264} 87 | \end{itemize} 88 | \end{frame} 89 | \begin{frame}[t] 90 | \frametitle{What else I can do with Python client: education} 91 | \begin{itemize} 92 | \item teach students who know Python a bit of Isabelle syntax 93 | \item generate finite models for different algebraic structures 94 | \item double-check the models found in Python 95 | \item (Advanced Logic course at the Université Côte d'Azur) 96 | \end{itemize} 97 | \end{frame} 98 | \begin{frame}[t] 99 | \frametitle{Who uses the Python client?} 100 | \begin{itemize} 101 | \item unfortunately, mostly its author 102 | \item but the students from my course did 103 | \item and Fabian Huch tested Proving for Fun backend with it 104 | \item Haslbeck, Maximilian PL, and Simon Wimmer. Competitive Proving for Fun. Kalpa Publications in Computing 10 (2019): 9-14. 105 | \end{itemize} 106 | \end{frame} 107 | \begin{frame}[t] 108 | \frametitle{How to get the Python client?} 109 | \begin{itemize} 110 | \item \texttt{pip}, \texttt{conda} or \texttt{Docker} 111 | \item Linux and Windows 112 | \item read the docs: \url{https://isabelle-client.rtfd.io} 113 | \end{itemize} 114 | \end{frame} 115 | \begin{frame}[t] 116 | \frametitle{Future plans} 117 | \begin{itemize} 118 | \item continue maintaining the package 119 | \item take part in Isabelle server development 120 | \item hear suggestions from you! 121 | \end{itemize} 122 | \end{frame} 123 | \begin{frame}[t] 124 | \frametitle{Thank you for your attention!} 125 | \begin{itemize} 126 | \item happy to answer your questions now 127 | \item or later during CICM in person 128 | \item or by email \url{mailto:boris.shminke@univ-cotedazur.fr} 129 | \end{itemize} 130 | \end{frame} 131 | \end{document} 132 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/_static/tty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/doc/_static/tty.gif -------------------------------------------------------------------------------- /doc/auto_examples/images/thumb/sphx_glr_plot_example_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/doc/auto_examples/images/thumb/sphx_glr_plot_example_thumb.png -------------------------------------------------------------------------------- /doc/auto_examples/index.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Isabelle client usage examples 4 | ============================== 5 | 6 | 7 | 8 | .. raw:: html 9 | 10 |
11 | 12 | .. thumbnail-parent-div-open 13 | 14 | .. raw:: html 15 | 16 |
17 | 18 | .. only:: html 19 | 20 | .. image:: /auto_examples/images/thumb/sphx_glr_plot_example_thumb.png 21 | :alt: 22 | 23 | :ref:`sphx_glr_auto_examples_plot_example.py` 24 | 25 | .. raw:: html 26 | 27 |
Basic usage example.
28 |
29 | 30 | 31 | .. thumbnail-parent-div-close 32 | 33 | .. raw:: html 34 | 35 |
36 | 37 | 38 | .. toctree:: 39 | :hidden: 40 | 41 | /auto_examples/plot_example 42 | 43 | 44 | 45 | .. only:: html 46 | 47 | .. rst-class:: sphx-glr-signature 48 | 49 | `Gallery generated by Sphinx-Gallery `_ 50 | -------------------------------------------------------------------------------- /doc/auto_examples/plot_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n# Basic usage example.\n" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## In what case to use\n\nThis client might be useful if:\n\n* you have a machine with Isabelle installed\n* you have scripts for automatic generation of theory files in Python\n* you want to communicate with the server not using\n [Scala](https://scala-lang.org/)_ and/or\n [Standard ML](https://polyml.org/)_\n\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## In what environment to use\n\nThe client works well in scripts and in Jupyter notebooks. For the\nlatter, one has to enable nested event loops first. Please refer to\n``nest_asyncio`` [documentation](https://pypi.org/project/nest-asyncio/)_.\n\n" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Starting Isabelle server\nFirst, we need to start an Isabelle server\n\n" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": { 35 | "collapsed": false 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "from isabelle_client import start_isabelle_server\n\nserver_info, _ = start_isabelle_server(\n name=\"test\", port=9999, log_file=\"server.log\"\n)" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "

Warning

When using [start_isabelle_server](package-documentation.html#isabelle_client.utils.start_isabelle_server)_\n utility function in Python REPL or terminal IPython, shutting the server\n down within the same session is known to cause a runtime error on exit from\n the session. This behaviour is related to a [well known issue](https://ipython.readthedocs.io/en/stable/interactive/autoawait.html#difference-between-terminal-ipython-and-ipykernel)_.

\n\n" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "We could also start the server outside this script and use its info (on\nWindows, this is done in Cygwin)::\n\n isabelle server\n\n" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "## Interacting with Isabelle server\nLet's create a client to our server\n\n" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": { 67 | "collapsed": false 68 | }, 69 | "outputs": [], 70 | "source": [ 71 | "from isabelle_client import get_isabelle_client\n\nisabelle = get_isabelle_client(server_info)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "We will log all the messages from the server to a file\n\n" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": { 85 | "collapsed": false 86 | }, 87 | "outputs": [], 88 | "source": [ 89 | "import logging\n\nisabelle.logger = logging.getLogger()\nisabelle.logger.setLevel(logging.INFO)\nisabelle.logger.addHandler(logging.FileHandler(\"session.log\"))" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "Isabelle client supports all the commands implemented in Isabelle server\n\n" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": { 103 | "collapsed": false 104 | }, 105 | "outputs": [], 106 | "source": [ 107 | "from pprint import pprint\n\npprint(isabelle.help())" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "Let's suppose we have a ``Example.thy`` theory file in our working directory\nwhich we, e.g. generated with another Python script\n\n.. literalinclude:: ../../examples/Example.thy\n\n\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "We can send this theory file to the server and get a response\n\n" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "metadata": { 128 | "collapsed": false 129 | }, 130 | "outputs": [], 131 | "source": [ 132 | "pprint(isabelle.use_theories(theories=[\"Example\"], master_dir=\".\"))" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "or we can build a session document using ``./ROOT`` file\n\n.. literalinclude:: ../../examples/ROOT\n\nand ``./document/root.tex`` file\n\n.. literalinclude:: ../../examples/document/root.tex\n :language: tex\n\n\n" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": { 146 | "collapsed": false 147 | }, 148 | "outputs": [], 149 | "source": [ 150 | "import json\n\npprint(\n json.loads(\n isabelle.session_build(dirs=[\".\"], session=\"examples\")[\n -1\n ].response_body\n )\n)" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "One can also issue a free-form command, e.g.\n\n" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": { 164 | "collapsed": false 165 | }, 166 | "outputs": [], 167 | "source": [ 168 | "import asyncio\n\npprint(asyncio.run(isabelle.execute_command(\"echo 42\", asynchronous=False)))" 169 | ] 170 | }, 171 | { 172 | "cell_type": "markdown", 173 | "metadata": {}, 174 | "source": [ 175 | "Finally, we can shut the server down.\n\n" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": null, 181 | "metadata": { 182 | "collapsed": false 183 | }, 184 | "outputs": [], 185 | "source": [ 186 | "pprint(isabelle.shutdown())" 187 | ] 188 | } 189 | ], 190 | "metadata": { 191 | "kernelspec": { 192 | "display_name": "Python 3", 193 | "language": "python", 194 | "name": "python3" 195 | }, 196 | "language_info": { 197 | "codemirror_mode": { 198 | "name": "ipython", 199 | "version": 3 200 | }, 201 | "file_extension": ".py", 202 | "mimetype": "text/x-python", 203 | "name": "python", 204 | "nbconvert_exporter": "python", 205 | "pygments_lexer": "ipython3", 206 | "version": "3.12.7" 207 | } 208 | }, 209 | "nbformat": 4, 210 | "nbformat_minor": 0 211 | } -------------------------------------------------------------------------------- /doc/auto_examples/plot_example.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Basic usage example. 16 | ==================== 17 | """ # noqa: D205 18 | 19 | # %% 20 | # In what case to use 21 | # ------------------- 22 | # 23 | # This client might be useful if: 24 | # 25 | # * you have a machine with Isabelle installed 26 | # * you have scripts for automatic generation of theory files in Python 27 | # * you want to communicate with the server not using 28 | # `Scala `__ and/or 29 | # `Standard ML `__ 30 | 31 | # %% 32 | # In what environment to use 33 | # -------------------------- 34 | # 35 | # The client works well in scripts and in Jupyter notebooks. For the 36 | # latter, one has to enable nested event loops first. Please refer to 37 | # ``nest_asyncio`` `documentation 38 | # `__. 39 | 40 | # %% 41 | # Starting Isabelle server 42 | # ------------------------ 43 | # First, we need to start an Isabelle server 44 | 45 | from isabelle_client import start_isabelle_server 46 | 47 | server_info, _ = start_isabelle_server( 48 | name="test", port=9999, log_file="server.log" 49 | ) 50 | 51 | # %% 52 | # .. warning:: 53 | # When using `start_isabelle_server 54 | # `__ 55 | # utility function in Python REPL or terminal IPython, shutting the server 56 | # down within the same session is known to cause a runtime error on exit from 57 | # the session. This behaviour is related to a `well known issue 58 | # `__. 59 | 60 | # %% 61 | # We could also start the server outside this script and use its info (on 62 | # Windows, this is done in Cygwin):: 63 | # 64 | # isabelle server 65 | 66 | # %% 67 | # Interacting with Isabelle server 68 | # -------------------------------- 69 | # Let's create a client to our server 70 | 71 | from isabelle_client import get_isabelle_client 72 | 73 | isabelle = get_isabelle_client(server_info) 74 | 75 | # %% 76 | # We will log all the messages from the server to a file 77 | 78 | import logging 79 | 80 | isabelle.logger = logging.getLogger() 81 | isabelle.logger.setLevel(logging.INFO) 82 | isabelle.logger.addHandler(logging.FileHandler("session.log")) 83 | 84 | # %% 85 | # Isabelle client supports all the commands implemented in Isabelle server 86 | 87 | from pprint import pprint 88 | 89 | pprint(isabelle.help()) 90 | 91 | # %% 92 | # Let's suppose we have a ``Example.thy`` theory file in our working directory 93 | # which we, e.g. generated with another Python script 94 | # 95 | # .. literalinclude:: ../../examples/Example.thy 96 | # 97 | 98 | # %% 99 | # We can send this theory file to the server and get a response 100 | 101 | pprint(isabelle.use_theories(theories=["Example"], master_dir=".")) 102 | 103 | # %% 104 | # or we can build a session document using ``./ROOT`` file 105 | # 106 | # .. literalinclude:: ../../examples/ROOT 107 | # 108 | # and ``./document/root.tex`` file 109 | # 110 | # .. literalinclude:: ../../examples/document/root.tex 111 | # :language: tex 112 | # 113 | 114 | import json 115 | 116 | pprint( 117 | json.loads( 118 | isabelle.session_build(dirs=["."], session="examples")[ 119 | -1 120 | ].response_body 121 | ) 122 | ) 123 | 124 | # %% 125 | # One can also issue a free-form command, e.g. 126 | 127 | import asyncio 128 | 129 | pprint(asyncio.run(isabelle.execute_command("echo 42", asynchronous=False))) 130 | 131 | # %% 132 | # Finally, we can shut the server down. 133 | 134 | pprint(isabelle.shutdown()) 135 | -------------------------------------------------------------------------------- /doc/auto_examples/plot_example.rst: -------------------------------------------------------------------------------- 1 | 2 | .. DO NOT EDIT. 3 | .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. 4 | .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: 5 | .. "auto_examples/plot_example.py" 6 | .. LINE NUMBERS ARE GIVEN BELOW. 7 | 8 | .. only:: html 9 | 10 | .. note:: 11 | :class: sphx-glr-download-link-note 12 | 13 | :ref:`Go to the end ` 14 | to download the full example code. 15 | 16 | .. rst-class:: sphx-glr-example-title 17 | 18 | .. _sphx_glr_auto_examples_plot_example.py: 19 | 20 | 21 | Basic usage example. 22 | ==================== 23 | 24 | .. GENERATED FROM PYTHON SOURCE LINES 21-31 25 | 26 | In what case to use 27 | ------------------- 28 | 29 | This client might be useful if: 30 | 31 | * you have a machine with Isabelle installed 32 | * you have scripts for automatic generation of theory files in Python 33 | * you want to communicate with the server not using 34 | `Scala `__ and/or 35 | `Standard ML `__ 36 | 37 | .. GENERATED FROM PYTHON SOURCE LINES 33-40 38 | 39 | In what environment to use 40 | -------------------------- 41 | 42 | The client works well in scripts and in Jupyter notebooks. For the 43 | latter, one has to enable nested event loops first. Please refer to 44 | ``nest_asyncio`` `documentation 45 | `__. 46 | 47 | .. GENERATED FROM PYTHON SOURCE LINES 42-45 48 | 49 | Starting Isabelle server 50 | ------------------------ 51 | First, we need to start an Isabelle server 52 | 53 | .. GENERATED FROM PYTHON SOURCE LINES 45-52 54 | 55 | .. code-block:: Python 56 | 57 | 58 | from isabelle_client import start_isabelle_server 59 | 60 | server_info, _ = start_isabelle_server( 61 | name="test", port=9999, log_file="server.log" 62 | ) 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | .. GENERATED FROM PYTHON SOURCE LINES 53-60 72 | 73 | .. warning:: 74 | When using `start_isabelle_server 75 | `__ 76 | utility function in Python REPL or terminal IPython, shutting the server 77 | down within the same session is known to cause a runtime error on exit from 78 | the session. This behaviour is related to a `well known issue 79 | `__. 80 | 81 | .. GENERATED FROM PYTHON SOURCE LINES 62-66 82 | 83 | We could also start the server outside this script and use its info (on 84 | Windows, this is done in Cygwin):: 85 | 86 | isabelle server 87 | 88 | .. GENERATED FROM PYTHON SOURCE LINES 68-71 89 | 90 | Interacting with Isabelle server 91 | -------------------------------- 92 | Let's create a client to our server 93 | 94 | .. GENERATED FROM PYTHON SOURCE LINES 71-76 95 | 96 | .. code-block:: Python 97 | 98 | 99 | from isabelle_client import get_isabelle_client 100 | 101 | isabelle = get_isabelle_client(server_info) 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | .. GENERATED FROM PYTHON SOURCE LINES 77-78 111 | 112 | We will log all the messages from the server to a file 113 | 114 | .. GENERATED FROM PYTHON SOURCE LINES 78-85 115 | 116 | .. code-block:: Python 117 | 118 | 119 | import logging 120 | 121 | isabelle.logger = logging.getLogger() 122 | isabelle.logger.setLevel(logging.INFO) 123 | isabelle.logger.addHandler(logging.FileHandler("session.log")) 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | .. GENERATED FROM PYTHON SOURCE LINES 86-87 133 | 134 | Isabelle client supports all the commands implemented in Isabelle server 135 | 136 | .. GENERATED FROM PYTHON SOURCE LINES 87-92 137 | 138 | .. code-block:: Python 139 | 140 | 141 | from pprint import pprint 142 | 143 | pprint(isabelle.help()) 144 | 145 | 146 | 147 | 148 | 149 | .. rst-class:: sphx-glr-script-out 150 | 151 | .. code-block:: none 152 | 153 | [IsabelleResponse(response_type='OK', 154 | response_body='{"isabelle_id":"29f2b8ff84f3","isabelle_name":"Isabelle2024"}', 155 | response_length=None), 156 | IsabelleResponse(response_type='OK', 157 | response_body='["cancel","echo","help","purge_theories","session_build","session_start","session_stop","shutdown","use_theories"]', 158 | response_length=118)] 159 | 160 | 161 | 162 | 163 | .. GENERATED FROM PYTHON SOURCE LINES 93-98 164 | 165 | Let's suppose we have a ``Example.thy`` theory file in our working directory 166 | which we, e.g. generated with another Python script 167 | 168 | .. literalinclude:: ../../examples/Example.thy 169 | 170 | 171 | .. GENERATED FROM PYTHON SOURCE LINES 100-101 172 | 173 | We can send this theory file to the server and get a response 174 | 175 | .. GENERATED FROM PYTHON SOURCE LINES 101-104 176 | 177 | .. code-block:: Python 178 | 179 | 180 | pprint(isabelle.use_theories(theories=["Example"], master_dir=".")) 181 | 182 | 183 | 184 | 185 | 186 | .. rst-class:: sphx-glr-script-out 187 | 188 | .. code-block:: none 189 | 190 | [IsabelleResponse(response_type='OK', 191 | response_body='{"isabelle_id":"29f2b8ff84f3","isabelle_name":"Isabelle2024"}', 192 | response_length=None), 193 | IsabelleResponse(response_type='OK', 194 | response_body='{"task":"93ecddd5-d6b5-4e4e-9ac4-28902a27abe7"}', 195 | response_length=None), 196 | IsabelleResponse(response_type='NOTE', 197 | response_body='{"percentage":99,"task":"93ecddd5-d6b5-4e4e-9ac4-28902a27abe7","message":"theory ' 198 | 'Draft.Example ' 199 | '99%","kind":"writeln","session":"","theory":"Draft.Example"}', 200 | response_length=161), 201 | IsabelleResponse(response_type='NOTE', 202 | response_body='{"percentage":100,"task":"93ecddd5-d6b5-4e4e-9ac4-28902a27abe7","message":"theory ' 203 | 'Draft.Example ' 204 | '100%","kind":"writeln","session":"","theory":"Draft.Example"}', 205 | response_length=163), 206 | IsabelleResponse(response_type='FINISHED', 207 | response_body='{"ok":true,"errors":[],"nodes":[{"messages":[{"kind":"writeln","message":"theorem ' 208 | '\\\\x. \\\\y. x = ' 209 | 'y","pos":{"line":5,"offset":59,"end_offset":61,"file":"Example.thy"}}],"exports":[],"status":{"percentage":100,"unprocessed":0,"running":0,"finished":7,"failed":0,"total":7,"consolidated":true,"canceled":false,"ok":true,"warned":0},"theory_name":"Draft.Example","node_name":"Example.thy"}],"task":"93ecddd5-d6b5-4e4e-9ac4-28902a27abe7"}', 210 | response_length=458)] 211 | 212 | 213 | 214 | 215 | .. GENERATED FROM PYTHON SOURCE LINES 105-114 216 | 217 | or we can build a session document using ``./ROOT`` file 218 | 219 | .. literalinclude:: ../../examples/ROOT 220 | 221 | and ``./document/root.tex`` file 222 | 223 | .. literalinclude:: ../../examples/document/root.tex 224 | :language: tex 225 | 226 | 227 | .. GENERATED FROM PYTHON SOURCE LINES 114-125 228 | 229 | .. code-block:: Python 230 | 231 | 232 | import json 233 | 234 | pprint( 235 | json.loads( 236 | isabelle.session_build(dirs=["."], session="examples")[ 237 | -1 238 | ].response_body 239 | ) 240 | ) 241 | 242 | 243 | 244 | 245 | 246 | .. rst-class:: sphx-glr-script-out 247 | 248 | .. code-block:: none 249 | 250 | {'ok': True, 251 | 'return_code': 0, 252 | 'sessions': [{'ok': True, 253 | 'return_code': 0, 254 | 'session': 'Pure', 255 | 'timeout': False, 256 | 'timing': {'cpu': 0, 'elapsed': 0, 'gc': 0}}, 257 | {'ok': True, 258 | 'return_code': 0, 259 | 'session': 'HOL', 260 | 'timeout': False, 261 | 'timing': {'cpu': 0, 'elapsed': 0, 'gc': 0}}, 262 | {'ok': True, 263 | 'return_code': 0, 264 | 'session': 'examples', 265 | 'timeout': False, 266 | 'timing': {'cpu': 0, 'elapsed': 0, 'gc': 0}}], 267 | 'task': 'fef060b0-a9cf-42d0-a696-746545968457'} 268 | 269 | 270 | 271 | 272 | .. GENERATED FROM PYTHON SOURCE LINES 126-127 273 | 274 | One can also issue a free-form command, e.g. 275 | 276 | .. GENERATED FROM PYTHON SOURCE LINES 127-132 277 | 278 | .. code-block:: Python 279 | 280 | 281 | import asyncio 282 | 283 | pprint(asyncio.run(isabelle.execute_command("echo 42", asynchronous=False))) 284 | 285 | 286 | 287 | 288 | 289 | .. rst-class:: sphx-glr-script-out 290 | 291 | .. code-block:: none 292 | 293 | [IsabelleResponse(response_type='OK', 294 | response_body='{"isabelle_id":"29f2b8ff84f3","isabelle_name":"Isabelle2024"}', 295 | response_length=None), 296 | IsabelleResponse(response_type='OK', response_body='42', response_length=None)] 297 | 298 | 299 | 300 | 301 | .. GENERATED FROM PYTHON SOURCE LINES 133-134 302 | 303 | Finally, we can shut the server down. 304 | 305 | .. GENERATED FROM PYTHON SOURCE LINES 134-136 306 | 307 | .. code-block:: Python 308 | 309 | 310 | pprint(isabelle.shutdown()) 311 | 312 | 313 | 314 | 315 | .. rst-class:: sphx-glr-script-out 316 | 317 | .. code-block:: none 318 | 319 | [IsabelleResponse(response_type='OK', 320 | response_body='{"isabelle_id":"29f2b8ff84f3","isabelle_name":"Isabelle2024"}', 321 | response_length=None), 322 | IsabelleResponse(response_type='OK', response_body='', response_length=None)] 323 | 324 | 325 | 326 | 327 | 328 | .. rst-class:: sphx-glr-timing 329 | 330 | **Total running time of the script:** (0 minutes 9.814 seconds) 331 | 332 | 333 | .. _sphx_glr_download_auto_examples_plot_example.py: 334 | 335 | .. only:: html 336 | 337 | .. container:: sphx-glr-footer sphx-glr-footer-example 338 | 339 | .. container:: sphx-glr-download sphx-glr-download-jupyter 340 | 341 | :download:`Download Jupyter notebook: plot_example.ipynb ` 342 | 343 | .. container:: sphx-glr-download sphx-glr-download-python 344 | 345 | :download:`Download Python source code: plot_example.py ` 346 | 347 | .. container:: sphx-glr-download sphx-glr-download-zip 348 | 349 | :download:`Download zipped: plot_example.zip ` 350 | 351 | 352 | .. only:: html 353 | 354 | .. rst-class:: sphx-glr-signature 355 | 356 | `Gallery generated by Sphinx-Gallery `_ 357 | -------------------------------------------------------------------------------- /doc/auto_examples/plot_example.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/doc/auto_examples/plot_example.zip -------------------------------------------------------------------------------- /doc/auto_examples/sg_execution_times.rst: -------------------------------------------------------------------------------- 1 | 2 | :orphan: 3 | 4 | .. _sphx_glr_auto_examples_sg_execution_times: 5 | 6 | 7 | Computation times 8 | ================= 9 | **00:09.814** total execution time for 1 file **from auto_examples**: 10 | 11 | .. container:: 12 | 13 | .. raw:: html 14 | 15 | 19 | 20 | 21 | 22 | 27 | 28 | .. list-table:: 29 | :header-rows: 1 30 | :class: table table-striped sg-datatable 31 | 32 | * - Example 33 | - Time 34 | - Mem (MB) 35 | * - :ref:`sphx_glr_auto_examples_plot_example.py` (``plot_example.py``) 36 | - 00:09.814 37 | - 0.0 38 | -------------------------------------------------------------------------------- /doc/code-of-conduct.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CODE_OF_CONDUCT.rst 2 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # type: ignore 2 | # Copyright 2021-2025 Boris Shminke 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | """Sphinx doc config.""" 16 | 17 | import os 18 | import sys 19 | 20 | sys.path.insert(0, os.path.abspath("..")) 21 | project = "isabelle-client" 22 | version = "0.5.6" 23 | copyright = "2021-2025, Boris Shminke" 24 | author = "Boris Shminke" 25 | extensions = [ 26 | "sphinx.ext.autodoc", 27 | "sphinx.ext.coverage", 28 | # uncomment to rebuild examples 29 | # "sphinx_gallery.gen_gallery", 30 | ] 31 | html_theme = "furo" 32 | sphinx_gallery_conf = { 33 | "download_all_examples": False, 34 | "run_stale_examples": True, 35 | "image_scrapers": (), 36 | "reset_modules": (), 37 | } 38 | -------------------------------------------------------------------------------- /doc/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Copyright 2021-2025 Boris Shminke 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | .. include:: ../README.rst 17 | 18 | .. toctree:: 19 | :hidden: 20 | :caption: API 21 | 22 | package-documentation 23 | 24 | .. toctree:: 25 | :hidden: 26 | :caption: Tutorials 27 | 28 | auto_examples/index.rst 29 | 30 | .. toctree:: 31 | :hidden: 32 | :caption: Development 33 | 34 | code-of-conduct 35 | contributing 36 | GitHub 37 | -------------------------------------------------------------------------------- /doc/package-documentation.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Copyright 2021-2025 Boris Shminke 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | 17 | Package Documentation 18 | ********************** 19 | 20 | .. automodule:: isabelle_client.isabelle__client 21 | :members: 22 | .. automodule:: isabelle_client.socket_communication 23 | :members: 24 | .. automodule:: isabelle_client.utils 25 | :members: 26 | .. automodule:: isabelle_client.isabelle_connector 27 | :members: 28 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-autodoc-typehints 2 | furo 3 | -------------------------------------------------------------------------------- /examples/Example.thy: -------------------------------------------------------------------------------- 1 | theory Example 2 | imports Main 3 | begin 4 | lemma "\ x. \ y. x = y" 5 | by auto 6 | end -------------------------------------------------------------------------------- /examples/README.rst: -------------------------------------------------------------------------------- 1 | Isabelle client usage examples 2 | ============================== 3 | -------------------------------------------------------------------------------- /examples/ROOT: -------------------------------------------------------------------------------- 1 | session examples = HOL + 2 | options [document = pdf, document_output = "output"] 3 | theories 4 | Example 5 | document_files 6 | "root.tex" 7 | -------------------------------------------------------------------------------- /examples/document/root.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{isabelle,isabellesym} 3 | \begin{document} 4 | \input{session} 5 | \end{document} 6 | -------------------------------------------------------------------------------- /examples/example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "bdc105c1-829b-43a6-886f-6d43dc950ed9", 6 | "metadata": { 7 | "collapsed": false, 8 | "jupyter": { 9 | "outputs_hidden": false 10 | } 11 | }, 12 | "source": [ 13 | "
\n",
 14 |     "Copyright 2021-2025 Boris Shminke\n",
 15 |     "\n",
 16 |     "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
 17 |     "you may not use this file except in compliance with the License.\n",
 18 |     "You may obtain a copy of the License at\n",
 19 |     "\n",
 20 |     "    https://www.apache.org/licenses/LICENSE-2.0\n",
 21 |     "\n",
 22 |     "Unless required by applicable law or agreed to in writing, software\n",
 23 |     "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
 24 |     "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
 25 |     "See the License for the specific language governing permissions and\n",
 26 |     "limitations under the License.\n",
 27 |     "
" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 1, 33 | "id": "1913689d-0f91-4cb3-bee2-357d6394db08", 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "# since both Jupyter and `isabelle-client` use `asyncio` we need to enable\n", 38 | "# nested event loops. We don't need that when using `isabelle-client` from\n", 39 | "# Python scripts outside Jupyter\n", 40 | "import nest_asyncio\n", 41 | "\n", 42 | "nest_asyncio.apply()" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 2, 48 | "id": "fecbb14f", 49 | "metadata": { 50 | "collapsed": false, 51 | "jupyter": { 52 | "outputs_hidden": false 53 | } 54 | }, 55 | "outputs": [], 56 | "source": [ 57 | "from isabelle_client import start_isabelle_server\n", 58 | "# first, we start Isabelle server\n", 59 | "server_info, _ = start_isabelle_server(\n", 60 | " name=\"test\", port=9999, log_file=\"server.log\"\n", 61 | ")" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 3, 67 | "id": "e02c57ff", 68 | "metadata": { 69 | "collapsed": false, 70 | "jupyter": { 71 | "outputs_hidden": false 72 | } 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "import logging\n", 77 | "\n", 78 | "from isabelle_client import get_isabelle_client\n", 79 | "# then we create Python client to Isabelle server\n", 80 | "isabelle = get_isabelle_client(server_info)\n", 81 | "!rm -f session.log\n", 82 | "# we will log all the messages from the server to a file\n", 83 | "isabelle.logger = logging.getLogger()\n", 84 | "isabelle.logger.setLevel(logging.INFO)\n", 85 | "isabelle.logger.addHandler(logging.FileHandler(\"session.log\"))" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 4, 91 | "id": "f63ba6e5", 92 | "metadata": { 93 | "collapsed": false, 94 | "jupyter": { 95 | "outputs_hidden": false 96 | } 97 | }, 98 | "outputs": [ 99 | { 100 | "name": "stdout", 101 | "output_type": "stream", 102 | "text": [ 103 | "theory Example\n", 104 | "imports Main\n", 105 | "begin\n", 106 | "lemma \"\\ x. \\ y. x = y\"\n", 107 | "by auto\n", 108 | "end" 109 | ] 110 | } 111 | ], 112 | "source": [ 113 | "# suppose we have an Isabelle theory file\n", 114 | "# (probably generated by another Python script)\n", 115 | "!cat Example.thy" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 5, 121 | "id": "1b9b1c81", 122 | "metadata": { 123 | "collapsed": false, 124 | "jupyter": { 125 | "outputs_hidden": false 126 | } 127 | }, 128 | "outputs": [ 129 | { 130 | "data": { 131 | "text/plain": [ 132 | "[IsabelleResponse(response_type='OK', response_body='{\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}', response_length=None),\n", 133 | " IsabelleResponse(response_type='OK', response_body='{\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\"}', response_length=None),\n", 134 | " IsabelleResponse(response_type='NOTE', response_body='{\"percentage\":14,\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\",\"message\":\"theory Draft.Example 14%\",\"kind\":\"writeln\",\"session\":\"\",\"theory\":\"Draft.Example\"}', response_length=161),\n", 135 | " IsabelleResponse(response_type='NOTE', response_body='{\"percentage\":99,\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\",\"message\":\"theory Draft.Example 99%\",\"kind\":\"writeln\",\"session\":\"\",\"theory\":\"Draft.Example\"}', response_length=161),\n", 136 | " IsabelleResponse(response_type='NOTE', response_body='{\"percentage\":100,\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\",\"message\":\"theory Draft.Example 100%\",\"kind\":\"writeln\",\"session\":\"\",\"theory\":\"Draft.Example\"}', response_length=163),\n", 137 | " IsabelleResponse(response_type='FINISHED', response_body='{\"ok\":true,\"errors\":[],\"nodes\":[{\"messages\":[{\"kind\":\"writeln\",\"message\":\"theorem \\\\\\\\x. \\\\\\\\y. x = y\",\"pos\":{\"line\":5,\"offset\":59,\"end_offset\":61,\"file\":\"Example.thy\"}}],\"exports\":[],\"status\":{\"percentage\":100,\"unprocessed\":0,\"running\":0,\"finished\":7,\"failed\":0,\"total\":7,\"consolidated\":true,\"canceled\":false,\"ok\":true,\"warned\":0},\"theory_name\":\"Draft.Example\",\"node_name\":\"Example.thy\"}],\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\"}', response_length=458)]" 138 | ] 139 | }, 140 | "execution_count": 5, 141 | "metadata": {}, 142 | "output_type": "execute_result" 143 | } 144 | ], 145 | "source": [ 146 | "# we can send this file to the server and get a response\n", 147 | "isabelle.use_theories(\n", 148 | " theories=[\"Example\"], master_dir=\".\", watchdog_timeout=0\n", 149 | ")" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 6, 155 | "id": "3dc1e5cf", 156 | "metadata": { 157 | "collapsed": false, 158 | "jupyter": { 159 | "outputs_hidden": false 160 | } 161 | }, 162 | "outputs": [ 163 | { 164 | "name": "stdout", 165 | "output_type": "stream", 166 | "text": [ 167 | "session examples = HOL +\n", 168 | " options [document = pdf, document_output = \"output\"]\n", 169 | " theories\n", 170 | " Example\n", 171 | " document_files\n", 172 | " \"root.tex\"\n" 173 | ] 174 | } 175 | ], 176 | "source": [ 177 | "# if we have a session description using ROOT file like this\n", 178 | "!rm -rf output\n", 179 | "!cat ROOT" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 7, 185 | "id": "63b4f95b", 186 | "metadata": { 187 | "collapsed": false, 188 | "jupyter": { 189 | "outputs_hidden": false 190 | } 191 | }, 192 | "outputs": [ 193 | { 194 | "data": { 195 | "text/plain": [ 196 | "[IsabelleResponse(response_type='OK', response_body='{\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}', response_length=None),\n", 197 | " IsabelleResponse(response_type='OK', response_body='{\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=None),\n", 198 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session Pure/Pure\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=117),\n", 199 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session Misc/Tools\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=118),\n", 200 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session HOL/HOL (main)\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=122),\n", 201 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session Unsorted/examples\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=125),\n", 202 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session Pure/Pure\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=117),\n", 203 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session Misc/Tools\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=118),\n", 204 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session HOL/HOL (main)\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=122),\n", 205 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Session Unsorted/examples\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=125),\n", 206 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Building examples ...\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=122),\n", 207 | " IsabelleResponse(response_type='NOTE', response_body='{\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\",\"message\":\"examples: theory examples.Example\",\"kind\":\"writeln\",\"session\":\"examples\",\"theory\":\"examples.Example\"}', response_length=165),\n", 208 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Preparing examples/document ...\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=132),\n", 209 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Finished examples/document (0:00:00 elapsed time)\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=150),\n", 210 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Document at \\\\\"/home/jovyan/isabelle-client-examples/output/document.pdf\\\\\"\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=174),\n", 211 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Timing examples (6 threads, 0.109s elapsed time, 0.143s cpu time, 0.000s GC time, factor 1.31)\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=194),\n", 212 | " IsabelleResponse(response_type='NOTE', response_body='{\"kind\":\"writeln\",\"message\":\"Finished examples (0:00:03 elapsed time, 0:00:05 cpu time, factor 1.37)\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=172),\n", 213 | " IsabelleResponse(response_type='FINISHED', response_body='{\"ok\":true,\"return_code\":0,\"sessions\":[{\"session\":\"Pure\",\"ok\":true,\"timeout\":false,\"timing\":{\"elapsed\":0,\"cpu\":0,\"gc\":0},\"return_code\":0},{\"session\":\"HOL\",\"ok\":true,\"timeout\":false,\"timing\":{\"elapsed\":0,\"cpu\":0,\"gc\":0},\"return_code\":0},{\"session\":\"examples\",\"ok\":true,\"timeout\":false,\"timing\":{\"elapsed\":3.86,\"cpu\":5.307,\"gc\":0},\"return_code\":0}],\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}', response_length=403)]" 214 | ] 215 | }, 216 | "execution_count": 7, 217 | "metadata": {}, 218 | "output_type": "execute_result" 219 | } 220 | ], 221 | "source": [ 222 | "# we can build session (`isabelle build`)\n", 223 | "isabelle.session_build(dirs=[\".\"], session=\"examples\")" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": 8, 229 | "id": "c576e2d4", 230 | "metadata": { 231 | "collapsed": false, 232 | "jupyter": { 233 | "outputs_hidden": false 234 | } 235 | }, 236 | "outputs": [ 237 | { 238 | "name": "stdout", 239 | "output_type": "stream", 240 | "text": [ 241 | "document document.pdf\n" 242 | ] 243 | } 244 | ], 245 | "source": [ 246 | "# the results will appear in `output` folder\n", 247 | "!ls output" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": 9, 253 | "id": "017283ff", 254 | "metadata": { 255 | "collapsed": false, 256 | "jupyter": { 257 | "outputs_hidden": false 258 | } 259 | }, 260 | "outputs": [ 261 | { 262 | "data": { 263 | "text/plain": [ 264 | "[IsabelleResponse(response_type='OK', response_body='{\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}', response_length=None),\n", 265 | " IsabelleResponse(response_type='OK', response_body='42', response_length=None)]" 266 | ] 267 | }, 268 | "execution_count": 9, 269 | "metadata": {}, 270 | "output_type": "execute_result" 271 | } 272 | ], 273 | "source": [ 274 | "import asyncio\n", 275 | "\n", 276 | "# or we can issue a free-text command through TCP\n", 277 | "# here `asynchronous` argument means 'asynchronous command' as defined\n", 278 | "# in section 4.2.6. of Isabelle System manual. `echo` is a synchronous command\n", 279 | "# but Python communicates with Isabelle asynchronously as always\n", 280 | "asyncio.run(isabelle.execute_command(\"echo 42\", asynchronous=False))" 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": 10, 286 | "id": "6d7136e2", 287 | "metadata": { 288 | "collapsed": false, 289 | "jupyter": { 290 | "outputs_hidden": false 291 | } 292 | }, 293 | "outputs": [ 294 | { 295 | "data": { 296 | "text/plain": [ 297 | "[IsabelleResponse(response_type='OK', response_body='{\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}', response_length=None),\n", 298 | " IsabelleResponse(response_type='OK', response_body='', response_length=None)]" 299 | ] 300 | }, 301 | "execution_count": 10, 302 | "metadata": {}, 303 | "output_type": "execute_result" 304 | } 305 | ], 306 | "source": [ 307 | "# we can also shut down the Isabelle server\n", 308 | "isabelle.shutdown()" 309 | ] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": 11, 314 | "id": "43ac6954", 315 | "metadata": { 316 | "collapsed": false, 317 | "jupyter": { 318 | "outputs_hidden": false 319 | } 320 | }, 321 | "outputs": [ 322 | { 323 | "name": "stdout", 324 | "output_type": "stream", 325 | "text": [ 326 | "206ea174-1c5c-4fb3-81c4-d7b3b21aa69f\n", 327 | "session_start {\"session\": \"Main\"}\n", 328 | "\n", 329 | "OK {\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}\n", 330 | "OK {\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 331 | "117\n", 332 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Pure/Pure\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 333 | "118\n", 334 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Misc/Tools\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 335 | "122\n", 336 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session HOL/HOL (main)\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 337 | "122\n", 338 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Doc/Main (doc)\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 339 | "117\n", 340 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Pure/Pure\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 341 | "118\n", 342 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Misc/Tools\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 343 | "122\n", 344 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session HOL/HOL (main)\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 345 | "122\n", 346 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Doc/Main (doc)\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 347 | "118\n", 348 | "NOTE {\"kind\":\"writeln\",\"message\":\"Building Main ...\",\"verbose\":\"false\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 349 | "151\n", 350 | "NOTE {\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\",\"message\":\"Main: theory Main.Main_Doc\",\"kind\":\"writeln\",\"session\":\"Main\",\"theory\":\"Main.Main_Doc\"}\n", 351 | "190\n", 352 | "NOTE {\"kind\":\"writeln\",\"message\":\"Timing Main (6 threads, 0.605s elapsed time, 0.687s cpu time, 0.017s GC time, factor 1.14)\",\"verbose\":\"true\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 353 | "168\n", 354 | "NOTE {\"kind\":\"writeln\",\"message\":\"Finished Main (0:00:04 elapsed time, 0:00:05 cpu time, factor 1.33)\",\"verbose\":\"false\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 355 | "126\n", 356 | "NOTE {\"kind\":\"writeln\",\"message\":\"Starting session Main ...\",\"verbose\":\"false\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 357 | "176\n", 358 | "FINISHED {\"session_id\":\"973b51f5-7f38-4723-b91f-489d3a381443\",\"tmp_dir\":\"/tmp/isabelle-jovyan/server_session6046005654409616093\",\"task\":\"b8308b4a-ee7b-4a38-bb46-37aed4871ecf\"}\n", 359 | "206ea174-1c5c-4fb3-81c4-d7b3b21aa69f\n", 360 | "use_theories {\"session_id\": \"973b51f5-7f38-4723-b91f-489d3a381443\", \"theories\": [\"Example\"], \"watchdog_timeout\": 0, \"master_dir\": \".\"}\n", 361 | "\n", 362 | "OK {\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}\n", 363 | "OK {\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\"}\n", 364 | "161\n", 365 | "NOTE {\"percentage\":14,\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\",\"message\":\"theory Draft.Example 14%\",\"kind\":\"writeln\",\"session\":\"\",\"theory\":\"Draft.Example\"}\n", 366 | "161\n", 367 | "NOTE {\"percentage\":99,\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\",\"message\":\"theory Draft.Example 99%\",\"kind\":\"writeln\",\"session\":\"\",\"theory\":\"Draft.Example\"}\n", 368 | "163\n", 369 | "NOTE {\"percentage\":100,\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\",\"message\":\"theory Draft.Example 100%\",\"kind\":\"writeln\",\"session\":\"\",\"theory\":\"Draft.Example\"}\n", 370 | "458\n", 371 | "FINISHED {\"ok\":true,\"errors\":[],\"nodes\":[{\"messages\":[{\"kind\":\"writeln\",\"message\":\"theorem \\\\x. \\\\y. x = y\",\"pos\":{\"line\":5,\"offset\":59,\"end_offset\":61,\"file\":\"Example.thy\"}}],\"exports\":[],\"status\":{\"percentage\":100,\"unprocessed\":0,\"running\":0,\"finished\":7,\"failed\":0,\"total\":7,\"consolidated\":true,\"canceled\":false,\"ok\":true,\"warned\":0},\"theory_name\":\"Draft.Example\",\"node_name\":\"Example.thy\"}],\"task\":\"ca3b10c5-7c8b-4a5a-b431-00fdcbe7a04f\"}\n", 372 | "206ea174-1c5c-4fb3-81c4-d7b3b21aa69f\n", 373 | "session_stop {\"session_id\": \"973b51f5-7f38-4723-b91f-489d3a381443\"}\n", 374 | "\n", 375 | "OK {\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}\n", 376 | "OK {\"task\":\"d8e924b1-f4e7-4b5e-8c67-7182c58c7599\"}\n", 377 | "FINISHED {\"ok\":true,\"return_code\":0,\"task\":\"d8e924b1-f4e7-4b5e-8c67-7182c58c7599\"}\n", 378 | "206ea174-1c5c-4fb3-81c4-d7b3b21aa69f\n", 379 | "session_build {\"session\": \"examples\", \"verbose\": false, \"dirs\": [\".\"]}\n", 380 | "\n", 381 | "OK {\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}\n", 382 | "OK {\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 383 | "117\n", 384 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Pure/Pure\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 385 | "118\n", 386 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Misc/Tools\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 387 | "122\n", 388 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session HOL/HOL (main)\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 389 | "125\n", 390 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Unsorted/examples\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 391 | "117\n", 392 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Pure/Pure\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 393 | "118\n", 394 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Misc/Tools\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 395 | "122\n", 396 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session HOL/HOL (main)\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 397 | "125\n", 398 | "NOTE {\"kind\":\"writeln\",\"message\":\"Session Unsorted/examples\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 399 | "122\n", 400 | "NOTE {\"kind\":\"writeln\",\"message\":\"Building examples ...\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 401 | "165\n", 402 | "NOTE {\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\",\"message\":\"examples: theory examples.Example\",\"kind\":\"writeln\",\"session\":\"examples\",\"theory\":\"examples.Example\"}\n", 403 | "132\n", 404 | "NOTE {\"kind\":\"writeln\",\"message\":\"Preparing examples/document ...\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 405 | "150\n", 406 | "NOTE {\"kind\":\"writeln\",\"message\":\"Finished examples/document (0:00:00 elapsed time)\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 407 | "174\n", 408 | "NOTE {\"kind\":\"writeln\",\"message\":\"Document at \\\"/home/jovyan/isabelle-client-examples/output/document.pdf\\\"\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 409 | "194\n", 410 | "NOTE {\"kind\":\"writeln\",\"message\":\"Timing examples (6 threads, 0.109s elapsed time, 0.143s cpu time, 0.000s GC time, factor 1.31)\",\"verbose\":\"true\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 411 | "172\n", 412 | "NOTE {\"kind\":\"writeln\",\"message\":\"Finished examples (0:00:03 elapsed time, 0:00:05 cpu time, factor 1.37)\",\"verbose\":\"false\",\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 413 | "403\n", 414 | "FINISHED {\"ok\":true,\"return_code\":0,\"sessions\":[{\"session\":\"Pure\",\"ok\":true,\"timeout\":false,\"timing\":{\"elapsed\":0,\"cpu\":0,\"gc\":0},\"return_code\":0},{\"session\":\"HOL\",\"ok\":true,\"timeout\":false,\"timing\":{\"elapsed\":0,\"cpu\":0,\"gc\":0},\"return_code\":0},{\"session\":\"examples\",\"ok\":true,\"timeout\":false,\"timing\":{\"elapsed\":3.86,\"cpu\":5.307,\"gc\":0},\"return_code\":0}],\"task\":\"4e8c256e-e3aa-4784-bf9c-fa318c14f7ab\"}\n", 415 | "206ea174-1c5c-4fb3-81c4-d7b3b21aa69f\n", 416 | "echo 42\n", 417 | "\n", 418 | "OK {\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}\n", 419 | "OK 42\n", 420 | "206ea174-1c5c-4fb3-81c4-d7b3b21aa69f\n", 421 | "shutdown\n", 422 | "\n", 423 | "OK {\"isabelle_id\":\"29f2b8ff84f3\",\"isabelle_name\":\"Isabelle2024\"}\n", 424 | "OK\n" 425 | ] 426 | } 427 | ], 428 | "source": [ 429 | "# all our communications with the server\n", 430 | "# were written to the log file specified earlier\n", 431 | "!cat session.log" 432 | ] 433 | } 434 | ], 435 | "metadata": { 436 | "kernelspec": { 437 | "display_name": "Python 3 (ipykernel)", 438 | "language": "python", 439 | "name": "python3" 440 | }, 441 | "language_info": { 442 | "codemirror_mode": { 443 | "name": "ipython", 444 | "version": 3 445 | }, 446 | "file_extension": ".py", 447 | "mimetype": "text/x-python", 448 | "name": "python", 449 | "nbconvert_exporter": "python", 450 | "pygments_lexer": "ipython3", 451 | "version": "3.10.12" 452 | }, 453 | "name": "example.ipynb" 454 | }, 455 | "nbformat": 4, 456 | "nbformat_minor": 5 457 | } 458 | -------------------------------------------------------------------------------- /examples/plot_example.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Basic usage example. 16 | ==================== 17 | """ # noqa: D205 18 | 19 | # %% 20 | # In what case to use 21 | # ------------------- 22 | # 23 | # This client might be useful if: 24 | # 25 | # * you have a machine with Isabelle installed 26 | # * you have scripts for automatic generation of theory files in Python 27 | # * you want to communicate with the server not using 28 | # `Scala `__ and/or 29 | # `Standard ML `__ 30 | 31 | # %% 32 | # In what environment to use 33 | # -------------------------- 34 | # 35 | # The client works well in scripts and in Jupyter notebooks. For the 36 | # latter, one has to enable nested event loops first. Please refer to 37 | # ``nest_asyncio`` `documentation 38 | # `__. 39 | 40 | # %% 41 | # Starting Isabelle server 42 | # ------------------------ 43 | # First, we need to start an Isabelle server 44 | 45 | from isabelle_client import start_isabelle_server 46 | 47 | server_info, _ = start_isabelle_server( 48 | name="test", port=9999, log_file="server.log" 49 | ) 50 | 51 | # %% 52 | # .. warning:: 53 | # When using `start_isabelle_server 54 | # `__ 55 | # utility function in Python REPL or terminal IPython, shutting the server 56 | # down within the same session is known to cause a runtime error on exit from 57 | # the session. This behaviour is related to a `well known issue 58 | # `__. 59 | 60 | # %% 61 | # We could also start the server outside this script and use its info (on 62 | # Windows, this is done in Cygwin):: 63 | # 64 | # isabelle server 65 | 66 | # %% 67 | # Interacting with Isabelle server 68 | # -------------------------------- 69 | # Let's create a client to our server 70 | 71 | from isabelle_client import get_isabelle_client 72 | 73 | isabelle = get_isabelle_client(server_info) 74 | 75 | # %% 76 | # We will log all the messages from the server to a file 77 | 78 | import logging 79 | 80 | isabelle.logger = logging.getLogger() 81 | isabelle.logger.setLevel(logging.INFO) 82 | isabelle.logger.addHandler(logging.FileHandler("session.log")) 83 | 84 | # %% 85 | # Isabelle client supports all the commands implemented in Isabelle server 86 | 87 | from pprint import pprint 88 | 89 | pprint(isabelle.help()) 90 | 91 | # %% 92 | # Let's suppose we have a ``Example.thy`` theory file in our working directory 93 | # which we, e.g. generated with another Python script 94 | # 95 | # .. literalinclude:: ../../examples/Example.thy 96 | # 97 | 98 | # %% 99 | # We can send this theory file to the server and get a response 100 | 101 | pprint(isabelle.use_theories(theories=["Example"], master_dir=".")) 102 | 103 | # %% 104 | # or we can build a session document using ``./ROOT`` file 105 | # 106 | # .. literalinclude:: ../../examples/ROOT 107 | # 108 | # and ``./document/root.tex`` file 109 | # 110 | # .. literalinclude:: ../../examples/document/root.tex 111 | # :language: tex 112 | # 113 | 114 | import json 115 | 116 | pprint( 117 | json.loads( 118 | isabelle.session_build(dirs=["."], session="examples")[ 119 | -1 120 | ].response_body 121 | ) 122 | ) 123 | 124 | # %% 125 | # One can also issue a free-form command, e.g. 126 | 127 | import asyncio 128 | 129 | pprint(asyncio.run(isabelle.execute_command("echo 42", asynchronous=False))) 130 | 131 | # %% 132 | # Finally, we can shut the server down. 133 | 134 | pprint(isabelle.shutdown()) 135 | -------------------------------------------------------------------------------- /isabelle_client/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """A Python client to `Isabelle `__ server.""" 15 | 16 | from isabelle_client.isabelle__client import IsabelleClient 17 | from isabelle_client.socket_communication import IsabelleResponse 18 | from isabelle_client.utils import get_isabelle_client, start_isabelle_server 19 | 20 | __version__ = "0.5.6" 21 | __all__ = [ 22 | "IsabelleClient", 23 | "IsabelleResponse", 24 | "get_isabelle_client", 25 | "start_isabelle_server", 26 | ] 27 | -------------------------------------------------------------------------------- /isabelle_client/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """Fixtures for unit tests live here.""" 15 | 16 | import threading 17 | from collections.abc import Generator 18 | from unittest.mock import Mock 19 | 20 | from pytest import fixture 21 | 22 | from isabelle_client.utils import ( 23 | BuggyDummyTCPHandler, 24 | DummyTCPHandler, 25 | ReusableDummyTCPServer, 26 | ) 27 | 28 | 29 | @fixture(autouse=True, scope="session") 30 | def tcp_servers() -> Generator[ 31 | tuple[ReusableDummyTCPServer, ReusableDummyTCPServer], None, None 32 | ]: 33 | """ 34 | Get a simplistic TCP server mocking Isabelle server behaviour. 35 | 36 | :yields: an instance of a mock working server and a mock buggy server 37 | """ 38 | with ( 39 | ReusableDummyTCPServer(("localhost", 9999), DummyTCPHandler) as server, 40 | ReusableDummyTCPServer( 41 | ("localhost", 9998), BuggyDummyTCPHandler 42 | ) as buggy_server, 43 | ): 44 | thread = threading.Thread(target=server.serve_forever) 45 | thread.daemon = True 46 | thread.start() 47 | buggy_thread = threading.Thread(target=buggy_server.serve_forever) 48 | buggy_thread.daemon = True 49 | buggy_thread.start() 50 | yield server, buggy_server 51 | 52 | 53 | @fixture 54 | def mock_logger() -> Mock: 55 | """ 56 | Get a mock for logger to spy on ``info`` calls. 57 | 58 | :returns: mock logger 59 | """ 60 | logger = Mock() 61 | logger.info = Mock() 62 | return logger 63 | -------------------------------------------------------------------------------- /isabelle_client/isabelle__client.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Isabelle Client 16 | ================ 17 | 18 | A Python client to `Isabelle `__ server 19 | """ # noqa: D205, D400 20 | 21 | import asyncio 22 | import json 23 | from enum import Enum 24 | from logging import Logger 25 | from typing import Any, Optional, Union 26 | 27 | from isabelle_client.socket_communication import ( 28 | IsabelleResponse, 29 | get_final_message, 30 | ) 31 | 32 | 33 | class SynchronousResultType(Enum): 34 | """Synchronous results of a server reply.""" 35 | 36 | OK = "OK" 37 | ERROR = "ERROR" 38 | 39 | 40 | class AsynchronousResultType(Enum): 41 | """Asynchronous results of a server reply.""" 42 | 43 | FAILED = "FAILED" 44 | FINISHED = "FINISHED" 45 | 46 | 47 | class IsabelleClient: 48 | """ 49 | A TCP client for an Isabelle server. 50 | 51 | :param address: IP or a domain name 52 | :param port: a port number on which the server listens 53 | :param password: a password to access the server through TCP 54 | :param logger: a Python logger to store all requests to 55 | and replies from the server 56 | """ 57 | 58 | def __init__( # noqa: D107 59 | self, 60 | address: str, 61 | port: int, 62 | password: str, 63 | logger: Optional[Logger] = None, 64 | ): 65 | self.address = address 66 | self.port = port 67 | self.password = password 68 | self.logger = logger 69 | 70 | async def execute_command( 71 | self, 72 | command: str, 73 | asynchronous: bool = True, 74 | ) -> list[IsabelleResponse]: 75 | r""" 76 | Execute a command and waits for results. 77 | 78 | >>> logger = getfixture("mock_logger") 79 | >>> isabelle_client = IsabelleClient( 80 | ... "localhost", 9999, "test_password", logger 81 | ... ) 82 | >>> test_response = asyncio.run( 83 | ... isabelle_client.execute_command("unknown command") 84 | ... ) 85 | >>> print(test_response[-1].response_type) 86 | ERROR 87 | >>> print(test_response[-1].response_body) 88 | "Bad command 'unknown'" 89 | >>> # error messages don't return the response length 90 | >>> print(test_response[-1].response_length) 91 | None 92 | >>> print(logger.info.mock_calls) 93 | [call('test_password\nunknown command\n'), 94 | call('OK {"isabelle_id":"mock","isabelle_name":"Isabelle2024"}'), 95 | call('ERROR "Bad command \'unknown\'"')] 96 | 97 | :param command: a full text of a command to Isabelle 98 | :param asynchronous: if ``False``, waits for ``OK``; else waits for 99 | ``FINISHED`` 100 | :returns: a list of Isabelle server responses 101 | """ 102 | final_message = ( 103 | { 104 | AsynchronousResultType.FINISHED.value, 105 | AsynchronousResultType.FAILED.value, 106 | SynchronousResultType.ERROR.value, 107 | } 108 | if asynchronous 109 | else { 110 | SynchronousResultType.OK.value, 111 | SynchronousResultType.ERROR.value, 112 | } 113 | ) 114 | reader, writer = await asyncio.open_connection(self.address, self.port) 115 | command = f"{self.password}\n{command}\n" 116 | writer.write(command.encode("utf-8")) 117 | await writer.drain() 118 | if self.logger is not None: 119 | self.logger.info(command) 120 | response = [] 121 | async for message in get_final_message( 122 | reader, final_message, self.logger 123 | ): 124 | response.append(message) 125 | return response 126 | 127 | def session_build( 128 | self, 129 | session: str, 130 | dirs: Optional[list[str]] = None, 131 | verbose: bool = False, 132 | **kwargs, 133 | ) -> list[IsabelleResponse]: 134 | r""" 135 | Build a session from ROOT file. 136 | 137 | >>> isabelle_client = IsabelleClient( 138 | ... "localhost", 9999, "test_password" 139 | ... ) 140 | >>> print(isabelle_client.session_build( 141 | ... session="test_session", dirs=["."], verbose=True, options=[] 142 | ... )[-1]) 143 | 400 144 | FINISHED {"ok":true,"return_code":0,"sessions":[{"session":"Pure",...} 145 | 146 | :param session: a name of the session from ROOT file 147 | :param dirs: where to look for ROOT files 148 | :param verbose: set to ``True`` for extra verbosity 149 | :param \**kwargs: additional arguments 150 | (see Isabelle System manual for details) 151 | :returns: an Isabelle response 152 | """ 153 | arguments: dict[str, Union[str, list[str], bool]] = { 154 | "session": session, 155 | "verbose": verbose, 156 | } 157 | if dirs is not None: 158 | arguments["dirs"] = dirs 159 | arguments.update(kwargs) 160 | response = asyncio.run( 161 | self.execute_command(f"session_build {json.dumps(arguments)}") 162 | ) 163 | return response 164 | 165 | def session_start(self, session: str = "Main", **kwargs) -> str: 166 | r""" 167 | Start a new session. 168 | 169 | >>> isabelle_client = IsabelleClient("localhost", 9998, "test") 170 | >>> print(isabelle_client.session_start(verbose=True)) 171 | Traceback (most recent call last): 172 | ... 173 | ValueError: Unexpected response type: ERROR 174 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 175 | >>> print(isabelle_client.session_start()) 176 | 167dd6d8-1eeb-4315-8022-c8c527d9bd87 177 | 178 | :param session: a name of a session to start 179 | :param \**kwargs: additional arguments 180 | (see Isabelle System manual for details) 181 | :returns: a ``session_id`` 182 | :raises ValueError: if the server response is malformed 183 | """ 184 | arguments = {"session": session} 185 | arguments.update(kwargs) 186 | response_list = asyncio.run( 187 | self.execute_command(f"session_start {json.dumps(arguments)}") 188 | ) 189 | if ( 190 | response_list[-1].response_type 191 | == AsynchronousResultType.FINISHED.value 192 | ): 193 | return json.loads(response_list[-1].response_body)["session_id"] 194 | raise ValueError( 195 | f"Unexpected response type: {response_list[-1].response_type}" 196 | ) 197 | 198 | def session_stop(self, session_id: str) -> list[IsabelleResponse]: 199 | """ 200 | Stop session with given ID. 201 | 202 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 203 | >>> test_response = isabelle_client.session_stop("test") 204 | >>> print(test_response[-1].response_type) 205 | FINISHED 206 | 207 | :param session_id: a string ID of a session 208 | :returns: Isabelle server response 209 | """ 210 | arguments = json.dumps({"session_id": session_id}) 211 | response = asyncio.run( 212 | self.execute_command(f"session_stop {arguments}") 213 | ) 214 | return response 215 | 216 | def use_theories( 217 | self, 218 | theories: list[str], 219 | session_id: Optional[str] = None, 220 | master_dir: Optional[str] = None, 221 | **kwargs, 222 | ) -> list[IsabelleResponse]: 223 | r""" 224 | Run the engine on theory files. 225 | 226 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 227 | >>> test_response = isabelle_client.use_theories( 228 | ... ["Mock"], master_dir="test", watchdog_timeout=0 229 | ... ) 230 | >>> print(test_response[-1].response_type) 231 | FINISHED 232 | 233 | :param theories: names of theory files (without extensions!) 234 | :param session_id: an ID of a session; if ``None``, a new session is 235 | created and then destroyed after trying to process theories 236 | :param master_dir: where to look for theory files; if ``None``, uses a 237 | temp folder of the session 238 | :param \**kwargs: additional arguments 239 | (see Isabelle System manual for details) 240 | :returns: Isabelle server response 241 | """ 242 | new_session_id = ( 243 | self.session_start() if session_id is None else session_id 244 | ) 245 | arguments: dict[str, Union[list[str], int, str]] = { 246 | "session_id": new_session_id, 247 | "theories": theories, 248 | } 249 | arguments.update(kwargs) 250 | if master_dir is not None: 251 | arguments["master_dir"] = master_dir 252 | response = asyncio.run( 253 | self.execute_command(f"use_theories {json.dumps(arguments)}") 254 | ) 255 | if session_id is None: 256 | self.session_stop(new_session_id) 257 | return response 258 | 259 | def echo(self, message: Any) -> list[IsabelleResponse]: 260 | """ 261 | Ask a server to echo a message. 262 | 263 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 264 | >>> test_response = isabelle_client.echo("test_message") 265 | >>> print(test_response[-1].response_body) 266 | "test_message" 267 | 268 | :param message: any text 269 | :returns: Isabelle server response 270 | """ 271 | response = asyncio.run( 272 | self.execute_command( 273 | f"echo {json.dumps(message)}", asynchronous=False 274 | ) 275 | ) 276 | return response 277 | 278 | def help(self) -> list[IsabelleResponse]: 279 | """ 280 | Ask a server to display the list of available commands. 281 | 282 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 283 | >>> test_response = isabelle_client.help() 284 | >>> print(test_response[-1].response_body) 285 | ["cancel","echo","help","purge_theories","session_build",...] 286 | 287 | :returns: Isabelle server response 288 | """ 289 | response = asyncio.run( 290 | self.execute_command("help", asynchronous=False) 291 | ) 292 | return response 293 | 294 | def purge_theories( 295 | self, 296 | session_id: str, 297 | theories: list[str], 298 | master_dir: Optional[str] = None, 299 | purge_all: Optional[bool] = None, 300 | ) -> list[IsabelleResponse]: 301 | """ 302 | Ask a server to purge listed theories from it. 303 | 304 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 305 | >>> test_response = isabelle_client.purge_theories( 306 | ... "test", [], "dir", True 307 | ... ) 308 | >>> print(test_response[-1].response_body) 309 | {"purged":[{"node_name":"/tmp/Mock.thy",...}],"retained":[]} 310 | 311 | :param session_id: an ID of the session from which to purge theories 312 | :param theories: a list of theory names to purge from the server 313 | :param master_dir: the master directory as in ``use_theories`` 314 | :param purge_all: set to ``True`` attempts to purge all presently 315 | loaded theories 316 | :returns: Isabelle server response 317 | """ 318 | arguments: dict[str, Union[str, list[str], bool]] = { 319 | "session_id": session_id, 320 | "theories": theories, 321 | } 322 | if master_dir is not None: 323 | arguments["master_dir"] = master_dir 324 | if purge_all is not None: 325 | arguments["all"] = purge_all 326 | response = asyncio.run( 327 | self.execute_command( 328 | f"purge_theories {json.dumps(arguments)}", asynchronous=False 329 | ) 330 | ) 331 | return response 332 | 333 | def cancel(self, task: str) -> list[IsabelleResponse]: 334 | """ 335 | Ask a server to try to cancel a task with a given ID. 336 | 337 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 338 | >>> test_response = isabelle_client.cancel("test_task") 339 | >>> print(test_response[-1].response_body) 340 | 341 | 342 | :param task: a task ID 343 | :returns: Isabelle server response 344 | """ 345 | arguments = {"task": task} 346 | response = asyncio.run( 347 | self.execute_command( 348 | f"cancel {json.dumps(arguments)}", asynchronous=False 349 | ) 350 | ) 351 | return response 352 | 353 | def shutdown(self) -> list[IsabelleResponse]: 354 | """ 355 | Ask a server to shutdown immediately. 356 | 357 | >>> isabelle_client = IsabelleClient("localhost", 9999, "test") 358 | >>> test_response = isabelle_client.shutdown() 359 | >>> print(test_response[-1].response_body) 360 | 361 | 362 | :returns: Isabelle server response 363 | """ 364 | response = asyncio.run( 365 | self.execute_command("shutdown", asynchronous=False) 366 | ) 367 | return response 368 | -------------------------------------------------------------------------------- /isabelle_client/isabelle_connector.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Isabelle Connector 16 | =================== 17 | 18 | A connector to the Isabelle server, hiding server interactions. 19 | """ # noqa: D205, D400 20 | 21 | import json 22 | import logging 23 | import os 24 | import tempfile 25 | from typing import Optional 26 | from uuid import uuid4 27 | 28 | from isabelle_client.utils import get_isabelle_client, start_isabelle_server 29 | 30 | 31 | class IsabelleTheoryError(RuntimeError): 32 | """Raised when the Isabelle response contains errors.""" 33 | 34 | 35 | class IsabelleConnector: 36 | r""" 37 | A connector to the Isabelle server, hiding server interactions. 38 | 39 | :param working_directory: a directory for storing the server logs, 40 | temporary theory files etc. 41 | 42 | >>> os.environ["PATH"] = "isabelle_client/resources:$PATH" 43 | >>> connector = IsabelleConnector() 44 | >>> print(connector.working_directory) 45 | /... 46 | >>> connector.verify_lemma( 47 | ... "\ x. \ y. x = y", theory="Mock") 48 | True 49 | >>> connector.verify_lemma( 50 | ... "\ x. \ y. x = y", theory="Fail") 51 | Traceback (most recent call last): 52 | ... 53 | isabelle...Error: Failed to finish proof\<^here>: 54 | goal (1 subgoal): 55 | 1. \x y. x = y 56 | """ 57 | 58 | def _get_or_create_working_directory( 59 | self, working_directory: Optional[str] 60 | ) -> str: 61 | new_working_directory = ( 62 | working_directory 63 | if working_directory is not None 64 | else os.path.join(tempfile.mkdtemp(), str(uuid4())) 65 | ) 66 | if not os.path.exists(new_working_directory): 67 | os.mkdir(new_working_directory) 68 | return new_working_directory 69 | 70 | def __init__(self, working_directory: Optional[str] = None): # noqa: D107 71 | self._working_directory = self._get_or_create_working_directory( 72 | working_directory 73 | ) 74 | server_info, self._server_process = start_isabelle_server( 75 | log_file=os.path.join( 76 | self._working_directory, "isabelle-server.log" 77 | ) 78 | ) 79 | self._client = get_isabelle_client(server_info=server_info) 80 | self._client.logger = logging.getLogger() 81 | self._client.logger.setLevel(logging.INFO) 82 | self._client.logger.addHandler( 83 | logging.FileHandler( 84 | os.path.join(self._working_directory, "session.log") 85 | ) 86 | ) 87 | 88 | def _write_temp_theory_file( 89 | self, 90 | lemma_text: str, 91 | task: str, 92 | theory: Optional[str] = None, 93 | ) -> str: 94 | theory_name = ( 95 | "T" + str(uuid4()).replace("-", "") if theory is None else theory 96 | ) 97 | with open( 98 | os.path.join(self._working_directory, f"{theory_name}.thy"), 99 | "w", 100 | encoding="utf8", 101 | ) as theory_file: 102 | theory_file.write(f"theory {theory_name}\n") 103 | theory_file.write("imports Main\n") 104 | theory_file.write("begin\n") 105 | theory_file.write(f'lemma "{lemma_text}"\n') 106 | theory_file.write(f"{task}\n") 107 | theory_file.write("end\n") 108 | return theory_name 109 | 110 | def verify_lemma( 111 | self, 112 | lemma_text: str, 113 | task: str = "by auto", 114 | theory: Optional[str] = None, 115 | ) -> bool: 116 | """ 117 | Verify a lemma statement using the Isabelle server. 118 | 119 | :param lemma_text: (hopefully) syntactically valid Isabelle lemma 120 | :param task: how to prove lemma. ``"by auto"`` by default 121 | :param theory: (for tests) fixed named for theory file 122 | :returns: True if validation successful 123 | :raises IsabelleTheoryError: if validation failed 124 | """ 125 | theory_name = self._write_temp_theory_file(lemma_text, task, theory) 126 | validation_result = self._client.use_theories( 127 | theories=[theory_name], master_dir=self._working_directory 128 | ) 129 | for isabelle_response in validation_result: 130 | if isabelle_response.response_type == "FINISHED": 131 | json_response = json.loads(isabelle_response.response_body) 132 | if errors := json_response["errors"]: 133 | raise IsabelleTheoryError(errors[0]["message"]) 134 | return True 135 | 136 | @property 137 | def working_directory(self) -> str: 138 | """Get working directory.""" 139 | return self._working_directory 140 | -------------------------------------------------------------------------------- /isabelle_client/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/isabelle_client/py.typed -------------------------------------------------------------------------------- /isabelle_client/resources/Cygwin-Isabelle.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set TEMP_WINDOWS=%TEMP% 4 | set HOME=%HOMEDRIVE%%HOMEPATH% 5 | set PATH=%ISABELLE_INST_DIR%\bin;%PATH% 6 | set LANG=en_US.UTF-8 7 | set CHERE_INVOKING=true 8 | set arg1=%1 9 | set unquoted_arg1=%arg1:"=% 10 | 11 | "%ISABELLE_INST_DIR%\contrib\cygwin\bin\bash" --login -i ^ 12 | -c "isabelle %unquoted_arg1%" -------------------------------------------------------------------------------- /isabelle_client/resources/example.txt: -------------------------------------------------------------------------------- 1 | # Hi! This is an example of using ``isabelle-client`` package 2 | ipython 3 | SLEEP 3 4 | # first, we need to start an Isabelle server 5 | from isabelle_client import start_isabelle_server 6 | 7 | server_info, _ = start_isabelle_server( 8 | name="test", port=9999, log_file="server.log" 9 | ) 10 | SLEEP 2 11 | # we could also start the server outside this script and use its info 12 | # now let's create a client to our server 13 | from isabelle_client import get_isabelle_client 14 | 15 | isabelle = get_isabelle_client(server_info) 16 | # we will log all the messages from the server to a file 17 | import logging 18 | 19 | isabelle.logger = logging.getLogger() 20 | isabelle.logger.setLevel(logging.INFO) 21 | isabelle.logger.addHandler(logging.FileHandler("session.log")) 22 | # let's suppose that we also have another Python script 23 | # which generates some theory files 24 | !cat Example.thy 25 | # now we can build a session document using ROOT and root.tex files 26 | !ls document 27 | !cat ROOT 28 | isabelle.session_build(dirs=["."], session="examples") 29 | SLEEP 12 30 | # all these messages are also saved to the log file 31 | !ls output 32 | # in addition, we can issue a free-form command through TCP 33 | import asyncio 34 | asyncio.run(isabelle.execute_command("echo 42", asynchronous=False)) 35 | isabelle.shutdown() 36 | # our sessions was logged to the file: 37 | !cat session.log 38 | SLEEP 3 39 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo 'server "isabelle" = 127.0.0.1:9999 (password "test_password")' 3 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/cancel: -------------------------------------------------------------------------------- 1 | OK 2 | 3 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/help: -------------------------------------------------------------------------------- 1 | 118 2 | OK ["cancel","echo","help","purge_theories","session_build","session_start","session_stop","shutdown","use_theories"] 3 | 4 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/purge_theories: -------------------------------------------------------------------------------- 1 | 87 2 | OK {"purged":[{"node_name":"/tmp/Mock.thy","theory_name":"Draft.Mock"}],"retained":[]} 3 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/session_build: -------------------------------------------------------------------------------- 1 | OK {"task":"e279a4da-51a0-412b-b15a-3d0d02b39287"} 2 | NOTE {"kind":"writeln","message":"Building Main ...","task":"e279a4da-51a0-412b-b15a-3d0d02b39287"} 3 | 151 4 | NOTE {"task":"e279a4da-51a0-412b-b15a-3d0d02b39287","message":"Main: theory Main.Main_Doc","kind":"writeln","session":"Main","theory":"Main.Main_Doc"} 5 | 150 6 | NOTE {"kind":"writeln","message":"Finished Main (0:00:06 elapsed time, 0:00:09 cpu time, factor 1.44)","task":"e279a4da-51a0-412b-b15a-3d0d02b39287"} 7 | 400 8 | FINISHED {"ok":true,"return_code":0,"sessions":[{"session":"Pure","ok":true,"timeout":false,"timing":{"elapsed":0,"cpu":0,"gc":0},"return_code":0},{"session":"HOL","ok":true,"timeout":false,"timing":{"elapsed":0,"cpu":0,"gc":0},"return_code":0},{"session":"Main","ok":true,"timeout":false,"timing":{"elapsed":6.643,"cpu":9.561,"gc":0},"return_code":0}],"task":"e279a4da-51a0-412b-b15a-3d0d02b39287"} 9 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/session_start: -------------------------------------------------------------------------------- 1 | OK {"task":"6c77254a-3b05-47cc-bc49-093ec7ccc2b8"} 2 | 108 3 | NOTE {"kind":"writeln","message":"Starting session Main ...","task":"6c77254a-3b05-47cc-bc49-093ec7ccc2b8"} 4 | 170 5 | FINISHED {"session_id":"167dd6d8-1eeb-4315-8022-c8c527d9bd87","tmp_dir":"/tmp/isabelle/server_session10866100026207629259","task":"6c77254a-3b05-47cc-bc49-093ec7ccc2b8"} 6 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/session_stop: -------------------------------------------------------------------------------- 1 | OK {"task":"93d5824a-4e03-4d0c-9f2d-ebea4dbe7795"} 2 | FINISHED {"ok":true,"return_code":0,"task":"93d5824a-4e03-4d0c-9f2d-ebea4dbe7795"} 3 | 4 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/shutdown: -------------------------------------------------------------------------------- 1 | OK 2 | 3 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/unknown: -------------------------------------------------------------------------------- 1 | ERROR "Bad command 'unknown'" 2 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/use_theories: -------------------------------------------------------------------------------- 1 | OK {"task":"97504f00-3946-40fc-91a4-e9b1228df480"} 2 | 158 3 | NOTE {"percentage":99,"task":"97504f00-3946-40fc-91a4-e9b1228df480","message":"theory Draft.Mock 99%","kind":"writeln","session":"","theory":"Draft.Example"} 4 | 157 5 | NOTE {"percentage":100,"task":"97504f00-3946-40fc-91a4-e9b1228df480","message":"theory Draft.Mock 100%","kind":"writeln","session":"","theory":"Draft.Mock"} 6 | 321 7 | FINISHED {"ok":true,"errors":[],"nodes":[{"messages":[],"exports":[],"status":{"percentage":100,"unprocessed":0,"running":0,"finished":7,"failed":0,"total":7,"consolidated":true,"canceled":false,"ok":true,"warned":0},"theory_name":"Draft.Mock","node_name":"/tmp/Mock.thy"}],"task":"97504f00-3946-40fc-91a4-e9b1228df480"} 8 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/use_theories.Fail: -------------------------------------------------------------------------------- 1 | OK {"task":"09383961-0def-4806-9198-773ccab8cd53"} 2 | 155 3 | NOTE {"percentage":99,"task":"09383961-0def-4806-9198-773ccab8cd53","message":"theory Draft.Fail 99%","kind":"writeln","session":"","theory":"Draft.Fail"} 4 | 157 5 | NOTE {"percentage":100,"task":"09383961-0def-4806-9198-773ccab8cd53","message":"theory Draft.Fail 100%","kind":"writeln","session":"","theory":"Draft.Fail"} 6 | 665 7 | FINISHED {"ok":false,"errors":[{"kind":"error","message":"Failed to finish proof\\<^here>:\ngoal (1 subgoal):\n 1. \\x y. x = y","pos":{"line":5,"offset":56,"end_offset":58,"file":"/tmp/Fail.thy"}}],"nodes":[{"messages":[{"kind":"error","message":"Failed to finish proof\\<^here>:\ngoal (1 subgoal):\n 1. \\x y. x = y","pos":{"line":5,"offset":56,"end_offset":58,"file":"/tmp/Fail.thy"}}],"exports":[],"status":{"percentage":100,"unprocessed":0,"running":0,"finished":7,"failed":1,"total":8,"consolidated":true,"canceled":false,"ok":false,"warned":0},"theory_name":"Draft.Fail","node_name":"/tmp/Fail.thy"}],"task":"09383961-0def-4806-9198-773ccab8cd53"} 8 | -------------------------------------------------------------------------------- /isabelle_client/resources/isabelle-responses/use_theories.Sledgehammer: -------------------------------------------------------------------------------- 1 | OK {"task":"a70d5f85-4cb3-415e-961c-13fdccbd54e5"} 2 | 171 3 | NOTE {"percentage":99,"task":"a70d5f85-4cb3-415e-961c-13fdccbd54e5","message":"theory Draft.Sledgehammer 99%","kind":"writeln","session":"","theory":"Draft.Sledgehammer"} 4 | 173 5 | NOTE {"percentage":100,"task":"a70d5f85-4cb3-415e-961c-13fdccbd54e5","message":"theory Draft.Sledgehammer 100%","kind":"writeln","session":"","theory":"Draft.Sledgehammer"} 6 | 2501 7 | FINISHED {"ok":true,"errors":[],"nodes":[{"messages":[{"kind":"writeln","message":"Sledgehammering...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"verit found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"verit: Try this: by simp (0.3 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"zipperposition found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"zipperposition found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"vampire found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"cvc4 found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"e found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"zipperposition: Try this: by simp (0.5 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"zipperposition: Try this: by simp (1 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"cvc4: Try this: by force (0.7 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"vampire: Try this: by blast (1 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"e: Try this: by simp (1 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"spass found a proof...","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"spass: Try this: by fastforce (2 ms)","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}},{"kind":"writeln","message":"QED","pos":{"line":5,"offset":85,"end_offset":97,"file":"/tmp/Sledgehammer.thy"}}],"exports":[],"status":{"percentage":100,"unprocessed":0,"running":0,"finished":10,"failed":0,"total":10,"consolidated":true,"canceled":false,"ok":true,"warned":0},"theory_name":"Draft.Sledgehammer","node_name":"/tmp/Sledgehammer.thy"}],"task":"a70d5f85-4cb3-415e-961c-13fdccbd54e5"} 8 | -------------------------------------------------------------------------------- /isabelle_client/sledgehammer_connector.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Sledgehammer Connector 16 | ======================= 17 | 18 | A connector to the Isabelle server, hiding server interactions. 19 | """ # noqa: D205, D400 20 | 21 | import json 22 | from typing import Optional 23 | 24 | from isabelle_client.isabelle_connector import IsabelleConnector 25 | 26 | 27 | class SledgehammerConnector(IsabelleConnector): 28 | r""" 29 | A connector to the Isabelle server parsing Sledgehammer response. 30 | 31 | >>> import os 32 | >>> os.environ["PATH"] = "isabelle_client/resources:$PATH" 33 | >>> sledgehammer = SledgehammerConnector() 34 | >>> sledgehammer.parse_sledgehammer_response( 35 | ... "\ x. \ y. x = y", theory="Sledgehammer") 36 | {'verit': 'by simp', 'zipperposition': 'by simp',...spass': 'by fastforce'} 37 | """ 38 | 39 | def parse_sledgehammer_response( 40 | self, lemma_text: str, theory: Optional[str] = None 41 | ) -> dict[str, str]: 42 | """ 43 | Verify a lemma statement using the Isabelle server. 44 | 45 | :param lemma_text: (hopefully) syntactically valid Isabelle lemma 46 | :param theory: (for tests) fixed named for theory file 47 | :returns: parsed Sledgehammer response 48 | """ 49 | theory_name = self._write_temp_theory_file( 50 | lemma_text=lemma_text, theory=theory, task="sledgehammer\noops" 51 | ) 52 | sledgehammer_responses = self._client.use_theories( 53 | theories=[theory_name], master_dir=self._working_directory 54 | ) 55 | messages = [] 56 | for sledgehammer_response in sledgehammer_responses: 57 | if sledgehammer_response.response_type == "FINISHED": 58 | json_response = json.loads(sledgehammer_response.response_body) 59 | messages = [ 60 | node["message"].split(": ") 61 | for node in json_response["nodes"][0]["messages"] 62 | if ": Try this: " in node["message"] 63 | ] 64 | return { 65 | message[0]: message[2].split("(")[0].strip() 66 | for message in messages 67 | } 68 | -------------------------------------------------------------------------------- /isabelle_client/socket_communication.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Socket Communication 16 | ===================== 17 | 18 | A collection of functions for TCP communication. 19 | """ # noqa: D205, D400 20 | 21 | import asyncio 22 | import re 23 | from dataclasses import dataclass 24 | from logging import Logger 25 | from typing import Optional 26 | from collections.abc import AsyncGenerator 27 | 28 | 29 | @dataclass 30 | class IsabelleResponse: 31 | """ 32 | A response from an Isabelle server. 33 | 34 | .. attribute :: response_type 35 | 36 | an all capitals word like ``FINISHED`` or ``ERROR`` 37 | 38 | .. attribute :: response_body 39 | 40 | a JSON-formatted response 41 | 42 | .. attribute :: response_length 43 | 44 | a length of JSON response 45 | """ 46 | 47 | response_type: str 48 | response_body: str 49 | response_length: Optional[int] = None 50 | 51 | def __str__(self) -> str: 52 | """ 53 | Pretty print Isabelle server response. 54 | 55 | :returns: a string representation of Isabelle server response 56 | """ 57 | return ( 58 | ( 59 | f"{self.response_length}\n" 60 | if self.response_length is not None 61 | else "" 62 | ) 63 | + self.response_type 64 | + (" " if self.response_body != "" else "") 65 | + self.response_body 66 | ) 67 | 68 | 69 | async def get_response_from_isabelle( 70 | reader: asyncio.StreamReader, 71 | ) -> IsabelleResponse: 72 | r""" 73 | Get a response from Isabelle server. 74 | 75 | Format: 76 | 77 | * a carriage-return delimited message or 78 | * a fixed length message after a carriage-return delimited message with 79 | only one integer number denoting length 80 | 81 | >>> async def awaiter(): 82 | ... test_reader, test_writer = await asyncio.open_connection( 83 | ... "localhost", 9999 84 | ... ) 85 | ... test_writer.write(b"test_password\nhelp\n") 86 | ... result = [str(await get_response_from_isabelle(test_reader))] 87 | ... result += [str(await get_response_from_isabelle(test_reader))] 88 | ... return result 89 | >>> print(asyncio.run(awaiter())) 90 | ['OK {"isabelle_id":"mock","isabelle_name":"Isabelle2024"}', '118\nOK [...] 91 | >>> async def awaiter(): 92 | ... test_reader, test_writer = await asyncio.open_connection( 93 | ... "localhost", 9998 94 | ... ) 95 | ... test_writer.write(b"test_password\nhelp\n") 96 | ... result = [str(await get_response_from_isabelle(test_reader))] 97 | ... result += [str(await get_response_from_isabelle(test_reader))] 98 | ... return result 99 | >>> print(asyncio.run(awaiter())) 100 | Traceback (most recent call last): 101 | ... 102 | ValueError: Unexpected response from Isabelle: # !!! 103 | 104 | :param reader: a StreamReader connected to a server 105 | :returns: a response from Isabelle 106 | :raises ValueError: if the server response is malformed 107 | """ 108 | response = (await reader.readline()).decode("utf-8") 109 | match = re.compile(r"(\d+)\n").match(response) 110 | length = int(match.group(1)) if match is not None else None 111 | if length is not None: 112 | response = (await reader.readexactly(length)).decode("utf-8") 113 | if (match := re.compile("(\\w+) ?(.*)").match(response)) is None: 114 | raise ValueError(f"Unexpected response from Isabelle: {response}") 115 | return IsabelleResponse(match.group(1), match.group(2), length) 116 | 117 | 118 | async def get_final_message( 119 | reader: asyncio.StreamReader, 120 | final_message: set[str], 121 | logger: Optional[Logger] = None, 122 | ) -> AsyncGenerator[IsabelleResponse]: 123 | r""" 124 | Get responses from Isabelle server. 125 | 126 | (until a message of specified 'final' type arrives) 127 | 128 | >>> test_logger = getfixture("mock_logger") 129 | >>> async def awaiter(): 130 | ... test_reader, test_writer = await asyncio.open_connection( 131 | ... "localhost", 9999 132 | ... ) 133 | ... test_writer.write(b"test_password\nhelp\n") 134 | ... result = [] 135 | ... async for message in get_final_message( 136 | ... test_reader, {"OK"}, test_logger 137 | ... ): 138 | ... result.append(message) 139 | ... return result 140 | >>> for response in asyncio.run(awaiter()): 141 | ... print(response) 142 | OK {"isabelle_id":"mock","isabelle_name":"Isabelle2024"} 143 | 118 144 | OK ["cancel","echo","help","purge_theories","session_build",...] 145 | >>> print(test_logger.info.mock_calls) 146 | [call('OK {"isabelle_id":"mock","isabelle_name":"Isabelle2024"}'), 147 | call('118\nOK ["cancel","echo","help","purge_theories","session_buil...')] 148 | 149 | :param reader: a ``StreamReader`` connected to Isabelle server 150 | :param final_message: a set of possible final message types 151 | :param logger: a logger where to send all server replies 152 | :yields: the final response from Isabelle server 153 | """ 154 | response = IsabelleResponse("", "") 155 | password_ok_received = False 156 | while ( 157 | response.response_type not in final_message or not password_ok_received 158 | ): 159 | if response.response_type == "OK": 160 | password_ok_received = True 161 | response = await get_response_from_isabelle(reader) 162 | if logger is not None: 163 | logger.info(str(response)) 164 | yield response 165 | -------------------------------------------------------------------------------- /isabelle_client/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Boris Shminke 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Utilities 16 | ========== 17 | 18 | A collection of different useful functions. 19 | """ # noqa: D205, D400 20 | 21 | import asyncio 22 | import json 23 | import os 24 | import re 25 | import socketserver 26 | import sys 27 | from enum import Enum 28 | from importlib.resources import files 29 | from typing import Optional 30 | 31 | from isabelle_client.isabelle__client import IsabelleClient 32 | 33 | MS_WINDOWS = "win32" 34 | 35 | 36 | class IsabelleServerCommands(Enum): 37 | """Supported Isabelle server commands.""" 38 | 39 | HELP = "help" 40 | USE_THEORIES = "use_theories" 41 | ECHO = "echo" 42 | 43 | 44 | def get_isabelle_client(server_info: str) -> IsabelleClient: 45 | """ 46 | Get an instance of ``IsabelleClient`` from server info. 47 | 48 | >>> server_inf = 'server "test" = 127.0.0.1:10000 (password "pass")' 49 | >>> print(get_isabelle_client(server_inf).port) 50 | 10000 51 | >>> get_isabelle_client("wrong") 52 | Traceback (most recent call last): 53 | ... 54 | ValueError: Unexpected server info: wrong 55 | 56 | :param server_info: a line returned by a server on start 57 | :returns: an Isabelle client 58 | :raises ValueError: if the server response is malformed 59 | """ 60 | match = re.compile( 61 | r"server \".*\" = (.*):(.*) \(password \"(.*)\"\)" 62 | ).match(server_info) 63 | if match is None: 64 | raise ValueError(f"Unexpected server info: {server_info}") 65 | address, port, password = match.groups() 66 | isabelle_client = IsabelleClient(address, int(port), password) 67 | return isabelle_client 68 | 69 | 70 | def start_isabelle_server( 71 | log_file: Optional[str] = None, 72 | name: Optional[str] = None, 73 | port: Optional[int] = None, 74 | ) -> tuple[str, asyncio.subprocess.Process]: 75 | """ 76 | Start Isabelle server. 77 | 78 | >>> os.environ["PATH"] = "isabelle_client/resources:$PATH" 79 | >>> print(start_isabelle_server()[0]) 80 | server "isabelle" = 127.0.0.1:9999 (password "test_password") 81 | 82 | 83 | :param log_file: a log file for exceptional output of internal server and 84 | session operations 85 | :param name: explicit server name (default: isabelle) 86 | :param port: explicit server port 87 | :returns: a line of server info and server process 88 | """ 89 | args = ( 90 | "server" 91 | + (f" -L {log_file}" if log_file is not None else "") 92 | + (f" -p {str(port)}" if port is not None else "") 93 | + (f" -n {name}" if name is not None else "") 94 | ) 95 | if sys.platform == MS_WINDOWS: 96 | return start_isabelle_server_win32(args) # pragma: no cover 97 | 98 | async def async_call() -> tuple[str, asyncio.subprocess.Process]: 99 | """ 100 | Start Isabelle server asynchronously. 101 | 102 | :returns: a line of server info and server process 103 | :raises ValueError: if no stdout seen after starting the server 104 | """ 105 | isabelle_server = await asyncio.create_subprocess_exec( 106 | "isabelle", *(args.split(" ")), stdout=asyncio.subprocess.PIPE 107 | ) 108 | if isabelle_server.stdout is not None: 109 | return (await isabelle_server.stdout.readline()).decode( 110 | "utf-8" 111 | ), isabelle_server 112 | raise ValueError( 113 | "No stdout while startnig the server." 114 | ) # pragma: no cover 115 | 116 | return asyncio.run(async_call()) 117 | 118 | 119 | def start_isabelle_server_win32( 120 | args: str, 121 | ) -> tuple[str, asyncio.subprocess.Process]: # pragma: no cover 122 | """ 123 | Start Isabelle server on Windows. 124 | 125 | :param args: Isabelle server arguments string 126 | :returns: a line of server info and server process 127 | """ 128 | # this line enables asyncio.create_subprocess_exec on Windows: 129 | # https://docs.python.org/3/library/asyncio-platforms.html#asyncio-windows-subprocess 130 | asyncio.set_event_loop_policy( 131 | asyncio.WindowsProactorEventLoopPolicy() # type: ignore 132 | ) 133 | 134 | async def async_call() -> tuple[str, asyncio.subprocess.Process]: 135 | """ 136 | Start Isabelle server in Cygwin asynchronously. 137 | 138 | :returns: a line of server info and server process 139 | :raises ValueError: if no stdout seen after starting the server 140 | """ 141 | isabelle_server = await asyncio.create_subprocess_exec( 142 | str( 143 | files("isabelle_client").joinpath( 144 | os.path.join("resources", "Cygwin-Isabelle.bat") 145 | ) 146 | ), 147 | args, 148 | stdout=asyncio.subprocess.PIPE, 149 | stderr=asyncio.subprocess.PIPE, 150 | ) 151 | if isabelle_server.stdout is not None: 152 | server_info = (await isabelle_server.stdout.readline()).decode( 153 | "utf-8" 154 | ) 155 | return server_info, isabelle_server 156 | raise ValueError("No stdout while startnig the server.") 157 | 158 | return asyncio.run(async_call()) 159 | 160 | 161 | class BuggyDummyTCPHandler(socketserver.BaseRequestHandler): 162 | """A dummy handler to mock bugs in Isabelle server response.""" 163 | 164 | def handle(self): 165 | """Return something weird.""" 166 | request = self.request.recv(4096).decode("utf-8").split("\n")[1] 167 | if request == IsabelleServerCommands.HELP.value: 168 | self.request.sendall(b"5\n") 169 | self.request.sendall(b"# !!!") 170 | else: 171 | self.request.sendall( 172 | b'OK {"isabelle_id":"mock","isabelle_name":"Isabelle2024"}\n' 173 | ) 174 | self.request.sendall(b"ERROR UNEXPECTED\n") 175 | 176 | 177 | class DummyTCPHandler(socketserver.BaseRequestHandler): 178 | """A dummy handler to mock Isabelle server.""" 179 | 180 | def _mock_command_execution(self, command: str, arguments: str): 181 | filename = command 182 | if command == IsabelleServerCommands.USE_THEORIES.value: 183 | if (theory_name := json.loads(arguments)["theories"][0]) != "Mock": 184 | filename += f".{theory_name}" 185 | with open( 186 | str( 187 | files("isabelle_client").joinpath( 188 | os.path.join("resources", "isabelle-responses", filename) 189 | ) 190 | ), 191 | encoding="utf8", 192 | ) as mock_response_file: 193 | self.request.sendall(mock_response_file.read().encode()) 194 | 195 | def handle(self): 196 | """Return something similar to what Isabelle server does.""" 197 | request = self.request.recv(4096).decode("utf-8").split("\n")[1] 198 | command = request.split(" ")[0] 199 | arguments = request[len(command) :] 200 | self.request.sendall( 201 | b'OK {"isabelle_id":"mock","isabelle_name":"Isabelle2024"}\n' 202 | ) 203 | if command == IsabelleServerCommands.ECHO.value: 204 | self.request.sendall(f"OK {arguments[1:]}\n".encode()) 205 | else: 206 | self._mock_command_execution(command, arguments) 207 | 208 | 209 | class ReusableDummyTCPServer(socketserver.TCPServer): 210 | """Ignore TIME-WAIT during testing.""" 211 | 212 | allow_reuse_address = True 213 | -------------------------------------------------------------------------------- /local-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | PACKAGE_NAME=isabelle_client 5 | cd doc 6 | make clean html coverage 7 | cat _build/coverage/python.txt 8 | cd .. 9 | ruff format 10 | ruff check 11 | pydoclint ${PACKAGE_NAME} 12 | mypy ${PACKAGE_NAME} 13 | pyroma -n 10 . 14 | coverage run 15 | coverage report 16 | scc --no-cocomo --by-file -i py ${PACKAGE_NAME} 17 | -------------------------------------------------------------------------------- /poetry.toml: -------------------------------------------------------------------------------- 1 | [virtualenvs] 2 | in-project = true 3 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "isabelle-client" 3 | version = "0.5.6" 4 | description = "A client to Isabelle proof assistant server" 5 | authors = ["Boris Shminke "] 6 | license = "Apache-2.0" 7 | repository = "https://github.com/inpefess/isabelle-client" 8 | readme = "README.rst" 9 | classifiers=[ 10 | "Programming Language :: Python :: 3.13", 11 | "Programming Language :: Python :: 3.12", 12 | "Programming Language :: Python :: 3.11", 13 | "Programming Language :: Python :: 3.10", 14 | "Programming Language :: Python :: 3.9", 15 | "License :: OSI Approved :: Apache Software License", 16 | "Operating System :: OS Independent", 17 | "Intended Audience :: Science/Research", 18 | "Development Status :: 4 - Beta", 19 | "Environment :: Console", 20 | "Natural Language :: English", 21 | "Topic :: Scientific/Engineering :: Artificial Intelligence", 22 | "Typing :: Typed" 23 | ] 24 | keywords = ["TCP client", "Isabelle proof assistant", "interactive theorem prover"] 25 | include = ["isabelle_client/py.typed"] 26 | 27 | [tool.poetry.dependencies] 28 | python = ">= 3.9.1, < 3.14" 29 | 30 | [tool.poetry.group.dev] 31 | optional = true 32 | 33 | [tool.poetry.group.dev.dependencies] 34 | mypy = "*" 35 | pre-commit = "*" 36 | sphinx-autodoc-typehints = "*" 37 | types-dataclasses = "*" 38 | tox = "*" 39 | tbump = "*" 40 | toml = "*" 41 | furo = "*" 42 | pyroma = "*" 43 | sphinx-gallery = "*" 44 | ruff = "*" 45 | python-lsp-server = {version = "*", extras = ["rope"]} 46 | pylsp-rope = "*" 47 | pylsp-mypy = "*" 48 | python-lsp-ruff = "*" 49 | pydoclint = "*" 50 | 51 | [tool.poetry.group.test.dependencies] 52 | coverage = "*" 53 | pytest = "*" 54 | 55 | [tool.isort] 56 | profile = "black" 57 | src_paths = ["isabelle_client"] 58 | 59 | [build-system] 60 | requires = ["poetry-core>=1.0.0"] 61 | build-backend = "poetry.core.masonry.api" 62 | 63 | [tool.pytest.ini_options] 64 | minversion = "6.0" 65 | addopts = """--doctest-modules 66 | --junit-xml test-results/isabelle-client.xml""" 67 | testpaths = ["isabelle_client"] 68 | 69 | [tool.mypy] 70 | show_error_codes = true 71 | incremental = true 72 | disable_error_code = "no-redef" 73 | 74 | [tool.tox] 75 | legacy_tox_ini = """ 76 | [tox] 77 | isolated_build = True 78 | envlist = py39,py310,py311,py312,py313 79 | 80 | [testenv] 81 | deps = 82 | pytest 83 | coverage 84 | mypy 85 | toml 86 | pyroma 87 | ruff 88 | pydoclint 89 | commands = 90 | ruff format 91 | ruff check 92 | pydoclint isabelle_client 93 | mypy isabelle_client 94 | pyroma -n 10 . 95 | coverage run 96 | coverage xml 97 | coverage report 98 | """ 99 | 100 | [tool.tbump] 101 | github_url = "https://github.com/inpfess/isabelle-client/" 102 | 103 | [tool.tbump.version] 104 | current = "0.5.6" 105 | regex = ''' 106 | (?P\d+) 107 | \. 108 | (?P\d+) 109 | \. 110 | (?P\d+) 111 | ''' 112 | 113 | [tool.tbump.git] 114 | message_template = "Bump to {new_version}" 115 | tag_template = "v{new_version}" 116 | 117 | [[tool.tbump.file]] 118 | src = "isabelle_client/__init__.py" 119 | 120 | [[tool.tbump.file]] 121 | src = "pyproject.toml" 122 | 123 | [[tool.tbump.file]] 124 | src = "doc/conf.py" 125 | 126 | [tool.coverage.run] 127 | command_line = "-m pytest" 128 | source = ["isabelle_client"] 129 | 130 | [tool.coverage.report] 131 | fail_under = 100 132 | show_missing = true 133 | 134 | [tool.ruff] 135 | line-length = 79 136 | 137 | [tool.ruff.lint] 138 | select = ["F", "E", "W", "D", "S", "UP", "PL"] 139 | 140 | [tool.ruff.lint.pydocstyle] 141 | convention = "pep257" 142 | 143 | [tool.ruff.lint.per-file-ignores] 144 | "doc/auto_examples/plot_example.py" = ["E402"] 145 | "examples/plot_example.py" = ["E402"] 146 | "examples/cicm2022_example.ipynb" = ["W605", "S311"] 147 | 148 | [tool.ruff.lint.pylint] 149 | max-statements = 10 150 | 151 | [tool.pydoclint] 152 | style = "sphinx" 153 | arg-type-hints-in-docstring = false 154 | check-return-types = false 155 | check-yield-types = false 156 | -------------------------------------------------------------------------------- /unpublished-pre-print/architecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inpefess/isabelle-client/bade1feb796b4a6a78b71d2c4b2aa3649e6ccb0f/unpublished-pre-print/architecture.pdf -------------------------------------------------------------------------------- /unpublished-pre-print/cicm2022.bib: -------------------------------------------------------------------------------- 1 | @article{haslbeck2019competitive, 2 | title={Competitive Proving for Fun}, 3 | author={Haslbeck, Maximilian PL and Wimmer, Simon}, 4 | journal={Kalpa Publications in Computing}, 5 | volume={10}, 6 | pages={9--14}, 7 | year={2019}, 8 | publisher={EasyChair} 9 | } 10 | @article{DBLP:journals/corr/abs-2109-05264, 11 | author = {Wesley Fussner and 12 | Boris Shminke}, 13 | title = {Mining counterexamples for wide-signature algebras with an Isabelle 14 | server}, 15 | journal = {CoRR}, 16 | volume = {abs/2109.05264}, 17 | year = {2021}, 18 | url = {https://arxiv.org/abs/2109.05264}, 19 | eprinttype = {arXiv}, 20 | eprint = {2109.05264}, 21 | timestamp = {Tue, 21 Sep 2021 17:46:04 +0200}, 22 | biburl = {https://dblp.org/rec/journals/corr/abs-2109-05264.bib}, 23 | bibsource = {dblp computer science bibliography, https://dblp.org} 24 | } 25 | @inproceedings{DBLP:conf/mkm/LiskaLNRSSSW21, 26 | author = {Martin L{\'{\i}}ska and 27 | D{\'{a}}vid Lupt{\'{a}}k and 28 | V{\'{\i}}t Novotn{\'{y}} and 29 | Michal Ruzicka and 30 | Boris Shminke and 31 | Petr Sojka and 32 | Michal Stef{\'{a}}nik and 33 | Makarius Wenzel}, 34 | editor = {Fairouz Kamareddine and 35 | Claudio Sacerdoti Coen}, 36 | title = {CICM'21 Systems Entries}, 37 | booktitle = {Intelligent Computer Mathematics - 14th International Conference, 38 | {CICM} 2021, Timisoara, Romania, July 26-31, 2021, Proceedings}, 39 | series = {Lecture Notes in Computer Science}, 40 | volume = {12833}, 41 | pages = {245--248}, 42 | publisher = {Springer}, 43 | year = {2021}, 44 | url = {https://doi.org/10.1007/978-3-030-81097-9\_20}, 45 | doi = {10.1007/978-3-030-81097-9\_20}, 46 | timestamp = {Mon, 03 Jan 2022 22:24:40 +0100}, 47 | biburl = {https://dblp.org/rec/conf/mkm/LiskaLNRSSSW21.bib}, 48 | bibsource = {dblp computer science bibliography, https://dblp.org} 49 | } 50 | @misc{conda_forge_community_2015_4774216, 51 | author = {conda-forge community}, 52 | title = {{The conda-forge Project: Community-based Software 53 | Distribution Built on the conda Package Format and 54 | Ecosystem}}, 55 | month = jul, 56 | year = 2015, 57 | publisher = {Zenodo}, 58 | doi = {10.5281/zenodo.4774216}, 59 | url = {https://doi.org/10.5281/zenodo.4774216} 60 | } 61 | @InProceedings{10.1007/978-3-030-79876-5_37, 62 | author="Moura, Leonardo de 63 | and Ullrich, Sebastian", 64 | editor="Platzer, Andr{\'e} 65 | and Sutcliffe, Geoff", 66 | title="The Lean 4 Theorem Prover and Programming Language", 67 | booktitle="Automated Deduction -- CADE 28", 68 | year="2021", 69 | publisher="Springer International Publishing", 70 | address="Cham", 71 | pages="625--635", 72 | abstract="Lean 4 is a reimplementation of the Lean interactive theorem prover (ITP) in Lean itself. It addresses many shortcomings of the previous versions and contains many new features. Lean 4 is fully extensible: users can modify and extend the parser, elaborator, tactics, decision procedures, pretty printer, and code generator. The new system has a hygienic macro system custom-built for ITPs. It contains a new typeclass resolution procedure based on tabled resolution, addressing significant performance problems reported by the growing user base. Lean 4 is also an efficient functional programming language based on a novel programming paradigm called functional but in-place. Efficient code generation is crucial for Lean users because many write custom proof automation procedures in Lean itself.", 73 | isbn="978-3-030-79876-5" 74 | } 75 | @misc{LeanClient, 76 | author = {Jason Rute and 77 | Patrick Massot and 78 | Julian Berman and 79 | Frederic Le Roux}, 80 | title = {Lean client for Python}, 81 | month = aug, 82 | year = 2021, 83 | url = {https://github.com/leanprover-community/lean-client-python} 84 | } 85 | @misc{CoqClient, 86 | author = {Emilio Jesus \relax{Gallego Arias} and 87 | Thierry Martinez}, 88 | title = {PyCoq: Access Coq from Python!}, 89 | month = jan, 90 | year = 2022, 91 | url = {https://github.com/ejgallego/pycoq} 92 | } 93 | @misc{TIOBEIndex, 94 | author = {\relax{TIOBE Software BV}}, 95 | title = {The TIOBE Programming Community index}, 96 | month = apr, 97 | year = 2022, 98 | url = {https://www.tiobe.com/tiobe-index/} 99 | } 100 | @software{the_coq_development_team_2022_5846982, 101 | author = {\relax{The Coq Development Team}}, 102 | title = {The Coq Proof Assistant}, 103 | month = jan, 104 | year = 2022, 105 | publisher = {Zenodo}, 106 | version = {8.15}, 107 | doi = {10.5281/zenodo.5846982}, 108 | url = {https://doi.org/10.5281/zenodo.5846982} 109 | } 110 | @inproceedings{IsabelleServer, 111 | author = {Makarius Wenzel}, 112 | title = {Isabelle/PIDE after 10 years of development}, 113 | booktitle = {13th International Workshop on User Interfaces for Theorem Provers (UITP 2018)}, 114 | series = {Federated Logic Conference 2018}, 115 | year = 2018, 116 | url = {https://sketis.net/wp-content/uploads/2018/08/isabelle-pide-uitp2018.pdf} 117 | } 118 | @book{DBLP:books/sp/NipkowPW02, 119 | author = {Tobias Nipkow and 120 | Lawrence C. Paulson and 121 | Markus Wenzel}, 122 | title = {Isabelle/HOL - {A} Proof Assistant for Higher-Order Logic}, 123 | series = {Lecture Notes in Computer Science}, 124 | volume = {2283}, 125 | publisher = {Springer}, 126 | year = {2002}, 127 | url = {https://doi.org/10.1007/3-540-45949-9}, 128 | doi = {10.1007/3-540-45949-9}, 129 | isbn = {3-540-43376-7}, 130 | timestamp = {Tue, 14 May 2019 10:00:35 +0200}, 131 | biburl = {https://dblp.org/rec/books/sp/NipkowPW02.bib}, 132 | bibsource = {dblp computer science bibliography, https://dblp.org} 133 | } 134 | @InProceedings{ project_jupyter-proc-scipy-2018, 135 | author = { {P}roject {J}upyter and {M}atthias {B}ussonnier and {J}essica {F}orde and {J}eremy {F}reeman and {B}rian {G}ranger and {T}im {H}ead and {C}hris {H}oldgraf and {K}yle {K}elley and {G}ladys {N}alvarte and {A}ndrew {O}sheroff and {M} {P}acer and {Y}uvi {P}anda and {F}ernando {P}erez and {B}enjamin {R}agan-{K}elley and {C}arol {W}illing }, 136 | title = { {B}inder 2.0 - {R}eproducible, interactive, sharable environments for science at scale }, 137 | booktitle = { {P}roceedings of the 17th {P}ython in {S}cience {C}onference }, 138 | pages = { 113 - 120 }, 139 | year = { 2018 }, 140 | editor = { {F}atih {A}kici and {D}avid {L}ippa and {D}illon {N}iederhut and {M} {P}acer }, 141 | doi = { 10.25080/Majora-4af1f417-011 } 142 | } 143 | @article{DBLP:journals/cse/GrangerP21, 144 | author = {Brian E. Granger and 145 | Fernando P{\'{e}}rez}, 146 | title = {Jupyter: Thinking and Storytelling With Code and Data}, 147 | journal = {Comput. Sci. Eng.}, 148 | volume = {23}, 149 | number = {2}, 150 | pages = {7--14}, 151 | year = {2021}, 152 | url = {https://doi.org/10.1109/MCSE.2021.3059263}, 153 | doi = {10.1109/MCSE.2021.3059263}, 154 | timestamp = {Thu, 29 Apr 2021 15:14:54 +0200}, 155 | biburl = {https://dblp.org/rec/journals/cse/GrangerP21.bib}, 156 | bibsource = {dblp computer science bibliography, https://dblp.org} 157 | } 158 | @misc{KaggleReport, 159 | author = {\relax{Kaggle Inc.}}, 160 | title = {State of Data Science and Machine Learning 2021}, 161 | month = oct, 162 | year = 2021, 163 | url = {https://www.kaggle.com/kaggle-survey-2021} 164 | } 165 | @misc{IsabelleSystemManual, 166 | author = {Makarius Wenzel}, 167 | title = {The Isabelle System Manual}, 168 | month = dec, 169 | year = 2021, 170 | url = {https://isabelle.in.tum.de/dist/Isabelle2021-1/doc/system.pdf} 171 | } 172 | @software{boris_shminke_2022_6490275, 173 | author = {Boris Shminke}, 174 | title = {Python client for Isabelle server}, 175 | month = apr, 176 | year = 2022, 177 | publisher = {Zenodo}, 178 | version = {0.3.5}, 179 | doi = {10.5281/zenodo.6490275}, 180 | url = {https://doi.org/10.5281/zenodo.6490275} 181 | } 182 | -------------------------------------------------------------------------------- /unpublished-pre-print/cicm2022.tex: -------------------------------------------------------------------------------- 1 | \documentclass[runningheads]{llncs} 2 | \usepackage[T1]{fontenc} 3 | \usepackage{graphicx} 4 | \usepackage{minted} 5 | \usemintedstyle{friendly} 6 | \usepackage{hyperref} 7 | \usepackage{color} 8 | \renewcommand\UrlFont{\color{blue}\rmfamily} 9 | 10 | \begin{document} 11 | \title{Python client for Isabelle server\thanks{This work has been supported by the French government, through the 3IA Côte d'Azur Investments in the Future project managed by the National Research Agency (ANR) with the reference number ANR-19-P3IA-0002.}} 12 | % 13 | %\titlerunning{Abbreviated paper title} 14 | % If the paper title is too long for the running head, you can set 15 | % an abbreviated paper title here 16 | % 17 | \author{Boris Shminke\inst{1}\orcidID{0000-0002-1291-9896}} 18 | \authorrunning{B. Shminke} 19 | \institute{Université Côte d'Azur, CNRS, LJAD, France \\ 20 | \email{boris.shminke@univ-cotedazur.fr}} 21 | \maketitle 22 | 23 | \begin{abstract} 24 | We contribute a Python client for the Isabelle server, which gives researchers and students using Python as their primary programming language an opportunity to communicate with the Isabelle server through TCP directly from a Python script. Such an approach helps avoid the complexities of integrating the existing Python script with languages used for Isabelle development (ML and Scala). We also describe new features that appeared since the announcement of the first version of the client a year ago. Finally, we give examples of the client's applications in research and education and discuss known limitations and possible directions for future development. 25 | 26 | \keywords{Isabelle \and Python \and client-server architecture} 27 | \end{abstract} 28 | \section{Introduction} 29 | Isabelle~\cite{DBLP:books/sp/NipkowPW02} interactive theorem prover (ITP) has included the Isabelle server as part of its standard distribution since 2018~\cite{IsabelleServer}. The Isabelle server enables users to run multiple sessions and manage concurrent tasks to process Isabelle theory files through TCP. It makes, in principle, possible to communicate with the Isabelle server using any popular programming language~\cite{TIOBEIndex}, including Python. Python clients already exist for other major ITPs, for example, one~\cite{LeanClient} for Lean~\cite{10.1007/978-3-030-79876-5_37} or another one~\cite{CoqClient} for Coq~\cite{the_coq_development_team_2022_5846982}. To our best knowledge, the previous version (0.2.0) of the \texttt{isabelle-client} announced last year~\cite{DBLP:conf/mkm/LiskaLNRSSSW21} was the first Python client for Isabelle. This paper describes version 0.3.5 of the client (the digital artefact is available on Zenodo~\cite{boris_shminke_2022_6490275}). 30 | 31 | \section{How to use} 32 | A typical scenario of \texttt{isabelle-client} application is represented by Fig.~\ref{fig:architecture}. First, one should start the Isabelle server, for example, using a utility function \texttt{start\_isabelle\_server} from the package. Second, one creates an instance of \texttt{IsabelleClient} object, e.g. using the factory function \texttt{get\_isabelle\_client}. Finally, one can issue any command supported by the Isabelle server (see section 4.4 in~\cite{IsabelleSystemManual} for a full list) using \texttt{IsabelleClient} object, which implements all these commands as methods. Usually, these commands rely on existing Isabelle theory files, for example, generated by third-party Python scripts (not by \texttt{isabelle-client}). See also listing \ref{lst:example} for a basic code snippet. 33 | 34 | \begin{listing}[H] 35 | \begin{minted}{python} 36 | """ An example of the ``isabelle-client`` usage """ 37 | from isabelle_client import get_isabelle_client, start_isabelle_server 38 | 39 | # first, we start Isabelle server 40 | server_info, _ = start_isabelle_server( 41 | name="test", port=9999, log_file="server.log" 42 | ) 43 | # then we create an ``IsabelleClient`` instance 44 | isabelle = get_isabelle_client(server_info) 45 | # now we can send theory files to the server and get a response 46 | isabelle.use_theories(theories=["Example"], master_dir=".") 47 | # or we can build a session document using ROOT and root.tex files 48 | isabelle.session_build(dirs=["."], session="examples") 49 | isabelle.shutdown() 50 | \end{minted} 51 | \caption{How to use \texttt{isabelle-client}.} 52 | \label{lst:example} 53 | \end{listing} 54 | 55 | Interested potential users of the client can also follow the package homepage~\footnote{\href{https://pypi.org/project/isabelle-client/}{https://pypi.org/project/isabelle-client/}} for more detailed information. 56 | 57 | \begin{figure} 58 | \includegraphics[width=\textwidth]{architecture} 59 | \caption{In a project where Python scripts are generating Isabelle theory files, \texttt{isabelle-client} can be used to start the Isabelle server, sending these files for parallel processing and getting back the results.} \label{fig:architecture} 60 | \end{figure} 61 | 62 | \section{New features since previous version} 63 | The first public version of this client~\cite{DBLP:conf/mkm/LiskaLNRSSSW21}, which appeared in March 2021, worked only for Python 3.7 on GNU/Linux and was supposed to be installed only with the \texttt{pip} package manager. The current version is available for any Python 3.6+ on GNU/Linux and Windows. Every new build is tested in a continuous integration workflow against each supported Python version. The package is hosted now not only on the Python Package Index (PyPI), but also on Conda Forge~\cite{conda_forge_community_2015_4774216}, which enables its installation with both \texttt{pip} and \texttt{conda} package managers. In addition, one can run the client inside a Docker container, for example, in a cloud using Binder~\cite{project_jupyter-proc-scipy-2018}. This option provides the client coupled with the Isabelle server and is particularly useful for students specialising in logic but not necessarily having much experience in information technologies. 64 | 65 | The current version of the client is tested to work with the latest Isabelle 2021-1 (released in December 2021). The last client version returns all server replies as a Python list, not only the last one as it was in the previous version giving more flexibility to the end-user. Last but not least, the current version arrives with detailed documentation pages and is nearly 100\% covered with unit tests using fixtures for emulating a working Isabelle server behaviour. 66 | 67 | \section{Known applications in research and education} 68 | The original system entry for \texttt{isabelle-client} expressed hope that it would be helpful to other projects. After the first year, we saw several applications confirming these aspirations. The most impressive one was a discovery of a proof~\cite{DBLP:journals/corr/abs-2109-05264} for an algebraic problem which stood open for two years despite the efforts of specialists in the field. For this project, the \texttt{isabelle-client} played a role of a bridge connecting Python scripts which generated relevant Isabelle theory files with the Isabelle server processing them. 69 | 70 | Another use case comes from higher education. The \texttt{isabelle-client} running in a Docker container on Binder was used during the practical sessions of the Advanced Logic course taught at the Université Côte d'Azur in the autumn of the 2021-2022 academic year. The client helped students not trained in functional programming languages used for Isabelle development to concentrate on understanding the Isabelle language syntax and consequently generating theory files in it with Python scripts without installing and running the Isabelle GUI on their laptops. 71 | 72 | Also, Fabian Huch used the \texttt{isabelle-client} for debugging the 'Proving for Fun' backend~\cite{haslbeck2019competitive}. The 'Proving for Fun' project already had in its codebase parts resembling the \texttt{isabelle-client}, but using the \texttt{socket} Python package that provides access to the BSD socket interface. The \texttt{isabelle-client} uses \texttt{asyncio}, providing a more high-level interface for TCP communications, and exists as a stand-alone piece of software striving to be easily reusable for different projects. 73 | 74 | \section{Known limitations, workarounds, and future work} 75 | The first thing one would want from a client-server application is running the server and the client on different machines (probably, with various operating systems) or, at least, in separate Docker containers. The attempts to do that with \texttt{isabelle-client} demonstrated that the current implementation of the Isabelle server doesn't support binding its IP address to anything but \texttt{localhost} for security reasons. A desirable solution is implementing an authentication mechanism for the remote Isabelle server (for example, with access tokens, as is done for the Jupyter~\cite{DBLP:journals/cse/GrangerP21} server). The current workaround is to use SSH tunnels or package the \texttt{isabelle-client} together with the Isabelle server in the same Docker container. 76 | 77 | Although the \texttt{isabelle-client} works perfectly on Windows for communication with the Isabelle server running on the same machine, it's impossible to start the Isabelle server on Windows with the utility function from the \texttt{isabelle-client} package. The reason is related to the fact that the Isabelle server on Windows runs under Cygwin and not as a proper Windows application. A possible solution could be to rewrite the Windows CMD file, which starts the Isabelle server, to make it pass the started server info from the Cygwin subsystem to the parent Windows process. The current workaround is to launch the Isabelle server manually. 78 | 79 | At some point, it became known that it's impossible to start a clean build of a session from the \texttt{isabelle-client}. The reason is that the Isabelle server (unlike \texttt{isabelle build} tool) lacks \texttt{-c} parameter in its API. Thus, achieving relative feature parity of the Isabelle server and other Isabelle tools seems to be an important direction in making the \texttt{isabelle-client} more applicable and interesting to its end users. 80 | \section{Conclusion} 81 | A year after its appearance \texttt{isabelle-client} became a more mature piece of software and found its applications in both scientific research and higher education. As shown in this paper, there are still many ways to improve it, and we hope for many possible occasions for its further application, not limited to but including machine learning (as a domain dominated by Python~\cite{KaggleReport}) for theorem proving. 82 | \bibliographystyle{splncs04} 83 | \bibliography{cicm2022} 84 | \end{document} 85 | --------------------------------------------------------------------------------