Dafny runtime for Python
The `dafnyruntimepython` library provides the necessary runtime support for Python code generated by the Dafny verifier-aware programming language. Dafny compiles its formally verified code into various target languages, including Python. This runtime library is automatically included as source when Dafny builds a Python target. The current version is 4.11.0, and the Dafny project maintains a regular release cadence, with minor versions often released monthly or bi-monthly.
Common errors
-
ModuleNotFoundError: No module named '_dafny'
cause The Python interpreter cannot find the `_dafny` runtime module, which is part of the Dafny-generated output. This usually happens when the `PYTHONPATH` environment variable is not correctly set to include the directory containing the generated code.fixEnsure that the directory created by the Dafny compiler (e.g., `MyProgram-py/`) is added to your `PYTHONPATH` environment variable before running the generated Python script. For example: `PYTHONPATH=./MyProgram-py python3 MyProgram-py/MyProgram.py`. -
dafny build --target:py MyProgram.dfy Error: The command 'dafny' could not be found.
cause The `dafny` command-line interface tool is not installed or not available in the system's PATH. The `dafnyruntimepython` library is a runtime dependency, but the initial compilation from Dafny source requires the `dafny` CLI.fixInstall the Dafny CLI tool. Instructions are available on the official Dafny website or GitHub repository. Typically, it's installed as a .NET tool (`dotnet tool install --global dafny`) or by downloading a pre-built binary and adding it to your PATH. -
TypeError: argument of type 'MyDafnyModule_C' is not iterable
cause This error can occur when a Dafny-generated type (e.g., a class instance) is passed to a native Python function that expects a standard Python iterable (like a list or tuple), but the Dafny type does not implement the necessary Python iteration protocols.fixExplicitly convert Dafny-generated collection types to native Python collections (e.g., lists, dicts) before passing them to Python functions that expect specific behaviors. Similarly, if passing native Python collections to Dafny code, ensure they conform to the expected Dafny types and contracts.
Warnings
- gotcha The `dafnyruntimepython` library is not intended for direct interaction or import by user-written Python code. It is an internal dependency for Python code generated by the Dafny compiler. Attempts to `import dafnyruntimepython` directly will not yield useful functionality as its components are typically exposed through the generated Dafny modules.
- gotcha When compiling Dafny to Python, ensure the `dafny` CLI tool is installed and its version is compatible with the `dafnyruntimepython` library version. Mismatched versions can lead to unexpected runtime behavior or compilation errors, though the runtime library itself aims for backward compatibility.
- gotcha Generated Python classes from Dafny currently cannot be directly compared or mixed with native Python types in a semantically equivalent way. This can lead to unexpected behavior when passing Dafny-generated objects to native Python functions or vice-versa, especially for complex data structures.
Install
-
pip install dafnyruntimepython
Imports
- Dafny generated modules
import dafnyruntimepython
from MyProgram_py import MyModule
- _dafny
import _dafny
from MyProgram_py._dafny import ...
Quickstart
import os
import subprocess
# 1. Create a dummy Dafny file
dafny_code = """
// MyDafnyProgram.dfy
module {:extern "MyDafnyModule"} MyModule {
class C {
static method SayHello() {
print "Hello from Dafny!\n";
}
}
}
method Main() {
MyModule.C.SayHello();
}
"""
with open("MyDafnyProgram.dfy", "w") as f:
f.write(dafny_code)
print("Dafny source file created: MyDafnyProgram.dfy")
# 2. Compile Dafny to Python
# Requires the 'dafny' CLI tool to be installed and in PATH.
# This step generates a directory like MyDafnyProgram-py/
compile_cmd = ["dafny", "build", "--target:py", "MyDafnyProgram.dfy"]
print(f"Executing: {' '.join(compile_cmd)}")
try:
subprocess.run(compile_cmd, check=True, capture_output=True, text=True)
print("Dafny compiled successfully to Python.")
except subprocess.CalledProcessError as e:
print(f"Dafny compilation failed:\n{e.stdout}\n{e.stderr}")
exit(1)
# 3. Execute the generated Python code
# Add the generated directory to PYTHONPATH to allow imports
os.environ["PYTHONPATH"] = os.getcwd() + ":" + os.path.join(os.getcwd(), "MyDafnyProgram-py")
# The entry point for the generated Python code is typically in the top-level generated .py file.
# The name will be derived from the .dfy file (e.g., MyDafnyProgram.py in MyDafnyProgram-py/)
# For Dafny 4.x, the Main method is typically directly runnable or imported.
# Let's find the main generated file.
output_dir = "MyDafnyProgram-py"
if os.path.exists(output_dir):
python_main_file = os.path.join(output_dir, "MyDafnyProgram.py")
if os.path.exists(python_main_file):
print(f"Executing generated Python: python3 {python_main_file}")
try:
run_cmd = ["python3", python_main_file]
result = subprocess.run(run_cmd, check=True, capture_output=True, text=True)
print("\n--- Generated Python Output ---")
print(result.stdout)
if result.stderr:
print("--- Generated Python Errors ---")
print(result.stderr)
print("-------------------------------")
except subprocess.CalledProcessError as e:
print(f"Execution of generated Python failed:\n{e.stdout}\n{e.stderr}")
exit(1)
else:
print(f"Error: Main Python file not found in {output_dir}")
exit(1)
else:
print(f"Error: Dafny output directory {output_dir} not found.")
exit(1)
# Clean up generated files (optional)
# import shutil
# if os.path.exists("MyDafnyProgram.dfy"):
# os.remove("MyDafnyProgram.dfy")
# if os.path.exists(output_dir):
# shutil.rmtree(output_dir)