diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4f6759bc5a..a0b06ab0dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,6 +24,7 @@ repos: entry: bash ./tools/synchro.sh language: python require_serial: true + fail_fast: true additional_dependencies: - ruff==0.1.3 - unasync diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7516fbc9ed..814e040048 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -246,6 +246,18 @@ you are attempting to validate new spec tests in PyMongo. Follow the [Python Driver Release Process Wiki](https://wiki.corp.mongodb.com/display/DRIVERS/Python+Driver+Release+Process). +## Asyncio considerations + +PyMongo adds asyncio capability by modifying the source files in `*/asynchronous` to `*/synchronous` using +[unasync](https://github.com/python-trio/unasync/) and some custom transforms. + +Where possible, edit the code in `*/asynchronous/*.py` and not the synchronous files. +You can run `pre-commit run --all-files synchro` before running tests if you are testing synchronous code. + +To prevent the `synchro` hook from accidentally overwriting code, it first checks to see whether a sync version +of a file is changing and not its async counterpart, and will fail. +In the unlikely scenario that you want to override this behavior, first export `OVERRIDE_SYNCHRO_CHECK=1`. + ## Converting a test to async The `tools/convert_test_to_async.py` script takes in an existing synchronous test file and outputs a partially-converted asynchronous version of the same name to the `test/asynchronous` directory. diff --git a/tools/synchro.py b/tools/synchro.py index 47617365f4..577e82d14e 100644 --- a/tools/synchro.py +++ b/tools/synchro.py @@ -19,7 +19,9 @@ from __future__ import annotations +import os import re +import sys from os import listdir from pathlib import Path @@ -356,6 +358,19 @@ def unasync_directory(files: list[str], src: str, dest: str, replacements: dict[ def main() -> None: + modified_files = [f"./{f}" for f in sys.argv[1:]] + errored = False + for fname in async_files + gridfs_files: + # If the async file was modified, we don't need to check if the sync file was also modified. + if str(fname) in modified_files: + continue + sync_name = str(fname).replace("asynchronous", "synchronous") + if sync_name in modified_files and "OVERRIDE_SYNCHRO_CHECK" not in os.environ: + print(f"Refusing to overwrite {sync_name}") + errored = True + if errored: + raise ValueError("Aborting synchro due to errors") + unasync_directory(async_files, _pymongo_base, _pymongo_dest_base, replacements) unasync_directory(gridfs_files, _gridfs_base, _gridfs_dest_base, replacements) unasync_directory(test_files, _test_base, _test_dest_base, replacements) diff --git a/tools/synchro.sh b/tools/synchro.sh index 2887509fe9..51c51a9548 100755 --- a/tools/synchro.sh +++ b/tools/synchro.sh @@ -1,5 +1,7 @@ -#!/bin/bash -eu +#!/bin/bash -python ./tools/synchro.py +set -eu + +python ./tools/synchro.py "$@" python -m ruff check pymongo/synchronous/ gridfs/synchronous/ test/ --fix --silent python -m ruff format pymongo/synchronous/ gridfs/synchronous/ test/ --silent