Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added complex types to str #140

Merged
merged 3 commits into from
Dec 5, 2024
Merged

Added complex types to str #140

merged 3 commits into from
Dec 5, 2024

Conversation

whitead
Copy link
Contributor

@whitead whitead commented Dec 5, 2024

We've been waiting a long time for it!

@whitead whitead requested a review from jamesbraza December 5, 2024 20:31
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Dec 5, 2024
@dosubot dosubot bot added the enhancement New feature or request label Dec 5, 2024
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Dec 5, 2024
@@ -393,6 +393,9 @@ def test_describe(self, subtests: SubTests) -> None:
with subtests.test("Test describe_json is callable"):
assert tool.info.describe_json()

with subtests.test("Test describe_str is callable"):
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test uses example_fxn. About 20 lines up there is test_describe_str that already handles example_fxn

To better cover this change, can you add many_edge_cases to test_describe_str?

Comment on lines +229 to +241
resolved_subschemas = [FunctionInfo.resolve_schema(s) for s in subschemas]

if key == "allOf":
for subschema in resolved_subschemas:
merged_schema.update(subschema)
elif key == "anyOf":
types = []
descriptions = []
for subschema in resolved_subschemas:
if "type" in subschema:
types.append(subschema["type"])
if "description" in subschema:
descriptions.append(subschema["description"])
Copy link

Choose a reason for hiding this comment

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

Suggested change
resolved_subschemas = [FunctionInfo.resolve_schema(s) for s in subschemas]
if key == "allOf":
for subschema in resolved_subschemas:
merged_schema.update(subschema)
elif key == "anyOf":
types = []
descriptions = []
for subschema in resolved_subschemas:
if "type" in subschema:
types.append(subschema["type"])
if "description" in subschema:
descriptions.append(subschema["description"])
resolved_subschemas = list(map(FunctionInfo.resolve_schema, subschemas))
types = [
subschema["type"]
for subschema in resolved_subschemas
if "type" in subschema
]
descriptions = [
subschema["description"]
for subschema in resolved_subschemas
if "description" in subschema
]

Copy link

codeflash-ai bot commented Dec 5, 2024

⚡️ Codeflash found optimizations for this PR

📄 FunctionInfo.resolve_schema in src/aviary/tools/base.py

✨ Performance Summary:

  • Speed Increase: 📈 28% (0.28x faster)
  • Runtime Reduction: ⏱️ From 1.64 millisecond down to 1.28 millisecond (best of 138 runs)

📝 Explanation and details

Here's an optimized version of your program for better performance while retaining the same functionality.

Explanation

  1. Using map: Instead of list comprehension to recursively resolve subschemas, map is used which is generally faster as it avoids the overhead of list creation.
  2. Precomputing Lists: Precomputing types and descriptions lists in anyOf before any further processing.
  3. Simplified Logic: The logic of merging properties into merged_schema is preserved but written more concisely.

Correctness verification

The new optimized code was tested for correctness. The results are listed below:

Test Status Details
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 42 Passed See below
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Coverage undefined

🌀 Generated Regression Tests Details

Click to view details
import pytest  # used for our unit tests
from aviary.tools.base import FunctionInfo
# function to test
from pydantic import BaseModel


# unit tests
def test_basic_schema_without_allOf_or_anyOf():
    # Simple schema without allOf or anyOf
    schema = { "type": "string" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_single_allOf_subschema():
    # Schema with a single allOf subschema
    schema = { "allOf": [{ "type": "string" }] }
    expected = { "type": "string" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_multiple_allOf_subschemas():
    # Schema with multiple allOf subschemas
    schema = { "allOf": [{ "type": "string" }, { "description": "A string value" }] }
    expected = { "type": "string", "description": "A string value" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_nested_allOf_subschemas():
    # Schema with nested allOf subschemas
    schema = { "allOf": [{ "allOf": [{ "type": "string" }, { "description": "A string value" }] }] }
    expected = { "type": "string", "description": "A string value" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_single_anyOf_subschema():
    # Schema with a single anyOf subschema
    schema = { "anyOf": [{ "type": "string" }] }
    expected = { "type": "string" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_multiple_anyOf_subschemas():
    # Schema with multiple anyOf subschemas
    schema = { "anyOf": [{ "type": "string" }, { "type": "integer" }] }
    expected = { "type": "string | integer" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_nested_anyOf_subschemas():
    # Schema with nested anyOf subschemas
    schema = { "anyOf": [{ "anyOf": [{ "type": "string" }, { "type": "integer" }] }] }
    expected = { "type": "string | integer" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_combining_descriptions_in_anyOf():
    # Schema with multiple descriptions in anyOf subschemas
    schema = { "anyOf": [{ "description": "First description" }, { "description": "Second description" }] }
    expected = { "description": "First description / Second description" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_both_allOf_and_anyOf():
    # Schema with both allOf and anyOf
    schema = { "allOf": [{ "type": "string" }], "anyOf": [{ "type": "integer" }] }
    expected = { "type": "integer" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_nested_allOf_within_anyOf():
    # Schema with nested allOf within anyOf
    schema = { "anyOf": [{ "allOf": [{ "type": "string" }, { "description": "A string value" }] }, { "type": "integer" }] }
    expected = { "type": "string | integer", "description": "A string value" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_nested_anyOf_within_allOf():
    # Schema with nested anyOf within allOf
    schema = { "allOf": [{ "anyOf": [{ "type": "string" }, { "type": "integer" }] }, { "description": "A combined schema" }] }
    expected = { "type": "string | integer", "description": "A combined schema" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_empty_schema():
    # Empty schema
    schema = {}
    expected = {}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_only_allOf_key():
    # Schema with only allOf key
    schema = { "allOf": [] }
    expected = {}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_only_anyOf_key():
    # Schema with only anyOf key
    schema = { "anyOf": [] }
    expected = {}
    codeflash_output = FunctionInfo.resolve_schema(schema)



def test_schema_with_additional_properties():
    # Schema with additional properties
    schema = { "allOf": [{ "type": "string" }], "title": "A title", "default": "default value" }
    expected = { "type": "string", "title": "A title", "default": "default value" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_large_number_of_subschemas_in_allOf():
    # Large number of subschemas in allOf
    schema = { "allOf": [{ "type": "string" }] * 1000 }
    expected = { "type": "string" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_large_number_of_subschemas_in_anyOf():
    # Large number of subschemas in anyOf
    schema = { "anyOf": [{ "type": "string" }, { "type": "integer" }] * 1000 }
    expected = { "type": "string | integer" }
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_deeply_nested_subschemas():
    # Deeply nested subschemas
    schema = { "allOf": [{ "anyOf": [{ "allOf": [{ "type": "string" }] * 10 }] * 10 }] * 10 }
    expected = { "type": "string" }
    codeflash_output = FunctionInfo.resolve_schema(schema)




import pytest  # used for our unit tests
from aviary.tools.base import FunctionInfo
# function to test
from pydantic import BaseModel

# unit tests

def test_simple_schema_without_allOf_or_anyOf():
    # Basic schema with a single type
    schema = {"type": "string"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Schema with multiple properties
    schema = {"type": "object", "properties": {"name": {"type": "string"}, "age": {"type": "integer"}}}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_allOf():
    # Single subschema in allOf
    schema = {"allOf": [{"type": "string"}]}
    expected = {"type": "string"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Multiple subschemas in allOf with non-conflicting properties
    schema = {"allOf": [{"type": "string"}, {"maxLength": 5}]}
    expected = {"type": "string", "maxLength": 5}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Multiple subschemas in allOf with conflicting properties
    schema = {"allOf": [{"type": "string"}, {"type": "integer"}]}
    expected = {"type": "integer"}  # Last subschema's type will overwrite previous ones
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Nested allOf within allOf
    schema = {"allOf": [{"allOf": [{"type": "string"}, {"maxLength": 5}]}]}
    expected = {"type": "string", "maxLength": 5}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_anyOf():
    # Single subschema in anyOf
    schema = {"anyOf": [{"type": "string"}]}
    expected = {"type": "string"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Multiple subschemas in anyOf with different types
    schema = {"anyOf": [{"type": "string"}, {"type": "integer"}]}
    expected = {"type": "string | integer"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Multiple subschemas in anyOf with descriptions
    schema = {"anyOf": [{"type": "string", "description": "A string"}, {"type": "integer", "description": "An integer"}]}
    expected = {"type": "string | integer", "description": "A string / An integer"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Nested anyOf within anyOf
    schema = {"anyOf": [{"anyOf": [{"type": "string"}, {"type": "integer"}]}]}
    expected = {"type": "string | integer"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_both_allOf_and_anyOf():
    # Combining allOf and anyOf at the same level
    schema = {"allOf": [{"type": "string"}], "anyOf": [{"type": "integer"}]}
    expected = {"type": "integer"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Nested allOf within anyOf
    schema = {"anyOf": [{"allOf": [{"type": "string"}, {"maxLength": 5}]}]}
    expected = {"type": "string", "maxLength": 5}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Nested anyOf within allOf
    schema = {"allOf": [{"anyOf": [{"type": "string"}, {"type": "integer"}]}]}
    expected = {"type": "string | integer"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_schema_with_additional_properties():
    # Schema with additional properties alongside allOf
    schema = {"allOf": [{"type": "string"}], "title": "Example Schema", "description": "A simple example"}
    expected = {"type": "string", "title": "Example Schema", "description": "A simple example"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Schema with additional properties alongside anyOf
    schema = {"anyOf": [{"type": "string"}, {"type": "integer"}], "title": "Example Schema", "description": "A simple example"}
    expected = {"type": "string | integer", "title": "Example Schema", "description": "A simple example"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_edge_cases():
    # Empty schema
    schema = {}
    expected = {}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Schema with empty allOf
    schema = {"allOf": []}
    expected = {}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Schema with empty anyOf
    schema = {"anyOf": []}
    expected = {}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Schema with invalid keys
    schema = {"allOf": [{"type": "string"}], "unknownKey": "value"}
    expected = {"type": "string", "unknownKey": "value"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

def test_large_scale():
    # Large number of subschemas in allOf
    schema = {"allOf": [{"type": "string"}] * 1000}
    expected = {"type": "string"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Large number of subschemas in anyOf
    schema = {"anyOf": [{"type": "string"}] * 1000}
    expected = {"type": "string"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Deeply nested schemas
    schema = {"allOf": [{"allOf": [{"allOf": [{"type": "string"}]}]}]}
    expected = {"type": "string"}
    codeflash_output = FunctionInfo.resolve_schema(schema)

    # Complex schema with multiple nested allOf and anyOf
    schema = {"allOf": [{"anyOf": [{"type": "string"}, {"type": "integer"}]}, {"allOf": [{"type": "boolean"}]}], "title": "Complex Schema"}
    expected = {"type": "string | integer", "title": "Complex Schema"}
    codeflash_output = FunctionInfo.resolve_schema(schema)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

📣 **Feedback**

If you have any feedback or need assistance, feel free to join our Discord community:

Discord

@whitead whitead merged commit dcb34e0 into main Dec 5, 2024
6 checks passed
@whitead whitead deleted the complex-types branch December 5, 2024 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request size:M This PR changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants