select-ai 1.0.0.dev10__tar.gz → 1.0.0rc2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of select-ai might be problematic. Click here for more details.

Files changed (70) hide show
  1. {select_ai-1.0.0.dev10/src/select_ai.egg-info → select_ai-1.0.0rc2}/PKG-INFO +10 -2
  2. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/README.md +6 -1
  3. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/pyproject.toml +5 -2
  4. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/vector_index_create.py +0 -1
  5. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/vector_index_rag.py +0 -1
  6. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_explain_sql.py +1 -3
  7. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_narrate.py +1 -3
  8. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_run_sql.py +1 -3
  9. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_show_sql.py +1 -3
  10. select_ai-1.0.0rc2/src/select_ai/_validations.py +123 -0
  11. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/async_profile.py +14 -6
  12. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/base_profile.py +1 -0
  13. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/profile.py +21 -11
  14. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/provider.py +9 -4
  15. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/synthetic_data.py +3 -2
  16. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/vector_index.py +10 -0
  17. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/version.py +1 -1
  18. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2/src/select_ai.egg-info}/PKG-INFO +10 -2
  19. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai.egg-info/SOURCES.txt +1 -0
  20. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/LICENSE.txt +0 -0
  21. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/MANIFEST.in +0 -0
  22. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/conversation_chat_session.py +0 -0
  23. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/conversations_list.py +0 -0
  24. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/create_ai_credential.py +0 -0
  25. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/delete_ai_credential.py +0 -0
  26. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/disable_ai_provider.py +0 -0
  27. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/enable_ai_provider.py +0 -0
  28. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_chat.py +0 -0
  29. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_create.py +0 -0
  30. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_explain_sql.py +0 -0
  31. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_gen_multi_table_synthetic_data.py +0 -0
  32. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_gen_single_table_synthetic_data.py +0 -0
  33. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_pipeline.py +0 -0
  34. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_run_sql.py +0 -0
  35. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_show_sql.py +0 -0
  36. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profile_sql_concurrent_tasks.py +0 -0
  37. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/profiles_list.py +0 -0
  38. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/vector_index_delete.py +0 -0
  39. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/async/vector_index_list.py +0 -0
  40. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/conversation_chat_session.py +0 -0
  41. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/conversation_create.py +0 -0
  42. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/conversation_delete.py +0 -0
  43. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/conversations_list.py +0 -0
  44. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/create_ai_credential.py +0 -0
  45. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/delete_ai_credential.py +0 -0
  46. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/disable_ai_provider.py +0 -0
  47. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/enable_ai_provider.py +0 -0
  48. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_chat.py +0 -0
  49. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_create.py +0 -0
  50. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_delete.py +0 -0
  51. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_gen_multi_table_synthetic_data.py +0 -0
  52. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profile_gen_single_table_synthetic_data.py +0 -0
  53. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/profiles_list.py +0 -0
  54. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/vector_index_create.py +0 -0
  55. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/vector_index_delete.py +0 -0
  56. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/vector_index_list.py +0 -0
  57. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/samples/vector_index_rag.py +0 -0
  58. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/setup.cfg +0 -0
  59. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/__init__.py +0 -0
  60. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/_abc.py +0 -0
  61. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/_enums.py +0 -0
  62. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/action.py +0 -0
  63. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/conversation.py +0 -0
  64. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/credential.py +0 -0
  65. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/db.py +0 -0
  66. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/errors.py +0 -0
  67. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai/sql.py +0 -0
  68. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai.egg-info/dependency_links.txt +0 -0
  69. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai.egg-info/requires.txt +0 -0
  70. {select_ai-1.0.0.dev10 → select_ai-1.0.0rc2}/src/select_ai.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: select_ai
3
- Version: 1.0.0.dev10
3
+ Version: 1.0.0rc2
4
4
  Summary: Select AI for Python
5
5
  Author-email: Abhishek Singh <abhishek.o.singh@oracle.com>
6
6
  Maintainer-email: Abhishek Singh <abhishek.o.singh@oracle.com>
@@ -8,8 +8,9 @@ License-Expression: UPL-1.0
8
8
  Project-URL: Homepage, https://github.com/oracle/python-select-ai
9
9
  Project-URL: Repository, https://github.com/oracle/python-select-ai
10
10
  Project-URL: Issues, https://github.com/oracle/python-select-ai/issues
11
+ Project-URL: Documentation, https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/pysai/
11
12
  Keywords: oracle,select-ai,adbs,autonomous database serverless
12
- Classifier: Development Status :: 4 - Beta
13
+ Classifier: Development Status :: 5 - Production/Stable
13
14
  Classifier: Intended Audience :: Developers
14
15
  Classifier: Natural Language :: English
15
16
  Classifier: Operating System :: OS Independent
@@ -21,6 +22,8 @@ Classifier: Programming Language :: Python :: 3.12
21
22
  Classifier: Programming Language :: Python :: 3.13
22
23
  Classifier: Programming Language :: Python :: Implementation :: CPython
23
24
  Classifier: Topic :: Database
25
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
27
  Requires-Python: >=3.9
25
28
  Description-Content-Type: text/markdown
26
29
  License-File: LICENSE.txt
@@ -43,6 +46,10 @@ Run
43
46
  python3 -m pip install select_ai
44
47
  ```
45
48
 
49
+ ## Documentation
50
+
51
+ See [Select AI for Python documentation][documentation]
52
+
46
53
  ## Samples
47
54
 
48
55
  Examples can be found in the [/samples][samples] directory
@@ -111,6 +118,7 @@ Released under the Universal Permissive License v1.0 as shown at
111
118
  <https://oss.oracle.com/licenses/upl/>.
112
119
 
113
120
  [contributing]: https://github.com/oracle/python-select-ai/blob/main/CONTRIBUTING.md
121
+ [documentation]: https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/pysai/
114
122
  [ghdiscussions]: https://github.com/oracle/python-select-ai/discussions
115
123
  [ghissues]: https://github.com/oracle/python-select-ai/issues
116
124
  [samples]: https://github.com/oracle/python-select-ai/tree/main/samples
@@ -13,6 +13,10 @@ Run
13
13
  python3 -m pip install select_ai
14
14
  ```
15
15
 
16
+ ## Documentation
17
+
18
+ See [Select AI for Python documentation][documentation]
19
+
16
20
  ## Samples
17
21
 
18
22
  Examples can be found in the [/samples][samples] directory
@@ -81,7 +85,8 @@ Released under the Universal Permissive License v1.0 as shown at
81
85
  <https://oss.oracle.com/licenses/upl/>.
82
86
 
83
87
  [contributing]: https://github.com/oracle/python-select-ai/blob/main/CONTRIBUTING.md
88
+ [documentation]: https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/pysai/
84
89
  [ghdiscussions]: https://github.com/oracle/python-select-ai/discussions
85
90
  [ghissues]: https://github.com/oracle/python-select-ai/issues
86
91
  [samples]: https://github.com/oracle/python-select-ai/tree/main/samples
