Skip to content

Conversation

@jovicdev97
Copy link

@jovicdev97 jovicdev97 commented Nov 14, 2025

fixes #10512

Root Cause:
similarity_search() method was not properly passing the namespace parameter to the underlying Pinecone query, resulting in searches against the wrong namespace and returning zero results.

Solution:

  • Modified search_documents() to query Pinecone directly using the native Pinecone client
  • Explicitly pass namespace parameter to index.query() when set
  • Maintain compatibility with existing Float32Embeddings wrapper
  • Preserve all existing functionality while ensuring namespace is respected

Testing:

  • Added comprehensive unit tests for namespace handling
  • Tests verify namespace is passed correctly in queries
  • Tests cover edge cases: with/without namespace, custom text_key, empty queries

implemented coderabbits suggestions

Summary by CodeRabbit

  • Tests

    • Added comprehensive unit tests for Pinecone vector store component, covering initialization, search operations, namespace handling, and error scenarios.
  • Refactor

    • Updated Pinecone integration implementation to optimize query handling and result processing.

…o results in Langflow 1.6.5 when using namespaces.

**Root Cause:**
 `similarity_search()` method was not properly passing the namespace parameter to the underlying Pinecone query, resulting in searches against the wrong namespace and returning zero results.

**Solution:**
- Modified `search_documents()` to query Pinecone directly using the native Pinecone client
- Explicitly pass namespace parameter to `index.query()` when set
- Maintain compatibility with existing Float32Embeddings wrapper
- Preserve all existing functionality while ensuring namespace is respected

**Testing:**
- Added comprehensive unit tests for namespace handling
- Tests verify namespace is passed correctly in queries
- Tests cover edge cases: with/without namespace, custom text_key, empty queries
@github-actions github-actions bot added the community Pull Request from an external contributor label Nov 14, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR addresses a Pinecone vector store regression by replacing the langchain-pinecone PineconeVectorStore integration with direct Pinecone client queries. The implementation wraps embeddings with Float32Embeddings, initializes the Pinecone client directly, embeds the query, and manually constructs Documents from results. Comprehensive unit tests validate initialization, namespace handling, custom metadata keys, and error scenarios.

Changes

Cohort / File(s) Summary
Test Suite
src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py
New unit test module covering initialization with OpenAI embeddings, namespace parameter propagation, configurable text\_key for metadata extraction, empty query handling, error handling for API and embedding failures, and robust metadata handling including missing or None values.
Implementation
src/lfx/src/lfx/components/pinecone/pinecone.py
Refactored search\_documents method to query Pinecone directly instead of delegating to PineconeVectorStore; now wraps embeddings with Float32Embeddings, computes query vector, queries index with top\_k and optional namespace, and converts matches to Documents using configured text\_key.

Sequence Diagram

