{"id":14966220,"url":"https://github.com/sr-lab/coqpyt","last_synced_at":"2025-10-25T16:30:43.804Z","repository":{"id":166916315,"uuid":"642101913","full_name":"sr-lab/coqpyt","owner":"sr-lab","description":"Python client for coq-lsp","archived":false,"fork":false,"pushed_at":"2024-10-18T16:49:13.000Z","size":544,"stargazers_count":31,"open_issues_count":8,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-31T07:51:29.034Z","etag":null,"topics":["coq","language-server-protocol","lsp-client"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"yeger00/pylspclient","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sr-lab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-17T20:34:01.000Z","updated_at":"2025-01-01T16:19:21.000Z","dependencies_parsed_at":"2024-05-02T16:54:07.824Z","dependency_job_id":"1efac7cf-ab9e-480e-b81b-6a7bacaf7e4e","html_url":"https://github.com/sr-lab/coqpyt","commit_stats":{"total_commits":287,"total_committers":10,"mean_commits":28.7,"dds":0.5923344947735192,"last_synced_commit":"226c0ffd64e5a5f0b408b7e2a6593102b2e6b2f9"},"previous_names":["pcarrott/pylspclient","pcarrott/coq-lsp-pyclient","sr-lab/coq-lsp-pyclient","sr-lab/coqpyt"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sr-lab%2Fcoqpyt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sr-lab%2Fcoqpyt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sr-lab%2Fcoqpyt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sr-lab%2Fcoqpyt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sr-lab","download_url":"https://codeload.github.com/sr-lab/coqpyt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238174114,"owners_count":19428628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coq","language-server-protocol","lsp-client"],"created_at":"2024-09-24T13:36:01.909Z","updated_at":"2025-10-25T16:30:43.798Z","avatar_url":"https://github.com/sr-lab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Logo](https://github.com/sr-lab/coqpyt/blob/master/images/logo.png?raw=true)\n\nInteract with Coq files and navigate through your proofs using our Python client for [coq-lsp](https://github.com/ejgallego/coq-lsp).\n\nExecute Coq files, retrieve the generated context and edit proofs through insertion and removal of steps.\n\nIf you use CoqPyt in an article, please cite:\n\n[CoqPyt: Proof Navigation in Python in the Era of LLMs](https://doi.org/10.1145/3663529.3663814)\n\n```\n@inproceedings{carrott2024coqpyt,\n  title={CoqPyt: Proof Navigation in Python in the Era of LLMs},\n  author={Carrott, Pedro and Saavedra, Nuno and Thompson, Kyle and Lerner, Sorin and Ferreira, Jo{\\~a}o F and First, Emily},\n  booktitle={Companion Proceedings of the 32nd ACM International Conference on the Foundations of Software Engineering},\n  pages={637--641},\n  year={2024}\n}\n```\n\n## Installation\n\n[Python](https://www.python.org/) must be installed on version \u003e= 3.11.\n\n[coq-lsp](https://github.com/ejgallego/coq-lsp) must be installed on version \u003e= 0.1.7. Follow the installation instructions provided [here](https://github.com/ejgallego/coq-lsp#%EF%B8%8F-installation).\n\n```bash\npip install -r requirements.txt\npython -m pip install -e .\n```\n\n### uv installation\n\nIn alternative, use [uv](https://github.com/astral-sh/uv) to setup the project and create a virtual environment.\n\n```bash\nuv sync --dev\nuv pip install -e .\n```\n\n## Usage\n\n![UML](https://github.com/sr-lab/coqpyt/blob/master/images/uml.png?raw=true)\n\nImport classes from the ``coqpyt`` package.\n\n\u003c!-- embedme examples/readme.py#L3-L7 --\u003e\n```py\nfrom coqpyt.coq.structs import TermType\nfrom coqpyt.coq.base_file import CoqFile\nfrom coqpyt.coq.proof_file import ProofFile\nfrom coqpyt.coq.changes import ProofAppend, ProofPop\nfrom coqpyt.coq.exceptions import InvalidChangeException\n```\n\n### Interaction with Coq\n\nCreate a CoqFile object, execute the file and extract the generated context.\n\n\u003c!-- embedme examples/readme.py#L9-L36 --\u003e\n```py\n# Open Coq file\nwith CoqFile(os.path.join(os.getcwd(), \"examples/readme.v\")) as coq_file:\n    coq_file.exec(nsteps=2)\n    # Get all terms defined until now\n    print(\"Number of terms:\", len(coq_file.context.terms))\n    # Filter by Tactics\n    print(\n        \"Number of tactics:\",\n        len(\n            list(\n                filter(\n                    lambda term: term.type == TermType.TACTIC,\n                    coq_file.context.terms.values(),\n                )\n            )\n        ),\n    )\n\n    # Save compiled file\n    coq_file.save_vo()\n    print(\"Compiled file exists:\", os.path.exists(\"examples/readme.vo\"))\n    os.remove(\"examples/readme.vo\")\n\n    # Run remaining file\n    coq_file.run()\n    print(\"Checked:\", coq_file.checked)\n    # Get all terms defined until now\n    print(\"Number of terms:\", len(coq_file.context.terms))\n```\n\nCreate a ProofFile object (a CoqFile instance) and interact with the proofs.\n\n\u003c!-- embedme examples/readme.py#L38-L75 --\u003e\n```py\n# Open Proof file\nwith ProofFile(os.path.join(os.getcwd(), \"examples/readme.v\")) as proof_file:\n    # Enter proof\n    proof_file.exec(nsteps=4)\n    print(\"In proof:\", proof_file.in_proof)\n    # Get current goals\n    print(proof_file.current_goals)\n\n    # Run remaining file\n    proof_file.run()\n    # Number of proofs in the file\n    print(\"Number of proofs:\", len(proof_file.proofs))\n    print(\"Proof:\", proof_file.proofs[0].text)\n\n    # Print steps of proof\n    for step in proof_file.proofs[0].steps:\n        print(step.text, end=\"\")\n    print()\n\n    # Get the context used in the third step\n    print(proof_file.proofs[0].steps[2].context)\n    # Print the goals in the third step\n    print(proof_file.proofs[0].steps[2].goals)\n\n    # Print number of terms in context\n    print(\"Number of terms:\", len(proof_file.context.terms))\n    # Filter for Notations only\n    print(\n        \"Number of notations:\",\n        len(\n            list(\n                filter(\n                    lambda term: term.type == TermType.NOTATION,\n                    proof_file.context.terms.values(),\n                )\n            )\n        ),\n    )\n```\n\n### Proof Modification\n\nGiven an admitted proof:\n\n\u003c!-- embedme examples/readme.v#L13-L19 --\u003e\n```coq\nLemma rev_append: forall {a} (l1 l2: list a),\n  rev (l1 ++ l2) = rev l2 ++ rev l1.\nProof.\nintros a l1 l2. induction l1; intros. \n  - simpl. rewrite app_nil_r. reflexivity.\n  - simpl. rewrite IHl1.\nAdmitted.\n```\n\nPerform step-wise changes to the proof.\n\n\u003c!-- embedme examples/readme.py#L87-L110 --\u003e\n```py\nwith ProofFile(os.path.join(os.getcwd(), \"examples/readme.v\")) as proof_file:\n    proof_file.run()\n    # Get the first admitted proof\n    unproven = proof_file.unproven_proofs[0]\n    # Steps for an incorrect proof\n    incorrect = [\" reflexivity.\", \"\\nQed.\"]\n    # Steps for a correct proof\n    correct = [\" rewrite app_assoc.\"] + incorrect\n\n    # Loop through both attempts\n    for attempt in [incorrect, correct]:\n        # Remove the \"\\nAdmitted.\" step\n        proof_file.pop_step(unproven)\n        try:\n            # Append all steps in the attempt\n            for i, s in enumerate(attempt):\n                proof_file.append_step(unproven, s)\n            print(\"Proof succeeded!\")\n            break\n        except InvalidChangeException:\n            # Some step was invalid, so we rollback the previous changes\n            [proof_file.pop_step(unproven) for _ in range(i)]\n            proof_file.append_step(unproven, \"\\nAdmitted.\")\n            print(\"Proof attempt not valid.\")\n```\n\nPerform changes to the proof transactionally.\n\n\u003c!-- embedme examples/readme.py#L113-L137 --\u003e\n```py\nwith ProofFile(os.path.join(os.getcwd(), \"examples/readme.v\")) as proof_file:\n    proof_file.run()\n    # Get the first admitted proof\n    unproven = proof_file.unproven_proofs[0]\n    # Steps for an incorrect proof\n    incorrect = [\" reflexivity.\", \"\\nQed.\"]\n    # Steps for a correct proof\n    correct = [\" rewrite app_assoc.\"] + incorrect\n\n    # Loop through both attempts\n    for attempt in [incorrect, correct]:\n        # Schedule the removal of the \"\\nAdmitted.\" step\n        changes = [ProofPop()]\n        # Schedule the addition of each step in the attempt\n        for s in attempt:\n            changes.append(ProofAppend(s))\n        try:\n            # Apply all changes in one batch\n            proof_file.change_proof(unproven, changes)\n            print(\"Proof succeeded!\")\n            break\n        except InvalidChangeException:\n            # Some batch of changes was invalid\n            # Rollback is automatic, so no rollback needed\n            print(\"Proof attempt not valid.\")\n```\n\n## Tests\n\nTo run the core tests for CoqPyt go to the folder ``coqpyt`` and run:\n```bash\npytest tests -rs\n```\n\nSkipped tests require the following external Coq libraries to run successfully:\n- [Coq-Equations](https://github.com/mattam82/Coq-Equations)\n\nTo run all tests go to the folder ``coqpyt`` and run:\n```bash\npytest tests -rs --runextra\n```\n\n## Contributing\n\nPull requests are welcome. \n\nFor major changes, please open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate.\n\n## Credits\n\nSpecial thanks to the developers of the [pylspclient](https://github.com/yeger00/pylspclient) project, which served as the initial template for CoqPyt. Additionally, we express our gratitude to [Kyle Thompson](https://github.com/rkthomps/) for his precious feedback, which has greatly contributed to the refinement of CoqPyt.\n\n## License\n\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsr-lab%2Fcoqpyt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsr-lab%2Fcoqpyt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsr-lab%2Fcoqpyt/lists"}