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>>'
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()
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)
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]] = []
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
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)
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, )
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
def addProperty( self, name: str, type: FlexiType, ) -> None: self._properties.append((name, unflex(type)))
def cast(self, newtype: FlexiType) -> "PanCast": return PanCast(unflex(newtype), self)
def getprop(self, propname: str, type: FlexiType) -> "PanProp": return PanProp(propname, unflex(type), self)
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