Support attr aliases for classes and fields (PY-26354)

This commit is contained in:
Semyon Proshev
2018-05-29 16:49:52 +03:00
parent a2e96cf594
commit 33f8bd2143
7 changed files with 43 additions and 194 deletions
+3 -188
View File
@@ -207,191 +207,6 @@ def get_run_validators() -> bool: ...
# aliases --
# FIXME: there is a bug in PyCharm with creating aliases to overloads.
# Use the aliases instead of the duplicated overloads when the bug is fixed:
# https://youtrack.jetbrains.com/issue/PY-27788
# s = attributes = attrs
# ib = attr = attrib
# dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
@overload
def ib(default: None = ...,
validator: None = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: None = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: None = ...,
converter: None = ...,
factory: None = ...,
) -> Any: ...
@overload
def ib(default: None = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
) -> _T: ...
@overload
def ib(default: _T,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
) -> _T: ...
@overload
def ib(default: Optional[_T] = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: object = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
) -> Any: ...
@overload
def attr(default: None = ...,
validator: None = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: None = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: None = ...,
converter: None = ...,
factory: None = ...,
) -> Any: ...
@overload
def attr(default: None = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
) -> _T: ...
@overload
def attr(default: _T,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
) -> _T: ...
@overload
def attr(default: Optional[_T] = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: object = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
) -> Any: ...
@overload
def attributes(maybe_cls: _C,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
str: bool = ...,
auto_attribs: bool = ...) -> _C: ...
@overload
def attributes(maybe_cls: None = ...,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
str: bool = ...,
auto_attribs: bool = ...) -> Callable[[_C], _C]: ...
@overload
def s(maybe_cls: _C,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
str: bool = ...,
auto_attribs: bool = ...) -> _C: ...
@overload
def s(maybe_cls: None = ...,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
str: bool = ...,
auto_attribs: bool = ...) -> Callable[[_C], _C]: ...
# same as above, but with auto_attrib=True
@overload
def dataclass(maybe_cls: _C,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
str: bool = ...) -> _C: ...
@overload
def dataclass(maybe_cls: None = ...,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
str: bool = ...) -> Callable[[_C], _C]: ...
s = attributes = attrs
ib = attr = attrib
dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
@@ -27,7 +27,10 @@ fun parseDataclassParameters(cls: PyClass, context: TypeEvalContext): PyDataclas
context,
mapOf(
KnownDecorator.DATACLASSES_DATACLASS to PyDataclassParameters.Type.STD,
KnownDecorator.ATTR_S to PyDataclassParameters.Type.ATTRS
KnownDecorator.ATTR_S to PyDataclassParameters.Type.ATTRS,
KnownDecorator.ATTR_ATTRS to PyDataclassParameters.Type.ATTRS,
KnownDecorator.ATTR_ATTRIBUTES to PyDataclassParameters.Type.ATTRS,
KnownDecorator.ATTR_DATACLASS to PyDataclassParameters.Type.ATTRS
)
)
}
@@ -71,7 +71,10 @@ public class PyKnownDecoratorUtil {
KOMBU_UTILS_CACHED_PROPERTY("kombu.utils.cached_property"),
DATACLASSES_DATACLASS("dataclasses.dataclass"),
ATTR_S("attr.__init__.s");
ATTR_S("attr.__init__.s"),
ATTR_ATTRS("attr.__init__.attrs"),
ATTR_ATTRIBUTES("attr.__init__.attributes"),
ATTR_DATACLASS("attr.__init__.dataclass");
private final QualifiedName myQualifiedName;
@@ -45,11 +45,13 @@ class PyDataclassFieldStubImpl private constructor(private val calleeName: Quali
val dataclassesField = QualifiedName.fromComponents("dataclasses", "field")
val attrIb = QualifiedName.fromComponents("attr", "ib")
val attrAttr = QualifiedName.fromComponents("attr", "attr")
val attrAttrib = QualifiedName.fromComponents("attr", "attrib")
for (originalQName in PyResolveUtil.resolveImportedElementQNameLocally(callee)) {
when (originalQName) {
dataclassesField -> return qualifiedName to PyDataclassParameters.Type.STD
attrIb -> return qualifiedName to PyDataclassParameters.Type.ATTRS
attrIb, attrAttr, attrAttrib -> return qualifiedName to PyDataclassParameters.Type.ATTRS
}
}
@@ -35,3 +35,18 @@ class B1:
B1(<arg4>)
@attr.attrs
class C1:
x = attr.ib()
y = attr.attr(default=0)
C1(<arg5>)
@attr.attributes
class C2:
x = attr.attr()
y = attr.attrib(default="0")
C2(<arg6>)
@@ -47,4 +47,12 @@ class C1:
a: typing.ClassVar[int]
b: int
C1(<arg5>)
C1(<arg5>)
@attr.dataclass
class D1:
x: int
y: str = "0"
D1(<arg6>)
@@ -756,7 +756,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
runWithLanguageLevel(
LanguageLevel.PYTHON36,
() -> {
final Map<String, PsiElement> marks = loadTest(5);
final Map<String, PsiElement> marks = loadTest(6);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("x: int, y: str, z: float=0.0", new String[]{"x: int, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("x: int, y: str, z: float=0.0", new String[]{"x: int, "});
@@ -769,6 +769,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
feignCtrlP(marks.get("<arg4>").getTextOffset()).check("self: B2, x: int", new String[]{"x: int"}, new String[]{"self: B2, "});
feignCtrlP(marks.get("<arg5>").getTextOffset()).check("b: int", new String[]{"b: int"});
feignCtrlP(marks.get("<arg6>").getTextOffset()).check("x: int, y: str=\"0\"", new String[]{"x: int, "});
}
);
}
@@ -778,12 +779,14 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
runWithLanguageLevel(
LanguageLevel.PYTHON36,
() -> {
final Map<String, PsiElement> marks = loadTest(4);
final Map<String, PsiElement> marks = loadTest(6);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("x, y, z: int=...", new String[]{"x, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("x, y, z: int=...", new String[]{"x, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("x, z: int=...", new String[]{"x, "});
feignCtrlP(marks.get("<arg4>").getTextOffset()).check("x, y, z: list=...", new String[]{"x, "});
feignCtrlP(marks.get("<arg5>").getTextOffset()).check("x, y: int=...", new String[]{"x, "});
feignCtrlP(marks.get("<arg6>").getTextOffset()).check("x, y: str=...", new String[]{"x, "});
}
);
}