예제 #1
0
def test_producing_typescript_types() -> None:
    from paradox.typing import (CrossAny, CrossCallable, CrossMap,
                                CrossNewType, CrossPythonOnlyType, CrossSet,
                                CrossTypeScriptOnlyType, dictof, listof, lit,
                                maybe, omittable, unflex, unionof)

    assert CrossAny().getTSType()[0] == 'any'
    assert unflex(str).getTSType()[0] == 'string'
    assert unflex(int).getTSType()[0] == 'number'
    assert unflex(bool).getTSType()[0] == 'boolean'
    assert unflex(None).getTSType()[0] == 'null'
    assert lit('cheese').getTSType()[0] == "'cheese'"
    assert omittable(int).getTSType()[0] == 'number | undefined'
    assert CrossNewType('Widget').getTSType()[0] == 'Widget'
    assert maybe(str).getTSType()[0] == 'string | null'
    assert listof(int).getTSType()[0] == 'number[]'
    assert CrossSet(unflex(str)).getTSType()[0] == 'Set<string>'
    assert dictof(str, int).getTSType()[0] == '{[k: string]: number}'
    assert CrossMap(unflex(str), unflex(int)).getTSType()[0] == 'Map<string, number>'
    assert unionof(str, int).getTSType()[0] == 'string | number'
    c = CrossCallable([unflex(str), unflex(int)], unflex(bool))
    assert c.getTSType()[0] == '(a: string, b: number) => boolean'

    with pytest.raises(NotImplementedError):
        assert CrossPythonOnlyType('typing.Iterable[int]').getTSType()

    promise = CrossTypeScriptOnlyType('Promise<string>')
    assert promise.getTSType()[0] == 'Promise<string>'

    # test that list of something complex changes to the Array<> syntax
    assert listof(promise).getTSType()[0] == 'Array<Promise<string>>'
예제 #2
0
def test_producing_python_types() -> None:
    from paradox.typing import (CrossAny, CrossCallable, CrossMap,
                                CrossNewType, CrossPythonOnlyType, CrossSet,
                                CrossTypeScriptOnlyType, dictof, listof, lit,
                                maybe, omittable, unflex, unionof)

    assert CrossAny().getPyType()[0] == 'typing.Any'
    assert unflex(str).getPyType()[0] == 'str'
    assert unflex(int).getPyType()[0] == 'int'
    assert unflex(bool).getPyType()[0] == 'bool'
    assert unflex(None).getPyType()[0] == 'None'
    assert lit('cheese').getPyType()[0] == "typing_extensions.Literal['cheese']"
    assert omittable(int).getPyType()[0] == 'typing.Union[int, builtins.ellipsis]'
    assert CrossNewType('Widget').getPyType()[0] == 'Widget'
    assert maybe(str).getPyType()[0] == 'typing.Optional[str]'
    assert listof(int).getPyType()[0] == 'typing.List[int]'
    assert CrossSet(unflex(str)).getPyType()[0] == 'typing.Set[str]'
    assert dictof(str, int).getPyType()[0] == 'typing.Dict[str, int]'
    assert CrossMap(unflex(str), unflex(int)).getPyType()[0] == 'typing.Mapping[str, int]'
    assert unionof(str, int).getPyType()[0] == 'typing.Union[str, int]'
    c = CrossCallable([unflex(str), unflex(int)], unflex(bool))
    assert c.getPyType()[0] == 'typing.Callable[[str, int], bool]'
    assert CrossPythonOnlyType('typing.Iterable[int]').getPyType()[0] == 'typing.Iterable[int]'

    with pytest.raises(NotImplementedError):
        assert CrossTypeScriptOnlyType('Promise<ApiFailure>').getPyType()