87
- [security]: https://github.com/oracle/python-select-ai/blob/main/SECURITY.md
92
+ [security]: https://github.com/oracle/python-select-ai/blob/main/SECURITY.md
@@ -23,7 +23,7 @@ keywords = [
23
23
  license = " UPL-1.0"
24
24
  license-files = ["LICENSE.txt"]
25
25
  classifiers = [
26
- "Development Status :: 4 - Beta",
26
+ "Development Status :: 5 - Production/Stable",
27
27
  "Intended Audience :: Developers",
28
28
  "Natural Language :: English",
29
29
  "Operating System :: OS Independent",
@@ -34,7 +34,9 @@ classifiers = [
34
34
  "Programming Language :: Python :: 3.12",
35
35
  "Programming Language :: Python :: 3.13",
36
36
  "Programming Language :: Python :: Implementation :: CPython",
37
- "Topic :: Database"
37
+ "Topic :: Database",
38
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
39
+ "Topic :: Software Development :: Libraries :: Python Modules"
38
40
  ]
39
41
  dependencies = [
40
42
  "oracledb",
@@ -45,6 +47,7 @@ dependencies = [
45
47
  Homepage = "https://github.com/oracle/python-select-ai"
46
48
  Repository = "https://github.com/oracle/python-select-ai"
47
49
  Issues = "https://github.com/oracle/python-select-ai/issues"
50
+ Documentation = "https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/pysai/"
48
51
 
49
52
  [tool.setuptools.packages.find]
50
53
  where = ["src"]
@@ -11,7 +11,6 @@
11
11
  # Create a vector index for Retrieval Augmented Generation (RAG)
12
12
  # -----------------------------------------------------------------------------
13
13
 
14
-
15
14
  import asyncio
16
15
  import os
17
16
 
@@ -11,7 +11,6 @@
11
11
  # Demonstrates Retrieval Augmented Generation (RAG) using ai_profile.narrate()
12
12
  # -----------------------------------------------------------------------------
13
13
 
14
-
15
14
  import asyncio
16
15
  import os
17
16
 
@@ -22,7 +22,5 @@ profile = select_ai.Profile(
22
22
  profile_name="oci_ai_profile",
23
23
  )
24
24
  print(profile.description)
25
- explanation = profile.explain_sql(
26
- prompt="How many promotions are there in the database?"
27
- )
25
+ explanation = profile.explain_sql(prompt="How many promotions?")
28
26
  print(explanation)
@@ -23,7 +23,5 @@ select_ai.connect(user=user, password=password, dsn=dsn)
23
23
  profile = select_ai.Profile(
24
24
  profile_name="oci_ai_profile",
25
25
  )
26
- narration = profile.narrate(
27
- prompt="How many promotions are there in the database?"
28
- )
26
+ narration = profile.narrate(prompt="How many promotions?")
29
27
  print(narration)
@@ -21,8 +21,6 @@ dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
21
21
 
22
22
  select_ai.connect(user=user, password=password, dsn=dsn)
23
23
  profile = select_ai.Profile(profile_name="oci_ai_profile")
24
- df = profile.run_sql(
25
- prompt="How many promotions are there in the database?"
26
- )
24
+ df = profile.run_sql(prompt="How many promotions ?")
27
25
  print(df.columns)
28
26
  print(df)
@@ -21,7 +21,5 @@ dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
21
21
 
22
22
  select_ai.connect(user=user, password=password, dsn=dsn)
23
23
  profile = select_ai.Profile(profile_name="oci_ai_profile")
24
- sql = profile.show_sql(
25
- prompt="How many promotions are there in the database?"
26
- )
24
+ sql = profile.show_sql(prompt="How many promotions ?")
27
25
  print(sql)
@@ -0,0 +1,123 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) 2025, Oracle and/or its affiliates.
3
+ #
4
+ # Licensed under the Universal Permissive License v 1.0 as shown at
5
+ # http://oss.oracle.com/licenses/upl.
6
+ # -----------------------------------------------------------------------------
7
+
8
+ import inspect
9
+ from collections.abc import Mapping, Sequence, Set
10
+ from functools import wraps
11
+ from typing import Any, get_args, get_origin, get_type_hints
12
+
13
+ NoneType = type(None)
14
+
15
+
16
+ def _match(value, annot) -> bool:
17
+ """Recursively validate value against a typing annotation."""
18
+ if annot is Any:
19
+ return True
20
+
21
+ origin = get_origin(annot)
22
+ args = get_args(annot)
23
+
24
+ # Handle Annotated[T, ...] → treat as T
25
+ if origin is getattr(__import__("typing"), "Annotated", None):
26
+ annot = args[0]
27
+ origin = get_origin(annot)
28
+ args = get_args(annot)
29
+
30
+ # Optional[T] is Union[T, NoneType]
31
+ if origin is getattr(__import__("typing"), "Union", None):
32
+ return any(_match(value, a) for a in args)
33
+
34
+ # Literal[…]
35
+ if origin is getattr(__import__("typing"), "Literal", None):
36
+ return any(value == lit for lit in args)
37
+
38
+ # Tuple cases
39
+ if origin is tuple:
40
+ if not isinstance(value, tuple):
41
+ return False
42
+ if len(args) == 2 and args[1] is Ellipsis:
43
+ # tuple[T, ...]
44
+ return all(_match(v, args[0]) for v in value)
45
+ if len(args) != len(value):
46
+ return False
47
+ return all(_match(v, a) for v, a in zip(value, args))
48
+
49
+ # Mappings (dict-like)
50
+ if origin in (dict, Mapping):
51
+ if not isinstance(value, Mapping):
52
+ return False
53
+ k_annot, v_annot = args if args else (Any, Any)
54
+ return all(
55
+ _match(k, k_annot) and _match(v, v_annot) for k, v in value.items()
56
+ )
57
+
58
+ # Sequences (list, Sequence) – but not str/bytes
59
+ if origin in (list, Sequence):
60
+ if isinstance(value, (str, bytes)):
61
+ return False
62
+ if not isinstance(value, Sequence):
63
+ return False
64
+ elem_annot = args[0] if args else Any
65
+ return all(_match(v, elem_annot) for v in value)
66
+
67
+ # Sets
68
+ if origin in (set, frozenset, Set):
69
+ if not isinstance(value, (set, frozenset)):
70
+ return False
71
+ elem_annot = args[0] if args else Any
72
+ return all(_match(v, elem_annot) for v in value)
73
+
74
+ # Fall back to normal isinstance for non-typing classes
75
+ if isinstance(annot, type):
76
+ return isinstance(value, annot)
77
+
78
+ # If annot is a typing alias like 'list' without args
79
+ if origin is not None:
80
+ # Treat bare containers as accepting anything inside
81
+ return isinstance(value, origin)
82
+
83
+ # Unknown/unsupported typing form: accept conservatively
84
+ return True
85
+
86
+
87
+ def enforce_types(func):
88
+ # Resolve ForwardRefs using function globals (handles "User" as a string, etc.)
89
+ hints = get_type_hints(
90
+ func, globalns=func.__globals__, include_extras=True
91
+ )
92
+ sig = inspect.signature(func)
93
+
94
+ def _check(bound):
95
+ for name, val in bound.arguments.items():
96
+ if name in hints:
97
+ annot = hints[name]
98
+ if not _match(val, annot):
99
+ raise TypeError(
100
+ f"Argument '{name}' failed type check: expected {annot!r}, "
101
+ f"got {type(val).__name__} -> {val!r}"
102
+ )
103
+
104
+ if inspect.iscoroutinefunction(func):
105
+
106
+ @wraps(func)
107
+ async def aw(*args, **kwargs):
108
+ bound = sig.bind(*args, **kwargs)
109
+ bound.apply_defaults()
110
+ _check(bound)
111
+ return await func(*args, **kwargs)
112
+
113
+ return aw
114
+ else:
115
+
116
+ @wraps(func)
117
+ def w(*args, **kwargs):
118
+ bound = sig.bind(*args, **kwargs)
119
+ bound.apply_defaults()
120
+ _check(bound)
121
+ return func(*args, **kwargs)
122
+
123
+ return w
@@ -344,8 +344,15 @@ class AsyncProfile(BaseProfile):
344
344
  keyword_parameters=parameters,
345
345
  )
346
346
  if data is not None:
347
- return await data.read()
348
- return None
347
+ result = await data.read()
348
+ else:
349
+ result = None
350
+ if action == Action.RUNSQL and result:
351
+ return pandas.DataFrame(json.loads(result))
352
+ elif action == Action.RUNSQL:
353
+ return pandas.DataFrame()
354
+ else:
355
+ return result
349
356
 
350
357
  async def chat(self, prompt, params: Mapping = None) -> str:
351
358
  """Asynchronously chat with the LLM
@@ -411,8 +418,7 @@ class AsyncProfile(BaseProfile):
411
418
  :param params: Parameters to include in the LLM request
412
419
  :return: pandas.DataFrame
413
420
  """
414
- data = await self.generate(prompt, action=Action.RUNSQL, params=params)
415
- return pandas.DataFrame(json.loads(data))
421
+ return await self.generate(prompt, action=Action.RUNSQL, params=params)
416
422
 
417
423
  async def show_sql(self, prompt, params: Mapping = None):
418
424
  """Show the generated SQL
@@ -451,8 +457,10 @@ class AsyncProfile(BaseProfile):
451
457
  raise ValueError("'synthetic_data_attributes' cannot be None")
452
458
 
453
459
  if not isinstance(synthetic_data_attributes, SyntheticDataAttributes):
454
- raise TypeError("'synthetic_data_attributes' must be an object "
455
- "of type select_ai.SyntheticDataAttributes")
460
+ raise TypeError(
461
+ "'synthetic_data_attributes' must be an object "
462
+ "of type select_ai.SyntheticDataAttributes"
463
+ )
456
464
 
457
465
  keyword_parameters = synthetic_data_attributes.prepare()
458
466
  keyword_parameters["profile_name"] = self.profile_name
@@ -73,6 +73,7 @@ class ProfileAttributes(SelectAIDataClass):
73
73
  vector_index_name: Optional[str] = None
74
74
 
75
75
  def __post_init__(self):
76
+ super().__post_init__()
76
77
  if self.provider and not isinstance(self.provider, Provider):
77
78
  raise ValueError(
78
79
  f"'provider' must be an object of " f"type select_ai.Provider"
@@ -8,7 +8,7 @@
8
8
  import json
9
9
  from contextlib import contextmanager
10
10
  from dataclasses import replace as dataclass_replace
11
- from typing import Iterator, Mapping, Optional, Union
11
+ from typing import Generator, Iterator, Mapping, Optional, Union
12
12
 
13
13
  import oracledb
14
14
  import pandas
@@ -258,7 +258,9 @@ class Profile(BaseProfile):
258
258
  raise ProfileNotFoundError(profile_name=profile_name)
259
259
 
260
260
  @classmethod
261
- def list(cls, profile_name_pattern: str = ".*") -> Iterator["Profile"]:
261
+ def list(
262
+ cls, profile_name_pattern: str = ".*"
263
+ ) -> Generator["Profile", None, None]:
262
264
  """List AI Profiles saved in the database.
263
265
 
264
266
  :param str profile_name_pattern: Regular expressions can be used
@@ -314,8 +316,15 @@ class Profile(BaseProfile):
314
316
  keyword_parameters=parameters,
315
317
  )
316
318
  if data is not None:
317
- return data.read()
318
- return None
319
+ result = data.read()
320
+ else:
321
+ result = None
322
+ if action == Action.RUNSQL and result:
323
+ return pandas.DataFrame(json.loads(result))
324
+ elif action == Action.RUNSQL:
325
+ return pandas.DataFrame()
326
+ else:
327
+ return result
319
328
 
320
329
  def chat(self, prompt: str, params: Mapping = None) -> str:
321
330
  """Chat with the LLM
@@ -375,10 +384,7 @@ class Profile(BaseProfile):
375
384
  :param params: Parameters to include in the LLM request
376
385
  :return: pandas.DataFrame
377
386
  """
378
- data = json.loads(
379
- self.generate(prompt, action=Action.RUNSQL, params=params)
380
- )
381
- return pandas.DataFrame(data)
387
+ return self.generate(prompt, action=Action.RUNSQL, params=params)
382
388
 
383
389
  def show_sql(self, prompt: str, params: Mapping = None) -> str:
384
390
  """Show the generated SQL
@@ -410,11 +416,15 @@ class Profile(BaseProfile):
410
416
 
411
417
  """
412
418
  if synthetic_data_attributes is None:
413
- raise ValueError("Param 'synthetic_data_attributes' cannot be None")
419
+ raise ValueError(
420
+ "Param 'synthetic_data_attributes' cannot be None"
421
+ )
414
422
 
415
423
  if not isinstance(synthetic_data_attributes, SyntheticDataAttributes):
416
- raise TypeError("'synthetic_data_attributes' must be an object "
417
- "of type select_ai.SyntheticDataAttributes")
424
+ raise TypeError(
425
+ "'synthetic_data_attributes' must be an object "
426
+ "of type select_ai.SyntheticDataAttributes"
427
+ )
418
428
 
419
429
  keyword_parameters = synthetic_data_attributes.prepare()
420
430
  keyword_parameters["profile_name"] = self.profile_name
@@ -9,6 +9,7 @@ from dataclasses import dataclass
9
9
  from typing import List, Optional, Union
10
10
 
11
11
  from select_ai._abc import SelectAIDataClass
12
+ from select_ai._validations import enforce_types
12
13
 
13
14
  from .db import async_cursor, cursor
14
15
  from .sql import (
@@ -194,6 +195,7 @@ class AnthropicProvider(Provider):
194
195
  provider_endpoint = "api.anthropic.com"
195
196
 
196
197
 
198
+ @enforce_types
197
199
  async def async_enable_provider(
198
200
  users: Union[str, List[str]], provider_endpoint: str = None
199
201
  ):
@@ -210,7 +212,7 @@ async def async_enable_provider(
210
212
 
211
213
  async with async_cursor() as cr:
212
214
  for user in users:
213
- await cr.execute(GRANT_PRIVILEGES_TO_USER.format(user))
215
+ await cr.execute(GRANT_PRIVILEGES_TO_USER.format(user.strip()))
214
216
  if provider_endpoint:
215
217
  await cr.execute(
216
218
  ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
@@ -219,6 +221,7 @@ async def async_enable_provider(
219
221
  )
220
222
 
221
223
 
224
+ @enforce_types
222
225
  async def async_disable_provider(
223
226
  users: Union[str, List[str]], provider_endpoint: str = None
224
227
  ):
@@ -234,7 +237,7 @@ async def async_disable_provider(
234
237
 
235
238
  async with async_cursor() as cr:
236
239
  for user in users:
237
- await cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user))
240
+ await cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user.strip()))
238
241
  if provider_endpoint:
239
242
  await cr.execute(
240
243
  DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
@@ -243,6 +246,7 @@ async def async_disable_provider(
243
246
  )
244
247
 
245
248
 
249
+ @enforce_types
246
250
  def enable_provider(
247
251
  users: Union[str, List[str]], provider_endpoint: str = None
248
252
  ):
@@ -256,7 +260,7 @@ def enable_provider(
256
260
 
257
261
  with cursor() as cr:
258
262
  for user in users:
259
- cr.execute(GRANT_PRIVILEGES_TO_USER.format(user))
263
+ cr.execute(GRANT_PRIVILEGES_TO_USER.format(user.strip()))
260
264
  if provider_endpoint:
261
265
  cr.execute(
262
266
  ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
@@ -265,6 +269,7 @@ def enable_provider(
265
269
  )
266
270
 
267
271
 
272
+ @enforce_types
268
273
  def disable_provider(
269
274
  users: Union[str, List[str]], provider_endpoint: str = None
270
275
  ):
@@ -279,7 +284,7 @@ def disable_provider(
279
284
 
280
285
  with cursor() as cr:
281
286
  for user in users:
282
- cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user))
287
+ cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user.strip()))
283
288
  if provider_endpoint:
284
289
  cr.execute(
285
290
  DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
@@ -62,8 +62,9 @@ class SyntheticDataAttributes(SelectAIDataClass):
62
62
 
63
63
  def __post_init__(self):
64
64
  if self.params and not isinstance(self.params, SyntheticDataParams):
65
- raise TypeError("'params' must be an object of"
66
- " type SyntheticDataParams'")
65
+ raise TypeError(
66
+ "'params' must be an object of" " type SyntheticDataParams'"
67
+ )
67
68
 
68
69
  def dict(self, exclude_null=True):
69
70
  attributes = {}
@@ -119,6 +119,16 @@ class _BaseVectorIndex(ABC):
119
119
  attributes: Optional[VectorIndexAttributes] = None,
120
120
  ):
121
121
  """Initialize a Vector Index"""
122
+ if attributes and not isinstance(attributes, VectorIndexAttributes):
123
+ raise TypeError(
124
+ "'attributes' must be an object of type "
125
+ "select_ai.VectorIndexAttributes"
126
+ )
127
+ if profile and not isinstance(profile, BaseProfile):
128
+ raise TypeError(
129
+ "'profile' must be an object of type "
130
+ "select_ai.Profile or select_ai.AsyncProfile"
131
+ )
122
132
  self.profile = profile
123
133
  self.index_name = index_name
124
134
  self.attributes = attributes
@@ -5,4 +5,4 @@
5
5
  # http://oss.oracle.com/licenses/upl.
6
6
  # -----------------------------------------------------------------------------
7
7
 
8
- __version__ = "1.0.0.dev10"
8
+ __version__ = "1.0.0rc2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: select_ai
3
- Version: 1.0.0.dev10
3
+ Version: 1.0.0rc2
4
4
  Summary: Select AI for Python
5
5
  Author-email: Abhishek Singh <abhishek.o.singh@oracle.com>
6
6
  Maintainer-email: Abhishek Singh <abhishek.o.singh@oracle.com>
@@ -8,8 +8,9 @@ License-Expression: UPL-1.0
8
8
  Project-URL: Homepage, https://github.com/oracle/python-select-ai
9
9
  Project-URL: Repository, https://github.com/oracle/python-select-ai
10
10
  Project-URL: Issues, https://github.com/oracle/python-select-ai/issues
11
+ Project-URL: Documentation, https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/pysai/
11
12
  Keywords: oracle,select-ai,adbs,autonomous database serverless
12
- Classifier: Development Status :: 4 - Beta
13
+ Classifier: Development Status :: 5 - Production/Stable
13
14
  Classifier: Intended Audience :: Developers
14
15
  Classifier: Natural Language :: English
15
16
  Classifier: Operating System :: OS Independent
@@ -21,6 +22,8 @@ Classifier: Programming Language :: Python :: 3.12
21
22
  Classifier: Programming Language :: Python :: 3.13
22
23
  Classifier: Programming Language :: Python :: Implementation :: CPython
23
24
  Classifier: Topic :: Database
25
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
27
  Requires-Python: >=3.9
25
28
  Description-Content-Type: text/markdown
26
29
  License-File: LICENSE.txt
@@ -43,6 +46,10 @@ Run
43
46
  python3 -m pip install select_ai
44
47
  ```
45
48
 
49
+ ## Documentation
50
+
51
+ See [Select AI for Python documentation][documentation]
52
+
46
53
  ## Samples
47
54
 
48
55
  Examples can be found in the [/samples][samples] directory
@@ -111,6 +118,7 @@ Released under the Universal Permissive License v1.0 as shown at
111
118
  <https://oss.oracle.com/licenses/upl/>.
112
119
 
113
120
  [contributing]: https://github.com/oracle/python-select-ai/blob/main/CONTRIBUTING.md
121
+ [documentation]: https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/pysai/
114
122
  [ghdiscussions]: https://github.com/oracle/python-select-ai/discussions
115
123
  [ghissues]: https://github.com/oracle/python-select-ai/issues
116
124
  [samples]: https://github.com/oracle/python-select-ai/tree/main/samples
@@ -47,6 +47,7 @@ samples/async/vector_index_rag.py
47
47
  src/select_ai/__init__.py
48
48
  src/select_ai/_abc.py
49
49
  src/select_ai/_enums.py
50
+ src/select_ai/_validations.py
50
51
  src/select_ai/action.py
51
52
  src/select_ai/async_profile.py
52
53
  src/select_ai/base_profile.py
File without changes