Skip to content

Commit

Permalink
Move python Checked and Check types into baml_client (#1122)
Browse files Browse the repository at this point in the history
This removes `Checked` and `Check` from `baml_py`. These two types
depended on `BaseModel`, incurring a dependency on `pydantic`, which is
not desirable for `baml_py`.

Now that these types are part of `baml_client` (which already has a
`pydantic` dep), `baml_py` itself can be installed without the
`pydantic` dependency.
<!-- ELLIPSIS_HIDDEN -->


----

> [!IMPORTANT]
> Move `Checked` and `Check` types from `baml_py` to `baml_client` to
remove `pydantic` dependency from `baml_py`.
> 
>   - **Behavior**:
> - Move `Checked` and `Check` types from `baml_py` to `baml_client` to
eliminate `pydantic` dependency in `baml_py`.
> - Update references to `Checked` and `Check` in `generate_types.rs`,
`mod.rs`, and `function_results.rs` to use the new location.
>   - **Types**:
> - Add `Checked` and `Check` classes to `types.py` in `baml_client`.
> - Implement `get_checks()` and `all_succeeded()` functions in
`types.py`.
>   - **Imports**:
> - Update imports in `async_client.py.j2`, `partial_types.py.j2`, and
`sync_client.py.j2` to import `Checked` and `Check` from
`baml_client/types.py`.
>   - **Misc**:
> - Remove `constraints.py` from `baml_py` as it is no longer needed.
> 
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=BoundaryML%2Fbaml&utm_source=github&utm_medium=referral)<sup>
for 46c9b78. It will automatically
update as commits are pushed.</sup>


<!-- ELLIPSIS_HIDDEN -->
  • Loading branch information
