Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Type Hints】Paddle 中引入 Tensor stub 文件 #63953

Merged
merged 25 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
828abaf
add tensor.pyi
megemini Apr 26, 2024
3877923
.pre-commit-config.yaml
megemini Apr 28, 2024
90646a9
run gen_tensor_stub.py
megemini Apr 28, 2024
ac2eed7
edit cmakelists.txt
megemini Apr 28, 2024
f6970e1
edit cmakelists.txt
megemini Apr 28, 2024
61b822b
gen pyi encoding
megemini Apr 29, 2024
ad945d5
not use removeprefix
megemini Apr 29, 2024
28b44cc
tensor.pyi with doc
megemini Apr 29, 2024
b847648
add tensor.pyi.in
megemini Apr 30, 2024
cd97ca8
update tensor.pyi.in
megemini May 1, 2024
d88a089
update tensor.py.in
megemini May 2, 2024
e0eb289
gen_tensor_stub.py with template
megemini May 4, 2024
770c25b
update pre-commit-config
megemini May 5, 2024
e6055d4
Merge branch 'develop' of https://github.com/PaddlePaddle/Paddle into…
megemini May 20, 2024
4bc21ba
[Update] tensor.pyi.in to tensor.prototype.pyi
megemini May 20, 2024
4aa925b
[Update] .pre-commit-config.yaml
megemini May 20, 2024
8f54b55
[Update] not pack tensor.prototype.pyi
megemini May 22, 2024
f744bdf
[Update] tensor.prototype.pyi type annotations
megemini May 22, 2024
6df6ba0
[Update] tensor.prototype.pyi
megemini May 23, 2024
0ba2cc1
use type string for `TYPE_CHECKING` only vars
SigureMo May 23, 2024
aae012e
[Update] tensor.prototype.pyi
megemini May 23, 2024
0bc457b
Merge branch 'develop' of https://github.com/PaddlePaddle/Paddle into…
megemini May 23, 2024
547b75d
[Update] tensor.prototype.pyi
megemini May 23, 2024
0496a7f
Merge branch 'type_hint_tensor' of github.com:megemini/Paddle into ty…
megemini May 23, 2024
e3a10f6
[Update] _typing.basic TensorLike
megemini May 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,16 @@ endif()
add_custom_target(paddle_python ALL
DEPENDS ${PADDLE_PYTHON_BUILD_DIR}/.timestamp)
if(BUILD_WHL_PACKAGE AND NOT WITH_SETUP_INSTALL)
add_custom_target(paddle_copy ALL
DEPENDS ${PADDLE_PYTHON_BUILD_DIR}/.timestamp_wheel)
add_custom_target(
paddle_copy ALL
# generate tensor.pyi for type hints
COMMAND
${CMAKE_COMMAND} -E env PYTHONPATH=${PADDLE_BINARY_DIR}/python
${PYTHON_EXECUTABLE} ${PADDLE_SOURCE_DIR}/tools/gen_tensor_stub.py
--input-file
${PADDLE_SOURCE_DIR}/python/paddle/tensor/tensor.prototype.pyi
--output-file ${PADDLE_BINARY_DIR}/python/paddle/tensor/tensor.pyi
DEPENDS ${PADDLE_PYTHON_BUILD_DIR}/.timestamp_wheel)
add_dependencies(paddle_copy paddle_python)
endif()

Expand Down
10 changes: 8 additions & 2 deletions python/paddle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import typing

try:
from paddle.cuda_env import * # noqa: F403
from paddle.version import ( # noqa: F401
Expand Down Expand Up @@ -69,8 +72,11 @@
uint8,
)

Tensor = framework.core.eager.Tensor
Tensor.__qualname__ = 'Tensor'
if typing.TYPE_CHECKING:
from .tensor.tensor import Tensor
else:
Tensor = framework.core.eager.Tensor
Tensor.__qualname__ = 'Tensor'

import paddle.distributed.fleet
import paddle.text
Expand Down
1 change: 1 addition & 0 deletions python/paddle/_typing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
NestedSequence as NestedSequence,
Numberic as Numberic,
NumbericSequence as NumbericSequence,
TensorLike as TensorLike,
TensorOrTensors as TensorOrTensors,
)

Expand Down
4 changes: 3 additions & 1 deletion python/paddle/_typing/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
# limitations under the License.
from __future__ import annotations

from typing import TYPE_CHECKING, Sequence, TypeVar, Union
from typing import TYPE_CHECKING, Any, Sequence, TypeVar, Union

import numpy as np
import numpy.typing as npt
from typing_extensions import TypeAlias

if TYPE_CHECKING:
from paddle import Tensor

Numberic: TypeAlias = Union[int, float, complex, np.number, "Tensor"]
TensorLike: TypeAlias = npt.NDArray[Any] | Tensor | Numberic
SigureMo marked this conversation as resolved.
Show resolved Hide resolved

_T = TypeVar("_T", bound=Numberic)
_SeqLevel1: TypeAlias = Sequence[_T]
Expand Down
32 changes: 23 additions & 9 deletions python/paddle/base/core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,37 @@
# See the License for the specific language governing permissions and
# limitations under the License.

