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

Enable --no-wrap in the Jupyter kernel #687

Closed
rtbs-dev opened this issue Nov 17, 2022 · 3 comments
Closed

Enable --no-wrap in the Jupyter kernel #687

rtbs-dev opened this issue Nov 17, 2022 · 3 comments

Comments

@rtbs-dev
Copy link

From the new documentation for type aliases, e.g.

[1]: type x = int
[2]: x

>>> 'int'

Is this expected behavior? I realize mypy probably doesn't care if typehints are str or not, but runtime typechecking (say, isinstance, or --- what i'm testing here --- beartype) needs class instances to operate.

Using eval can be a nasty work around for this, but I ran into a problem if the type aliases are used in future definitions.

type E_ID = int | str
type Entity[Data<=bt.Iterable] = (E_ID; Data?)

[3]: eval(E_ID)  # it's not an alias, it's just the classes
>>> int | str

[4]: eval(Entity)  # now we're getting relative fwd refs? 
>>> typing.Tuple[ForwardRef('int | str'), typing.Optional[~_coconut_typevar_Data_1]]

This nested generic type unfortunately can't be used with isinstance, but it's a normal check e.g. for beartype (which I thought the door API would pair lovely with coconut! 😄):

from beartype.door import TypeHint as th
def eth(typehint) = typehint |> eval |> th  # need to eval, then wrap in TypeHint

[5]: eth(Entity).is_bearable(('hi',(2,3,4)))
python3.10/site-packages/beartype/_util/hint/pep/utilpeptest.py:345: BeartypeDecorHintPep585DeprecationWarning: PEP 484 type hint typing.Tuple[ForwardRef('int | str'), typing.Optional[~_coconut_typevar_Data_1]] deprecated by PEP 585 scheduled for removal in the first Python version released after October 5th, 2025. To resolve this, import this hint from "beartype.typing" rather than "typing". See this discussion for further details and alternatives:
    https://github.com/beartype/beartype#pep-585-deprecations
  warn(

[...]

File ~/miniconda3/envs/grabble/lib/python3.10/site-packages/beartype/_check/checkmake.py:234, in make_func_tester(hint, conf, exception_cls)
    207 # If this hint contains one or more relative forward references, this hint
    208 # is non-portable across lexical scopes. Why? Because this hint is relative
    209 # to and thus valid only with respect to the caller's current lexical scope.
   (...)
    231 # factory (e.g., our increasingly popular public beartype.door.is_bearable()
    232 # tester) sufficiently slow as to be pragmatically infeasible.
    233 if hint_forwardrefs_class_basename:
--> 234     raise BeartypeDecorHintForwardRefException(
    235         f'{EXCEPTION_PLACEHOLDER}type hint {repr(hint)} '
    236         f'contains one or more relative forward references:\n'
    237         f'\t{repr(hint_forwardrefs_class_basename)}\n'
    238         f'Beartype prohibits relative forward references outside of '
    239         f'@beartype-decorated callables. For your own personal safety and '
    240         f'those of the codebases you love, consider canonicalizing these '
    241         f'relative forward references into absolute forward references '
    242         f'(e.g., by replacing "MuhClass" with "muh_module.MuhClass").'
    243     )
    244 # Else, this hint contains *NO* relative forward references.
    245 
    246 # Unqualified basename of this tester function, uniquified by suffixing an
    247 # arbitrary integer guaranteed to be unique to this tester function.
    248 func_tester_name = (
    249     f'{FUNC_TESTER_NAME_PREFIX}{next(_func_tester_name_counter)}')

BeartypeDecorHintForwardRefException: is_bearable() type hint typing.Tuple[ForwardRef('int | str'), typing.Optional[~_coconut_typevar_Data_1]] contains one or more relative forward references:
	('int | str',)
Beartype prohibits relative forward references outside of @beartype-decorated callables. For your own personal safety and those of the codebases you love, consider canonicalizing these relative forward references into absolute forward references (e.g., by replacing "MuhClass" with "muh_module.MuhClass").

as they point out, this use of ForwardRef probably won't be around forever, if I'm understanding?

It works fine without the new syntax:

E_ID = bt.Union[int,str]
DataType = bt.TypeVar('DataType', bound=bt.Iterable)
Entity = bt.Tuple[E_ID, bt.Optional[DataType]]
[0]: (th(Entity).is_bearable(('hi',(2,3,4))),
 th(Entity).is_bearable((1.20,(2,3,4))),
 th(Entity).is_bearable((0,None)))

>>> (True, False, True)

As an aside here, I do think friendly interop with beartype has a lot of potential for functional style e.g. coconut, since it clarifies a ton of nasty situations like type(MyEnum.member) is MyEnum, and runs very fast. Providing an option for beartype users to run coconut with e.g. a beartype.typing backend would be very nice. See some other examples if this is interesting to you, e.g. the explanation for numerary or ... this other proposal I'm on, dealing with faster type-based dispatch via plum. I'm hoping to use beartype+plum for some kind of typeclass approximation soon, for rich type-based ad hoc polymorphism 😅 (rather than just pattern matching... more like rust traits)

@rtbs-dev
Copy link
Author

Forgot to mention, that fwd ref is coming from the string. I can remove that issue with more evals, or (I guess?) some kind of recursive eval when there are type aliases.

type Entity[Data<=bt.Iterable] = (eval(E_ID); Data?)
eval(Entity)

>>> typing.Tuple[int | str, typing.Optional[~_coconut_typevar_Data_2]]

This works fine (except for the complaint about typing.Tuple being deprecated in the future). But it requires us to keep track of every time I use a type alias downstream. And I just kinda hate eval haha.

@evhub
Copy link
Owner

evhub commented Nov 18, 2022

This is what --no-wrap is for—if you pass --no-wrap, type annotations won't be wrapped in strings so you can make use of them at runtime. By default, Coconut wraps all type annotations in strings to a) enable easy forward references, b) improve runtime performance, and c) be compatible with PEP 563. But if you don't want that—e.g. because you want to use type annotations at runtime—then --no-wrap disables all wrapping/deferring of type annotations, so it should do exactly what you want here.

evhub added a commit that referenced this issue Nov 18, 2022
@evhub
Copy link
Owner

evhub commented Nov 18, 2022

Another question here maybe worth considering is whether --no-wrap should be enabled by default in Coconut's Jupyter kernel to support using type hints at runtime there.

@evhub evhub changed the title TypeAlias declaration syntax returns str, rather than typing.TypeAliasType Enable --no-wrap in the Jupyter kernel Nov 18, 2022
evhub added a commit that referenced this issue Nov 18, 2022
@evhub evhub added the resolved label Nov 18, 2022
@evhub evhub closed this as completed Nov 18, 2022
@evhub evhub added this to the v2.1.2 milestone Nov 18, 2022
@evhub evhub mentioned this issue Dec 28, 2022
evhub added a commit that referenced this issue Dec 30, 2022
evhub added a commit that referenced this issue Dec 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants