Skip to content

Comments

Support Quarto Markdown language markers#22947

Merged
amyreese merged 3 commits intoastral-sh:mainfrom
tvatter:markdown-curly-brace-syntax
Feb 5, 2026
Merged

Support Quarto Markdown language markers#22947
amyreese merged 3 commits intoastral-sh:mainfrom
tvatter:markdown-curly-brace-syntax

Conversation

@tvatter
Copy link
Contributor

@tvatter tvatter commented Jan 29, 2026

See this comment from #22470. Also related to #6140.

Summary

Add support for formatting code blocks with curly brace syntax (e.g., ```{python}, ```{py}, ```{pyi}) in Markdown files. This syntax is commonly used in tools like Quarto and R Markdown.

The regex pattern now matches both the standard syntax (```python) and the curly brace variant (```{python}).

Test Plan

Added test cases.

Fix #22951

@ntBre ntBre requested a review from amyreese January 29, 2026 18:30
@amyreese amyreese linked an issue Jan 29, 2026 that may be closed by this pull request
@amyreese amyreese force-pushed the markdown-curly-brace-syntax branch from 92c2086 to 4a6e940 Compare February 3, 2026 19:31
@amyreese amyreese changed the title Support curly brace syntax for Python code blocks in Markdown Support Quarto Markdown language markers Feb 3, 2026
@amyreese amyreese added the formatter Related to the formatter label Feb 3, 2026
@amyreese amyreese requested a review from ntBre February 3, 2026 19:32
@amyreese amyreese added the preview Related to preview mode features label Feb 3, 2026
@amyreese
Copy link
Member

amyreese commented Feb 3, 2026

Rebuilt this PR on latest main using a simpler regex change, and updated the test cases.

Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thank you!

@ntBre
Copy link
Contributor

ntBre commented Feb 3, 2026

I removed the closing keyword for #6140, which I believe also includes linting.

@amyreese do you know if this will actually work with the current Markdown formatting code if Quarto uses the extension .qmd? That's the extension mentioned in #6140.

@amyreese amyreese enabled auto-merge (squash) February 3, 2026 19:40
@amyreese amyreese disabled auto-merge February 3, 2026 19:40
@amyreese
Copy link
Member

amyreese commented Feb 3, 2026

Currently, no, ruff will still only trigger markdown formatting on file extensions matching exactly .md.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 3, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+987 -1440 violations, +0 -0 fixes in 15 projects; 40 projects unchanged)

DisnakeDev/disnake (+2 -2 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- tests/ui/test_action_row.py:19:17: PLC2701 Private name import `_types` from external module `disnake.ui`
- tests/ui/test_action_row.py:19:17: PLC2701 Private name import `_types` from external module `disnake.ui`
+ tests/ui/test_action_row.py:19:31: PLC2701 Private name import `_types` from external module `disnake.ui`
+ tests/ui/test_action_row.py:19:58: PLC2701 Private name import `_types` from external module `disnake.ui`

PlasmaPy/PlasmaPy (+2 -2 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

+ src/plasmapy/tests/_helpers/exceptions.py:16:30: PLC2701 Private name import `_pytest`
- src/plasmapy/tests/_helpers/exceptions.py:16:6: PLC2701 Private name import `_pytest`
- tests/particles/conftest.py:6:25: PLC2701 Private name import `_special_particles` from external module `plasmapy.particles`
+ tests/particles/conftest.py:6:51: PLC2701 Private name import `_special_particles` from external module `plasmapy.particles`

apache/airflow (+238 -700 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

- airflow-core/tests/integration/otel/test_otel.py:30:14: PLC2701 Private name import `_shared` from external module `airflow`
+ airflow-core/tests/integration/otel/test_otel.py:30:39: PLC2701 Private name import `_shared` from external module `airflow`
- airflow-core/tests/unit/api_fastapi/auth/test_tokens.py:31:14: PLC2701 Private name import `_shared` from external module `airflow`
+ airflow-core/tests/unit/api_fastapi/auth/test_tokens.py:31:39: PLC2701 Private name import `_shared` from external module `airflow`
- airflow-core/tests/unit/api_fastapi/common/db/test_dags.py:24:14: PLC2701 Private name import `_shared` from external module `airflow`
+ airflow-core/tests/unit/api_fastapi/common/db/test_dags.py:24:48: PLC2701 Private name import `_shared` from external module `airflow`
- airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_assets.py:27:14: PLC2701 Private name import `_shared` from external module `airflow`
+ airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_assets.py:27:39: PLC2701 Private name import `_shared` from external module `airflow`
- airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py:27:14: PLC2701 Private name import `_shared` from external module `airflow`
+ airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py:27:39: PLC2701 Private name import `_shared` from external module `airflow`
... 467 additional changes omitted for rule PLC2701
- airflow-core/tests/unit/ti_deps/deps/test_task_concurrency.py:35:16: AIR321 `airflow.models.baseoperator.BaseOperator` is moved in Airflow 3.1
- dev/airflow_perf/scheduler_dag_execution_timing.py:181:24: AIR321 [*] `airflow.utils.timezone.utcnow` is moved in Airflow 3.1
- kubernetes-tests/tests/kubernetes_tests/test_kubernetes_pod_operator.py:59:20: AIR321 [*] `airflow.utils.timezone.datetime` is moved in Airflow 3.1
- performance/src/performance_dags/performance_dag/performance_dag_utils.py:83:27: AIR321 [*] `airflow.utils.timezone.utcnow` is moved in Airflow 3.1
- providers/alibaba/tests/unit/alibaba/cloud/log/test_oss_task_handler.py:59:26: AIR321 `airflow.utils.timezone.datetime` is moved in Airflow 3.1
- providers/alibaba/tests/unit/alibaba/cloud/sensors/test_analyticdb_spark.py:26:16: AIR321 [*] `airflow.utils.timezone.datetime` is moved in Airflow 3.1
- providers/amazon/src/airflow/providers/amazon/aws/executors/utils/exponential_backoff_retry.py:72:20: AIR321 [*] `airflow.utils.timezone.utcnow` is moved in Airflow 3.1
- providers/amazon/tests/system/amazon/aws/example_mongo_to_s3.py:45:16: AIR321 `airflow.utils.timezone.datetime` is moved in Airflow 3.1
- providers/amazon/tests/system/amazon/aws/example_mwaa.py:121:35: AIR321 [*] `airflow.utils.timezone.utc` is moved in Airflow 3.1
... 919 additional changes omitted for project

apache/superset (+3 -3 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

- superset/config.py:47:13: PLC2701 Private name import `_libs` from external module `pandas`
+ superset/config.py:47:34: PLC2701 Private name import `_libs` from external module `pandas`
- tests/integration_tests/db_engine_specs/mysql_tests.py:55:22: PLC2701 Private name import `_exceptions` from external module `MySQLdb`
+ tests/integration_tests/db_engine_specs/mysql_tests.py:55:41: PLC2701 Private name import `_exceptions` from external module `MySQLdb`
- tests/unit_tests/dataframe_test.py:23:13: PLC2701 Private name import `_libs` from external module `pandas`
+ tests/unit_tests/dataframe_test.py:23:33: PLC2701 Private name import `_libs` from external module `pandas`

aws/aws-sam-cli (+59 -59 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- tests/integration/package/test_package_command_image.py:13:22: PLC2701 Private name import `_utils` from external module `samcli.commands`
+ tests/integration/package/test_package_command_image.py:13:45: PLC2701 Private name import `_utils` from external module `samcli.commands`
- tests/integration/sync/test_sync_adl.py:5:22: PLC2701 Private name import `_utils` from external module `samcli.commands`
- tests/integration/sync/test_sync_adl.py:5:22: PLC2701 Private name import `_utils` from external module `samcli.commands`
+ tests/integration/sync/test_sync_adl.py:5:49: PLC2701 Private name import `_utils` from external module `samcli.commands`
+ tests/integration/sync/test_sync_adl.py:5:67: PLC2701 Private name import `_utils` from external module `samcli.commands`
- tests/unit/commands/_utils/custom_options/test_hook_package_id_option.py:7:22: PLC2701 Private name import `_utils` from external module `samcli.commands`
- tests/unit/commands/_utils/custom_options/test_hook_package_id_option.py:7:22: PLC2701 Private name import `_utils` from external module `samcli.commands`
+ tests/unit/commands/_utils/custom_options/test_hook_package_id_option.py:7:68: PLC2701 Private name import `_utils` from external module `samcli.commands`
+ tests/unit/commands/_utils/custom_options/test_hook_package_id_option.py:7:84: PLC2701 Private name import `_utils` from external module `samcli.commands`
... 108 additional changes omitted for project

bokeh/bokeh (+89 -88 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

+ tests/unit/bokeh/command/subcommands/test_json__subcommands.py:29:31: PLC2701 Private name import `_util_subcommands`
- tests/unit/bokeh/command/subcommands/test_json__subcommands.py:29:6: PLC2701 Private name import `_util_subcommands`
+ tests/unit/bokeh/core/property/test_aliases.py:29:28: PLC2701 Private name import `_util_property`
+ tests/unit/bokeh/core/property/test_aliases.py:29:43: PLC2701 Private name import `_util_property`
- tests/unit/bokeh/core/property/test_aliases.py:29:6: PLC2701 Private name import `_util_property`
- tests/unit/bokeh/core/property/test_aliases.py:29:6: PLC2701 Private name import `_util_property`
+ tests/unit/bokeh/core/property/test_any.py:22:28: PLC2701 Private name import `_util_property`
+ tests/unit/bokeh/core/property/test_any.py:22:43: PLC2701 Private name import `_util_property`
- tests/unit/bokeh/core/property/test_any.py:22:6: PLC2701 Private name import `_util_property`
- tests/unit/bokeh/core/property/test_any.py:22:6: PLC2701 Private name import `_util_property`
... 167 additional changes omitted for project

ibis-project/ibis (+3 -3 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- ibis/backends/sql/compilers/bigquery/udf/core.py:11:21: PLC2701 Private name import `_empty` from external module `inspect`
+ ibis/backends/sql/compilers/bigquery/udf/core.py:11:31: PLC2701 Private name import `_empty` from external module `inspect`
- ibis/backends/sql/compilers/bigquery/udf/rewrite.py:4:21: PLC2701 Private name import `_empty` from external module `inspect`
+ ibis/backends/sql/compilers/bigquery/udf/rewrite.py:4:31: PLC2701 Private name import `_empty` from external module `inspect`
- ibis/tests/benchmarks/benchfuncs.py:6:13: PLC2701 Private name import `_libs` from external module `pandas`
+ ibis/tests/benchmarks/benchfuncs.py:6:34: PLC2701 Private name import `_libs` from external module `pandas`

langchain-ai/langchain (+112 -112 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- libs/core/tests/unit_tests/_api/test_beta_decorator.py:8:21: PLC2701 Private name import `_api` from external module `langchain_core`
- libs/core/tests/unit_tests/_api/test_beta_decorator.py:8:21: PLC2701 Private name import `_api` from external module `langchain_core`
+ libs/core/tests/unit_tests/_api/test_beta_decorator.py:8:48: PLC2701 Private name import `_api` from external module `langchain_core`
+ libs/core/tests/unit_tests/_api/test_beta_decorator.py:8:54: PLC2701 Private name import `_api` from external module `langchain_core`
+ libs/core/tests/unit_tests/_api/test_deprecation.py:10:5: PLC2701 Private name import `_api` from external module `langchain_core`
+ libs/core/tests/unit_tests/_api/test_deprecation.py:11:5: PLC2701 Private name import `_api` from external module `langchain_core`
- libs/core/tests/unit_tests/_api/test_deprecation.py:8:21: PLC2701 Private name import `_api` from external module `langchain_core`
- libs/core/tests/unit_tests/_api/test_deprecation.py:8:21: PLC2701 Private name import `_api` from external module `langchain_core`
- libs/core/tests/unit_tests/_api/test_deprecation.py:8:21: PLC2701 Private name import `_api` from external module `langchain_core`
+ libs/core/tests/unit_tests/_api/test_deprecation.py:9:5: PLC2701 Private name import `_api` from external module `langchain_core`
... 214 additional changes omitted for project

latchbio/latch (+8 -8 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- src/latch_cli/click_utils.py:5:12: PLC2701 Private name import `_compat` from external module `click`
+ src/latch_cli/click_utils.py:5:27: PLC2701 Private name import `_compat` from external module `click`
- src/latch_cli/services/cp/main.py:10:18: PLC2701 Private name import `_transfer` from external module `latch.ldata`
+ src/latch_cli/services/cp/main.py:10:52: PLC2701 Private name import `_transfer` from external module `latch.ldata`
- src/latch_cli/services/cp/main.py:7:18: PLC2701 Private name import `_transfer` from external module `latch.ldata`
+ src/latch_cli/services/cp/main.py:7:56: PLC2701 Private name import `_transfer` from external module `latch.ldata`
- src/latch_cli/services/cp/main.py:8:18: PLC2701 Private name import `_transfer` from external module `latch.ldata`
+ src/latch_cli/services/cp/main.py:8:44: PLC2701 Private name import `_transfer` from external module `latch.ldata`
- src/latch_cli/services/cp/main.py:9:18: PLC2701 Private name import `_transfer` from external module `latch.ldata`
+ src/latch_cli/services/cp/main.py:9:62: PLC2701 Private name import `_transfer` from external module `latch.ldata`
... 6 additional changes omitted for project

... Truncated remaining completed project reports due to GitHub comment length restrictions

Changes by rule (2 rules affected)

code total + violation - violation + fix - fix
PLC2701 1965 987 978 0 0
AIR321 462 0 462 0 0

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@ntBre
Copy link
Contributor

ntBre commented Feb 3, 2026

Hmm, in that case I'm not sure it's worth landing the regex change on its own. Should we consider allowing the .qmd extension in this PR too?

@amyreese
Copy link
Member

amyreese commented Feb 3, 2026

Is it worth making a documentation change for this?

@ntBre
Copy link
Contributor

ntBre commented Feb 3, 2026

Yeah, I guess it's probably worth mentioning briefly somewhere.

@amyreese
Copy link
Member

amyreese commented Feb 4, 2026

Added small example of quarto style, along with examples for the normal py/pyi styles. Any better example you would suggest, or changes to wording?

@amyreese amyreese force-pushed the markdown-curly-brace-syntax branch from 5fbc4b3 to 730d4e0 Compare February 4, 2026 01:51
@amyreese amyreese merged commit ddd192a into astral-sh:main Feb 5, 2026
45 checks passed
@jolars
Copy link

jolars commented Feb 12, 2026

For anyone who might be interested in this, I have created a auto-formatter for Pandoc markdown, including Quarto and RMarkdown: https://github.com/jolars/panache

It allows delegating formatting of code blocks to external formatters, like ruff, or whatever else, by specifying a configuration setting (in panache.toml):

[formatters.python]
preset = "ruff"

It of course also formats the actual markdown content properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

formatter Related to the formatter preview Related to preview mode features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support quarto markdown language markers

4 participants