class CPUPlace: ...

class CUDAPlace:
class Place:
def custom_device_id(self) -> int: ...
def custom_device_type(self) -> str: ...
def gpu_device_id(self) -> int: ...
def ipu_device_id(self) -> int: ...
def is_cpu_place(self) -> bool: ...
def is_cuda_pinned_place(self) -> bool: ...
def is_custom_place(self) -> bool: ...
def is_gpu_place(self) -> bool: ...
def is_ipu_place(self) -> bool: ...
def is_xpu_place(self) -> bool: ...
def set_place(self, place: Place) -> None: ...
def xpu_device_id(self) -> int: ...

class CPUPlace(Place): ...

class CUDAPlace(Place):
def __init__(self, id: int, /) -> None: ...

class CUDAPinnedPlace: ...
class CUDAPinnedPlace(Place): ...

class NPUPlace:
class NPUPlace(Place):
def __init__(self, id: int, /) -> None: ...

class IPUPlace: ...
class IPUPlace(Place): ...

class CustomPlace:
class CustomPlace(Place):
def __init__(self, name: str, id: int, /) -> None: ...

class MLUPlace:
class MLUPlace(Place):
def __init__(self, id: int, /) -> None: ...

class XPUPlace:
class XPUPlace(Place):
def __init__(self, id: int, /) -> None: ...
263 changes: 263 additions & 0 deletions python/paddle/tensor/tensor.prototype.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# The `Tensor` template for `tools/gen_tensor_stub.py` generates the stub file `tensor.pyi`.
# Add docstring, attributes, methods and alias with type annotaions for `Tensor`
# if not conveniently coding in original place (like c++ source file).

from typing import Any, overload

import numpy.typing as npt
from typing_extensions import TypeAlias

import paddle
from paddle import _typing

# avoid same name: Tensor.slice
_Slice: TypeAlias = slice

class Tensor:
# annotation: ${tensor_docstring}

# annotation: ${tensor_attributes}

# If method defined below, we should make the method's signature complete,
# and ignore the signature extracted from `paddle.Tensor`.
# `gen_tensor.stub.py` will NOT overwrite the signature below.
# If method has docstring (ignoring the spaces), `gen_tensor.stub.py` also will NOT overwrite it.

# annotation: ${tensor_methods}
@overload
def __init__(self) -> None: ...
@overload
def __init__(
self, dtype, dims, name: str, type, persistable: bool
) -> None: ...
@overload
def __init__(
self,
value: npt.NDArray[Any],
place,
persistable: bool,
zero_copy: bool,
name: str,
stop_gradient: bool,
) -> None: ...
@overload
def __init__(self, value: npt.NDArray[Any]) -> None: ...
@overload
def __init__(self, value: Tensor) -> None: ...
@overload
def __init__(
self, value: Tensor, place, name: str, process_mesh, placements
) -> None: ...
@overload
def __init__(
self, value: Tensor, dims, name: str, process_mesh, placements
) -> None: ...
@overload
def __init__(self, value: Tensor, place, name: str) -> None: ...
@overload
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""
ref: paddle/fluid/pybind/eager.cc