sequenceDiagram
    participant User
    participant Component as PineconeComponent
    participant Float32 as Float32Embeddings
    participant Pinecone as Pinecone Client
    participant Index as Pinecone Index
    
    User->>Component: search_documents(query)
    Component->>Float32: wrap embedding
    Component->>Pinecone: initialize with API key
    Component->>Float32: embed_query(query)
    Float32-->>Component: query_vector
    Component->>Index: query(vector, top_k, namespace, include_metadata)
    Index-->>Component: matches with metadata
    
    rect rgb(200, 220, 250)
    Note over Component: Convert matches to Documents
    Component->>Component: extract text from metadata[text_key]
    Component->>Component: create Document(page_content, metadata)
    end
    
    Component-->>User: list[Data]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Direct Pinecone API integration: Verify correct parameter passing (namespace, top\_k, include\_metadata) and result handling
  • Float32Embeddings wrapper usage: Confirm proper instantiation and invocation via embed\_query
  • Metadata extraction logic: Ensure text\_key configuration is applied correctly and handles missing/None metadata gracefully
  • Error handling: Validate that API errors and embedding errors are caught and re-raised as ValueError with consistent messaging
  • Test comprehensiveness: Review that test mocking strategy adequately covers all code paths including namespace present/absent and metadata edge cases

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Test Quality And Coverage ⚠️ Warning Test suite has incorrect mocking targets and lacks parametrization, failing to properly validate returned Data objects and coverage. Fix patch targets from 'lfx.components.pinecone.pinecone.Pinecone' to 'pinecone.Pinecone', add parametrized tests, enhance assertions to validate Data object content, test build() method, and add trailing newline.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the issue being fixed (#10512) and describes the main problem (Pinecone returning zero results), accurately reflecting the primary change in the PR.
Linked Issues check ✅ Passed The PR implementation directly addresses all key objectives from #10512: diagnoses the namespace parameter issue, implements direct Pinecone client querying as a workaround, preserves Float32Embeddings compatibility, adds comprehensive unit tests covering namespace handling and edge cases.
Out of Scope Changes check ✅ Passed All changes are focused on fixing the Pinecone vector store namespace parameter bug and testing the fix; no unrelated or out-of-scope modifications are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Test Coverage For New Implementations ✅ Passed Test file follows naming conventions and covers all major functionality changes including namespace parameter handling, direct Pinecone querying, metadata extraction, error handling, and Float32Embeddings wrapper usage.
Test File Naming And Structure ✅ Passed Test file follows pytest conventions with correct test_*.py naming and is properly organized in the backend tests directory structure with comprehensive test coverage.
Excessive Mock Usage Warning ✅ Passed Test file uses appropriately-scoped external dependency mocks (~2.3 per test) with reasonable setup-to-assertion ratio. Mocks target Pinecone API, embeddings, and external services that genuinely require mocking. Tests verify both mock interactions and actual component behavior.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jovicdev97 jovicdev97 changed the title fixes issue #10512 where Pinecone vector store returns zero results … fix(pinecone): issue #10512 Pinecone vector store returns zero results Nov 14, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 14, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 14, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/lfx/src/lfx/components/pinecone/pinecone.py (2)

94-138: search_documents logic looks correct; adjust inner imports and consider status on empty queries

  • The new flow (Float32Embeddings → Pinecone client → conditional namespace in query_params) correctly addresses the namespace regression and keeps tests’ expectations for error handling intact.
  • The inner import block is triggering Ruff I001; swap the two lines so they are alphabetically ordered by module path:
-            from pinecone import Pinecone
-            from langchain_core.documents import Document
+            from langchain_core.documents import Document
+            from pinecone import Pinecone
  • Minor behavioral note: when search_query is empty you return [] early, so self.status is left unchanged. If callers rely on self.status reflecting “last search”, you may want to explicitly reset it to [] before returning; otherwise current behavior is acceptable.

145-165: Float32Embeddings implementation is fine; add newline at EOF

  • _force_float32 correctly normalizes any numeric input to a Python float via np.float32, which is consistent with the wrapper’s intent.
  • Ruff reports W292 No newline at end of file; add a trailing newline after this return to satisfy the linter:
-        return float(np.float32(value))
+        return float(np.float32(value))
+
src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py (2)

1-41: Minor cleanup: redundant OPENAI API key handling in default_kwargs

get_openai_api_key() already calls pytest.skip when OPENAI_API_KEY is not set, so the surrounding try/except ValueError and extra pytest.skip are effectively dead code:

try:
    api_key = get_openai_api_key()
except ValueError:
    pytest.skip("OPENAI_API_KEY is not set")

You can simplify this fixture to just:

api_key = get_openai_api_key()

Behavior is unchanged, and the intent is clearer.


352-352: Fix Ruff W292: add newline at end of test file

Ruff reports W292 No newline at end of file here. Add a trailing newline after the last assertion to satisfy the linter and unblock the style check.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1d005c and 5e6cf75.

📒 Files selected for processing (2)
  • src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py (1 hunks)
  • src/lfx/src/lfx/components/pinecone/pinecone.py (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-05T22:51:27.961Z
Learnt from: edwinjosechittilappilly
Repo: langflow-ai/langflow PR: 0
File: :0-0
Timestamp: 2025-08-05T22:51:27.961Z
Learning: The TestComposioComponentAuth test in src/backend/tests/unit/components/bundles/composio/test_base_composio.py demonstrates proper integration testing patterns for external API components, including real API calls with mocking for OAuth completion, comprehensive resource cleanup, and proper environment variable handling with pytest.skip() fallbacks.

Applied to files:

  • src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py
🧬 Code graph analysis (2)
src/lfx/src/lfx/components/pinecone/pinecone.py (1)
src/lfx/src/lfx/field_typing/constants.py (1)
  • Document (43-44)
src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py (4)
src/lfx/src/lfx/components/pinecone/pinecone.py (3)
  • PineconeVectorStoreComponent (10-142)
  • embed_query (157-161)
  • search_documents (94-142)
src/lfx/src/lfx/schema/data.py (1)
  • Data (26-288)
src/backend/tests/base.py (2)
  • ComponentTestBaseWithoutClient (166-167)
  • VersionComponentMapping (15-18)
src/backend/tests/api_keys.py (1)
  • get_openai_api_key (33-37)
🪛 GitHub Actions: Ruff Style Check
src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py

[error] 352-352: ruff check failed: W292 No newline at end of file.

🪛 GitHub Check: Ruff Style Check (3.13)
src/lfx/src/lfx/components/pinecone/pinecone.py

[failure] 100-101: Ruff (I001)
src/lfx/src/lfx/components/pinecone/pinecone.py:100:13: I001 Import block is un-sorted or un-formatted


[failure] 165-165: Ruff (W292)
src/lfx/src/lfx/components/pinecone/pinecone.py:165:40: W292 No newline at end of file

src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py

[failure] 352-352: Ruff (W292)
src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py:352:41: W292 No newline at end of file

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Lint Backend / Run Mypy (3.10)
  • GitHub Check: Lint Backend / Run Mypy (3.12)
  • GitHub Check: Lint Backend / Run Mypy (3.11)
  • GitHub Check: Test Docker Images / Test docker images
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
  • GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
  • GitHub Check: Run Backend Tests / LFX Tests - Python 3.10
  • GitHub Check: Test Starter Templates
  • GitHub Check: Update Component Index

Comment on lines +43 to +351
def test_search_documents_with_namespace(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that search_documents properly passes namespace parameter.

This test verifies the fix for issue #10512 where namespace wasn't being
properly passed to Pinecone queries, resulting in zero results.
"""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results
mock_match = Mock()
mock_match.metadata = {"text": "test result", "source": "test"}
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
results = component.search_documents()

# Verify Pinecone was called correctly
mock_pinecone.Index.assert_called_once_with("test-index")
mock_index.query.assert_called_once()

# Verify namespace was passed
call_kwargs = mock_index.query.call_args[1]
assert "namespace" in call_kwargs
assert call_kwargs["namespace"] == "test-namespace"
assert call_kwargs["top_k"] == 4
assert call_kwargs["include_metadata"] is True

# Verify results are returned
assert len(results) == 1
assert isinstance(results[0], Data)
assert results[0].text == "test result"

def test_search_documents_without_namespace(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that search_documents works without namespace."""
# Remove namespace from kwargs
default_kwargs.pop("namespace", None)
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results
mock_match = Mock()
mock_match.metadata = {"text": "test result"}
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
results = component.search_documents()

# Verify namespace was NOT passed when not set
call_kwargs = mock_index.query.call_args[1]
assert "namespace" not in call_kwargs

# Verify results are still returned
assert len(results) == 1

def test_search_documents_empty_query(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that empty query returns empty results."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)
component.set(search_query="")
results = component.search_documents()
assert results == []

def test_search_documents_with_custom_text_key(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that custom text_key is properly used to extract content."""
default_kwargs["text_key"] = "chunk_text"
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results with custom text key
mock_match = Mock()
mock_match.metadata = {"chunk_text": "custom text content", "source": "test"}
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

# Mock Float32Embeddings
with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
results = component.search_documents()

# Verify the custom text_key was used
assert len(results) == 1
assert results[0].text == "custom text content"

def test_search_documents_pinecone_api_error(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that Pinecone API errors are properly handled."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client to raise an error
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_index.query.side_effect = Exception("Pinecone API error")
mock_pinecone.Index.return_value = mock_index

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")

# Verify error is raised
with pytest.raises(ValueError, match="Error searching documents"):
component.search_documents()

def test_search_documents_embedding_error(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that embedding errors are properly handled."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock Float32Embeddings to raise an error
with patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32:
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.side_effect = Exception("Embedding error")
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")

# Verify error is raised
with pytest.raises(ValueError, match="Error searching documents"):
component.search_documents()

def test_float32_embeddings_wrapper_usage(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that Float32Embeddings wrapper is correctly instantiated and used."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results
mock_match = Mock()
mock_match.metadata = {"text": "test result"}
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
component.search_documents()

# Verify Float32Embeddings was instantiated with the correct embeddings
mock_float32.assert_called_once_with(default_kwargs["embedding"])

# Verify embed_query was called with the search query
mock_embeddings_instance.embed_query.assert_called_once_with("test query")

def test_pinecone_client_initialization(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that Pinecone client is initialized with correct parameters."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results
mock_match = Mock()
mock_match.metadata = {"text": "test result"}
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone) as mock_pc_class,
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
component.search_documents()

# Verify Pinecone was initialized with correct API key
mock_pc_class.assert_called_once_with(api_key="test-pinecone-key")

# Verify Index was called with correct index name
mock_pinecone.Index.assert_called_once_with("test-index")

def test_search_documents_with_missing_text_key_in_metadata(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that documents with missing text_key in metadata are handled gracefully."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results with metadata missing the text key
mock_match = Mock()
mock_match.metadata = {"source": "test"} # Missing "text" key
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
results = component.search_documents()

# Verify results are returned with empty text
assert len(results) == 1
assert results[0].text == ""

def test_search_documents_with_none_metadata(
self, component_class: type[PineconeVectorStoreComponent], default_kwargs: dict[str, Any]
) -> None:
"""Test that documents with None metadata are handled gracefully."""
component: PineconeVectorStoreComponent = component_class().set(**default_kwargs)

# Mock the Pinecone client and index
mock_pinecone = MagicMock()
mock_index = MagicMock()
mock_pinecone.Index.return_value = mock_index

# Mock query results with None metadata
mock_match = Mock()
mock_match.metadata = None
mock_results = Mock()
mock_results.matches = [mock_match]
mock_index.query.return_value = mock_results

with (
patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
patch("lfx.components.pinecone.pinecone.Float32Embeddings") as mock_float32,
):
mock_embeddings_instance = MagicMock()
mock_embeddings_instance.embed_query.return_value = [0.1] * 3072
mock_float32.return_value = mock_embeddings_instance

component.set(search_query="test query")
results = component.search_documents()

# Verify results are returned with empty text and metadata
assert len(results) == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Pinecone mocking target doesn’t match implementation import; tests may call the real client

In search_documents the implementation does a local import:

from pinecone import Pinecone
pc = Pinecone(api_key=self.pinecone_api_key)

This binds Pinecone as a local name from the external pinecone module. The tests, however, patch lfx.components.pinecone.pinecone.Pinecone, which is a different symbol and won’t intercept that local import. As a result, these tests can end up using the real Pinecone client (or failing with ImportError) instead of the mocked one.

To ensure the tests actually mock what’s used at runtime, you have two main options:

  • Option A (change tests, keep implementation as-is – simplest):

Update all contexts like:

patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone)

to patch the external module instead:

-            patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone),
+            patch("pinecone.Pinecone", return_value=mock_pinecone),

This way from pinecone import Pinecone pulls in the mocked class.

  • Option B (change implementation to use module-level import), then patch the component module’s symbol.

If you prefer to keep patching lfx.components.pinecone.pinecone.Pinecone, move the import to module scope with a guarded pattern and have search_documents reference the global Pinecone. That’s a broader behavioral change (and may affect optional-dependency semantics), so Option A is safer for this PR.

Also note that test_search_documents_embedding_error doesn’t patch Pinecone at all; if pinecone isn’t installed, the resulting ValueError("Error searching documents") would be due to an import error, not the embedding error. The assertion still passes, but the failure mode is different from what the test name suggests.


[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Find PineconeVectorStoreComponent implementation file
find . -name "*.py" -type f | xargs grep -l "class PineconeVectorStoreComponent" | grep -v test | head -5

Length of output: 49


🏁 Script executed:

#!/bin/bash
# Inspect the search_documents method in PineconeVectorStoreComponent
ast-grep --pattern 'def search_documents($$$) {
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check import statements at module level and inside search_documents
rg -n "from pinecone import|import pinecone" --type=py -g "!test*" | head -20

Length of output: 93


🏁 Script executed:

#!/bin/bash
# Check for EOF newline in the test file (W292 - no newline at EOF)
tail -c 1 "src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py" | od -A x -t x1z

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Count lines to confirm file structure
wc -l "src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py"

Length of output: 90


🏁 Script executed:

#!/bin/bash
# Show last 10 lines of test file to check EOF
tail -10 "src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py"

Length of output: 447


🏁 Script executed:

#!/bin/bash
# Find all patch targets in the test file to understand mocking strategy
rg -n 'patch\("' "src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py"

Length of output: 1620


🏁 Script executed:

#!/bin/bash
# Get the actual implementation of search_documents
ast-grep --pattern 'def search_documents($_) {
  $$$
}' | head -100

Length of output: 0


[/run_scripts]


🏁 Script executed:

#!/bin/bash
# View the implementation file header and imports
head -20 "src/lfx/src/lfx/components/pinecone/pinecone.py"

Length of output: 817


🏁 Script executed:

#!/bin/bash
# View context around line 100 to see search_documents and import
sed -n '90,120p' "src/lfx/src/lfx/components/pinecone/pinecone.py"

Length of output: 1125


🏁 Script executed:

#!/bin/bash
# View the search_documents method more completely
sed -n '90,150p' "src/lfx/src/lfx/components/pinecone/pinecone.py"

Length of output: 2154


🏁 Script executed:

#!/bin/bash
# Check if there's a module-level Pinecone import
grep -n "^from pinecone\|^import pinecone" "src/lfx/src/lfx/components/pinecone/pinecone.py"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Show last line of test file with hex dump alternative to confirm no newline
tail -1 "src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py" | wc -c

Length of output: 2


🏁 Script executed:

#!/bin/bash
# Check full context: what's the actual module path structure?
find . -path "*/lfx/components/pinecone/pinecone.py" -o -path "*/lfx/components/pinecone/__init__.py" | head -5

Length of output: 99


Pinecone mocking target doesn't match implementation import; tests may call the real client

In search_documents() (line 100), the implementation does a local import:

from pinecone import Pinecone
pc = Pinecone(api_key=self.pinecone_api_key)

This creates a local binding to the external pinecone module. The tests, however, patch lfx.components.pinecone.pinecone.Pinecone, which doesn't exist at module scope (Pinecone is never imported there). As a result, these tests won't intercept the local import and can end up using the real Pinecone client instead of the mocked one.

To fix, update all patch calls from:

patch("lfx.components.pinecone.pinecone.Pinecone", return_value=mock_pinecone)

to:

patch("pinecone.Pinecone", return_value=mock_pinecone)

This ensures from pinecone import Pinecone pulls in the mocked class.

Also, the test file is missing a trailing newline at EOF (W292).

🤖 Prompt for AI Agents
src/backend/tests/unit/components/vectorstores/test_pinecone_vector_store_component.py
lines 43-351: the tests patch "lfx.components.pinecone.pinecone.Pinecone" but
the implementation does a local import "from pinecone import Pinecone", so
update every patch(...) call that targets Pinecone to patch "pinecone.Pinecone"
(e.g. patch("pinecone.Pinecone", return_value=mock_pinecone)) so the local
import is mocked, and add a trailing newline at EOF to fix W292.

@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working community Pull Request from an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pinecone vector store returns zero results in Langflow 1.6.5 (regression from 1.5.0)

1 participant