You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This patch adds beartype for runtime type checking. This gives us the
best of both worlds: we do static type checking of our own library with
mypy, and we export our static types, but for clients who do not run
static type checking of their own code, runtime type checking in our
library can help them catch bugs earlier.
`tests/test_codex_tool.py::test_bad_argument_type` serves as an example:
this fails at initialization time of `CodexTool`, whereas without
runtime type checking, this would fail later (e.g., when the user calls
the `query` method on the object).
Because we're performing runtime type checking, some of the imports that
were behind `if TYPE_CHECKING` flags have to be moved to runtime. This
patch updates the linter config to allow imports that are only used for
type checking.
This patch also switches to consistent `from __future__ import
annotations` everywhere, stops using type hints deprecated by PEP 585 by
using `beartype.typing` instead, and updates the linter config
accordingly. This patch also updates the CI config to run static type
checking for all supported Python versions.
beartype relies on `isinstance` for runtime type checks, which needs to
be taken into account when using mocks by overriding the `__class__`
attribute. This patch updates the tests accordingly.
Copy file name to clipboardExpand all lines: DEVELOPMENT.md
+32-9
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,30 @@
1
1
# Development
2
2
3
+
## Guidelines
4
+
5
+
### Typing
6
+
7
+
This project uses [mypy][mypy] for static type checking as well as [beartype][beartype] for runtime type checking.
8
+
9
+
The combination of using beartype and supporting Python 3.8+ leads to some [challenges][beartype-pep585] related to [PEP 585][pep-585] deprecations. For this reason, this package:
10
+
11
+
- Imports from `beartype.typing` all types that are deprecated in PEP 585 (e.g., `List` and `Callable`)
12
+
- Imports directly from `typing` all other types (e.g., `Optional` and `Literal`)
13
+
- These symbols are also available in `beartype.typing`, but we import them directly from `typing` because Ruff has special treatment of these imports. For example, Ruff will complain about `Literal["foo"]` if we import `Literal` from `beartype.typing`.
14
+
15
+
Relatedly, this package also cannot use [PEP 604][pep-604] syntax:
16
+
17
+
- Instead of using types like `A | B`, use `Union[A, B]`
18
+
- Instead of using types like `A | None`, use `Optional[A]`
You can install the pre-commit hooks to automatically run type checking, formatting, and linting on every commit.
49
72
@@ -61,7 +84,7 @@ pre-commit install
61
84
62
85
[pipx]: https://pipx.pypa.io/
63
86
64
-
## Packaging
87
+
###Packaging
65
88
66
89
You can use [`hatch build`][hatch-build] to create build artifacts, a [source distribution ("sdist")][sdist] and a [built distribution ("wheel")][bdist].
67
90
@@ -73,7 +96,7 @@ You can use [`hatch publish`][hatch-publish] if you want to manually publish bui
Automated releases are handled by the [release workflow][release-workflow] which is triggered by pushing a new tag to the repository. To create a new release:
79
102
@@ -88,7 +111,7 @@ Automated releases are handled by the [release workflow][release-workflow] which
entries (list[EntryCreate]): The entries to add to the Codex project.
66
+
entries (List[EntryCreate]): The entries to add to the Codex project.
67
67
project_id (int): The ID of the project to add the entries to.
68
68
69
69
Raises:
@@ -102,20 +102,20 @@ def query(
102
102
project_id: Optional[str] =None, # TODO: update to uuid once project IDs are changed to UUIDs
103
103
fallback_answer: Optional[str] =None,
104
104
read_only: bool=False,
105
-
) ->tuple[Optional[str], Optional[Entry]]:
105
+
) ->Tuple[Optional[str], Optional[Entry]]:
106
106
"""Query Codex to check if the Codex project contains an answer to this question and add the question to the Codex project for SME review if it does not.
107
107
108
108
Args:
109
109
question (str): The question to ask the Codex API.
110
-
project_id (:obj:`int`, optional): The ID of the project to query.
110
+
project_id (:obj:`str`, optional): The ID of the project to query.
111
111
If the client is authenticated with a user-level API Key, this is required.
112
112
If the client is authenticated with a project-level Access Key, this is optional. The client will use the Access Key's project ID by default.
113
113
fallback_answer (:obj:`str`, optional): Optional fallback answer to return if Codex is unable to answer the question.
114
114
read_only (:obj:`bool`, optional): Whether to query the Codex API in read-only mode. If True, the question will not be added to the Codex project for SME review.
115
115
This can be useful for testing purposes before when setting up your project configuration.
116
116
117
117
Returns:
118
-
tuple[Optional[str], Optional[Entry]]: A tuple representing the answer for the query and the existing or new entry in the Codex project.
118
+
Tuple[Optional[str], Optional[Entry]]: A tuple representing the answer for the query and the existing or new entry in the Codex project.
119
119
If Codex is able to answer the question, the first element will be the answer returned by Codex and the second element will be the existing entry in the Codex project.
120
120
If Codex is unable to answer the question, the first element will be `fallback_answer` if provided, otherwise None, and the second element will be a new entry in the Codex project.
Copy file name to clipboardExpand all lines: src/cleanlab_codex/codex_tool.py
+5-3
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,8 @@
2
2
3
3
fromtypingimportAny, ClassVar, Optional
4
4
5
+
frombeartype.typingimportDict, List
6
+
5
7
fromcleanlab_codex.codeximportCodex
6
8
7
9
@@ -10,13 +12,13 @@ class CodexTool:
10
12
11
13
_tool_name="ask_advisor"
12
14
_tool_description="Asks an all-knowing advisor this query in cases where it cannot be answered from the provided Context. If the answer is avalible, this returns None."
13
-
_tool_properties: ClassVar[dict[str, Any]] = {
15
+
_tool_properties: ClassVar[Dict[str, Any]] = {
14
16
"question": {
15
17
"type": "string",
16
18
"description": "The question to ask the advisor. This should be the same as the original user question, except in cases where the user question is missing information that could be additionally clarified.",
0 commit comments