From aa96b8e72523a131c349d41abd38088706c1ef27 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 11:02:27 +0330 Subject: [PATCH 01/12] update readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 531d12d..c277d90 100644 --- a/readme.md +++ b/readme.md @@ -21,7 +21,7 @@ Implementation of .NET's [IEnumerable](https://learn.microsoft.com/en-us/dotnet/ - [ ] Join - [x] Intersect - [ ] Group join - - [ ] Group by + - [x] Group by - [x] Prepend - [x] Order - [x] Min From 68bb1b7cee585b57f106a56a6ff4b6c0378905bf Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 11:16:14 +0330 Subject: [PATCH 02/12] remove group by overloads with result selector because of python limitation in conditional generics; desired behaviour can be achieved by select, before or after the group by --- pyenumerable/protocol/_supports_group_by.py | 40 --------------------- 1 file changed, 40 deletions(-) diff --git a/pyenumerable/protocol/_supports_group_by.py b/pyenumerable/protocol/_supports_group_by.py index 9618d3e..fd444d8 100644 --- a/pyenumerable/protocol/_supports_group_by.py +++ b/pyenumerable/protocol/_supports_group_by.py @@ -9,27 +9,6 @@ class SupportsGroupBy[TSource](Protocol): - @overload - def group_by[TKey: Comparable, TElement, TResult]( - self, - key_selector: Callable[[TSource], TKey], - /, - *, - element_selector: Callable[[TSource], TElement], - result_selector: Callable[[TKey, "Enumerable[TElement]"], TResult], - ) -> "Enumerable[TResult]": ... - - @overload - def group_by[TKey, TElement, TResult]( - self, - key_selector: Callable[[TSource], TKey], - /, - *, - element_selector: Callable[[TSource], TElement], - result_selector: Callable[[TKey, "Enumerable[TElement]"], TResult], - comparer: Comparer[TKey], - ) -> "Enumerable[TResult]": ... - @overload def group_by[TKey: Comparable, TElement]( self, @@ -49,25 +28,6 @@ def group_by[TKey, TElement]( comparer: Comparer[TKey], ) -> "Enumerable[Associable[TKey, TElement]]": ... - @overload - def group_by[TKey: Comparable, TResult]( - self, - key_selector: Callable[[TSource], TKey], - /, - *, - result_selector: Callable[[TKey, "Enumerable[TSource]"], TResult], - ) -> "Enumerable[TResult]": ... - - @overload - def group_by[TKey, TResult]( - self, - key_selector: Callable[[TSource], TKey], - /, - *, - result_selector: Callable[[TKey, "Enumerable[TSource]"], TResult], - comparer: Comparer[TKey], - ) -> "Enumerable[TResult]": ... - @overload def group_by[TKey: Comparable]( self, From 382470496a5230aab5734c6dd7c3a43720822a62 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 11:17:39 +0330 Subject: [PATCH 03/12] remove pp pkg and use it as a module instead --- .../{pure_python/_enumerable.py => pure_python.py} | 0 pyenumerable/implementations/pure_python/__init__.py | 1 - 2 files changed, 1 deletion(-) rename pyenumerable/implementations/{pure_python/_enumerable.py => pure_python.py} (100%) delete mode 100644 pyenumerable/implementations/pure_python/__init__.py diff --git a/pyenumerable/implementations/pure_python/_enumerable.py b/pyenumerable/implementations/pure_python.py similarity index 100% rename from pyenumerable/implementations/pure_python/_enumerable.py rename to pyenumerable/implementations/pure_python.py diff --git a/pyenumerable/implementations/pure_python/__init__.py b/pyenumerable/implementations/pure_python/__init__.py deleted file mode 100644 index 1df0692..0000000 --- a/pyenumerable/implementations/pure_python/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._enumerable import PurePythonEnumerable From 791787a076089dbb33f77c8677b98ac511d24a64 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 11:55:45 +0330 Subject: [PATCH 04/12] restructure unit tests --- test/unit/pure_python/{ => enumerable}/__init__.py | 0 test/unit/pure_python/{ => enumerable}/aggregate/__init__.py | 0 .../{ => enumerable}/aggregate/test_aggregate_method.py | 0 test/unit/pure_python/{ => enumerable}/all/__init__.py | 0 test/unit/pure_python/{ => enumerable}/all/test_all_method.py | 0 test/unit/pure_python/{ => enumerable}/any/__init__.py | 0 test/unit/pure_python/{ => enumerable}/any/test_any_method.py | 0 test/unit/pure_python/{ => enumerable}/append/__init__.py | 0 .../pure_python/{ => enumerable}/append/test_append_method.py | 0 test/unit/pure_python/{ => enumerable}/average/__init__.py | 0 .../pure_python/{ => enumerable}/average/test_average_method.py | 0 test/unit/pure_python/{ => enumerable}/chunk_/__init__.py | 0 .../unit/pure_python/{ => enumerable}/chunk_/test_chunk_method.py | 0 test/unit/pure_python/{ => enumerable}/concat/__init__.py | 0 .../pure_python/{ => enumerable}/concat/test_concat_method.py | 0 test/unit/pure_python/{ => enumerable}/contains/__init__.py | 0 .../pure_python/{ => enumerable}/contains/test_contains_method.py | 0 test/unit/pure_python/{ => enumerable}/count/__init__.py | 0 test/unit/pure_python/{ => enumerable}/count/test_count_method.py | 0 test/unit/pure_python/{ => enumerable}/distinct/__init__.py | 0 .../{ => enumerable}/distinct/test_distinct_by_method.py | 0 .../pure_python/{ => enumerable}/distinct/test_distinct_method.py | 0 test/unit/pure_python/{ => enumerable}/except_/__init__.py | 0 .../pure_python/{ => enumerable}/except_/test_except_by_method.py | 0 .../pure_python/{ => enumerable}/except_/test_except_method.py | 0 test/unit/pure_python/{ => enumerable}/intersect/__init__.py | 0 .../{ => enumerable}/intersect/test_intersect_by_method.py | 0 .../{ => enumerable}/intersect/test_intersect_method.py | 0 test/unit/pure_python/{ => enumerable}/max/__init__.py | 0 test/unit/pure_python/{ => enumerable}/max/test_max_by_method.py | 0 test/unit/pure_python/{ => enumerable}/max/test_max_method.py | 0 test/unit/pure_python/{ => enumerable}/min/__init__.py | 0 test/unit/pure_python/{ => enumerable}/min/test_min_by_method.py | 0 test/unit/pure_python/{ => enumerable}/min/test_min_method.py | 0 test/unit/pure_python/{ => enumerable}/of_type/__init__.py | 0 .../pure_python/{ => enumerable}/of_type/test_of_type_method.py | 0 test/unit/pure_python/{ => enumerable}/order/__init__.py | 0 .../{ => enumerable}/order/test_order_by_descending_method.py | 0 .../pure_python/{ => enumerable}/order/test_order_by_method.py | 0 .../{ => enumerable}/order/test_order_descending_method.py | 0 test/unit/pure_python/{ => enumerable}/order/test_order_method.py | 0 test/unit/pure_python/{ => enumerable}/prepend/__init__.py | 0 .../pure_python/{ => enumerable}/prepend/test_prepend_method.py | 0 test/unit/pure_python/{ => enumerable}/reverse/__init__.py | 0 .../pure_python/{ => enumerable}/reverse/test_reverse_method.py | 0 test/unit/pure_python/{ => enumerable}/select_/__init__.py | 0 .../{ => enumerable}/select_/test_select_many_method.py | 0 .../pure_python/{ => enumerable}/select_/test_select_method.py | 0 test/unit/pure_python/{ => enumerable}/sequence_equal/__init__.py | 0 .../{ => enumerable}/sequence_equal/test_sequence_equal_method.py | 0 test/unit/pure_python/{ => enumerable}/single/__init__.py | 0 .../pure_python/{ => enumerable}/single/test_single_method.py | 0 .../{ => enumerable}/single/test_single_or_default_method.py | 0 test/unit/pure_python/{ => enumerable}/skip/__init__.py | 0 .../pure_python/{ => enumerable}/skip/test_skip_last_method.py | 0 test/unit/pure_python/{ => enumerable}/skip/test_skip_method.py | 0 .../pure_python/{ => enumerable}/skip/test_skip_while_method.py | 0 .../unit/pure_python/{ => enumerable}/source_property/__init__.py | 0 .../{ => enumerable}/source_property/test_source_property.py | 0 test/unit/pure_python/{ => enumerable}/sum/__init__.py | 0 test/unit/pure_python/{ => enumerable}/sum/test_sum_method.py | 0 test/unit/pure_python/{ => enumerable}/take/__init__.py | 0 .../pure_python/{ => enumerable}/take/test_take_last_method.py | 0 test/unit/pure_python/{ => enumerable}/take/test_take_method.py | 0 .../pure_python/{ => enumerable}/take/test_take_while_method.py | 0 test/unit/pure_python/{ => enumerable}/union/__init__.py | 0 .../pure_python/{ => enumerable}/union/test_union_by_method.py | 0 test/unit/pure_python/{ => enumerable}/union/test_union_method.py | 0 test/unit/pure_python/{ => enumerable}/where/__init__.py | 0 test/unit/pure_python/{ => enumerable}/where/test_where_method.py | 0 test/unit/pure_python/{ => enumerable}/zip/__init__.py | 0 test/unit/pure_python/{ => enumerable}/zip/test_zip_method.py | 0 72 files changed, 0 insertions(+), 0 deletions(-) rename test/unit/pure_python/{ => enumerable}/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/aggregate/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/aggregate/test_aggregate_method.py (100%) rename test/unit/pure_python/{ => enumerable}/all/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/all/test_all_method.py (100%) rename test/unit/pure_python/{ => enumerable}/any/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/any/test_any_method.py (100%) rename test/unit/pure_python/{ => enumerable}/append/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/append/test_append_method.py (100%) rename test/unit/pure_python/{ => enumerable}/average/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/average/test_average_method.py (100%) rename test/unit/pure_python/{ => enumerable}/chunk_/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/chunk_/test_chunk_method.py (100%) rename test/unit/pure_python/{ => enumerable}/concat/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/concat/test_concat_method.py (100%) rename test/unit/pure_python/{ => enumerable}/contains/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/contains/test_contains_method.py (100%) rename test/unit/pure_python/{ => enumerable}/count/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/count/test_count_method.py (100%) rename test/unit/pure_python/{ => enumerable}/distinct/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/distinct/test_distinct_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/distinct/test_distinct_method.py (100%) rename test/unit/pure_python/{ => enumerable}/except_/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/except_/test_except_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/except_/test_except_method.py (100%) rename test/unit/pure_python/{ => enumerable}/intersect/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/intersect/test_intersect_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/intersect/test_intersect_method.py (100%) rename test/unit/pure_python/{ => enumerable}/max/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/max/test_max_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/max/test_max_method.py (100%) rename test/unit/pure_python/{ => enumerable}/min/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/min/test_min_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/min/test_min_method.py (100%) rename test/unit/pure_python/{ => enumerable}/of_type/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/of_type/test_of_type_method.py (100%) rename test/unit/pure_python/{ => enumerable}/order/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/order/test_order_by_descending_method.py (100%) rename test/unit/pure_python/{ => enumerable}/order/test_order_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/order/test_order_descending_method.py (100%) rename test/unit/pure_python/{ => enumerable}/order/test_order_method.py (100%) rename test/unit/pure_python/{ => enumerable}/prepend/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/prepend/test_prepend_method.py (100%) rename test/unit/pure_python/{ => enumerable}/reverse/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/reverse/test_reverse_method.py (100%) rename test/unit/pure_python/{ => enumerable}/select_/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/select_/test_select_many_method.py (100%) rename test/unit/pure_python/{ => enumerable}/select_/test_select_method.py (100%) rename test/unit/pure_python/{ => enumerable}/sequence_equal/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/sequence_equal/test_sequence_equal_method.py (100%) rename test/unit/pure_python/{ => enumerable}/single/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/single/test_single_method.py (100%) rename test/unit/pure_python/{ => enumerable}/single/test_single_or_default_method.py (100%) rename test/unit/pure_python/{ => enumerable}/skip/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/skip/test_skip_last_method.py (100%) rename test/unit/pure_python/{ => enumerable}/skip/test_skip_method.py (100%) rename test/unit/pure_python/{ => enumerable}/skip/test_skip_while_method.py (100%) rename test/unit/pure_python/{ => enumerable}/source_property/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/source_property/test_source_property.py (100%) rename test/unit/pure_python/{ => enumerable}/sum/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/sum/test_sum_method.py (100%) rename test/unit/pure_python/{ => enumerable}/take/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/take/test_take_last_method.py (100%) rename test/unit/pure_python/{ => enumerable}/take/test_take_method.py (100%) rename test/unit/pure_python/{ => enumerable}/take/test_take_while_method.py (100%) rename test/unit/pure_python/{ => enumerable}/union/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/union/test_union_by_method.py (100%) rename test/unit/pure_python/{ => enumerable}/union/test_union_method.py (100%) rename test/unit/pure_python/{ => enumerable}/where/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/where/test_where_method.py (100%) rename test/unit/pure_python/{ => enumerable}/zip/__init__.py (100%) rename test/unit/pure_python/{ => enumerable}/zip/test_zip_method.py (100%) diff --git a/test/unit/pure_python/__init__.py b/test/unit/pure_python/enumerable/__init__.py similarity index 100% rename from test/unit/pure_python/__init__.py rename to test/unit/pure_python/enumerable/__init__.py diff --git a/test/unit/pure_python/aggregate/__init__.py b/test/unit/pure_python/enumerable/aggregate/__init__.py similarity index 100% rename from test/unit/pure_python/aggregate/__init__.py rename to test/unit/pure_python/enumerable/aggregate/__init__.py diff --git a/test/unit/pure_python/aggregate/test_aggregate_method.py b/test/unit/pure_python/enumerable/aggregate/test_aggregate_method.py similarity index 100% rename from test/unit/pure_python/aggregate/test_aggregate_method.py rename to test/unit/pure_python/enumerable/aggregate/test_aggregate_method.py diff --git a/test/unit/pure_python/all/__init__.py b/test/unit/pure_python/enumerable/all/__init__.py similarity index 100% rename from test/unit/pure_python/all/__init__.py rename to test/unit/pure_python/enumerable/all/__init__.py diff --git a/test/unit/pure_python/all/test_all_method.py b/test/unit/pure_python/enumerable/all/test_all_method.py similarity index 100% rename from test/unit/pure_python/all/test_all_method.py rename to test/unit/pure_python/enumerable/all/test_all_method.py diff --git a/test/unit/pure_python/any/__init__.py b/test/unit/pure_python/enumerable/any/__init__.py similarity index 100% rename from test/unit/pure_python/any/__init__.py rename to test/unit/pure_python/enumerable/any/__init__.py diff --git a/test/unit/pure_python/any/test_any_method.py b/test/unit/pure_python/enumerable/any/test_any_method.py similarity index 100% rename from test/unit/pure_python/any/test_any_method.py rename to test/unit/pure_python/enumerable/any/test_any_method.py diff --git a/test/unit/pure_python/append/__init__.py b/test/unit/pure_python/enumerable/append/__init__.py similarity index 100% rename from test/unit/pure_python/append/__init__.py rename to test/unit/pure_python/enumerable/append/__init__.py diff --git a/test/unit/pure_python/append/test_append_method.py b/test/unit/pure_python/enumerable/append/test_append_method.py similarity index 100% rename from test/unit/pure_python/append/test_append_method.py rename to test/unit/pure_python/enumerable/append/test_append_method.py diff --git a/test/unit/pure_python/average/__init__.py b/test/unit/pure_python/enumerable/average/__init__.py similarity index 100% rename from test/unit/pure_python/average/__init__.py rename to test/unit/pure_python/enumerable/average/__init__.py diff --git a/test/unit/pure_python/average/test_average_method.py b/test/unit/pure_python/enumerable/average/test_average_method.py similarity index 100% rename from test/unit/pure_python/average/test_average_method.py rename to test/unit/pure_python/enumerable/average/test_average_method.py diff --git a/test/unit/pure_python/chunk_/__init__.py b/test/unit/pure_python/enumerable/chunk_/__init__.py similarity index 100% rename from test/unit/pure_python/chunk_/__init__.py rename to test/unit/pure_python/enumerable/chunk_/__init__.py diff --git a/test/unit/pure_python/chunk_/test_chunk_method.py b/test/unit/pure_python/enumerable/chunk_/test_chunk_method.py similarity index 100% rename from test/unit/pure_python/chunk_/test_chunk_method.py rename to test/unit/pure_python/enumerable/chunk_/test_chunk_method.py diff --git a/test/unit/pure_python/concat/__init__.py b/test/unit/pure_python/enumerable/concat/__init__.py similarity index 100% rename from test/unit/pure_python/concat/__init__.py rename to test/unit/pure_python/enumerable/concat/__init__.py diff --git a/test/unit/pure_python/concat/test_concat_method.py b/test/unit/pure_python/enumerable/concat/test_concat_method.py similarity index 100% rename from test/unit/pure_python/concat/test_concat_method.py rename to test/unit/pure_python/enumerable/concat/test_concat_method.py diff --git a/test/unit/pure_python/contains/__init__.py b/test/unit/pure_python/enumerable/contains/__init__.py similarity index 100% rename from test/unit/pure_python/contains/__init__.py rename to test/unit/pure_python/enumerable/contains/__init__.py diff --git a/test/unit/pure_python/contains/test_contains_method.py b/test/unit/pure_python/enumerable/contains/test_contains_method.py similarity index 100% rename from test/unit/pure_python/contains/test_contains_method.py rename to test/unit/pure_python/enumerable/contains/test_contains_method.py diff --git a/test/unit/pure_python/count/__init__.py b/test/unit/pure_python/enumerable/count/__init__.py similarity index 100% rename from test/unit/pure_python/count/__init__.py rename to test/unit/pure_python/enumerable/count/__init__.py diff --git a/test/unit/pure_python/count/test_count_method.py b/test/unit/pure_python/enumerable/count/test_count_method.py similarity index 100% rename from test/unit/pure_python/count/test_count_method.py rename to test/unit/pure_python/enumerable/count/test_count_method.py diff --git a/test/unit/pure_python/distinct/__init__.py b/test/unit/pure_python/enumerable/distinct/__init__.py similarity index 100% rename from test/unit/pure_python/distinct/__init__.py rename to test/unit/pure_python/enumerable/distinct/__init__.py diff --git a/test/unit/pure_python/distinct/test_distinct_by_method.py b/test/unit/pure_python/enumerable/distinct/test_distinct_by_method.py similarity index 100% rename from test/unit/pure_python/distinct/test_distinct_by_method.py rename to test/unit/pure_python/enumerable/distinct/test_distinct_by_method.py diff --git a/test/unit/pure_python/distinct/test_distinct_method.py b/test/unit/pure_python/enumerable/distinct/test_distinct_method.py similarity index 100% rename from test/unit/pure_python/distinct/test_distinct_method.py rename to test/unit/pure_python/enumerable/distinct/test_distinct_method.py diff --git a/test/unit/pure_python/except_/__init__.py b/test/unit/pure_python/enumerable/except_/__init__.py similarity index 100% rename from test/unit/pure_python/except_/__init__.py rename to test/unit/pure_python/enumerable/except_/__init__.py diff --git a/test/unit/pure_python/except_/test_except_by_method.py b/test/unit/pure_python/enumerable/except_/test_except_by_method.py similarity index 100% rename from test/unit/pure_python/except_/test_except_by_method.py rename to test/unit/pure_python/enumerable/except_/test_except_by_method.py diff --git a/test/unit/pure_python/except_/test_except_method.py b/test/unit/pure_python/enumerable/except_/test_except_method.py similarity index 100% rename from test/unit/pure_python/except_/test_except_method.py rename to test/unit/pure_python/enumerable/except_/test_except_method.py diff --git a/test/unit/pure_python/intersect/__init__.py b/test/unit/pure_python/enumerable/intersect/__init__.py similarity index 100% rename from test/unit/pure_python/intersect/__init__.py rename to test/unit/pure_python/enumerable/intersect/__init__.py diff --git a/test/unit/pure_python/intersect/test_intersect_by_method.py b/test/unit/pure_python/enumerable/intersect/test_intersect_by_method.py similarity index 100% rename from test/unit/pure_python/intersect/test_intersect_by_method.py rename to test/unit/pure_python/enumerable/intersect/test_intersect_by_method.py diff --git a/test/unit/pure_python/intersect/test_intersect_method.py b/test/unit/pure_python/enumerable/intersect/test_intersect_method.py similarity index 100% rename from test/unit/pure_python/intersect/test_intersect_method.py rename to test/unit/pure_python/enumerable/intersect/test_intersect_method.py diff --git a/test/unit/pure_python/max/__init__.py b/test/unit/pure_python/enumerable/max/__init__.py similarity index 100% rename from test/unit/pure_python/max/__init__.py rename to test/unit/pure_python/enumerable/max/__init__.py diff --git a/test/unit/pure_python/max/test_max_by_method.py b/test/unit/pure_python/enumerable/max/test_max_by_method.py similarity index 100% rename from test/unit/pure_python/max/test_max_by_method.py rename to test/unit/pure_python/enumerable/max/test_max_by_method.py diff --git a/test/unit/pure_python/max/test_max_method.py b/test/unit/pure_python/enumerable/max/test_max_method.py similarity index 100% rename from test/unit/pure_python/max/test_max_method.py rename to test/unit/pure_python/enumerable/max/test_max_method.py diff --git a/test/unit/pure_python/min/__init__.py b/test/unit/pure_python/enumerable/min/__init__.py similarity index 100% rename from test/unit/pure_python/min/__init__.py rename to test/unit/pure_python/enumerable/min/__init__.py diff --git a/test/unit/pure_python/min/test_min_by_method.py b/test/unit/pure_python/enumerable/min/test_min_by_method.py similarity index 100% rename from test/unit/pure_python/min/test_min_by_method.py rename to test/unit/pure_python/enumerable/min/test_min_by_method.py diff --git a/test/unit/pure_python/min/test_min_method.py b/test/unit/pure_python/enumerable/min/test_min_method.py similarity index 100% rename from test/unit/pure_python/min/test_min_method.py rename to test/unit/pure_python/enumerable/min/test_min_method.py diff --git a/test/unit/pure_python/of_type/__init__.py b/test/unit/pure_python/enumerable/of_type/__init__.py similarity index 100% rename from test/unit/pure_python/of_type/__init__.py rename to test/unit/pure_python/enumerable/of_type/__init__.py diff --git a/test/unit/pure_python/of_type/test_of_type_method.py b/test/unit/pure_python/enumerable/of_type/test_of_type_method.py similarity index 100% rename from test/unit/pure_python/of_type/test_of_type_method.py rename to test/unit/pure_python/enumerable/of_type/test_of_type_method.py diff --git a/test/unit/pure_python/order/__init__.py b/test/unit/pure_python/enumerable/order/__init__.py similarity index 100% rename from test/unit/pure_python/order/__init__.py rename to test/unit/pure_python/enumerable/order/__init__.py diff --git a/test/unit/pure_python/order/test_order_by_descending_method.py b/test/unit/pure_python/enumerable/order/test_order_by_descending_method.py similarity index 100% rename from test/unit/pure_python/order/test_order_by_descending_method.py rename to test/unit/pure_python/enumerable/order/test_order_by_descending_method.py diff --git a/test/unit/pure_python/order/test_order_by_method.py b/test/unit/pure_python/enumerable/order/test_order_by_method.py similarity index 100% rename from test/unit/pure_python/order/test_order_by_method.py rename to test/unit/pure_python/enumerable/order/test_order_by_method.py diff --git a/test/unit/pure_python/order/test_order_descending_method.py b/test/unit/pure_python/enumerable/order/test_order_descending_method.py similarity index 100% rename from test/unit/pure_python/order/test_order_descending_method.py rename to test/unit/pure_python/enumerable/order/test_order_descending_method.py diff --git a/test/unit/pure_python/order/test_order_method.py b/test/unit/pure_python/enumerable/order/test_order_method.py similarity index 100% rename from test/unit/pure_python/order/test_order_method.py rename to test/unit/pure_python/enumerable/order/test_order_method.py diff --git a/test/unit/pure_python/prepend/__init__.py b/test/unit/pure_python/enumerable/prepend/__init__.py similarity index 100% rename from test/unit/pure_python/prepend/__init__.py rename to test/unit/pure_python/enumerable/prepend/__init__.py diff --git a/test/unit/pure_python/prepend/test_prepend_method.py b/test/unit/pure_python/enumerable/prepend/test_prepend_method.py similarity index 100% rename from test/unit/pure_python/prepend/test_prepend_method.py rename to test/unit/pure_python/enumerable/prepend/test_prepend_method.py diff --git a/test/unit/pure_python/reverse/__init__.py b/test/unit/pure_python/enumerable/reverse/__init__.py similarity index 100% rename from test/unit/pure_python/reverse/__init__.py rename to test/unit/pure_python/enumerable/reverse/__init__.py diff --git a/test/unit/pure_python/reverse/test_reverse_method.py b/test/unit/pure_python/enumerable/reverse/test_reverse_method.py similarity index 100% rename from test/unit/pure_python/reverse/test_reverse_method.py rename to test/unit/pure_python/enumerable/reverse/test_reverse_method.py diff --git a/test/unit/pure_python/select_/__init__.py b/test/unit/pure_python/enumerable/select_/__init__.py similarity index 100% rename from test/unit/pure_python/select_/__init__.py rename to test/unit/pure_python/enumerable/select_/__init__.py diff --git a/test/unit/pure_python/select_/test_select_many_method.py b/test/unit/pure_python/enumerable/select_/test_select_many_method.py similarity index 100% rename from test/unit/pure_python/select_/test_select_many_method.py rename to test/unit/pure_python/enumerable/select_/test_select_many_method.py diff --git a/test/unit/pure_python/select_/test_select_method.py b/test/unit/pure_python/enumerable/select_/test_select_method.py similarity index 100% rename from test/unit/pure_python/select_/test_select_method.py rename to test/unit/pure_python/enumerable/select_/test_select_method.py diff --git a/test/unit/pure_python/sequence_equal/__init__.py b/test/unit/pure_python/enumerable/sequence_equal/__init__.py similarity index 100% rename from test/unit/pure_python/sequence_equal/__init__.py rename to test/unit/pure_python/enumerable/sequence_equal/__init__.py diff --git a/test/unit/pure_python/sequence_equal/test_sequence_equal_method.py b/test/unit/pure_python/enumerable/sequence_equal/test_sequence_equal_method.py similarity index 100% rename from test/unit/pure_python/sequence_equal/test_sequence_equal_method.py rename to test/unit/pure_python/enumerable/sequence_equal/test_sequence_equal_method.py diff --git a/test/unit/pure_python/single/__init__.py b/test/unit/pure_python/enumerable/single/__init__.py similarity index 100% rename from test/unit/pure_python/single/__init__.py rename to test/unit/pure_python/enumerable/single/__init__.py diff --git a/test/unit/pure_python/single/test_single_method.py b/test/unit/pure_python/enumerable/single/test_single_method.py similarity index 100% rename from test/unit/pure_python/single/test_single_method.py rename to test/unit/pure_python/enumerable/single/test_single_method.py diff --git a/test/unit/pure_python/single/test_single_or_default_method.py b/test/unit/pure_python/enumerable/single/test_single_or_default_method.py similarity index 100% rename from test/unit/pure_python/single/test_single_or_default_method.py rename to test/unit/pure_python/enumerable/single/test_single_or_default_method.py diff --git a/test/unit/pure_python/skip/__init__.py b/test/unit/pure_python/enumerable/skip/__init__.py similarity index 100% rename from test/unit/pure_python/skip/__init__.py rename to test/unit/pure_python/enumerable/skip/__init__.py diff --git a/test/unit/pure_python/skip/test_skip_last_method.py b/test/unit/pure_python/enumerable/skip/test_skip_last_method.py similarity index 100% rename from test/unit/pure_python/skip/test_skip_last_method.py rename to test/unit/pure_python/enumerable/skip/test_skip_last_method.py diff --git a/test/unit/pure_python/skip/test_skip_method.py b/test/unit/pure_python/enumerable/skip/test_skip_method.py similarity index 100% rename from test/unit/pure_python/skip/test_skip_method.py rename to test/unit/pure_python/enumerable/skip/test_skip_method.py diff --git a/test/unit/pure_python/skip/test_skip_while_method.py b/test/unit/pure_python/enumerable/skip/test_skip_while_method.py similarity index 100% rename from test/unit/pure_python/skip/test_skip_while_method.py rename to test/unit/pure_python/enumerable/skip/test_skip_while_method.py diff --git a/test/unit/pure_python/source_property/__init__.py b/test/unit/pure_python/enumerable/source_property/__init__.py similarity index 100% rename from test/unit/pure_python/source_property/__init__.py rename to test/unit/pure_python/enumerable/source_property/__init__.py diff --git a/test/unit/pure_python/source_property/test_source_property.py b/test/unit/pure_python/enumerable/source_property/test_source_property.py similarity index 100% rename from test/unit/pure_python/source_property/test_source_property.py rename to test/unit/pure_python/enumerable/source_property/test_source_property.py diff --git a/test/unit/pure_python/sum/__init__.py b/test/unit/pure_python/enumerable/sum/__init__.py similarity index 100% rename from test/unit/pure_python/sum/__init__.py rename to test/unit/pure_python/enumerable/sum/__init__.py diff --git a/test/unit/pure_python/sum/test_sum_method.py b/test/unit/pure_python/enumerable/sum/test_sum_method.py similarity index 100% rename from test/unit/pure_python/sum/test_sum_method.py rename to test/unit/pure_python/enumerable/sum/test_sum_method.py diff --git a/test/unit/pure_python/take/__init__.py b/test/unit/pure_python/enumerable/take/__init__.py similarity index 100% rename from test/unit/pure_python/take/__init__.py rename to test/unit/pure_python/enumerable/take/__init__.py diff --git a/test/unit/pure_python/take/test_take_last_method.py b/test/unit/pure_python/enumerable/take/test_take_last_method.py similarity index 100% rename from test/unit/pure_python/take/test_take_last_method.py rename to test/unit/pure_python/enumerable/take/test_take_last_method.py diff --git a/test/unit/pure_python/take/test_take_method.py b/test/unit/pure_python/enumerable/take/test_take_method.py similarity index 100% rename from test/unit/pure_python/take/test_take_method.py rename to test/unit/pure_python/enumerable/take/test_take_method.py diff --git a/test/unit/pure_python/take/test_take_while_method.py b/test/unit/pure_python/enumerable/take/test_take_while_method.py similarity index 100% rename from test/unit/pure_python/take/test_take_while_method.py rename to test/unit/pure_python/enumerable/take/test_take_while_method.py diff --git a/test/unit/pure_python/union/__init__.py b/test/unit/pure_python/enumerable/union/__init__.py similarity index 100% rename from test/unit/pure_python/union/__init__.py rename to test/unit/pure_python/enumerable/union/__init__.py diff --git a/test/unit/pure_python/union/test_union_by_method.py b/test/unit/pure_python/enumerable/union/test_union_by_method.py similarity index 100% rename from test/unit/pure_python/union/test_union_by_method.py rename to test/unit/pure_python/enumerable/union/test_union_by_method.py diff --git a/test/unit/pure_python/union/test_union_method.py b/test/unit/pure_python/enumerable/union/test_union_method.py similarity index 100% rename from test/unit/pure_python/union/test_union_method.py rename to test/unit/pure_python/enumerable/union/test_union_method.py diff --git a/test/unit/pure_python/where/__init__.py b/test/unit/pure_python/enumerable/where/__init__.py similarity index 100% rename from test/unit/pure_python/where/__init__.py rename to test/unit/pure_python/enumerable/where/__init__.py diff --git a/test/unit/pure_python/where/test_where_method.py b/test/unit/pure_python/enumerable/where/test_where_method.py similarity index 100% rename from test/unit/pure_python/where/test_where_method.py rename to test/unit/pure_python/enumerable/where/test_where_method.py diff --git a/test/unit/pure_python/zip/__init__.py b/test/unit/pure_python/enumerable/zip/__init__.py similarity index 100% rename from test/unit/pure_python/zip/__init__.py rename to test/unit/pure_python/enumerable/zip/__init__.py diff --git a/test/unit/pure_python/zip/test_zip_method.py b/test/unit/pure_python/enumerable/zip/test_zip_method.py similarity index 100% rename from test/unit/pure_python/zip/test_zip_method.py rename to test/unit/pure_python/enumerable/zip/test_zip_method.py From 3ca31c5e3353986164f0b38873e625b5abca95cc Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 11:55:56 +0330 Subject: [PATCH 05/12] add pytest settings to pyproject --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index aa88466..09fabac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,3 +60,7 @@ lint.fixable = ["ALL"] typeCheckingMode = "strict" reportUnusedImport = false reportUnusedVariable = false + +[tool.pytest.ini_options] +pythonpath = ["."] +testpaths = ["test"] From 72da51d3cd0a149bb5c772af1536334e5e39fb45 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 11:58:16 +0330 Subject: [PATCH 06/12] update pytest settings --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 09fabac..ceaeec0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,4 +63,4 @@ reportUnusedVariable = false [tool.pytest.ini_options] pythonpath = ["."] -testpaths = ["test"] +testpaths = ["test/unit"] From a1d4c0970c8ac7011b5a023940c14d93db1894c3 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 14:02:57 +0330 Subject: [PATCH 07/12] add unit tests for group by method --- .../enumerable/group_by/__init__.py | 0 .../group_by/test_group_by_method.py | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 test/unit/pure_python/enumerable/group_by/__init__.py create mode 100644 test/unit/pure_python/enumerable/group_by/test_group_by_method.py diff --git a/test/unit/pure_python/enumerable/group_by/__init__.py b/test/unit/pure_python/enumerable/group_by/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/pure_python/enumerable/group_by/test_group_by_method.py b/test/unit/pure_python/enumerable/group_by/test_group_by_method.py new file mode 100644 index 0000000..88f95d8 --- /dev/null +++ b/test/unit/pure_python/enumerable/group_by/test_group_by_method.py @@ -0,0 +1,40 @@ +from pyenumerable.implementations.pure_python import PurePythonEnumerable +from test.unit.pure_python.test_utility import Point + + +class TestGroupByMethod: + def test_group_by(self) -> None: + number_of_groups = 2 + first_group_key, number_of_first_group_members = 1, 3 + second_group_key, number_of_second_group_members = 2, 2 + obj = PurePythonEnumerable( + *( + Point(i, first_group_key) + for i in range(number_of_first_group_members) + ), + *( + Point(i, second_group_key) + for i in range(number_of_second_group_members) + ), + ) + + res = obj.group_by(lambda point: point.y) + + first_group_index, second_group_index = 0, 1 + assert len(res.source) == number_of_groups + assert len( + res.source[first_group_index].source + ) == number_of_first_group_members + assert len( + res.source[second_group_index].source + ) == number_of_second_group_members + assert all( + p.y == first_group_key for p in res.source[ + first_group_index + ].source + ) + assert all( + p.y == second_group_key for p in res.source[ + second_group_index + ].source + ) From cf6d5defe62954b9f7a580469dd31833e11419c2 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 14:03:15 +0330 Subject: [PATCH 08/12] add unit tests for key property and constructor of association pp impl --- test/unit/pure_python/associable/__init__.py | 0 .../pure_python/associable/constructor/__init__.py | 0 .../associable/constructor/test_constructor.py | 10 ++++++++++ 3 files changed, 10 insertions(+) create mode 100644 test/unit/pure_python/associable/__init__.py create mode 100644 test/unit/pure_python/associable/constructor/__init__.py create mode 100644 test/unit/pure_python/associable/constructor/test_constructor.py diff --git a/test/unit/pure_python/associable/__init__.py b/test/unit/pure_python/associable/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/pure_python/associable/constructor/__init__.py b/test/unit/pure_python/associable/constructor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/pure_python/associable/constructor/test_constructor.py b/test/unit/pure_python/associable/constructor/test_constructor.py new file mode 100644 index 0000000..f4f1051 --- /dev/null +++ b/test/unit/pure_python/associable/constructor/test_constructor.py @@ -0,0 +1,10 @@ +from pyenumerable.implementations.pure_python import PurePythonAssociable + + +class TestConstructor: + def test_initialization(self) -> None: + obj: PurePythonAssociable[str, int] = PurePythonAssociable( + key := "Key" + ) + + assert obj.key == key From 86bfbcd8bf0c744335e564929424c451fb5f4fb0 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 14:03:34 +0330 Subject: [PATCH 09/12] remove comparer tests because they were user code --- .../__init__.py | 0 .../test_constructor.py} | 0 .../contains/test_contains_method.py | 22 ++-------------- .../except_/test_except_by_method.py | 21 +-------------- .../enumerable/except_/test_except_method.py | 10 +------ .../intersect/test_intersect_by_method.py | 26 +------------------ .../intersect/test_intersect_method.py | 10 +------ .../enumerable/max/test_max_by_method.py | 12 +-------- .../enumerable/max/test_max_method.py | 9 +------ .../enumerable/min/test_min_by_method.py | 12 +-------- .../enumerable/min/test_min_method.py | 9 +------ .../enumerable/union/test_union_by_method.py | 26 +------------------ .../enumerable/union/test_union_method.py | 12 +-------- 13 files changed, 12 insertions(+), 157 deletions(-) rename test/unit/pure_python/enumerable/{source_property => constructor}/__init__.py (100%) rename test/unit/pure_python/enumerable/{source_property/test_source_property.py => constructor/test_constructor.py} (100%) diff --git a/test/unit/pure_python/enumerable/source_property/__init__.py b/test/unit/pure_python/enumerable/constructor/__init__.py similarity index 100% rename from test/unit/pure_python/enumerable/source_property/__init__.py rename to test/unit/pure_python/enumerable/constructor/__init__.py diff --git a/test/unit/pure_python/enumerable/source_property/test_source_property.py b/test/unit/pure_python/enumerable/constructor/test_constructor.py similarity index 100% rename from test/unit/pure_python/enumerable/source_property/test_source_property.py rename to test/unit/pure_python/enumerable/constructor/test_constructor.py diff --git a/test/unit/pure_python/enumerable/contains/test_contains_method.py b/test/unit/pure_python/enumerable/contains/test_contains_method.py index 1848153..b7ca819 100644 --- a/test/unit/pure_python/enumerable/contains/test_contains_method.py +++ b/test/unit/pure_python/enumerable/contains/test_contains_method.py @@ -3,17 +3,7 @@ class TestContainsMethod: - def test_positive_without_comparer(self) -> None: - existing_item = "existing-item" - obj = PurePythonEnumerable( - "not-being-tested", - "also-not-being-tested", - existing_item, - ) - - assert obj.contains(existing_item) is True - - def test_positive_with_comparer(self) -> None: + def test_positive(self) -> None: obj = PurePythonEnumerable( Person("john doe", 14), Person("jane doe", 12), @@ -28,15 +18,7 @@ def test_positive_with_comparer(self) -> None: is True ) - def test_negative_without_comparer(self) -> None: - obj = PurePythonEnumerable( - "not-being-tested", - "also-not-being-tested", - ) - - assert obj.contains("non-existing-item") is False - - def test_negative_with_comparer(self) -> None: + def test_negative(self) -> None: obj = PurePythonEnumerable( Person("john doe", 14), Person("jane doe", 12), diff --git a/test/unit/pure_python/enumerable/except_/test_except_by_method.py b/test/unit/pure_python/enumerable/except_/test_except_by_method.py index c448a96..1181391 100644 --- a/test/unit/pure_python/enumerable/except_/test_except_by_method.py +++ b/test/unit/pure_python/enumerable/except_/test_except_by_method.py @@ -3,7 +3,7 @@ class TestExceptByMethod: - def test_with_comparer(self) -> None: + def test_except_by(self) -> None: first_object = PurePythonEnumerable( Point(0, 1), first := Point(3, 2), @@ -17,22 +17,3 @@ def test_with_comparer(self) -> None: res = first_object.except_by(second_object, lambda point: point.y) assert res.source == (first, second) - - def test_without_comparer(self) -> None: - first_object = PurePythonEnumerable( - first := Point(0, 2), - Point(9, 7), - second := Point(3, 1), - Point(4, -4), - ) - second_object = PurePythonEnumerable( - Point(5, 4), Point(8, 9), Point(-1, 3), Point(4, -7) - ) - - res = first_object.except_by( - second_object, - lambda point: point.y, - comparer=lambda first_y, second_y: abs(first_y) == abs(second_y), - ) - - assert res.source == (first, second) diff --git a/test/unit/pure_python/enumerable/except_/test_except_method.py b/test/unit/pure_python/enumerable/except_/test_except_method.py index 10ee67a..e381a18 100644 --- a/test/unit/pure_python/enumerable/except_/test_except_method.py +++ b/test/unit/pure_python/enumerable/except_/test_except_method.py @@ -3,15 +3,7 @@ class TestExceptMethod: - def test_without_comparer(self) -> None: - first_object = PurePythonEnumerable(*range(7)) - second_object = PurePythonEnumerable(*range(start := 3, 9)) - - res = first_object.except_(second_object) - - assert res.source == tuple(range(start)) - - def test_with_comparer(self) -> None: + def test_except(self) -> None: first_object = PurePythonEnumerable( Point(0, 1), first := Point(1, 3), diff --git a/test/unit/pure_python/enumerable/intersect/test_intersect_by_method.py b/test/unit/pure_python/enumerable/intersect/test_intersect_by_method.py index b1d5841..8ef0650 100644 --- a/test/unit/pure_python/enumerable/intersect/test_intersect_by_method.py +++ b/test/unit/pure_python/enumerable/intersect/test_intersect_by_method.py @@ -19,31 +19,7 @@ def test_when_second_empty(self) -> None: assert res.source == () - def test_without_comparer(self) -> None: - first_object = PurePythonEnumerable( - first := Person("john doe", 12, Person("marray doe", 27)), - Person("jane doe", 10, Person("larry doe", 31)), - Person("james doe", 11, None), - second := Person("jacob doe", 17, Person("harry doe", 41)), - third := Person(" doe", 14, Person("jerry doe", 34)), - ) - second_object = PurePythonEnumerable( - Person("john doe", 12, Person("arry doe", 27)), - Person("jane doe", 10, Person("curry doe", 35)), - Person("jacob doe", 17, Person("harry doe", 41)), - Person(" doe", 14, Person("jerry doe", 34)), - ) - - res = first_object.intersect_by( - second_object, - lambda person: None - if person.parent is None - else person.parent.age, - ) - - assert res.source == (first, second, third) - - def test_with_comparer(self) -> None: + def test_intersect_by(self) -> None: first_object = PurePythonEnumerable( first := Point(5, 1), Point(3, 3), diff --git a/test/unit/pure_python/enumerable/intersect/test_intersect_method.py b/test/unit/pure_python/enumerable/intersect/test_intersect_method.py index 7613d62..5b99343 100644 --- a/test/unit/pure_python/enumerable/intersect/test_intersect_method.py +++ b/test/unit/pure_python/enumerable/intersect/test_intersect_method.py @@ -19,15 +19,7 @@ def test_when_second_empty(self) -> None: assert res.source == () - def test_without_comparer(self) -> None: - first_object = PurePythonEnumerable(*range(end := 7)) - second_object = PurePythonEnumerable(*range(start := 3, 9)) - - res = first_object.intersect(second_object) - - assert res.source == tuple(range(start, end)) - - def test_with_comparer(self) -> None: + def test_intersect(self) -> None: first_object = PurePythonEnumerable( first := Point(0, 1), Point(0, 3), diff --git a/test/unit/pure_python/enumerable/max/test_max_by_method.py b/test/unit/pure_python/enumerable/max/test_max_by_method.py index a9d5617..14c8f3f 100644 --- a/test/unit/pure_python/enumerable/max/test_max_by_method.py +++ b/test/unit/pure_python/enumerable/max/test_max_by_method.py @@ -20,7 +20,7 @@ def test_exc_raise_when_uncomparable(self) -> None: with pytest.raises(TypeError): obj.max_by(lambda person: person.parent) - def test_with_comparer(self) -> None: + def test_max_by(self) -> None: obj = PurePythonEnumerable( Person("jane doe", 12, Person("james doe", 34)), maximum := Person("john doe", 4, Person("jessie doe", 40)), @@ -33,16 +33,6 @@ def test_with_comparer(self) -> None: assert maximum is res - def test_without_comparer(self) -> None: - obj = PurePythonEnumerable( - maximum := Person("jane doe", 12, Person("james doe", 34)), - Person("john doe", 4, Person("jessie doe", 40)), - ) - - res = obj.max_by(lambda person: person.age) - - assert res is maximum - @staticmethod def age_comparer( first: Person | None, diff --git a/test/unit/pure_python/enumerable/max/test_max_method.py b/test/unit/pure_python/enumerable/max/test_max_method.py index 6e6574c..e7e8180 100644 --- a/test/unit/pure_python/enumerable/max/test_max_method.py +++ b/test/unit/pure_python/enumerable/max/test_max_method.py @@ -17,16 +17,9 @@ def test_exc_raise_when_uncomparable(self) -> None: with pytest.raises(TypeError): obj.max_() - def test_with_comparer(self) -> None: + def test_max(self) -> None: obj = PurePythonEnumerable(Point(4, 5), maximum := Point(6, 3)) res = obj.max_(comparer=lambda first, second: first.x > second.x) assert res is maximum - - def test_without_comparer(self) -> None: - obj = PurePythonEnumerable(6, 8, maximum := 10, 9, 7) - - res = obj.max_() - - assert res == maximum diff --git a/test/unit/pure_python/enumerable/min/test_min_by_method.py b/test/unit/pure_python/enumerable/min/test_min_by_method.py index 0c7973a..62462d7 100644 --- a/test/unit/pure_python/enumerable/min/test_min_by_method.py +++ b/test/unit/pure_python/enumerable/min/test_min_by_method.py @@ -20,7 +20,7 @@ def test_exc_raise_when_uncomparable(self) -> None: with pytest.raises(TypeError): obj.min_by(lambda person: person.parent) - def test_with_comparer(self) -> None: + def test_min_by(self) -> None: obj = PurePythonEnumerable( Person("john doe", 4, Person("jessie doe", 40)), minimum := Person("jane doe", 12, Person("james doe", 34)), @@ -33,16 +33,6 @@ def test_with_comparer(self) -> None: assert minimum is res - def test_without_comparer(self) -> None: - obj = PurePythonEnumerable( - Person("jane doe", 12, Person("james doe", 34)), - minimum := Person("john doe", 4, Person("jessie doe", 40)), - ) - - res = obj.min_by(lambda person: person.age) - - assert res is minimum - @staticmethod def age_comparer( first: Person | None, diff --git a/test/unit/pure_python/enumerable/min/test_min_method.py b/test/unit/pure_python/enumerable/min/test_min_method.py index 67a5006..b2c898f 100644 --- a/test/unit/pure_python/enumerable/min/test_min_method.py +++ b/test/unit/pure_python/enumerable/min/test_min_method.py @@ -17,16 +17,9 @@ def test_exc_raise_when_uncomparable(self) -> None: with pytest.raises(TypeError): obj.min_() - def test_with_comparer(self) -> None: + def test_min(self) -> None: obj = PurePythonEnumerable(Point(6, 3), minimum := Point(4, 5)) res = obj.min_(comparer=lambda first, second: first.x < second.x) assert res is minimum - - def test_without_comparer(self) -> None: - obj = PurePythonEnumerable(minimum := 6, 8, 10, 9, 7) - - res = obj.min_() - - assert res == minimum diff --git a/test/unit/pure_python/enumerable/union/test_union_by_method.py b/test/unit/pure_python/enumerable/union/test_union_by_method.py index adcf256..0945c94 100644 --- a/test/unit/pure_python/enumerable/union/test_union_by_method.py +++ b/test/unit/pure_python/enumerable/union/test_union_by_method.py @@ -3,31 +3,7 @@ class TestUnionByMethod: - def test_without_comparer(self) -> None: - first_object = PurePythonEnumerable( - *( - first_items := ( - Point(0, 1), - Point(0, 2), - Point(0, 3), - ) - ) - ) - second_object = PurePythonEnumerable( - *( - second_items := ( - Point(0, 4), - Point(0, 5), - Point(0, 6), - ) - ) - ) - - res = first_object.union_by(second_object, lambda point: point.y) - - assert res.source == first_items + second_items - - def test_with_comparer(self) -> None: + def test_union_by(self) -> None: first_object = PurePythonEnumerable( *( first_items := ( diff --git a/test/unit/pure_python/enumerable/union/test_union_method.py b/test/unit/pure_python/enumerable/union/test_union_method.py index 05b01cf..e1d7756 100644 --- a/test/unit/pure_python/enumerable/union/test_union_method.py +++ b/test/unit/pure_python/enumerable/union/test_union_method.py @@ -12,17 +12,7 @@ def test_exc_raise_when_unhashable(self) -> None: with pytest.raises(TypeError): first_object.union(second_object) - def test_without_comparer(self) -> None: - first_object = PurePythonEnumerable(*(first_items := tuple(range(3)))) - second_object = PurePythonEnumerable( - *(second_items := tuple(range(7, 10))) - ) - - res = first_object.union(second_object) - - assert res.source == first_items + second_items - - def test_with_comparer(self) -> None: + def test_union(self) -> None: first_object = PurePythonEnumerable(*(items := tuple(range(7)))) second_object = PurePythonEnumerable(*(-i for i in items)) From 34804594833f0774d7ef6059abf451e8ba5aefbf Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 14:04:05 +0330 Subject: [PATCH 10/12] restructure pp implementation, add group by impl --- .../__init__.py} | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) rename pyenumerable/implementations/{pure_python.py => pure_python/__init__.py} (94%) diff --git a/pyenumerable/implementations/pure_python.py b/pyenumerable/implementations/pure_python/__init__.py similarity index 94% rename from pyenumerable/implementations/pure_python.py rename to pyenumerable/implementations/pure_python/__init__.py index f25c229..0cb5026 100644 --- a/pyenumerable/implementations/pure_python.py +++ b/pyenumerable/implementations/pure_python/__init__.py @@ -735,8 +735,48 @@ def union_by[TKey]( out.append(outer) return PurePythonEnumerable(*out) + def group_by[TKey]( + self, + key_selector: Callable[[TSource], TKey], + /, + *, + comparer: Comparer[TKey] | None = None, + ) -> PurePythonEnumerable[PurePythonAssociable[TKey, TSource]]: + comparer_: Comparer[TKey] = ( + comparer if comparer is not None else lambda i, o: i == o + ) + keys: list[TKey] = [] + values: dict[int, list[TSource]] = {} + for item in self.source: + item_key = key_selector(item) + for index, k in enumerate(keys): + if comparer_(k, item_key): + values[index].append(item) + break + else: + keys.append(item_key) + values[len(keys) - 1] = [item] + return PurePythonEnumerable( + *(PurePythonAssociable(keys[kid], *v) for kid, v in values.items()) + ) + @staticmethod def _assume_not_empty(instance: PurePythonEnumerable[Any]) -> None: if len(instance.source) == 0: msg = "Enumerable (self) is empty" raise ValueError(msg) + + +class PurePythonAssociable[TKey, TSource](PurePythonEnumerable[TSource]): + def __init__( + self, + key: TKey, + *items: TSource, + from_iterable: Iterable[Iterable[TSource]] | None = None, + ) -> None: + self._key = key + super().__init__(*items, from_iterable=from_iterable) + + @property + def key(self) -> TKey: + return self._key From 49e33c7acf483f0a9e0e119b7fb2281a13c5a4d5 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 14:04:23 +0330 Subject: [PATCH 11/12] modify supports group by protocol; remove selector overloads --- pyenumerable/protocol/_supports_group_by.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pyenumerable/protocol/_supports_group_by.py b/pyenumerable/protocol/_supports_group_by.py index fd444d8..5b9cf69 100644 --- a/pyenumerable/protocol/_supports_group_by.py +++ b/pyenumerable/protocol/_supports_group_by.py @@ -9,25 +9,6 @@ class SupportsGroupBy[TSource](Protocol): - @overload - def group_by[TKey: Comparable, TElement]( - self, - key_selector: Callable[[TSource], TKey], - /, - *, - element_selector: Callable[[TSource], TElement], - ) -> "Enumerable[Associable[TKey, TElement]]": ... - - @overload - def group_by[TKey, TElement]( - self, - key_selector: Callable[[TSource], TKey], - /, - *, - element_selector: Callable[[TSource], TElement], - comparer: Comparer[TKey], - ) -> "Enumerable[Associable[TKey, TElement]]": ... - @overload def group_by[TKey: Comparable]( self, From efa2fb50ce19f29b10cb756ff02bf5b13126f725 Mon Sep 17 00:00:00 2001 From: AmirHossein Ahmadi Date: Fri, 21 Mar 2025 14:05:05 +0330 Subject: [PATCH 12/12] ruff format --- .../group_by/test_group_by_method.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/unit/pure_python/enumerable/group_by/test_group_by_method.py b/test/unit/pure_python/enumerable/group_by/test_group_by_method.py index 88f95d8..539911a 100644 --- a/test/unit/pure_python/enumerable/group_by/test_group_by_method.py +++ b/test/unit/pure_python/enumerable/group_by/test_group_by_method.py @@ -22,19 +22,19 @@ def test_group_by(self) -> None: first_group_index, second_group_index = 0, 1 assert len(res.source) == number_of_groups - assert len( - res.source[first_group_index].source - ) == number_of_first_group_members - assert len( - res.source[second_group_index].source - ) == number_of_second_group_members + assert ( + len(res.source[first_group_index].source) + == number_of_first_group_members + ) + assert ( + len(res.source[second_group_index].source) + == number_of_second_group_members + ) assert all( - p.y == first_group_key for p in res.source[ - first_group_index - ].source + p.y == first_group_key + for p in res.source[first_group_index].source ) assert all( - p.y == second_group_key for p in res.source[ - second_group_index - ].source + p.y == second_group_key + for p in res.source[second_group_index].source )