imalsogreg authored Oct 30, 2024
1 parent 222cdd0 commit 0ccf473
Show file tree
Hide file tree
Showing 16 changed files with 87 additions and 1,775 deletions.
6 changes: 3 additions & 3 deletions engine/language_client_codegen/src/python/generate_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ fn type_def_for_checks(checks: TypeCheckAttributes) -> PythonClass<'static> {
fields: checks
.0
.into_iter()
.map(|check_name| (Cow::Owned(check_name), "baml_py.Check".to_string()))
.map(|check_name| (Cow::Owned(check_name), "Check".to_string()))
.collect(),
dynamic: false,
}
Expand Down Expand Up @@ -254,7 +254,7 @@ impl ToTypeReferenceInTypeDefinition for FieldType {
Some(checks) => {
let base_type_ref = base.to_type_ref(ir);
let checks_type_ref = type_name_for_checks(&checks);
format!("baml_py.Checked[{base_type_ref},{checks_type_ref}]")
format!("Checked[{base_type_ref},{checks_type_ref}]")
}
None => base.to_type_ref(ir),
},
Expand Down Expand Up @@ -314,7 +314,7 @@ impl ToTypeReferenceInTypeDefinition for FieldType {
Some(checks) => {
let base_type_ref = base.to_partial_type_ref(ir, false);
let checks_type_ref = type_name_for_checks(&checks);
format!("baml_py.Checked[{base_type_ref},{checks_type_ref}]")
format!("Checked[{base_type_ref},{checks_type_ref}]")
}
None => base_type_ref,
}
Expand Down
4 changes: 2 additions & 2 deletions engine/language_client_codegen/src/python/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl ToTypeReferenceInClientDefinition for FieldType {
Some(checks) => {
let base_type_ref = base.to_type_ref(ir, with_checked);
let checks_type_ref = type_name_for_checks(&checks);
format!("baml_py.Checked[{base_type_ref},types.{checks_type_ref}]")
format!("Checked[{base_type_ref},types.{checks_type_ref}]")
}
None => base.to_type_ref(ir, with_checked),
},
Expand Down Expand Up @@ -288,7 +288,7 @@ impl ToTypeReferenceInClientDefinition for FieldType {
Some(checks) => {
let base_type_ref = base.to_partial_type_ref(ir, with_checked);
let checks_type_ref = type_name_for_checks(&checks);
format!("baml_py.Checked[{base_type_ref},types.{checks_type_ref}]")
format!("Checked[{base_type_ref},types.{checks_type_ref}]")
}
None => base.to_partial_type_ref(ir, with_checked),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import baml_py
from pydantic import BaseModel, ValidationError, create_model

from . import partial_types, types
from .types import Checked, Check
from .type_builder import TypeBuilder
from .globals import DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX, DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ from pydantic import BaseModel, ConfigDict
from typing import Dict, List, Optional, Union, Literal

from . import types
from .types import Checked, Check

###############################################################################
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import baml_py
from pydantic import BaseModel, ValidationError, create_model

from . import partial_types, types
from .types import Checked, Check
from .type_builder import TypeBuilder
from .globals import DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX, DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME

Expand Down
22 changes: 21 additions & 1 deletion engine/language_client_codegen/src/python/templates/types.py.j2
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,27 @@
import baml_py
from enum import Enum
from pydantic import BaseModel, ConfigDict
from typing import Dict, List, Optional, Union, Literal
from typing import Dict, Generic, List, Literal, Optional, TypeVar, Union


T = TypeVar('T')
CheckName = TypeVar('CheckName', bound=str)

class Check(BaseModel):
name: str
expression: str
status: str

class Checked(BaseModel, Generic[T,CheckName]):
value: T
checks: Dict[CheckName, Check]

def get_checks(checks: Dict[CheckName, Check]) -> List[Check]:
return list(checks.values())

def all_succeeded(checks: Dict[CheckName, Check]) -> bool:
return all(check.status == "succeeded" for check in get_checks(checks))


{# Enums -#}
{% for enum in enums %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
)
from .stream import BamlStream, BamlSyncStream
from .ctx_manager import CtxManager as BamlCtxManager
from .constraints import Check, Checked

__all__ = [
"BamlRuntime",
Expand Down
20 changes: 0 additions & 20 deletions engine/language_client_python/python_src/baml_py/constraints.py

This file was deleted.

11 changes: 4 additions & 7 deletions engine/language_client_python/src/types/function_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ impl FunctionResult {

fn pythonize_checks<'a>(
py: Python<'a>,
baml_py: &Bound<'_, PyModule>,
types_module: &Bound<'_, PyModule>,
checks: &Vec<ResponseCheck>,
) -> PyResult<Bound<'a, PyDict>> {
let dict = PyDict::new_bound(py);
let check_class: &PyType = baml_py.getattr("Check")?.extract()?;
let check_class: &PyType = types_module.getattr("Check")?.extract()?;
checks.iter().try_for_each(|ResponseCheck{name, expression, status}| {
// Construct the Check.
let check_properties_dict = pyo3::types::PyDict::new_bound(py);
Expand All @@ -70,7 +70,6 @@ fn pythonize_strict(
enum_module: &Bound<'_, PyModule>,
cls_module: &Bound<'_, PyModule>,
) -> PyResult<PyObject> {
let baml_py = py.import_bound("baml_py")?;
let meta = parsed.meta().clone();
let py_value_without_constraints = match parsed {
BamlValueWithMeta::String(val, _) => PyResult::Ok(val.into_py(py)),
Expand Down Expand Up @@ -163,7 +162,7 @@ fn pythonize_strict(
} else {

// Generate the Python checks
let python_checks = pythonize_checks(py, &baml_py, &meta)?;
let python_checks = pythonize_checks(py, &cls_module, &meta)?;

// Get the type of the original value
let value_type = py_value_without_constraints.bind(py).get_type();
Expand All @@ -184,9 +183,7 @@ fn pythonize_strict(
properties_dict.set_item("value", py_value_without_constraints)?;
properties_dict.set_item("checks", python_checks)?;

// Import the `baml_py` module and get the `Checked` constructor
let baml_py = py.import_bound("baml_py")?;
let class_checked_type_constructor = baml_py.getattr("Checked")?;
let class_checked_type_constructor = cls_module.getattr("Checked")?;

// Prepare type parameters for Checked[...]
let type_parameters_tuple = PyTuple::new_bound(py, &[value_type.as_ref(), &literal_check_names]);
Expand Down
6 changes: 3 additions & 3 deletions fern/01-guide/05-baml-advanced/validations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ runtime.

<CodeBlocks>
```python Python
List[baml_py.Checked[int, Dict[Literal["less_than_zero"]]]]
List[Checked[int, Dict[Literal["less_than_zero"]]]]
```

```typescript Typescript
Expand Down Expand Up @@ -243,7 +243,7 @@ function GetCitation(full_text: string) -> Citation {
<CodeBlocks>
```python Python
from baml_client import b
from baml_client.types import Citation
from baml_client.types import Citation, get_checks

def main():
citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...")
Expand All @@ -257,7 +257,7 @@ def main():
print(f"Citation match status: {quote_match_check})")

# Access each check and its status.
for check in baml_py.get_checks(citation.quote.checks):
for check in get_checks(citation.quote.checks):
print(f"Check {check.name}: {check.status}")
```

Expand Down
13 changes: 7 additions & 6 deletions integ-tests/python/baml_client/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from pydantic import BaseModel, ValidationError, create_model

from . import partial_types, types
from .types import Checked, Check
from .type_builder import TypeBuilder
from .globals import DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX, DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME

Expand Down Expand Up @@ -1341,7 +1342,7 @@ async def PredictAgeBare(
self,
inp: str,
baml_options: BamlCallOptions = {},
) -> baml_py.Checked[int,types.Literal["too_big"]]:
) -> Checked[int,types.Literal["too_big"]]:
__tb__ = baml_options.get("tb", None)
if __tb__ is not None:
tb = __tb__._tb
Expand All @@ -1358,7 +1359,7 @@ async def PredictAgeBare(
tb,
__cr__,
)
return cast(baml_py.Checked[int,types.Literal["too_big"]], raw.cast_to(types, types))
return cast(Checked[int,types.Literal["too_big"]], raw.cast_to(types, types))

async def PromptTestClaude(
self,
Expand Down Expand Up @@ -4208,7 +4209,7 @@ def PredictAgeBare(
self,
inp: str,
baml_options: BamlCallOptions = {},
) -> baml_py.BamlStream[baml_py.Checked[Optional[int],types.Literal["too_big"]], baml_py.Checked[int,types.Literal["too_big"]]]:
) -> baml_py.BamlStream[Checked[Optional[int],types.Literal["too_big"]], Checked[int,types.Literal["too_big"]]]:
__tb__ = baml_options.get("tb", None)
if __tb__ is not None:
tb = __tb__._tb
Expand All @@ -4227,10 +4228,10 @@ def PredictAgeBare(
__cr__,
)

return baml_py.BamlStream[baml_py.Checked[Optional[int],types.Literal["too_big"]], baml_py.Checked[int,types.Literal["too_big"]]](
return baml_py.BamlStream[Checked[Optional[int],types.Literal["too_big"]], Checked[int,types.Literal["too_big"]]](
raw,
lambda x: cast(baml_py.Checked[Optional[int],types.Literal["too_big"]], x.cast_to(types, partial_types)),
lambda x: cast(baml_py.Checked[int,types.Literal["too_big"]], x.cast_to(types, types)),
lambda x: cast(Checked[Optional[int],types.Literal["too_big"]], x.cast_to(types, partial_types)),
lambda x: cast(Checked[int,types.Literal["too_big"]], x.cast_to(types, types)),
self.__ctx_manager.get(),
)

Expand Down
11 changes: 6 additions & 5 deletions integ-tests/python/baml_client/partial_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from typing import Dict, List, Optional, Union, Literal

from . import types
from .types import Checked, Check

###############################################################################
#
Expand Down Expand Up @@ -121,7 +122,7 @@ class DynamicOutput(BaseModel):
class Earthling(BaseModel):


age: baml_py.Checked[Optional[int],Literal["earth_aged", "no_infants"]]
age: Checked[Optional[int],Literal["earth_aged", "no_infants"]]

class Education(BaseModel):

Expand Down Expand Up @@ -170,8 +171,8 @@ class FooAny(BaseModel):


planetary_age: Optional[Union["Martian", "Earthling"]] = None
certainty: baml_py.Checked[Optional[int],Literal["unreasonably_certain"]]
species: baml_py.Checked[Optional[str],Literal["regex_bad", "regex_good", "trivial"]]
certainty: Checked[Optional[int],Literal["unreasonably_certain"]]
species: Checked[Optional[str],Literal["regex_bad", "regex_good", "trivial"]]

class GroceryReceipt(BaseModel):

Expand Down Expand Up @@ -224,7 +225,7 @@ class LiteralClassTwo(BaseModel):
class MalformedConstraints(BaseModel):


foo: baml_py.Checked[Optional[int],Literal["foo_check"]]
foo: Checked[Optional[int],Literal["foo_check"]]

class MalformedConstraints2(BaseModel):

Expand All @@ -234,7 +235,7 @@ class MalformedConstraints2(BaseModel):
class Martian(BaseModel):


age: baml_py.Checked[Optional[int],Literal["young_enough"]]
age: Checked[Optional[int],Literal["young_enough"]]

class NamedArgsSingleClass(BaseModel):

Expand Down
13 changes: 7 additions & 6 deletions integ-tests/python/baml_client/sync_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from pydantic import BaseModel, ValidationError, create_model

from . import partial_types, types
from .types import Checked, Check
from .type_builder import TypeBuilder
from .globals import DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX, DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME

Expand Down Expand Up @@ -1338,7 +1339,7 @@ def PredictAgeBare(
self,
inp: str,
baml_options: BamlCallOptions = {},
) -> baml_py.Checked[int,types.Literal["too_big"]]:
) -> Checked[int,types.Literal["too_big"]]:
__tb__ = baml_options.get("tb", None)
if __tb__ is not None:
tb = __tb__._tb
Expand All @@ -1355,7 +1356,7 @@ def PredictAgeBare(
tb,
__cr__,
)
return cast(baml_py.Checked[int,types.Literal["too_big"]], raw.cast_to(types, types))
return cast(Checked[int,types.Literal["too_big"]], raw.cast_to(types, types))

def PromptTestClaude(
self,
Expand Down Expand Up @@ -4206,7 +4207,7 @@ def PredictAgeBare(
self,
inp: str,
baml_options: BamlCallOptions = {},
) -> baml_py.BamlSyncStream[baml_py.Checked[Optional[int],types.Literal["too_big"]], baml_py.Checked[int,types.Literal["too_big"]]]:
) -> baml_py.BamlSyncStream[Checked[Optional[int],types.Literal["too_big"]], Checked[int,types.Literal["too_big"]]]:
__tb__ = baml_options.get("tb", None)
if __tb__ is not None:
tb = __tb__._tb
Expand All @@ -4225,10 +4226,10 @@ def PredictAgeBare(
__cr__,
)

return baml_py.BamlSyncStream[baml_py.Checked[Optional[int],types.Literal["too_big"]], baml_py.Checked[int,types.Literal["too_big"]]](
return baml_py.BamlSyncStream[Checked[Optional[int],types.Literal["too_big"]], Checked[int,types.Literal["too_big"]]](
raw,
lambda x: cast(baml_py.Checked[Optional[int],types.Literal["too_big"]], x.cast_to(types, partial_types)),
lambda x: cast(baml_py.Checked[int,types.Literal["too_big"]], x.cast_to(types, types)),
lambda x: cast(Checked[Optional[int],types.Literal["too_big"]], x.cast_to(types, partial_types)),
lambda x: cast(Checked[int,types.Literal["too_big"]], x.cast_to(types, types)),
self.__ctx_manager.get(),
)

Expand Down
Loading

0 comments on commit 0ccf473

Please sign in to comment.