diff --git a/libs/core/langchain_core/messages/utils.py b/libs/core/langchain_core/messages/utils.py index 5331b1040f5..5fc86222b24 100644 --- a/libs/core/langchain_core/messages/utils.py +++ b/libs/core/langchain_core/messages/utils.py @@ -504,7 +504,7 @@ def filter_messages( ) ] - msg = msg.model_copy( + msg = msg.model_copy( # noqa: PLW2901 update={"tool_calls": tool_calls, "content": content} ) elif ( diff --git a/libs/core/langchain_core/output_parsers/json.py b/libs/core/langchain_core/output_parsers/json.py index 18c1257a9ad..642387e7a12 100644 --- a/libs/core/langchain_core/output_parsers/json.py +++ b/libs/core/langchain_core/output_parsers/json.py @@ -125,5 +125,11 @@ class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]): # For backwards compatibility SimpleJsonOutputParser = JsonOutputParser -parse_partial_json = parse_partial_json -parse_and_check_json_markdown = parse_and_check_json_markdown + + +__all__ = [ + "JsonOutputParser", + "SimpleJsonOutputParser", # For backwards compatibility + "parse_partial_json", # For backwards compatibility + "parse_and_check_json_markdown", # For backwards compatibility +] diff --git a/libs/core/langchain_core/output_parsers/list.py b/libs/core/langchain_core/output_parsers/list.py index 6977079f5ae..8461d08f7e4 100644 --- a/libs/core/langchain_core/output_parsers/list.py +++ b/libs/core/langchain_core/output_parsers/list.py @@ -73,9 +73,10 @@ class ListOutputParser(BaseTransformOutputParser[list[str]]): chunk_content = chunk.content if not isinstance(chunk_content, str): continue - chunk = chunk_content - # add current chunk to buffer - buffer += chunk + buffer += chunk_content + else: + # add current chunk to buffer + buffer += chunk # parse buffer into a list of parts try: done_idx = 0 @@ -105,9 +106,10 @@ class ListOutputParser(BaseTransformOutputParser[list[str]]): chunk_content = chunk.content if not isinstance(chunk_content, str): continue - chunk = chunk_content - # add current chunk to buffer - buffer += chunk + buffer += chunk_content + else: + # add current chunk to buffer + buffer += chunk # parse buffer into a list of parts try: done_idx = 0 diff --git a/libs/core/langchain_core/tracers/evaluation.py b/libs/core/langchain_core/tracers/evaluation.py index 0a918cd2e9d..057b8f4565f 100644 --- a/libs/core/langchain_core/tracers/evaluation.py +++ b/libs/core/langchain_core/tracers/evaluation.py @@ -29,7 +29,6 @@ _TRACERS: weakref.WeakSet[EvaluatorCallbackHandler] = weakref.WeakSet() def wait_for_all_evaluators() -> None: """Wait for all tracers to finish.""" - global _TRACERS for tracer in list(_TRACERS): if tracer is not None: tracer.wait_for_futures() @@ -100,7 +99,6 @@ class EvaluatorCallbackHandler(BaseTracer): self.project_name = project_name self.logged_eval_results: dict[tuple[str, str], list[EvaluationResult]] = {} self.lock = threading.Lock() - global _TRACERS _TRACERS.add(self) def _evaluate_in_project(self, run: Run, evaluator: langsmith.RunEvaluator) -> None: diff --git a/libs/core/langchain_core/tracers/langchain.py b/libs/core/langchain_core/tracers/langchain.py index 9fdc76d9436..e489ab283e4 100644 --- a/libs/core/langchain_core/tracers/langchain.py +++ b/libs/core/langchain_core/tracers/langchain.py @@ -41,7 +41,6 @@ def log_error_once(method: str, exception: Exception) -> None: method: The method that raised the exception. exception: The exception that was raised. """ - global _LOGGED if (method, type(exception)) in _LOGGED: return _LOGGED.add((method, type(exception))) @@ -61,7 +60,7 @@ def get_client() -> Client: def _get_executor() -> ThreadPoolExecutor: """Get the executor.""" - global _EXECUTOR + global _EXECUTOR # noqa: PLW0603 if _EXECUTOR is None: _EXECUTOR = ThreadPoolExecutor() return _EXECUTOR diff --git a/libs/core/langchain_core/utils/_merge.py b/libs/core/langchain_core/utils/_merge.py index be8f8293874..9e86777eff2 100644 --- a/libs/core/langchain_core/utils/_merge.py +++ b/libs/core/langchain_core/utils/_merge.py @@ -96,9 +96,12 @@ def merge_lists(left: Optional[list], *others: Optional[list]) -> Optional[list] if to_merge: # TODO: Remove this once merge_dict is updated with special # handling for 'type'. - if "type" in e: - e = {k: v for k, v in e.items() if k != "type"} - merged[to_merge[0]] = merge_dicts(merged[to_merge[0]], e) + new_e = ( + {k: v for k, v in e.items() if k != "type"} + if "type" in e + else e + ) + merged[to_merge[0]] = merge_dicts(merged[to_merge[0]], new_e) else: merged.append(e) else: diff --git a/libs/core/langchain_core/utils/json.py b/libs/core/langchain_core/utils/json.py index 472ef94b7a3..28154c62b9f 100644 --- a/libs/core/langchain_core/utils/json.py +++ b/libs/core/langchain_core/utils/json.py @@ -64,11 +64,14 @@ def parse_partial_json(s: str, *, strict: bool = False) -> Any: # Process each character in the string one at a time. for char in s: + new_char = char if is_inside_string: if char == '"' and not escaped: is_inside_string = False elif char == "\n" and not escaped: - char = "\\n" # Replace the newline character with the escape sequence. + new_char = ( + "\\n" # Replace the newline character with the escape sequence. + ) elif char == "\\": escaped = not escaped else: @@ -89,7 +92,7 @@ def parse_partial_json(s: str, *, strict: bool = False) -> Any: return None # Append the processed character to the new string. - new_chars.append(char) + new_chars.append(new_char) # If we're still inside a string at the end of processing, # we need to close the string. diff --git a/libs/core/langchain_core/utils/mustache.py b/libs/core/langchain_core/utils/mustache.py index 4c42c47fed9..3a95e06bb08 100644 --- a/libs/core/langchain_core/utils/mustache.py +++ b/libs/core/langchain_core/utils/mustache.py @@ -125,8 +125,6 @@ def parse_tag(template: str, l_del: str, r_del: str) -> tuple[tuple[str, str], s ChevronError: If the tag is unclosed. ChevronError: If the set delimiter tag is unclosed. """ - global _CURRENT_LINE, _LAST_TAG_LINE - tag_types = { "!": "comment", "#": "section", @@ -352,32 +350,33 @@ def _get_key( if scope in (0, False): return scope + resolved_scope = scope # For every dot separated key for child in key.split("."): # Return an empty string if falsy, with two exceptions # 0 should return 0, and False should return False - if scope in (0, False): - return scope + if resolved_scope in (0, False): + return resolved_scope # Move into the scope try: # Try subscripting (Normal dictionaries) - scope = cast(dict[str, Any], scope)[child] + resolved_scope = cast(dict[str, Any], resolved_scope)[child] except (TypeError, AttributeError): try: - scope = getattr(scope, child) + resolved_scope = getattr(resolved_scope, child) except (TypeError, AttributeError): # Try as a list - scope = scope[int(child)] # type: ignore + resolved_scope = resolved_scope[int(child)] # type: ignore try: # This allows for custom falsy data types # https://github.com/noahmorrison/chevron/issues/35 - if scope._CHEVRON_return_scope_when_falsy: # type: ignore - return scope + if resolved_scope._CHEVRON_return_scope_when_falsy: # type: ignore + return resolved_scope except AttributeError: - if scope in (0, False): - return scope - return scope or "" + if resolved_scope in (0, False): + return resolved_scope + return resolved_scope or "" except (AttributeError, KeyError, IndexError, ValueError): # We couldn't find the key in the current scope # We'll try again on the next pass diff --git a/libs/core/pyproject.toml b/libs/core/pyproject.toml index 5e0a3e9ef26..f7350e0e165 100644 --- a/libs/core/pyproject.toml +++ b/libs/core/pyproject.toml @@ -77,7 +77,7 @@ target-version = "py39" [tool.ruff.lint] -select = [ "ANN", "ASYNC", "B", "C4", "COM", "DJ", "E", "EM", "EXE", "F", "FLY", "FURB", "I", "ICN", "INT", "LOG", "N", "NPY", "PD", "PIE", "PTH", "Q", "RSE", "S", "SIM", "SLOT", "T10", "T201", "TC", "TID", "TRY", "UP", "W", "YTT",] +select = [ "ANN", "ASYNC", "B", "C4", "COM", "DJ", "E", "EM", "EXE", "F", "FLY", "FURB", "I", "ICN", "INT", "LOG", "N", "NPY", "PD", "PIE", "PLW", "PTH", "Q", "RSE", "S", "SIM", "SLOT", "T10", "T201", "TC", "TID", "TRY", "UP", "W", "YTT",] ignore = [ "ANN401", "COM812", "UP007", "S110", "S112", "TC001", "TC002", "TC003"] flake8-type-checking.runtime-evaluated-base-classes = ["pydantic.BaseModel","langchain_core.load.serializable.Serializable","langchain_core.runnables.base.RunnableSerializable"] flake8-annotations.allow-star-arg-any = true @@ -96,6 +96,7 @@ filterwarnings = [ "ignore::langchain_core._api.beta_decorator.LangChainBetaWarn classmethod-decorators = [ "classmethod", "langchain_core.utils.pydantic.pre_init", "pydantic.field_validator", "pydantic.v1.root_validator",] [tool.ruff.lint.per-file-ignores] +"langchain_core/utils/mustache.py" = [ "PLW0603",] "tests/unit_tests/prompts/test_chat.py" = [ "E501",] "tests/unit_tests/runnables/test_runnable.py" = [ "E501",] "tests/unit_tests/runnables/test_graph.py" = [ "E501",] diff --git a/libs/core/tests/unit_tests/test_imports.py b/libs/core/tests/unit_tests/test_imports.py index 64f93aa606c..30e320ee68e 100644 --- a/libs/core/tests/unit_tests/test_imports.py +++ b/libs/core/tests/unit_tests/test_imports.py @@ -22,7 +22,7 @@ def try_to_import(module_name: str) -> tuple[int, str]: getattr(module, cls_) result = subprocess.run( - ["python", "-c", f"import langchain_core.{module_name}"], + ["python", "-c", f"import langchain_core.{module_name}"], check=True ) return result.returncode, module_name