예제 #3
0
    def addOverload(
        self,
        modifications: Dict[str, Optional[FlexiType]],
        returntype: Union[FlexiType, Literal["no_return"]],
    ) -> None:
        # make a new function spec with the modifications mentioned
        overload = FunctionSpec(self._name, returntype)
        overload._ismethod = self._ismethod
        overload._isasync = self._isasync
        overload._decorators_py.append('@typing.overload')
        overload._statements.append(PanExprStatement(pyexpr('...')))

        arglist = [
            (self._pargs, overload._pargs),
            (self._kwargs, overload._kwargs),
        ]

        for source, dest in arglist:
            for name, crosstype, default in source:
                try:
                    modified: Optional[FlexiType] = modifications[name]
                except KeyError:
                    # append the argument without modifications and without a default
                    dest.append((name, crosstype, None))
                else:
                    if modified is None:
                        # the argument has been disabled in this overload
                        continue

                    # append the argument with the modified type and no default
                    dest.append((name, unflex(modified), None))

        self._overloads.append(overload)
예제 #4
0
    def __init__(self, var: Union[str, PanVar], keytype: FlexiType,
                 valtype: FlexiType) -> None:
        super().__init__()

        keytype = unflex(keytype)
        assert isinstance(keytype,
                          CrossStr), "Only str keys are currently supported"
        realtype = CrossDict(keytype, unflex(valtype))

        if isinstance(var, str):
            self._var = PanVar(var, realtype)
        else:
            self._var = var
        self._type = realtype

        self._keys: List[Tuple[str, bool]] = []
예제 #5
0
 def alsoDeclare(
     self,
     target: Union[str, PanVar],
     type: Union[None, FlexiType, Literal["no_type"]],
     value: "Union[Pannable, builtins.ellipsis]" = ...,
 ) -> PanVar:
     declaretype = True
     if isinstance(target, PanVar):
         realtarget = target
     elif type is None:
         if not isinstance(value, PanExpr):
             raise Exception(
                 "alsoDeclare() requires a type, or target to be a PanVar"
                 ", or value to be a PanExpr with a known type")
         realtarget = PanVar(target, value.getPanType())
     elif type == "no_type":
         realtarget = PanVar(target, None)
         declaretype = False
     else:
         # FIXME: get rid of type: ignore here
         realtarget = PanVar(target, unflex(type))
     self._statements.append(
         AssignmentStatement(
             realtarget,
             None if value is ... else pan(value),
             declare=True,
             declaretype=declaretype,
         ))
     return realtarget
예제 #6
0
    def addProperty(
        self,
        name: str,
        type: FlexiType,
        *,
        initarg: bool = False,
        default: Union[Pannable, NoDefault] = NO_DEFAULT,
        tsobservable: bool = False,
        tsreadonly: bool = False,
    ) -> PanProp:
        crosstype = unflex(type)
        realdefault = _pan_nodef(default)
        if initarg:
            self._initargs.append((name, crosstype, realdefault))
        elif realdefault is not None:
            self._initdefaults.append((name, realdefault))

        self._properties.append(
            ClassProperty(
                propname=name,
                proptype=crosstype,
                propdefault=realdefault,
                tsobservable=tsobservable,
                tsreadonly=tsreadonly,
            ))
        return PanProp(name, crosstype, None)
예제 #7
0
 def addPositionalArg(
     self,
     name: str,
     crosstype: FlexiType,
     *,
     default: Union[Pannable, NoDefault] = NO_DEFAULT,
     allowomit: bool = False,
 ) -> PanVar:
     return self._addArg(
         self._pargs,
         name=name,
         crosstype=unflex(crosstype),
         default=_pan_nodef(default),
         allowomit=allowomit,
         nullable=False,
     )
예제 #8
0
    def __init__(
        self,
        name: str,
        returntype: Union[FlexiType, Literal["no_return", "is_constructor"]],
        *,
        isabstract: bool = False,
        isconstructor: bool = False,
        ismethod: bool = False,
        isstaticmethod: bool = False,
        isasync: bool = False,
        docstring: List[str] = None,
    ) -> None:
        super().__init__()

        self._name = name

        if isconstructor:
            assert returntype == "is_constructor"
            self._rettype = None
        elif returntype == "is_constructor":
            raise Exception(
                "Using returntype 'is_constructor' when isconstructor is False"
            )
        elif returntype == "no_return":
            # function declaration should have typescript "void" or python "None"
            self._rettype = None
        else:
            # using type: ignore because we know here that returntype must be a FlexiType by this
            # point
            self._rettype = unflex(returntype)

        # list((name, type, default)))
        self._pargs: List[Tuple[str, CrossType, Optional[PanExpr]]] = []
        self._kwargs: List[Tuple[str, CrossType, Optional[PanExpr]]] = []
        self._overloads: List[FunctionSpec] = []
        self._decorators_py: List[str] = []
        self._decorators_ts: List[str] = []
        self._isabstract: bool = isabstract
        self._isconstructor: bool = isconstructor
        self._ismethod: bool = ismethod
        self._isstaticmethod: bool = isstaticmethod
        self._isasync: bool = isasync
        # TODO: add support for this in PHP/Typescript also
        self._docstring: Optional[List[str]] = docstring
