nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: getindata/kedro-kubeflow
Pull request #70 (2021-08-31 07:54:31)

Passing Kedro env to the steps
#### Description

Kedro environment is now included in the steps invocation (similarly like it's done in `kedro-airflow-k8s`), so users can have different configuration (in my case different catalog) for local vs kubeflow execution.

##### PR Checklist
- [x] Tests added
- [x] [Changelog](CHANGELOG.md) updated 



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea918f1..80755c6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 ## [Unreleased]
 
+-   Kedro environment used by `kedro kubeflow` invocation is passed to the steps
+
 ## [0.4.2] - 2021-08-19
 
 -   Improved Vertex scheduling: removal of stale schedules
diff --git a/kedro_kubeflow/generator.py b/kedro_kubeflow/generator.py
index f66811d..06f1928 100644
--- a/kedro_kubeflow/generator.py
+++ b/kedro_kubeflow/generator.py
@@ -138,6 +138,8 @@ class PipelineGenerator(object):
                     command=["kedro"],
                     arguments=[
                         "kubeflow",
+                        "--env",
+                        self.context.env,
                         "mlflow-start",
                         dsl.RUN_ID_PLACEHOLDER,
                     ],
@@ -176,6 +178,8 @@ class PipelineGenerator(object):
                     command=["kedro"],
                     arguments=[
                         "run",
+                        "--env",
+                        self.context.env,
                         "--params",
                         params,
                         "--pipeline",


Test patch:
diff --git a/tests/test_generator.py b/tests/test_generator.py
index 7d2d72f..57736be 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -149,6 +149,8 @@ class TestGenerator(unittest.TestCase):
         assert init_step.image == "unittest-image"
         assert init_step.args == [
             "kubeflow",
+            "--env",
+            "unittests",
             "mlflow-start",
             "{{workflow.uid}}",
         ]
@@ -201,6 +203,8 @@ class TestGenerator(unittest.TestCase):
             args = dsl_pipeline.ops[node_name].container.args
             assert args == [
                 "run",
+                "--env",
+                "unittests",
                 "--params",
                 "param1:{{pipelineparam:op=;name=param1}},"
                 "param2:{{pipelineparam:op=;name=param2}}",
@@ -312,6 +316,7 @@ class TestGenerator(unittest.TestCase):
             "obj",
             (object,),
             {
+                "env": "unittests",
                 "params": params,
                 "config_loader": config_loader,
                 "pipelines": {
Repository: quora/pyanalyze
Pull request #769 (2024-05-06 17:21:50)

Fix pos-only defaults in stubs


Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index 048533f..deb9563 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -2,6 +2,8 @@
 
 ## Unreleased
 
+- Fix handling of stub functions with positional-only parameters with
+  defaults (#769)
 - Recognize exhaustive pattern matching (#766)
 - Narrow the types of variables assigned within complex patterns (#766)
 - New error code `generator_return` is raised when a generator does not
diff --git a/pyanalyze/typeshed.py b/pyanalyze/typeshed.py
index 6333d67..23804a7 100644
--- a/pyanalyze/typeshed.py
+++ b/pyanalyze/typeshed.py
@@ -914,7 +914,7 @@ class TypeshedFinder:
         if num_pos_only_defaults > 0:
             num_without_default = num_pos_only_args - num_pos_only_defaults
             pos_only_defaults = [None] * num_without_default + defaults[
-                num_pos_only_defaults:
+                :num_pos_only_defaults
             ]
             defaults = defaults[num_pos_only_defaults:]
         else:


Test patch:
diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/posonly.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/posonly.pyi
index 9359755..b607eb1 100644
--- a/pyanalyze/stubs/_pyanalyze_tests-stubs/posonly.pyi
+++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/posonly.pyi
@@ -1,3 +1,4 @@
 def f(x: int, /, y: int, z: int = ...) -> None: ...
 def g(x: int = ..., /, y: int = ...) -> None: ...
 def h(x: int, /, y: int = ..., z: int = ...) -> None: ...
+def two_pos_only(x: int, y: str = ..., /) -> None: ...
diff --git a/pyanalyze/test_typeshed.py b/pyanalyze/test_typeshed.py
index e25587d..017e89f 100644
--- a/pyanalyze/test_typeshed.py
+++ b/pyanalyze/test_typeshed.py
@@ -248,7 +248,7 @@ class TestBundledStubs(TestNameCheckVisitorBase):
     @assert_passes()
     def test_pos_only(self):
         def capybara():
-            from _pyanalyze_tests.posonly import f, g, h
+            from _pyanalyze_tests.posonly import f, g, h, two_pos_only
 
             f(1, 2)
             f(1, 2, 3)
@@ -268,6 +268,11 @@ class TestBundledStubs(TestNameCheckVisitorBase):
             h(1, y=2)
             h(1, 2, 3)
 
+            two_pos_only(1, "x")
+            two_pos_only(1)
+            two_pos_only(x=1)  # E: incompatible_call
+            two_pos_only(1, y="x")  # E: incompatible_call
+
     def test_typeddict(self):
         tsf = TypeshedFinder.make(Checker(), TEST_OPTIONS, verbose=True)
         mod = "_pyanalyze_tests.typeddict"
Repository: quora/pyanalyze
Pull request #777 (2024-06-03 17:54:24)

Fix crash on ParamSpec with Any callable


Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index f49bc8c..a81531e 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -3,7 +3,7 @@
 ## Unreleased
 
 - Fix various issues with Python 3.13 and 3.14 support (#773)
-- Improve `ParamSpec` support (#772)
+- Improve `ParamSpec` support (#772, #777)
 - Fix handling of stub functions with positional-only parameters with
   defaults (#769)
 - Recognize exhaustive pattern matching (#766)
diff --git a/pyanalyze/signature.py b/pyanalyze/signature.py
index 04ab3b0..d41c866 100644
--- a/pyanalyze/signature.py
+++ b/pyanalyze/signature.py
@@ -1756,6 +1756,11 @@ class Signature:
                     elif isinstance(new_val, AnyValue):
                         new_param = SigParameter(param.name, ParameterKind.ELLIPSIS)
                         params.append((param.name, new_param))
+                    elif isinstance(new_val, CallValue):
+                        new_param = SigParameter(
+                            param.name, ParameterKind.PARAM_SPEC, annotation=new_val
+                        )
+                        params.append((param.name, new_param))
                     else:
                         assert isinstance(new_val, CallableValue), new_val
                         assert isinstance(new_val.signature, Signature), new_val


Test patch:
diff --git a/pyanalyze/test_annotations.py b/pyanalyze/test_annotations.py
index cc392c8..cc88d9f 100644
--- a/pyanalyze/test_annotations.py
+++ b/pyanalyze/test_annotations.py
@@ -1849,6 +1849,45 @@ class TestParamSpec(TestNameCheckVisitorBase):
             assert_type(apply(sample, 1), str)
             apply(sample, "x")  # E: incompatible_call
 
+    @assert_passes()
+    def test_apply_bound_method(self):
+        from typing import Callable, TypeVar
+
+        from typing_extensions import ParamSpec, assert_type
+
+        P = ParamSpec("P")
+        T = TypeVar("T")
+
+        def apply(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
+            return func(*args, **kwargs)
+
+        class X:
+            def sample(self, x: int) -> str:
+                return str(x)
+
+        def capybara(x: X) -> None:
+            assert_type(apply(x.sample, 1), str)
+            apply(x.sample, "x")  # E: incompatible_call
+
+    @assert_passes()
+    def test_apply_any(self):
+        from typing import Any, Callable, TypeVar
+
+        from typing_extensions import ParamSpec, assert_type
+
+        P = ParamSpec("P")
+        T = TypeVar("T")
+
+        def apply(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
+            return func(*args, **kwargs)
+
+        def capybara(x, args, kwargs) -> None:
+            assert_type(apply(x, 1), Any)
+            assert_type(apply(x.foo, 1), Any)
+            assert_type(apply(x), Any)
+            assert_type(apply(x, y=3), Any)
+            assert_type(apply(x, *args, **kwargs), Any)
+
     @assert_passes()
     def test_param_spec_errors(self):
         from typing import Callable, TypeVar
Repository: quora/pyanalyze
Pull request #788 (2024-07-11 18:48:57)

Improve representation of KnownValue of type, function, module


Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index a168ea1..aec5478 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -2,6 +2,8 @@
 
 ## Unreleased
 
+- Improve representation of known module, function, and type objects
+  in error messages (#788)
 - Add a mechanism to allow overriding the global variables in an
   analyzed module. Use this mechanism to set the type of
   `qcore.testing.Anything` to `Any`. (#786)
diff --git a/pyanalyze/value.py b/pyanalyze/value.py
index f0908fa..46e457f 100644
--- a/pyanalyze/value.py
+++ b/pyanalyze/value.py
@@ -26,7 +26,7 @@ import textwrap
 from collections import deque
 from dataclasses import InitVar, dataclass, field
 from itertools import chain
-from types import FunctionType
+from types import FunctionType, ModuleType
 from typing import (
     Any,
     Callable,
@@ -583,6 +583,12 @@ class KnownValue(Value):
     def __str__(self) -> str:
         if self.val is None:
             return "None"
+        elif isinstance(self.val, ModuleType):
+            return f"module {self.val.__name__!r}"
+        elif isinstance(self.val, FunctionType):
+            return f"function {get_fully_qualified_name(self.val)!r}"
+        elif isinstance(self.val, type):
+            return f"type {get_fully_qualified_name(self.val)!r}"
         else:
             return f"Literal[{self.val!r}]"
 
@@ -601,6 +607,18 @@ class KnownValue(Value):
         return val.simplify()
 
 
+def get_fully_qualified_name(obj: Union[FunctionType, type]) -> str:
+    mod = getattr(obj, "__module__", None)
+    if mod == "builtins":
+        mod = None
+    name = getattr(obj, "__qualname__", None)
+    if name is None:
+        return repr(obj)
+    if mod:
+        return f"{mod}.{name}"
+    return name
+
+
 @dataclass(frozen=True)
 class KnownValueWithTypeVars(KnownValue):
     """Subclass of KnownValue that records a TypeVar substitution."""


Test patch:
diff --git a/pyanalyze/test_value.py b/pyanalyze/test_value.py
index a9476a0..f70c8c4 100644
--- a/pyanalyze/test_value.py
+++ b/pyanalyze/test_value.py
@@ -62,8 +62,16 @@ def test_any_value() -> None:
 def test_known_value() -> None:
     val = KnownValue(3)
     assert 3 == val.val
-    assert "Literal[3]" == str(val)
-    assert "Literal['']" == str(KnownValue(""))
+    assert str(val) == "Literal[3]"
+    assert str(KnownValue("")) == "Literal['']"
+    assert str(KnownValue(None)) == "None"
+    assert str(KnownValue(str)) == "type 'str'"
+    assert str(KnownValue(KnownValue)) == "type 'pyanalyze.value.KnownValue'"
+    assert (
+        str(KnownValue(test_known_value))
+        == "function 'pyanalyze.test_value.test_known_value'"
+    )
+    assert str(KnownValue(ast)) == "module 'ast'"
     assert val.is_type(int)
     assert not val.is_type(str)
Repository: quora/pyanalyze
Pull request #797 (2024-07-16 01:34:25)

Fix crash on ParamSpec


Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index 97f9494..620368e 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -2,6 +2,7 @@
 
 ## Unreleased
 
+- Fix crash on some occurrences of `ParamSpec` in stub files (#797)
 - Fix crash when Pydantic 1 is installed (#793)
 - Fix error on use of TypeVar defaults in stubs (PEP 696). The
   default is still ignored, but now the TypeVar is treated as
diff --git a/pyanalyze/annotations.py b/pyanalyze/annotations.py
index 09a7c5a..6e72fcb 100644
--- a/pyanalyze/annotations.py
+++ b/pyanalyze/annotations.py
@@ -557,12 +557,14 @@ def _type_from_runtime(
 def make_type_var_value(tv: TypeVarLike, ctx: Context) -> TypeVarValue:
     if (
         isinstance(tv, (TypeVar, typing_extensions.TypeVar))
-        and tv.__bound__ is not None
+        and getattr(tv, "__bound__", None) is not None
     ):
         bound = _type_from_runtime(tv.__bound__, ctx)
     else:
         bound = None
-    if isinstance(tv, (TypeVar, typing_extensions.TypeVar)) and tv.__constraints__:
+    if isinstance(tv, (TypeVar, typing_extensions.TypeVar)) and getattr(
+        tv, "__constraints__", ()
+    ):
         constraints = tuple(
             _type_from_runtime(constraint, ctx) for constraint in tv.__constraints__
         )
@@ -1083,7 +1085,7 @@ class _Visitor(ast.NodeVisitor):
                     else:
                         return None
             return KnownValue(func.val(*args, **kwargs))
-        elif func.val == TypeVar:
+        elif is_typing_name(func.val, "TypeVar"):
             arg_values = [self.visit(arg) for arg in node.args]
             kwarg_values = [(kw.arg, self.visit(kw.value)) for kw in node.keywords]
             if not arg_values:


Test patch:
diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/paramspec.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/paramspec.pyi
new file mode 100644
index 0000000..2027ba1
--- /dev/null
+++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/paramspec.pyi
@@ -0,0 +1,7 @@
+from typing_extensions import Callable, ParamSpec, TypeVar
+
+T = TypeVar("T")
+P = ParamSpec("P")
+
+def f(x: T) -> T: ...
+def g(x: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: ...
diff --git a/pyanalyze/test_typeshed.py b/pyanalyze/test_typeshed.py
index a6d4efe..041342e 100644
--- a/pyanalyze/test_typeshed.py
+++ b/pyanalyze/test_typeshed.py
@@ -281,6 +281,19 @@ class TestBundledStubs(TestNameCheckVisitorBase):
 
             assert_type(f(x), int)
 
+    @assert_passes()
+    def test_typing_extensions_paramspec(self):
+        def some_func(x: int) -> str:
+            return str(x)
+
+        def capybara(x: int):
+            from _pyanalyze_tests.paramspec import f, g
+            from typing_extensions import assert_type
+
+            assert_type(f(x), int)
+            assert_type(g(some_func, x), str)
+            g(some_func, "not an int")  # TODO should error
+
     def test_typeddict(self):
         tsf = TypeshedFinder.make(Checker(), TEST_OPTIONS, verbose=True)
         mod = "_pyanalyze_tests.typeddict"
Repository: quora/pyanalyze
Pull request #800 (2024-07-22 16:52:24)

Flag unused iterators


Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index 620368e..9758c61 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -2,6 +2,7 @@
 
 ## Unreleased
 
+- Flag use of generators that are immediately discarded (#800)
 - Fix crash on some occurrences of `ParamSpec` in stub files (#797)
 - Fix crash when Pydantic 1 is installed (#793)
 - Fix error on use of TypeVar defaults in stubs (PEP 696). The
diff --git a/pyanalyze/error_code.py b/pyanalyze/error_code.py
index f64ef5f..f3d08aa 100644
--- a/pyanalyze/error_code.py
+++ b/pyanalyze/error_code.py
@@ -169,6 +169,7 @@ ErrorCode = ErrorRegistry(
         Error("readonly_typeddict", "TypedDict is read-only"),
         Error("generator_return", "Generator must return an iterable"),
         Error("unsafe_comparison", "Non-overlapping equality checks"),
+        Error("must_use", "Value cannot be discarded"),
     ]
 )
 
diff --git a/pyanalyze/name_check_visitor.py b/pyanalyze/name_check_visitor.py
index 1b7d7b7..b9e3840 100644
--- a/pyanalyze/name_check_visitor.py
+++ b/pyanalyze/name_check_visitor.py
@@ -4658,6 +4658,14 @@ class NameCheckVisitor(node_visitor.ReplacingNodeVisitor):
             self._show_error_if_checking(
                 node, error_code=ErrorCode.missing_await, replacement=replacement
             )
+        elif value.is_type(collections.abc.Generator) or value.is_type(
+            collections.abc.AsyncGenerator
+        ):
+            self._show_error_if_checking(
+                node,
+                f"Must use {value} (for example, by iterating over it)",
+                error_code=ErrorCode.must_use,
+            )
         return value
 
     # Assignments


Test patch:
diff --git a/pyanalyze/test_name_check_visitor.py b/pyanalyze/test_name_check_visitor.py
index c74ed2b..77d466c 100644
--- a/pyanalyze/test_name_check_visitor.py
+++ b/pyanalyze/test_name_check_visitor.py
@@ -2257,3 +2257,27 @@ class TestContextManagerWithSuppression(TestNameCheckVisitorBase):
             async with async_empty_contextlib_manager():
                 a = 3
             assert_is_value(a, KnownValue(3))
+
+
+class TestMustUse(TestNameCheckVisitorBase):
+    @assert_passes()
+    def test_generator(self):
+        from typing import Generator
+
+        def gen() -> Generator[int, None, None]:
+            yield 1
+            yield 2
+
+        def capybara() -> None:
+            gen()  # E: must_use
+
+    @assert_passes()
+    def test_async_generator(self):
+        from typing import AsyncGenerator
+
+        async def gen() -> AsyncGenerator[int, None]:
+            yield 1
+            yield 2
+
+        def capybara() -> None:
+            gen()  # E: must_use