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

Lazily initialize config drivers field #1062

Merged
merged 4 commits into from
Aug 15, 2024
Merged

Conversation

collindutter
Copy link
Member

@collindutter collindutter commented Aug 14, 2024

Describe your changes

Lazily initializes the config.driver field so that the OpenAiChatPromptDriver doesn't initialize itself when the user doesn't intend to use it.

Issue ticket number and link

NA

@collindutter
Copy link
Member Author

Not sure how to unit test this because of schrodinger's initialization. Inspecting the config.driver property immediately gives it a value.

@vachillo
Copy link
Member

vachillo commented Aug 14, 2024

unit tests you could inspect config._drivers ?

@collindutter
Copy link
Member Author

Technically there is no _drivers because of the alias. I'll remove the attrs magic since users will never create a _Config directly. It'll always be used via the setters.

Copy link

codecov bot commented Aug 14, 2024

Codecov Report

Attention: Patch coverage is 96.77419% with 1 line in your changes missing coverage. Please review.

Files Patch % Lines
griptape/config/config.py 95.45% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@vachillo
Copy link
Member

Technically there is no _drivers because of the alias. I'll remove the attrs magic since users will never create a _Config directly. It'll always be used via the setters.

the alias is just for init isnt it? the actual field still exists on the class.

dylanholmes
dylanholmes previously approved these changes Aug 14, 2024
Copy link
Contributor

@dylanholmes dylanholmes left a comment

Choose a reason for hiding this comment

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

I can't think of any reason this would be bad off the top of my head, but it makes me a little nervous

Comment on lines 12 to 19
_drivers: BaseDriverConfig = field(default=None)

@property
def drivers(self) -> BaseDriverConfig:
"""Lazily instantiates the drivers configuration to avoid client errors like missing API key."""
if self._drivers is None:
self._drivers = OpenAiDriverConfig()
return self._drivers
Copy link
Contributor

Choose a reason for hiding this comment

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

encapsulation to the rescue

class _Config(BaseConfig):
drivers: BaseDriverConfig = field(default=Factory(lambda: OpenAiDriverConfig()), kw_only=True)
logging: LoggingConfig = field(default=Factory(lambda: LoggingConfig()), kw_only=True)
logging: LoggingConfig = field(default=Factory(lambda: LoggingConfig()))
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be proactive and do this for logging too?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I'd rather avoid introducing weird hacks like this if we can avoid it. Until there's a clear reason to introduce for logging, I say we avoid -- the API won't change either way.

@collindutter
Copy link
Member Author

Ok I really don't know how to test this because of this root conftest which immediately initializes the value for all tests. According to Codecov we're already covered here 🤷‍♂️

@vachillo
Copy link
Member

Ok I really don't know how to test this because of this root conftest which immediately initializes the value for all tests. According to Codecov we're already covered here 🤷‍♂️

what about setting it to None at the top of the test file and then importing everything? including setting os.environ["OPENAI_API_KEY"] = None

drivers: BaseDriverConfig = field(default=Factory(lambda: OpenAiDriverConfig()), kw_only=True)
logging: LoggingConfig = field(default=Factory(lambda: LoggingConfig()), kw_only=True)
logging: LoggingConfig = field(default=Factory(lambda: LoggingConfig()))
_drivers: BaseDriverConfig = field(default=None)
Copy link
Member

@vachillo vachillo Aug 14, 2024

Choose a reason for hiding this comment

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

fyi on aliases (aliai?)

attrs follows the doctrine that there is no such thing as a private argument and strips the underscores from the name when writing the init method signature

so removing alias=drivers makes no difference, its just less obvious what the parameter name is

dylanholmes
dylanholmes previously approved these changes Aug 14, 2024
Copy link
Contributor

@dylanholmes dylanholmes left a comment

Choose a reason for hiding this comment

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

Seems fine enough, but added a couple of prodding questions

Comment on lines 23 to 24
# Some tests we don't want to use the autouse fixture's MockDriverConfig
if "skip_autouse_fixture" in request.keywords:
Copy link
Contributor

Choose a reason for hiding this comment

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

Is skip_autouse_fixture a pytest thing or something we just made up? If it is a pytest thing, does it disable all autouse fixtures? If it disabled all autouse fixtures, then why would this line be needed? I'm guessing we just made this up. If so, can we make the naming more specific to the mock_config fixture?

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated the name to skip_mock_config

from .logging_config import LoggingConfig
if TYPE_CHECKING:
from .base_driver_config import BaseDriverConfig
from .logging_config import LoggingConfig


@define(kw_only=True)
class BaseConfig(SerializableMixin, ABC):
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of scope for this PR, but why do we have this base class? How would we a subclass other than _Config?

I only bring it up, because the reset method in here feels weird.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed that it's probably redundant here (and maybe even adds some confusion), but I think I'd prefer to keep consistent with the pattern of having a base class for any inheritance hierarchy.

Who knows what the config classes may evolve into over time.

@collindutter collindutter merged commit c76b453 into dev Aug 15, 2024
13 checks passed
@collindutter collindutter deleted the fix/lazy-config-init branch August 15, 2024 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants