Skip to content

Commit

Permalink
Merge pull request #218 from jorenham/codemod-posonly-self
Browse files Browse the repository at this point in the history
Codemod for pos-only `self` parameters
  • Loading branch information
jorenham authored Nov 28, 2024
2 parents 6c10331 + 32294fa commit 305d30d
Show file tree
Hide file tree
Showing 85 changed files with 859 additions and 739 deletions.
1 change: 1 addition & 0 deletions codegen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ where `$NAME` is the name is the name of the codemod, which can be one of:

- `AnnotateMissing` - Sets the default return type to `None`, and sets the other missing annotations to `scipy._typing.Untyped`.
- `FixTrailingComma` - Adds a trailing comma to parameters that don't fit on one line, so that ruff formats them correctly.
- `PosOnlySelf` - nsures `self` is a positional-only parameter.

> [!NOTE]
> The codemods require `libcst`, which is installable through the **optional** `codegen` dependency group:
Expand Down
50 changes: 48 additions & 2 deletions codegen/mods.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self, /, context: CodemodContext) -> None:
super().__init__(context)

@override
def leave_Module(self, original_node: cst.Module, updated_node: cst.Module) -> cst.Module:
def leave_Module(self, /, original_node: cst.Module, updated_node: cst.Module) -> cst.Module:
if not self.updated:
raise SkipFile("unchanged")

Expand Down Expand Up @@ -100,7 +100,7 @@ class FixTrailingComma(_BaseMod):
DESCRIPTION = "Adds a trailing comma to parameters that don't fit on one line, so that ruff formats them correctly."

@override
def leave_FunctionDef(self, original_node: cst.FunctionDef, updated_node: cst.FunctionDef) -> cst.FunctionDef:
def leave_FunctionDef(self, /, original_node: cst.FunctionDef, updated_node: cst.FunctionDef) -> cst.FunctionDef:
params = updated_node.params.params

