dbrattli / Expression

Pragmatic functional programming for Python inspired by F#
https://expression.readthedocs.io
MIT License
421 stars 30 forks source link

Type aliases using Union syntax incompatible with Python 3.9 #107

Closed aiq-kgielow closed 5 months ago

aiq-kgielow commented 1 year ago

Describe the bug A basic Python script bombs when importing from expression.collections.

To Reproduce

  1. Install expression into Python 3.9 virtual environment using pip install.
  2. Create a basic top-level script that imports expression.collections.
  3. Run script with Python 3.9 from virtual environment.

Expected behavior Python script runs without issue.

Code or Screenshots Here is the code from my Python script:

from expression.collections import seq, Seq

if __name__ == '__main__':
    print("All done!")

Here is the traceback I get:

Traceback (most recent call last):
  File "/home/atonally/develop/sandbox-py39/main.py", line 3, in <module>
    from expression.collections import seq, Seq
  File "/home/atonally/develop/sandbox-py39/.venv/lib/python3.9/site-packages/expression/__init__.py", line 11, in <module>
    from . import collections, core, effect
  File "/home/atonally/develop/sandbox-py39/.venv/lib/python3.9/site-packages/expression/collections/__init__.py", line 4, in <module>
    from . import array, asyncseq, block, map, seq
  File "/home/atonally/develop/sandbox-py39/.venv/lib/python3.9/site-packages/expression/collections/array.py", line 28, in <module>
    from expression.core import (
  File "/home/atonally/develop/sandbox-py39/.venv/lib/python3.9/site-packages/expression/core/__init__.py", line 20, in <module>
    from .fn import TailCall, TailCallResult, tailrec, tailrec_async
  File "/home/atonally/develop/sandbox-py39/.venv/lib/python3.9/site-packages/expression/core/fn.py", line 24, in <module>
    TailCallResult = _TResult | TailCall[_P]
TypeError: unsupported operand type(s) for |: 'TypeVar' and '_GenericAlias'

Additional context

aiq-kgielow commented 1 year ago

I can't make a pull request, but here's the patch that I'm applying locally to get expression 4.2.2 to work with Python 3.9:

diff --git a/expression/collections/array.py b/expression/collections/array.py
index d1f27f6..399f57b 100644
--- a/expression/collections/array.py
+++ b/expression/collections/array.py
@@ -23,6 +23,7 @@ from typing import (
     Tuple,
     TypeVar,
     cast,
+    Union
 )

 from expression.core import (
@@ -44,7 +45,7 @@ _TState = TypeVar("_TState")
 _TSourceSortable = TypeVar("_TSourceSortable", bound=SupportsLessThan)

 _TSourceSum = TypeVar("_TSourceSum", bound=SupportsSum)
-_Array = List[_TSource] | MutableSequence[_TSource]
+_Array = Union[List[_TSource], MutableSequence[_TSource]]

 class int8(int):
diff --git a/expression/core/fn.py b/expression/core/fn.py
index 4461f27..80a75b9 100644
--- a/expression/core/fn.py
+++ b/expression/core/fn.py
@@ -1,7 +1,7 @@
 from __future__ import annotations

 import functools
-from typing import Awaitable, Callable, Generic, TypeVar
+from typing import Awaitable, Callable, Generic, TypeVar, Union

 from typing_extensions import ParamSpec

@@ -21,7 +21,7 @@ class TailCall(Generic[_P]):
         self.kw = kw

-TailCallResult = _TResult | TailCall[_P]
+TailCallResult = Union[_TResult, TailCall[_P]]

 def tailrec(fn: Callable[_P, TailCallResult[_TResult, _P]]) -> Callable[_P, _TResult]:
aiq-kgielow commented 1 year ago

Just curious if you're abandoning support for Python 3.9. Your documentation still states support for Python 3.9+

yuuuxt commented 1 year ago

So the break started from version 4.2.0 (in #77). Haven't seen any discussion or content in documentation about dropping python 3.9.

Hope the compatibility is fixed as I'm using Anaconda which supports python 3.9 (version 2022.10).

dbrattli commented 5 months ago

Closing this issue since the issue was fixed in #117. However, just giving a heads-up that Expression v5 just took a hard dependency on dataclass_transforms in Python 3.11, so we are now Python 3.11+.