We should have init function with signature:
1.
def __init__ ()
2.
def __init__ (
dtype: paddle::framework::proto::VarType::Type,
dims: vector<int>,
name: std::string,
type: paddle::framework::proto::VarType::LodTensor,
persistable: bool)
3. (multi-place)
(should have at least one parameter, one parameter equals to case 4, zero
parameter equals to case 1)
def __init__ (
value: ndarray,
place: paddle::platform::Place,
persistable: bool,
zero_copy: bool,
name: std::string,
stop_gradient: bool)
4.
def __init__ (
value: ndarray)
5.
def __init__ (
tensor: Tensor)
6. (multi-place)
(should have at least one parameter, one parameter equals to case 5, zero
parameter equals to case 1.)
def __init__ (
global_tensor: Tensor,
place: paddle::platform::Place,
name: std::string,
process_mesh: phi::distributed::ProcessMesh
placements: std::vector<Placement>)
7. (multi-place)
(should have at least one parameter, one parameter equals to case 5, zero
parameter equals to case 1.)
def __init__ (
local_tensor: Tensor,
global_dims: vector<int>,
name: std::string,
process_mesh: phi::distributed::ProcessMesh
placements: std::vector<Placement>)
8. (multi-place) (should have at least one parameter, one parameter similar
to case 5, zero parameter equals to case 1.)
def __init__ (
tensor: FrameworkTensor,
place: paddle::platform::Place,
name: std::string)
"""
...
# rich comparison
def __eq__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore[override]
def __ge__(self, y: _typing.TensorLike) -> Tensor: ...
def __gt__(self, y: _typing.TensorLike) -> Tensor: ...
def __lt__(self, y: _typing.TensorLike) -> Tensor: ...
def __le__(self, y: _typing.TensorLike) -> Tensor: ...
def __ne__(self, y: _typing.TensorLike) -> Tensor: ... # type: ignore[override]

# binary arithmetic operations
def __add__(self, y: _typing.TensorLike) -> Tensor: ...
def __sub__(self, y: _typing.TensorLike) -> Tensor: ...
def __mul__(self, y: _typing.TensorLike) -> Tensor: ...
def __matmul__(self, y: _typing.TensorLike) -> Tensor: ...
def __truediv__(self, y: _typing.TensorLike) -> Tensor: ...
def __floordiv__(self, y: _typing.TensorLike) -> Tensor: ...
def __mod__(self, y: _typing.TensorLike) -> Tensor: ...
def __pow__(self, y: _typing.TensorLike) -> Tensor: ...
def __and__(self, y: _typing.TensorLike) -> Tensor: ...
def __div__(self, y: _typing.TensorLike) -> Tensor: ...
def __radd__(self, y: _typing.TensorLike) -> Tensor: ...
def __rsub__(self, y: _typing.TensorLike) -> Tensor: ...
def __rmul__(self, y: _typing.TensorLike) -> Tensor: ...
def __rtruediv__(self, y: _typing.TensorLike) -> Tensor: ...
def __rpow__(self, y: _typing.TensorLike) -> Tensor: ...
def __rdiv__(self, y: _typing.TensorLike) -> Tensor: ...

# type cast
def __bool__(self) -> bool: ...
def __float__(self) -> float: ...
def __int__(self) -> int: ...
def __long__(self) -> float: ...
def __nonzero__(self) -> bool: ...

# emulating container types
def __getitem__(
self,
item: (
None
| bool
| int
| _Slice
| tuple[None | bool | int | _Slice, ...]
| list[Tensor | bool | int]
),
) -> Tensor: ...
def __setitem__(
self,
item: (
None
| bool
| int
| _Slice
| tuple[None | bool | int | _Slice, ...]
| list[Tensor | bool | int]
),
value: Tensor | npt.NDArray[Any] | int | float | complex | bool,
) -> None: ...
def __len__(self) -> int: ...

# emulating numeric types
def __index__(self) -> int: ...

# unary arithmetic operations
def __invert__(self) -> Tensor: ...
def __neg__(self) -> Tensor: ...

# basic
def __hash__(self) -> int: ...
def clear_gradient(self, set_to_zero: bool = True) -> None: ...
def clone(self) -> Tensor: ...
def cols(self) -> Tensor: ...
def contiguous(self) -> Tensor: ...
def copy_(self) -> Tensor: ...
def crows(self) -> Tensor: ...
@property
def data(self) -> Tensor: ...
def data_ptr(self) -> int: ...
def detach(self) -> Tensor: ...
def detach_(self) -> Tensor: ...
@property
def dtype(self) -> paddle.dtype: ...
def element_size(self) -> int: ...
def get_map_tensor(self) -> Tensor: ...
def get_selected_rows(self) -> None: ...
def get_strides(self) -> list[int]: ...
def get_tensor(self) -> Tensor: ...
@property
def grad(self) -> Tensor | None: ...
@property
def grad_(self) -> Tensor | None: ...
@property
def grad_fn(self) -> Any: ...
def is_contiguous(self) -> bool: ...
def is_dense(self) -> bool: ...
def is_dist(self) -> bool: ...
@property
def is_leaf(self) -> bool: ...
def is_same_shape(self, y: Tensor) -> bool: ...
def is_selected_rows(self) -> bool: ...
def is_sparse(self) -> bool: ...
def is_sparse_coo(self) -> bool: ...
def is_sparse_csr(self) -> bool: ...
@property
def layout(self) -> _typing.DataLayoutND: ...
@property
def name(self) -> str: ...
@property
def ndim(self) -> int: ...
def nnz(self) -> int: ...
@property
def num_shard(self) -> int: ...
def numpy(self) -> npt.NDArray[Any]: ...
@property
def offset(self) -> int: ...
@property
def persistable(self) -> bool: ...
@property
def place(self) -> paddle.core.Place: ...
@property
def placements(self) -> list[paddle.distributed.Placement] | None: ...
@property
def process_mesh(self) -> paddle.distributed.ProcessMesh | None: ...
def rows(self) -> list[int]: ...
def set_string_list(self, value: str) -> None: ...
def set_vocab(self, value: dict) -> None: ...
@property
def shape(self) -> list[int]: ...
@property
def size(self) -> int: ...
@property
def strides(self) -> list[int]: ...
@property
def type(self) -> Tensor: ...

# annotation: ${tensor_alias}
__qualname__ = "Tensor"
2 changes: 2 additions & 0 deletions python/setup.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,8 @@ package_data['paddle.framework'] = package_data.get(
package_data['paddle.base'] = package_data.get('paddle.base', []) + [
'*.pyi'
]
package_data['paddle.tensor'] = package_data.get('paddle.tensor', []) + ['tensor.pyi']


with redirect_stdout():
setup(name='${PACKAGE_NAME}',
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,9 @@ def get_package_data_and_package_dir():
package_data['paddle.base'] = package_data.get('paddle.base', []) + [
'*.pyi'
]
package_data['paddle.tensor'] = package_data.get('paddle.tensor', []) + [
'tensor.pyi'
]

return package_data, package_dir, ext_modules

Expand Down
Loading