Skip to content

Commit 44e8f75

Browse files
committed
feat(backcompat): restore friendly AttributeError for removed top-level functions (BCG-012, BCG-252)
Intercepts access to 11 removed module-level names (init, create_index, delete_index, list_indexes, describe_index, configure_index, scale_index, create_collection, delete_collection, describe_collection, list_collections) in __getattr__ and raises AttributeError with legacy-verbatim migration guidance including an Example: block. Adds parametrised unit tests covering all 12 names (11 + init call-form).
1 parent 05b6a5c commit 44e8f75

2 files changed

Lines changed: 167 additions & 0 deletions

File tree

pinecone/__init__.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,137 @@
545545
}
546546

547547

548+
_REMOVED_TOPLEVEL_FUNCTIONS: tuple[str, ...] = (
549+
"init",
550+
"create_index",
551+
"delete_index",
552+
"list_indexes",
553+
"describe_index",
554+
"configure_index",
555+
"scale_index",
556+
"create_collection",
557+
"delete_collection",
558+
"describe_collection",
559+
"list_collections",
560+
)
561+
562+
_REMOVED_FUNCTION_EXAMPLES: dict[str, str] = {
563+
"init": """
564+
import os
565+
from pinecone import Pinecone, ServerlessSpec
566+
567+
pc = Pinecone(
568+
api_key=os.environ.get("PINECONE_API_KEY")
569+
)
570+
571+
# Now do stuff
572+
if 'my_index' not in pc.list_indexes().names():
573+
pc.create_index(
574+
name='my_index',
575+
dimension=1536,
576+
metric='euclidean',
577+
spec=ServerlessSpec(
578+
cloud='aws',
579+
region='us-west-2'
580+
)
581+
)
582+
""",
583+
"list_indexes": """
584+
from pinecone import Pinecone
585+
586+
pc = Pinecone(api_key='YOUR_API_KEY')
587+
588+
index_name = "quickstart" # or your index name
589+
590+
if index_name not in pc.list_indexes().names():
591+
# do something
592+
""",
593+
"describe_index": """
594+
from pinecone import Pinecone
595+
596+
pc = Pinecone(api_key='YOUR_API_KEY')
597+
pc.describe_index('my_index')
598+
""",
599+
"create_index": """
600+
from pinecone import Pinecone, ServerlessSpec
601+
602+
pc = Pinecone(api_key='YOUR_API_KEY')
603+
pc.create_index(
604+
name='my-index',
605+
dimension=1536,
606+
metric='euclidean',
607+
spec=ServerlessSpec(
608+
cloud='aws',
609+
region='us-west-2'
610+
)
611+
)
612+
""",
613+
"delete_index": """
614+
from pinecone import Pinecone
615+
616+
pc = Pinecone(api_key='YOUR_API_KEY')
617+
pc.delete_index('my_index')
618+
""",
619+
"scale_index": """
620+
from pinecone import Pinecone
621+
622+
pc = Pinecone(api_key='YOUR_API_KEY')
623+
pc.configure_index('my_index', replicas=2)
624+
""",
625+
"create_collection": """
626+
from pinecone import Pinecone
627+
628+
pc = Pinecone(api_key='YOUR_API_KEY')
629+
pc.create_collection(name='my_collection', source='my_index')
630+
""",
631+
"list_collections": """
632+
from pinecone import Pinecone
633+
634+
pc = Pinecone(api_key='YOUR_API_KEY')
635+
pc.list_collections()
636+
""",
637+
"delete_collection": """
638+
from pinecone import Pinecone
639+
640+
pc = Pinecone(api_key='YOUR_API_KEY')
641+
pc.delete_collection('my_collection')
642+
""",
643+
"describe_collection": """
644+
from pinecone import Pinecone
645+
646+
pc = Pinecone(api_key='YOUR_API_KEY')
647+
pc.describe_collection('my_collection')
648+
""",
649+
"configure_index": """
650+
from pinecone import Pinecone
651+
652+
pc = Pinecone(api_key='YOUR_API_KEY')
653+
pc.configure_index('my_index', replicas=2)
654+
""",
655+
}
656+
657+
658+
def _removed_function_message(name: str) -> str:
659+
example = _REMOVED_FUNCTION_EXAMPLES[name]
660+
if name == "init":
661+
return (
662+
"init is no longer a top-level attribute of the pinecone package.\n\n"
663+
"Please create an instance of the Pinecone class instead.\n\n"
664+
f"Example:\n{example}\n"
665+
)
666+
if name == "scale_index":
667+
return (
668+
"scale_index is no longer a top-level attribute of the pinecone package.\n\n"
669+
"Please create a client instance and call the configure_index method instead.\n\n"
670+
f"Example:\n{example}\n"
671+
)
672+
return (
673+
f"{name} is no longer a top-level attribute of the pinecone package.\n\n"
674+
f"To use {name}, please create a client instance and call the method there instead.\n\n"
675+
f"Example:\n{example}\n"
676+
)
677+
678+
548679
def __getattr__(name: str) -> Any:
549680
if name == "ValidationError":
550681
import warnings
@@ -558,6 +689,8 @@ def __getattr__(name: str) -> Any:
558689

559690
globals()["ValidationError"] = ValidationError
560691
return ValidationError
692+
if name in _REMOVED_TOPLEVEL_FUNCTIONS:
693+
raise AttributeError(_removed_function_message(name))
561694
if name in _LAZY_IMPORTS:
562695
module_path, attr = _LAZY_IMPORTS[name]
563696
import importlib
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
import pinecone
6+
7+
REMOVED_NAMES = [
8+
"init",
9+
"create_index",
10+
"delete_index",
11+
"list_indexes",
12+
"describe_index",
13+
"configure_index",
14+
"scale_index",
15+
"create_collection",
16+
"delete_collection",
17+
"describe_collection",
18+
"list_collections",
19+
]
20+
21+
22+
@pytest.mark.parametrize("name", REMOVED_NAMES)
23+
def test_removed_function_raises_attribute_error(name: str) -> None:
24+
with pytest.raises(AttributeError) as exc_info:
25+
getattr(pinecone, name)
26+
msg = str(exc_info.value)
27+
assert name in msg
28+
assert "no longer a top-level attribute of the pinecone package" in msg
29+
assert "Example:" in msg
30+
31+
32+
def test_removed_function_calls_raise_attribute_error() -> None:
33+
with pytest.raises(AttributeError):
34+
pinecone.init() # type: ignore[attr-defined]

0 commit comments

Comments
 (0)