if (
Expand All @@ -119,3 +119,49 @@ def leave_FunctionDef(self, original_node: cst.FunctionDef, updated_node: cst.Fu
return updated_node.with_deep_changes(params[-1], comma=cst.Comma())

return updated_node


@final
class PosOnlySelf(_BaseMod):
DESCRIPTION = "Ensures `self` is a positional-only parameter."

class_depth: int

@override
def __init__(self, /, context: CodemodContext) -> None:
self.class_depth = 0
super().__init__(context)

@override
def visit_ClassDef(self, node: cst.ClassDef) -> bool | None:
self.class_depth += 1
return super().visit_ClassDef(node)

@override
def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.ClassDef:
self.class_depth -= 1
return updated_node

@override
def leave_FunctionDef(self, /, original_node: cst.FunctionDef, updated_node: cst.FunctionDef) -> cst.FunctionDef:
params = updated_node.params
if not self.class_depth or params.posonly_params or not params.params:
return updated_node

decorators = {get_full_name_for_node(d.decorator) for d in updated_node.decorators}
if "staticmethod" in decorators or "classmethod" in decorators:
return updated_node

# TODO(jorenham): pos-only `@property` setter value parameters

self_param = params.params[0]
if self_param.name.value != "self":
return updated_node

self.updated += 1
return updated_node.with_changes(
params=params.with_changes(
params=params.params[1:],
posonly_params=(self_param,),
)
)
2 changes: 1 addition & 1 deletion scipy-stubs/_lib/_ccallback.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class _CFFIType(Protocol):
def is_integer_type(self, /) -> bool: ...
def has_c_name(self, /) -> bool: ...
def get_c_name(self, /, replace_with: str = "", context: str = "a C file", quals: int = 0) -> str: ...
def get_cached_btype(self, ffi: object, finishlist: list[object], can_delay: bool = False) -> _CFFIBackendType: ...
def get_cached_btype(self, /, ffi: object, finishlist: list[object], can_delay: bool = False) -> _CFFIBackendType: ...

# virtual
def build_backend_type(self, /, ffi: object, finishlist: list[object]) -> _CFFIBackendType: ...
Expand Down
22 changes: 11 additions & 11 deletions scipy-stubs/_lib/_docscrape.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class Parameter(NamedTuple):
class Reader:
def __init__(self, /, data: str | list[str]) -> None: ...
def __getitem__(self, n: op.CanIndex, /) -> str: ...
def reset(self) -> None: ...
def read(self) -> str: ...
def seek_next_non_empty_line(self) -> None: ...
def eof(self) -> bool: ...
def read_to_condition(self, condition_func: Callable[[str], object]) -> list[str]: ...
def read_to_next_empty_line(self) -> list[str]: ...
def read_to_next_unindented_line(self) -> list[str]: ...
def peek(self, n: int = 0) -> str: ...
def is_empty(self) -> bool: ...
def reset(self, /) -> None: ...
def read(self, /) -> str: ...
def seek_next_non_empty_line(self, /) -> None: ...
def eof(self, /) -> bool: ...
def read_to_condition(self, /, condition_func: Callable[[str], object]) -> list[str]: ...
def read_to_next_empty_line(self, /) -> list[str]: ...
def read_to_next_unindented_line(self, /) -> list[str]: ...
def peek(self, /, n: int = 0) -> str: ...
def is_empty(self, /) -> bool: ...

class NumpyDocString(Mapping[str, _SectionValue]):
empty_description: ClassVar[str] = ".."
Expand Down Expand Up @@ -58,9 +58,9 @@ class ClassDoc(NumpyDocString):
extra_public_methods: ClassVar[Sequence[str]]
show_inherited_members: Final[bool]
@property
def methods(self) -> list[str]: ...
def methods(self, /) -> list[str]: ...
@property
def properties(self) -> list[str]: ...
def properties(self, /) -> list[str]: ...
def __init__(
self,
/,
Expand Down
14 changes: 7 additions & 7 deletions scipy-stubs/_lib/_testutils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ class _TestPythranFunc:
arguments: dict[int, tuple[onp.Array, list[np.generic]]]
partialfunc: Callable[..., object] | None
expected: object | None
def setup_method(self) -> None: ...
def get_optional_args(self, func: Callable[..., object]) -> dict[str, object]: ...
def get_max_dtype_list_length(self) -> int: ...
def get_dtype(self, dtype_list: Sequence[np.generic], dtype_idx: int) -> np.generic: ...
def test_all_dtypes(self) -> None: ...
def test_views(self) -> None: ...
def test_strided(self) -> None: ...
def setup_method(self, /) -> None: ...
def get_optional_args(self, /, func: Callable[..., object]) -> dict[str, object]: ...
def get_max_dtype_list_length(self, /) -> int: ...
def get_dtype(self, /, dtype_list: Sequence[np.generic], dtype_idx: int) -> np.generic: ...
def test_all_dtypes(self, /) -> None: ...
def test_views(self, /) -> None: ...
def test_strided(self, /) -> None: ...

def check_free_memory(free_mb: float) -> None: ...
10 changes: 5 additions & 5 deletions scipy-stubs/_typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ NormalizationMode: TypeAlias = Literal["backward", "ortho", "forward"]
@type_check_only
class _FortranFunction(Protocol):
@property
def dtype(self) -> np.dtype[np.number[Any]]: ...
def dtype(self, /) -> np.dtype[np.number[Any]]: ...
@property
def int_dtype(self) -> np.dtype[np.integer[Any]]: ...
def int_dtype(self, /) -> np.dtype[np.integer[Any]]: ...
@property
def module_name(self) -> LiteralString: ...
def module_name(self, /) -> LiteralString: ...
@property
def prefix(self) -> LiteralString: ...
def prefix(self, /) -> LiteralString: ...
@property
def typecode(self) -> LiteralString: ...
def typecode(self, /) -> LiteralString: ...
def __call__(self, /, *args: object, **kwargs: object) -> object: ...
8 changes: 5 additions & 3 deletions scipy-stubs/integrate/_ivp/base.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class OdeSolver:
@overload
def __init__(
self,
/,
fun: Callable[[float, onp.ArrayND[np.float64]], onp.ToFloatND],
t0: onp.ToFloatND,
y0: onp.ToFloatND,
Expand All @@ -36,6 +37,7 @@ class OdeSolver:
@overload
def __init__(
self,
/,
fun: Callable[[float, onp.ArrayND[np.float64 | np.complex128]], onp.ToComplexND],
t0: onp.ToFloat,
y0: onp.ToComplexND,
Expand All @@ -44,9 +46,9 @@ class OdeSolver:
support_complex: Literal[True],
) -> None: ...
@property
def step_size(self) -> float | None: ...
def step(self) -> str | None: ...
def dense_output(self) -> ConstantDenseOutput: ...
def step_size(self, /) -> float | None: ...
def step(self, /) -> str | None: ...
def dense_output(self, /) -> ConstantDenseOutput: ...

class DenseOutput:
t_old: Final[float]
Expand Down
14 changes: 7 additions & 7 deletions scipy-stubs/interpolate/_bsplines.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ class BSpline:
extrapolate: Untyped
axis: Untyped
@property
def tck(self) -> Untyped: ...
def __init__(self, t: Untyped, c: Untyped, k: Untyped, extrapolate: bool = True, axis: int = 0) -> None: ...
def __call__(self, x: Untyped, nu: int = 0, extrapolate: Untyped | None = None) -> Untyped: ...
def derivative(self, nu: int = 1) -> Untyped: ...
def antiderivative(self, nu: int = 1) -> Untyped: ...
def integrate(self, a: Untyped, b: Untyped, extrapolate: Untyped | None = None) -> Untyped: ...
def insert_knot(self, x: Untyped, m: int = 1) -> Untyped: ...
def tck(self, /) -> Untyped: ...
def __init__(self, /, t: Untyped, c: Untyped, k: Untyped, extrapolate: bool = True, axis: int = 0) -> None: ...
def __call__(self, /, x: Untyped, nu: int = 0, extrapolate: Untyped | None = None) -> Untyped: ...
def derivative(self, /, nu: int = 1) -> Untyped: ...
def antiderivative(self, /, nu: int = 1) -> Untyped: ...
def integrate(self, /, a: Untyped, b: Untyped, extrapolate: Untyped | None = None) -> Untyped: ...
def insert_knot(self, /, x: Untyped, m: int = 1) -> Untyped: ...
@classmethod
def basis_element(cls, t: Untyped, extrapolate: bool = True) -> Untyped: ...
@classmethod
Expand Down
9 changes: 7 additions & 2 deletions scipy-stubs/interpolate/_cubic.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CubicHermiteSpline(PPoly[_CT_co]):
@overload
def __init__(
self: CubicHermiteSpline[np.float64],
/,
x: onp.ToFloat1D,
y: onp.ToFloatND,
dydx: onp.ToFloatND,
Expand All @@ -36,6 +37,7 @@ class CubicHermiteSpline(PPoly[_CT_co]):
@overload
def __init__(
self: CubicHermiteSpline[np.float64 | np.complex128],
/,
x: onp.ToFloat1D,
y: onp.ToComplexND,
dydx: onp.ToComplexND,
Expand All @@ -44,11 +46,12 @@ class CubicHermiteSpline(PPoly[_CT_co]):
) -> None: ...

class PchipInterpolator(CubicHermiteSpline[np.float64]):
def __init__(self, x: onp.ToFloat1D, y: onp.ToFloatND, axis: _ToAxis = 0, extrapolate: bool | None = None) -> None: ...
def __init__(self, /, x: onp.ToFloat1D, y: onp.ToFloatND, axis: _ToAxis = 0, extrapolate: bool | None = None) -> None: ...

class Akima1DInterpolator(CubicHermiteSpline[np.float64]):
def __init__(
self,
/,
x: onp.ToFloat1D,
y: onp.ToFloatND,
axis: _ToAxis = 0,
Expand All @@ -59,7 +62,7 @@ class Akima1DInterpolator(CubicHermiteSpline[np.float64]):

# the following (class)methods will raise `NotImplementedError` when called
@override
def extend(self, c: object, x: object, right: object = True) -> Never: ...
def extend(self, /, c: object, x: object, right: object = True) -> Never: ...
@classmethod
@override
def from_spline(cls, tck: object, extrapolate: object = ...) -> Never: ...
Expand All @@ -71,6 +74,7 @@ class CubicSpline(CubicHermiteSpline[_CT_co], Generic[_CT_co]):
@overload
def __init__(
self: CubicSpline[np.float64],
/,
x: onp.ToFloat1D,
y: onp.ToFloatND,
axis: _ToAxis = 0,
Expand All @@ -80,6 +84,7 @@ class CubicSpline(CubicHermiteSpline[_CT_co], Generic[_CT_co]):
@overload
def __init__(
self: CubicSpline[np.float64 | np.complex128],
/,
x: onp.ToFloat1D,
y: onp.ToComplexND,
axis: _ToAxis = 0,
Expand Down
Loading

0 comments on commit 305d30d

Please sign in to comment.