mirror of
https://github.com/Instagram/LibCST.git
synced 2025-12-23 10:35:53 +00:00
Enable support for free-threading (#1295)
This PR: 1. marks the `libcst.native` module as free-threading-compatible 2. replaces the use of ProcessPoolExecutor with ThreadPoolExecutor if free-threaded CPython is detected at runtime
This commit is contained in:
parent
52acdf4163
commit
16ed48d74b
5 changed files with 52 additions and 87 deletions
56
.github/workflows/ci.yml
vendored
56
.github/workflows/ci.yml
vendored
|
|
@ -13,8 +13,13 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.13t"]
|
||||
steps:
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install hatch
|
||||
run: pip install -U hatch
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
|
@ -24,9 +29,6 @@ jobs:
|
|||
cache: pip
|
||||
cache-dependency-path: "pyproject.toml"
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install hatch
|
||||
run: |
|
||||
pip install -U hatch
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
|
@ -44,50 +46,6 @@ jobs:
|
|||
hatch run coverage combine .coverage.pure
|
||||
hatch run coverage report
|
||||
|
||||
# TODO:
|
||||
# merge into regular CI once hatch has support for creating environments on
|
||||
# the free-threaded build: https://github.com/pypa/hatch/issues/1931
|
||||
free-threaded-tests:
|
||||
name: "test (${{ matrix.os }}, 3.13t)"
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
cache: pip
|
||||
cache-dependency-path: "pyproject.toml"
|
||||
python-version: '3.13t'
|
||||
- name: Build LibCST
|
||||
run: |
|
||||
# Install build-system.requires dependencies
|
||||
pip install setuptools setuptools-scm setuptools-rust wheel
|
||||
# Jupyter is annoying to install on free-threaded Python
|
||||
pip install -e .[dev-without-jupyter]
|
||||
- name: Native Parser Tests
|
||||
# TODO: remove when native modules declare free-threaded support
|
||||
env:
|
||||
PYTHON_GIL: '0'
|
||||
run: |
|
||||
python -m coverage run -m libcst.tests
|
||||
- name: Pure Parser Tests
|
||||
env:
|
||||
COVERAGE_FILE: .coverage.pure
|
||||
LIBCST_PARSER_TYPE: pure
|
||||
run: |
|
||||
python -m coverage run -m libcst.tests
|
||||
- name: Coverage
|
||||
run: |
|
||||
python -m coverage combine .coverage.pure
|
||||
python -m coverage report
|
||||
|
||||
|
||||
# Run linters
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -139,7 +97,7 @@ jobs:
|
|||
- name: Install hatch
|
||||
run: pip install -U hatch
|
||||
- uses: ts-graphviz/setup-graphviz@v2
|
||||
- run: hatch run docs
|
||||
- run: hatch run docs:docs
|
||||
- name: Archive Docs
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -8,18 +8,19 @@ Provides helpers for CLI interaction.
|
|||
"""
|
||||
|
||||
import difflib
|
||||
import functools
|
||||
import os.path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from concurrent.futures import as_completed, Executor, ProcessPoolExecutor
|
||||
from concurrent.futures import as_completed, Executor
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from multiprocessing import cpu_count
|
||||
from pathlib import Path
|
||||
from typing import AnyStr, cast, Dict, List, Optional, Sequence, Type, Union
|
||||
from typing import AnyStr, Callable, cast, Dict, List, Optional, Sequence, Type, Union
|
||||
from warnings import warn
|
||||
|
||||
from libcst import parse_module, PartialParserConfig
|
||||
|
|
@ -624,14 +625,20 @@ def parallel_exec_transform_with_prettyprint( # noqa: C901
|
|||
python_version=python_version,
|
||||
)
|
||||
|
||||
pool_impl: type[Executor]
|
||||
pool_impl: Callable[[], Executor]
|
||||
if total == 1 or jobs == 1:
|
||||
# Simple case, we should not pay for process overhead.
|
||||
# Let's just use a dummy synchronous executor.
|
||||
jobs = 1
|
||||
pool_impl = DummyExecutor
|
||||
elif getattr(sys, "_is_gil_enabled", lambda: False)(): # pyre-ignore[16]
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
pool_impl = functools.partial(ThreadPoolExecutor, max_workers=jobs)
|
||||
else:
|
||||
pool_impl = ProcessPoolExecutor
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
|
||||
pool_impl = functools.partial(ProcessPoolExecutor, max_workers=jobs)
|
||||
# Warm the parser, pre-fork.
|
||||
parse_module(
|
||||
"",
|
||||
|
|
@ -650,7 +657,7 @@ def parallel_exec_transform_with_prettyprint( # noqa: C901
|
|||
deepcopy(transform.context.scratch) if isinstance(transform, Codemod) else {}
|
||||
)
|
||||
|
||||
with pool_impl(max_workers=jobs) as executor: # type: ignore
|
||||
with pool_impl() as executor: # type: ignore
|
||||
try:
|
||||
futures = [
|
||||
executor.submit(
|
||||
|
|
|
|||
|
|
@ -22,9 +22,6 @@ class DummyExecutor(Executor):
|
|||
Synchronous dummy `concurrent.futures.Executor` analogue.
|
||||
"""
|
||||
|
||||
def __init__(self, max_workers: Optional[int] = None) -> None:
|
||||
pass
|
||||
|
||||
def submit(
|
||||
self,
|
||||
fn: Callable[Params, Return],
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
use crate::nodes::traits::py::TryIntoPy;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pymodule]
|
||||
#[pymodule(gil_used = false)]
|
||||
#[pyo3(name = "native")]
|
||||
pub fn libcst_native(_py: Python, m: &Bound<PyModule>) -> PyResult<()> {
|
||||
#[pyfn(m)]
|
||||
|
|
|
|||
|
|
@ -18,33 +18,9 @@ classifiers = [
|
|||
"Typing :: Typed",
|
||||
]
|
||||
requires-python = ">=3.9"
|
||||
dependencies = ["pyyaml>=5.2"]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"libcst[dev-without-jupyter]",
|
||||
"jupyter>=1.0.0",
|
||||
"nbsphinx>=0.4.2",
|
||||
]
|
||||
dev-without-jupyter = [
|
||||
"black==25.1.0",
|
||||
"coverage[toml]>=4.5.4",
|
||||
"build>=0.10.0",
|
||||
"fixit==2.1.0",
|
||||
"flake8==7.2.0",
|
||||
"Sphinx>=5.1.1",
|
||||
"hypothesis>=4.36.0",
|
||||
"hypothesmith>=0.0.4",
|
||||
"maturin>=1.7.0,<1.8",
|
||||
"prompt-toolkit>=2.0.9",
|
||||
"pyre-check==0.9.18; platform_system != 'Windows'",
|
||||
"setuptools_scm>=6.0.1",
|
||||
"sphinx-rtd-theme>=0.4.3",
|
||||
"ufmt==2.8.0",
|
||||
"usort==1.0.8.post1",
|
||||
"setuptools-rust>=1.5.2",
|
||||
"slotscheck>=0.7.1",
|
||||
"jinja2==3.1.6",
|
||||
dependencies = [
|
||||
"pyyaml>=5.2; python_version < '3.13'",
|
||||
"pyyaml-ft; python_version >= '3.13'",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
|
@ -63,10 +39,26 @@ show_missing = true
|
|||
skip_covered = true
|
||||
|
||||
[tool.hatch.envs.default]
|
||||
features = ["dev"]
|
||||
installer = "uv"
|
||||
dependencies = [
|
||||
"black==25.1.0",
|
||||
"coverage[toml]>=4.5.4",
|
||||
"build>=0.10.0",
|
||||
"fixit==2.1.0",
|
||||
"flake8==7.2.0",
|
||||
"hypothesis>=4.36.0",
|
||||
"hypothesmith>=0.0.4",
|
||||
"maturin>=1.7.0,<1.8",
|
||||
"prompt-toolkit>=2.0.9",
|
||||
"pyre-check==0.9.18; platform_system != 'Windows'",
|
||||
"setuptools_scm>=6.0.1",
|
||||
"ufmt==2.8.0",
|
||||
"usort==1.0.8.post1",
|
||||
"setuptools-rust>=1.5.2",
|
||||
"slotscheck>=0.7.1",
|
||||
]
|
||||
|
||||
[tool.hatch.envs.default.scripts]
|
||||
docs = "sphinx-build -ab html docs/source docs/build"
|
||||
fixtures = ["python scripts/regenerate-fixtures.py", "git diff --exit-code"]
|
||||
format = "ufmt format libcst scripts"
|
||||
lint = [
|
||||
|
|
@ -78,6 +70,17 @@ lint = [
|
|||
test = ["python --version", "python -m coverage run -m libcst.tests"]
|
||||
typecheck = ["pyre --version", "pyre check"]
|
||||
|
||||
[tool.hatch.envs.docs]
|
||||
extra-dependencies = [
|
||||
"Sphinx>=5.1.1",
|
||||
"sphinx-rtd-theme>=0.4.3",
|
||||
"jupyter>=1.0.0",
|
||||
"nbsphinx>=0.4.2",
|
||||
"jinja2==3.1.6",
|
||||
]
|
||||
[tool.hatch.envs.docs.scripts]
|
||||
docs = "sphinx-build -ab html docs/source docs/build"
|
||||
|
||||
[tool.slotscheck]
|
||||
exclude-modules = '^libcst\.(testing|tests)'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue