diff --git a/REMINDERS.md b/REMINDERS.md index b904406..32db423 100644 --- a/REMINDERS.md +++ b/REMINDERS.md @@ -1,10 +1,17 @@ # Reminders +## v0.9.0 + +- Complete deprecation of grammar rule `dtype_to_expand`. + Remove rule in `doctype.lark` and `DoctypeTranformer`. + Remove warning in `_app_generate_stubs::generate_stubs`. + + ## With Python >=3.13 -Remove vendored `glob_translate` in `docstub._vendored.stdlib`. +- Remove vendored `glob_translate` in `docstub._vendored.stdlib`. ## With Python >=3.14 -Remove vendored `ProcessPoolExecutor` in `docstub._vendored.stdlib`. +- Remove vendored `ProcessPoolExecutor` in `docstub._vendored.stdlib`. diff --git a/src/docstub-stubs/doctype.pyi b/src/docstub-stubs/doctype.pyi index e15111b..37c77d0 100644 --- a/src/docstub-stubs/doctype.pyi +++ b/src/docstub-stubs/doctype.pyi @@ -101,6 +101,7 @@ class DoctypeTransformer(lark.visitors.Transformer): def natlang_array(self, tree: lark.Tree) -> Expr: ... def array_name(self, tree: lark.Tree) -> Term: ... def dtype(self, tree: lark.Tree) -> Expr: ... + def dtype_union(self, tree: lark.Tree) -> Expr: ... def dtype_to_expand(self, tree: lark.Tree) -> Expr: ... def shape(self, tree: lark.Tree) -> Expr: ... def optional_info(self, tree: lark.Tree) -> lark.visitors._DiscardType: ... diff --git a/src/docstub/_app_generate_stubs.py b/src/docstub/_app_generate_stubs.py index 541b5b1..fb5fcf0 100644 --- a/src/docstub/_app_generate_stubs.py +++ b/src/docstub/_app_generate_stubs.py @@ -386,6 +386,18 @@ def generate_stubs( grammar = plugin_hooks.docstub_load_doctype_grammar() doctype_transformer = plugin_hooks.docstub_load_doctype_transformer() + if (doctype_transformer and hasattr(doctype_transformer, "dtype_to_expand")) or ( + grammar and "dtype_to_expand" in grammar + ): + logger.warning( + "The grammar rule 'dtype_to_expand' is deprecated in favor of 'dtype_union'", + extra={ + "details": "It will be removed in v0.9.0. Since `numpy.dtype` supports " + "unions, the rule was renamed. Use the rule 'dtype_union' if you want " + "to modify this expression in a plugin." + }, + ) + doctype_transpiler = doctype.DoctypeTranspiler( grammar=grammar, transformer=doctype_transformer ) diff --git a/src/docstub/doctype.lark b/src/docstub/doctype.lark index 65015ac..30d8962 100644 --- a/src/docstub/doctype.lark +++ b/src/docstub/doctype.lark @@ -126,11 +126,15 @@ ARRAY_NAME: "array" | "ndarray" | "array-like" | "array_like" // The dtype used in an array expression. -dtype: qualname | dtype_to_expand +dtype: qualname | dtype_union | dtype_to_expand -// Dtypes may be specified as a union. But I'm not sure if `np.dtype` accepts -// a union. So we use expansion here instead. +// Dtypes may be specified as a union. But we don't want to allow any `_type`, +// so we define a dtype-specific union. +dtype_union.1: "(" qualname (_OR qualname)+ ")" + + +// DEPRECATED in favor of `dtype_union`, will be removed in v0.9.0. dtype_to_expand: "(" qualname (_OR qualname)+ ")" diff --git a/src/docstub/doctype.py b/src/docstub/doctype.py index 610c07a..bd306f7 100644 --- a/src/docstub/doctype.py +++ b/src/docstub/doctype.py @@ -709,6 +709,18 @@ def dtype(self, tree): expr = self._create_subscription_expr(children, rule="dtype") return expr + def dtype_union(self, tree): + """ + Parameters + ---------- + tree : lark.Tree + + Returns + ------- + out : Expr + """ + return self.union(tree) + def dtype_to_expand(self, tree): """ Parameters diff --git a/tests/test_doctype.py b/tests/test_doctype.py index dd794da..f457a66 100644 --- a/tests/test_doctype.py +++ b/tests/test_doctype.py @@ -357,20 +357,20 @@ def test_malformed_shape(self, shape): ("ndarray of dtype int", "ndarray[tuple[Any, ...], np.dtype[int]]"), ( "ndarray of dtype (int or float)", - "ndarray[tuple[Any, ...], np.dtype[int]]" - " | ndarray[tuple[Any, ...], np.dtype[float]]", + "ndarray[tuple[Any, ...], np.dtype[int | float]]", ), ( "ndarray of dtype (int | float | complex)", - "ndarray[tuple[Any, ...], np.dtype[int]]" - " | ndarray[tuple[Any, ...], np.dtype[float]]" - " | ndarray[tuple[Any, ...], np.dtype[complex]]", + "ndarray[tuple[Any, ...], np.dtype[int | float | complex]]", ), ], ) def test_dtype(self, doctype, expected): expr = DoctypeTranspiler()(doctype) assert expr.as_code() == expected + assert expr.find_one(rule="dtype") + if " or " in doctype: + assert expr.find_one(rule="union") @pytest.mark.parametrize( ("doctype", "expected"), @@ -381,10 +381,8 @@ def test_dtype(self, doctype, expected): ), ( "ndarray of dtype (int or float) and shape ([N,] M)", - "ndarray[tuple[int], np.dtype[int]]" - " | ndarray[tuple[int], np.dtype[float]]" - " | ndarray[tuple[int, int], np.dtype[int]]" - " | ndarray[tuple[int, int], np.dtype[float]]", + "ndarray[tuple[int], np.dtype[int | float]]" + " | ndarray[tuple[int, int], np.dtype[int | float]]", ), ], )