예제 #9
0
 def addProperty(
     self,
     name: str,
     type: FlexiType,
 ) -> None:
     self._properties.append((name, unflex(type)))
예제 #10
0
 def cast(self, newtype: FlexiType) -> "PanCast":
     return PanCast(unflex(newtype), self)
예제 #11
0
 def getprop(self, propname: str, type: FlexiType) -> "PanProp":
     return PanProp(propname, unflex(type), self)
예제 #12
0
def test_producing_php_types() -> None:
    from paradox.typing import (CrossAny, CrossCallable, CrossMap,
                                CrossNewType, CrossPythonOnlyType, CrossSet,
                                CrossTypeScriptOnlyType, dictof, listof, lit,
                                maybe, omittable, unflex, unionof)

    assert CrossAny().getPHPTypes()[0] is None
    assert CrossAny().getPHPTypes()[1] == 'mixed'
    assert unflex(str).getPHPTypes()[0] == 'string'
    assert unflex(str).getPHPTypes()[1] == 'string'
    assert unflex(int).getPHPTypes()[0] == 'int'
    assert unflex(int).getPHPTypes()[1] == 'int'
    assert unflex(bool).getPHPTypes()[0] == 'bool'
    assert unflex(bool).getPHPTypes()[1] == 'boolean'
    assert unflex(None).getPHPTypes()[0] is None
    assert unflex(None).getPHPTypes()[1] == 'null'
    assert lit('cheese').getPHPTypes()[0] == "string"
    assert lit('cheese').getPHPTypes()[1] == "string"

    with pytest.raises(NotImplementedError):
        # no way to support this in PHP
        assert omittable(int).getPHPTypes()

    assert CrossNewType('Widget').getPHPTypes()[0] == 'Widget'
    assert CrossNewType('Widget').getPHPTypes()[1] == 'Widget'
    assert maybe(str).getPHPTypes()[0] is None
    assert maybe(str).getPHPTypes()[1] == 'null|string'
    assert listof(int).getPHPTypes()[0] == 'array'
    assert listof(int).getPHPTypes()[1] == 'int[]'

    with pytest.raises(NotImplementedError):
        # no way to support this in PHP
        assert CrossSet(unflex(str)).getPHPTypes()

    # hell yeah PHP
    assert dictof(str, int).getPHPTypes()[0] == 'array'
    assert dictof(str, int).getPHPTypes()[1] == 'int[]'

    assert CrossMap(unflex(str), unflex(int)).getPHPTypes()[0] == 'Ds\\Map'
    assert CrossMap(unflex(str), unflex(int)).getPHPTypes()[1] == 'Ds\\Map'
    assert unionof(str, int).getPHPTypes()[0] is None
    assert unionof(str, int).getPHPTypes()[1] == 'string|int'
    c = CrossCallable([unflex(str), unflex(int)], unflex(bool))
    assert c.getPHPTypes()[0] is None
    assert c.getPHPTypes()[1] == 'callable'

    with pytest.raises(NotImplementedError):
        assert CrossPythonOnlyType('typing.Iterable[int]').getPHPTypes()

    with pytest.raises(NotImplementedError):
        assert CrossTypeScriptOnlyType('Promise<string>').getPHPTypes()

    # test that list of something complex changes to just 'mixed'
    assert listof(listof(unflex(int))).getPHPTypes()[0] == 'array'
    assert listof(listof(unflex(int))).getPHPTypes()[1] == 'mixed'  # more PHP greatness