-
Notifications
You must be signed in to change notification settings - Fork 71
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
Expose All Response Types/Objects #464
Expose All Response Types/Objects #464
Conversation
Warning Rate limit exceeded@dvonthenen has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 13 seconds before requesting another review. How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughThe changes involve a comprehensive restructuring of import statements and organization of classes across multiple files in the Deepgram SDK. New entities have been added, existing entities have been reorganized into categorized sections, and several classes have been renamed or removed to streamline the codebase. The modifications focus on improving clarity and maintainability without altering the core functionality of the SDK. Changes
Possibly related PRs
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
ab2aea8
to
b2c6dce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Inline review comments failed to post
Actionable comments posted: 27
Outside diff range and nitpick comments (46)
deepgram/clients/live/v1/__init__.py (1)
13-14
: LGTM! Consider updating documentation.The addition of
ListenWSMetadataResponse
and retainingMetadataResponse
for backward compatibility aligns well with the PR objectives. This change successfully exposes the new type at the top level while maintaining support for existing code.Consider updating the documentation to:
- Explain the difference between
ListenWSMetadataResponse
andMetadataResponse
.- Guide users on when to use each type.
- Indicate that
MetadataResponse
is maintained for backward compatibility but may be deprecated in future versions.This will help users understand and adopt the new structure more effectively.
deepgram/clients/listen/v1/websocket/__init__.py (1)
22-30
: Great further categorization of response classesThe additional categorization of response classes into "between rest and websocket" and "unique" sections further enhances the clarity and organization of the imports. This change aligns perfectly with the PR objective of exposing all types and classes at the top level, making it easier for users to access any object in a response by its name or reference.
One minor suggestion for consistency:
Consider adding a comment for the "Metadata" class similar to the other categories:
Channel, Word, - #### unique - Metadata, + #### unique + Metadata,This small change would maintain the consistent style throughout the import section.
deepgram/clients/analyze/v1/__init__.py (2)
17-24
: LGTM! Analyze-specific options grouped together.The reorganization of imports improves code structure by grouping analyze-specific options together. This change, along with the addition of
AnalyzeStreamSource
andAnalyzeSource
, supports the PR objective of exposing all types at the top level.Consider adding a blank line before the "analyze" comment (line 17) for consistency with the "common" section above.
42-46
: LGTM! Unique response types added to complete the set.The addition of
Metadata
,Results
, andSummary
as unique response types completes the set of exposed types, fully aligning with the PR objective. This change enhances the SDK's completeness and usability without breaking existing functionality.Consider adding a blank line before the "unique" comment (line 42) for consistency with the "shared" section above and to improve readability.
deepgram/clients/common/v1/__init__.py (1)
Line range hint
1-47
: Overall, the changes successfully implement the PR objectives with a minor concern.The modifications to this
__init__.py
file effectively expose all types and classes at the top level of the response results, aligning with the PR objectives. The import structure is clean, logical, and follows Python best practices.However, there's one minor concern to address:
- Potential naming conflict: The
Sentiment
class is imported from bothenums
andrest_response
modules. To resolve this, consider one of the following options:
a. Use an alias for one of the imports to differentiate them.
b. If they represent the same concept, consider consolidating them into a single import.
c. If they are different and both necessary, consider renaming one to avoid confusion.To resolve the naming conflict, you could modify the import statement as follows:
from .enums import Sentiment as EnumSentiment # ... other imports ... from .rest_response import ( # ... other imports ... Sentiment as ResponseSentiment, # ... other imports ... )This approach clearly distinguishes between the two
Sentiment
classes while maintaining backward compatibility.deepgram/clients/speak/v1/__init__.py (2)
5-19
: Improved import organization and exposure of types.The reorganization of imports from the
.rest
module enhances code readability and aligns with the PR objective of exposing all types at the top level. The categorization into "top level," "common," and "unique" sections provides a clear structure.There's a minor inconsistency in naming convention:
- Line 18 uses
SpeakRESTSource
- Line 17 uses
SpeakRestSource
Consider standardizing to either
REST
orRest
for consistency.
28-47
: Improved websocket import organization and type exposure.The reorganization of imports from the
.websocket
module enhances code readability and aligns with the PR objective of exposing all types at the top level. The categorization into "top level" and "shared" sections provides a clear structure.The alias
SpeakWSMetadataResponse
forMetadataResponse
is a good practice to avoid potential naming conflicts.Consider grouping all imports from
.websocket
into a singlefrom .websocket import (...)
statement for better consistency with the rest imports. This would make the import structure more uniform across the file.deepgram/clients/manage/__init__.py (1)
33-52
: LGTM: Comprehensive additions enhance SDK functionalityThe extensive additions to the "shared" section significantly enhance the SDK's functionality and align well with the PR objectives. The inclusion of various types like
STTDetails
,TTSMetadata
,Member
, etc., improves the SDK's flexibility and usability. MovingBalance
to this section is logical and maintains consistency.These changes appear to be backwards compatible and greatly improve the SDK's capabilities.
Consider grouping related types together (e.g., STT-related, TTS-related, Usage-related) for improved readability. For example:
# STT-related STTDetails, STTUsageDetails, STTTokens, # TTS-related TTSMetadata, TTSDetails, TTSUsageDetails, TTSTokens, # Usage-related UsageSummaryResults, UsageModel, # Other types...deepgram/clients/speak/__init__.py (1)
14-25
: LGTM: Well-organized imports with a suggestionThe categorization of imports into "top level", "common", and "unique" sections greatly improves code organization and readability. Moving SpeakOptions to the top level aligns with the PR objective of exposing all types at the top level. The addition of various Source types provides more granular control over input sources, which is beneficial for users.
Consider adding a brief comment above each category (top level, common, unique) to explain their purpose or criteria for inclusion. This would further enhance code readability and maintainability.
deepgram/clients/listen/v1/rest/__init__.py (1)
46-58
: Excellent addition of unique response types with a suggestion for documentation.The inclusion of numerous unique response types (e.g.,
Entity
,Metadata
,Paragraph
,Results
) greatly enhances the SDK's capability to handle diverse response data. This aligns perfectly with the PR objective of exposing all response types at the top level.Consider adding a brief inline comment or docstring to explain the distinction between "shared", "unique", and "between rest and websocket" categories. This would further improve the code's self-documentation and help users understand the purpose and scope of each category.
deepgram/clients/common/v1/websocket_response.py (4)
16-22
: Consider using a more specific type for the 'type' attribute.The
OpenResponse
class looks good overall, but consider the following suggestion:Instead of initializing
type
as an empty string, it might be more appropriate to use a more specific type or a default value that accurately represents an "open" message. This could improve type safety and make the code more self-documenting.Consider modifying the class definition as follows:
from typing import Literal @dataclass class OpenResponse(BaseResponse): """ Open Message from the Deepgram Platform """ type: Literal["open"] = "open"This change ensures that
type
can only be "open" and provides a meaningful default value.
28-34
: Apply the same type improvement to CloseResponse.Similar to the
OpenResponse
class, consider improving the type definition for theCloseResponse
class:Modify the class definition as follows:
from typing import Literal @dataclass class CloseResponse(BaseResponse): """ Close Message from the Deepgram Platform """ type: Literal["close"] = "close"This change ensures type safety and provides a meaningful default value for the
type
attribute.
40-51
: Good use of Optional and custom metadata, consider improving attribute initialization.The
ErrorResponse
class is well-structured with appropriate use ofOptional
and custom metadata for JSON serialization. However, consider the following suggestions:
Instead of initializing
description
,message
, andtype
as empty strings, consider usingNone
as the default value. This makes it clear when these fields haven't been set.Use
field(default=None)
for these attributes to maintain consistency with thevariant
attribute.Here's a suggested improvement:
@dataclass class ErrorResponse(BaseResponse): """ Error Message from the Deepgram Platform """ description: Optional[str] = field(default=None) message: Optional[str] = field(default=None) type: Optional[str] = field(default=None) variant: Optional[str] = field( default=None, metadata=dataclass_config(exclude=lambda f: f is None) )This change improves consistency and makes it clearer when fields haven't been set.
57-64
: Consider improving attribute initialization for UnhandledResponse.The
UnhandledResponse
class structure is clear, but the attribute initialization can be improved:
- For the
type
attribute, consider using a more specific type or a default value that accurately represents an "unhandled" message.- For the
raw
attribute, consider usingNone
as the default value to clearly indicate when it hasn't been set.Here's a suggested improvement:
from typing import Literal, Optional @dataclass class UnhandledResponse(BaseResponse): """ Unhandled Message from the Deepgram Platform """ type: Literal["unhandled"] = "unhandled" raw: Optional[str] = field(default=None)This change improves type safety for the
type
attribute and makes it clearer when theraw
field hasn't been set.deepgram/clients/live/v1/client.py (1)
11-11
: Approve renaming of MetadataResponse importThe renaming of
MetadataResponse
toListenWSMetadataResponse
improves clarity by specifying its relation to WebSocket listening. This change aligns well with the PR objective of exposing all types at the top level.Consider adding a brief comment explaining the purpose of this specific response type to enhance code readability. For example:
# Response type for WebSocket listening metadata ListenWSMetadataResponse as ListenWSMetadataResponseLatest,deepgram/clients/speak/v1/rest/options.py (1)
61-64
: Approve type aliases, improve comment, and address pylint issue.The new type aliases
SpeakSource
,SpeakRestSource
, andSpeakRESTSource
are good additions, providing clear definitions for the types of sources accepted by the Speak API.However, there are a few points to consider:
The comment "unique" is vague. Consider replacing it with a more descriptive comment explaining the purpose of these aliases.
The pylint disable comment for
SpeakRESTSource
suggests a naming convention issue. Instead of disabling the pylint check, consider renaming the alias to follow the naming convention (e.g.,SpeakRestSource
).
SpeakRestSource
andSpeakRESTSource
are identical. Consider keeping only one of them to avoid confusion.Here's a suggested improvement:
# Define source types for the Speak API SpeakSource = Union[FileSource, BufferedReader] SpeakRestSource = SpeakSourcedeepgram/clients/analyze/v1/options.py (1)
83-83
: Clarify the relationship between AnalyzeSource and AnalyzeStreamSource.While
AnalyzeStreamSource
is still defined, it's no longer part ofAnalyzeSource
. This separation might not be immediately clear to users.Consider adding a comment explaining the relationship between these types and why
AnalyzeStreamSource
is separate fromAnalyzeSource
. Additionally, update the documentation to reflect this change in the type hierarchy.deepgram/clients/analyze/client.py (1)
Line range hint
80-87
: LGTM: Client aliases are correctly defined. Consider adding a clarification comment.The aliases for AnalyzeClient and AsyncAnalyzeClient are properly defined, pointing to their respective "Latest" versions. The additional aliases (ReadClient and AsyncReadClient) are also correctly set up.
Consider adding a brief comment explaining the purpose of the ReadClient and AsyncReadClient aliases. For example:
# Aliases for backwards compatibility or alternative naming ReadClient = AnalyzeClientLatest AsyncReadClient = AsyncAnalyzeClientLatestThis would provide clarity on why these additional aliases exist.
deepgram/clients/speak/client.py (3)
Line range hint
5-50
: Improved import organization and versioning.The reorganization of imports and the addition of "Latest" suffixes to class aliases significantly enhance code readability and maintainability. This structure clearly indicates the most up-to-date versions of classes and provides a good overview of the SDK's components.
Consider adding comments to separate the import groups more clearly, for example:
# REST-related imports from .v1 import ( ... ) # WebSocket-related imports from .v1 import ( ... ) # Response type imports from .v1 import ( ... )This would further improve readability, especially as the number of imports grows.
Line range hint
55-83
: Well-structured alias declarations for backward compatibility.The alias declarations are well-organized, maintaining backward compatibility while allowing for future version updates. The grouping into REST and WebSocket sections, further divided into input and output classes, significantly improves code readability and organization.
Regarding the
# pylint: disable=invalid-name
comment on line 65:SpeakRESTSource = SpeakRESTSourceLatest # pylint: disable=invalid-nameConsider moving this pylint disable to the top of the file or creating a
.pylintrc
file to globally configure this rule if it applies to multiple lines. This would reduce inline comments and improve overall code cleanliness.
Line range hint
86-97
: Comprehensive client declarations with backward compatibility.The declarations effectively maintain backward compatibility while providing clear entry points for both REST and WebSocket clients, including their asynchronous counterparts. This approach ensures flexibility for various use cases and smooth transitions for existing users.
To improve clarity, consider adding a brief comment explaining the purpose of the backward compatibility aliases. For example:
# Backward compatibility aliases for users of older SDK versions SpeakResponse = SpeakRESTResponseLatest SpeakClient = SpeakRESTClientLatest # Current client classes SpeakRESTClient = SpeakRESTClientLatest AsyncSpeakRESTClient = AsyncSpeakRESTClientLatest # ... (rest of the client declarations)This would help future maintainers understand the rationale behind these aliases.
deepgram/clients/manage/client.py (3)
31-54
: LGTM: Comprehensive addition of new response classesThe extensive addition of new response classes significantly enhances the SDK's capability to handle various response types, aligning well with the PR objectives. The naming conventions are consistent, and the imports are logically organized.
Consider grouping the imports more explicitly, perhaps with comments separating different categories (e.g., "General", "STT-related", "TTS-related", "Usage-related"). This could improve readability and make it easier to locate specific imports in the future.
83-106
: LGTM: Comprehensive addition of new response class assignmentsThe extensive addition of assignments for the newly imported response classes is consistent with the PR objectives and maintains the pattern of aliasing the latest version of each class. This ensures that all new types are exposed at the top level while maintaining backwards compatibility.
To improve readability and maintain consistency with the import section, consider grouping these assignments more explicitly, perhaps with comments separating different categories (e.g., "General", "STT-related", "TTS-related", "Usage-related"). This would make it easier to locate specific assignments and maintain parallelism with the import section.
Line range hint
1-106
: Overall LGTM: Successful exposure of all response types/objectsThe changes in this file successfully achieve the PR objective of exposing all types and classes at the top level of the response results. The modifications:
- Add numerous new response classes to the imports.
- Create corresponding assignments for these new classes.
- Maintain backwards compatibility by following the existing pattern of aliasing the latest versions.
- Preserve consistent naming conventions and code structure.
These changes enhance the SDK's capability to handle various response types while ensuring that existing client code remains unaffected. The expanded set of response classes, particularly in STT and TTS functionalities, provides users with more granular access to response data.
As the number of response types grows, consider implementing a more scalable approach to organizing and documenting these types. This could involve:
- Creating separate modules for different categories of response types (e.g.,
stt_responses.py
,tts_responses.py
,usage_responses.py
).- Implementing a dynamic import mechanism to reduce the number of explicit imports in this file.
- Generating API documentation that clearly outlines all available response types and their structures.
These steps would improve maintainability and make it easier for users to understand and utilize the full range of response types available in the SDK.
deepgram/clients/listen/v1/websocket/options.py (2)
Line range hint
48-57
: Address the TODO comment for theendpointing
field type.The TODO comment indicates that the
endpointing
field type needs to be updated in a future release. To address this:
- Create a separate issue to track this change and link it to this PR.
- Plan for a deprecation cycle:
a. In the next minor release, add a deprecation warning when a string value is used.
b. In a future major release, change the type toOptional[Union[bool, int]]
.- Update the documentation to reflect the planned change and guide users on migrating their code.
Would you like me to create a GitHub issue to track this TODO and outline the deprecation plan?
Line range hint
17-157
: Consider refactoring theLiveOptions
class for improved maintainability.The
LiveOptions
class has a large number of optional fields, which might make it difficult to use and maintain. Consider the following improvements:
- Group related fields into nested dataclasses to improve organization and readability.
- Use a builder pattern or factory methods to create
LiveOptions
instances with specific configurations.- Implement property methods for fields that require additional validation or transformation logic.
Additionally, the
check
method modifies the logger level, which might have unintended side effects. Consider refactoring it to:
- Use a separate logger instance for this method to avoid affecting the global logger configuration.
- Return a list of warnings instead of logging them directly, allowing the caller to handle the warnings as needed.
Here's an example of how you might start refactoring the class:
from dataclasses import dataclass from typing import List, Optional @dataclass class AudioOptions: encoding: Optional[str] = None sample_rate: Optional[int] = None channels: Optional[int] = None @dataclass class TranscriptionOptions: model: str = "nova-2" language: Optional[str] = None punctuate: Optional[bool] = None # ... other transcription-related fields @dataclass class LiveOptions(BaseResponse): audio: AudioOptions = field(default_factory=AudioOptions) transcription: TranscriptionOptions = field(default_factory=TranscriptionOptions) # ... other top-level fields @classmethod def with_audio_config(cls, encoding: str, sample_rate: int, channels: int) -> 'LiveOptions': return cls(audio=AudioOptions(encoding=encoding, sample_rate=sample_rate, channels=channels)) def check(self) -> List[str]: warnings = [] if self.transcription.tier: warnings.append("Tier is deprecated. Will be removed in a future version.") # ... other checks return warningsThis refactoring improves organization, reduces the number of top-level fields, and provides a more flexible way to create and validate
LiveOptions
instances.deepgram/clients/__init__.py (1)
71-78
: Approved with a minor suggestion: Consider naming consistencyThe changes effectively remove duplicate imports and add new source types, aligning with the PR objectives. However, there's a minor inconsistency in naming:
PreRecordedStreamSource
uses "RecOrded"PrerecordedSource
uses "recorded"Consider standardizing the capitalization for consistency, preferably to
PrerecordedStreamSource
.deepgram/clients/listen/v1/rest/options.py (1)
173-178
: Review new type alias and clarify comment.The addition of
PrerecordedSource = Union[UrlSource, FileSource]
provides a clear type hint for accepted source types. This is a good improvement for code clarity.However, there's a potential issue with the comment on line 177-178:
# PrerecordedSource for backwards compatibility PreRecordedStreamSource = StreamSourceThis comment seems to be misplaced or incorrect, as it doesn't match the alias name
PreRecordedStreamSource
.Consider updating the comment to accurately reflect the purpose of
PreRecordedStreamSource
:# Retained for backwards compatibility PreRecordedStreamSource = StreamSourceAlso, consider adding a brief comment explaining the purpose of the new
PrerecordedSource
alias.deepgram/__init__.py (3)
48-61
: LGTM: New response-related imports addedThe addition of these imports aligns well with the PR objective of exposing all types and classes at the top level. The logical grouping enhances code organization and readability.
Consider alphabetizing the imports within each group for even better organization and easier maintenance. For example:
from .client import ( Average, Intent, Intents, IntentsInfo, Segment, Sentiment, SentimentInfo, Sentiments, SummaryInfo, Topic, Topics, TopicsInfo, )
83-94
: LGTM: WebSocket-related imports reorganized and expandedThe reorganization and addition of WebSocket-related imports enhance the SDK's structure and align with the PR objective. The categorization (top level, common websocket response, unique) improves code readability and organization.
Consider using a consistent comment style for better readability. For example:
# Top level LiveResultResponse, ListenWSMetadataResponse, SpeechStartedResponse, UtteranceEndResponse, # Common websocket response # OpenResponse, # CloseResponse, # UnhandledResponse, # ErrorResponse, # Unique ListenWSMetadata,
Line range hint
216-291
: LGTM: Client-related imports reorganized and expandedThe reorganization and addition of client-related imports enhance the SDK's structure and align with the PR objective. The categorization (top level, shared) improves code readability and organization.
Consider alphabetizing the imports within each category for even better organization and easier maintenance. For example:
# Top level BalancesResponse, InvitesResponse, KeyResponse, KeysResponse, MembersResponse, Message, ModelResponse, ModelsResponse, ProjectsResponse, ScopesResponse, UsageFieldsResponse, UsageRequest, UsageRequestsResponse, UsageResponse, UsageSummaryResponse, # Shared Balance, Callback, Config, Invite, Key, Member, Project, Resolution, ...This alphabetical ordering will make it easier to locate specific imports and maintain the file in the future.
deepgram/client.py (3)
Line range hint
22-207
: Improved import organization and new class additions.The reorganization of imports and addition of new classes significantly enhances code readability and aligns with the PR objective of exposing all types and classes at the top level of the response results. This change will make it easier for users to access any object in a response by its name or reference.
Consider using
__all__
at the end of the file to explicitly define the public API. This would further clarify which classes and functions are intended to be used by external code.
Line range hint
300-451
: Expanded DeepgramClient capabilities and API updates.The additions of
read
andspeak
properties enhance the client's functionality, allowing for more comprehensive interaction with Deepgram's services. The deprecation notices forasyncspeak
,onprem
, andasynconprem
properties indicate a thoughtful evolution of the API design.Consider updating the class-level docstring for
DeepgramClient
to include descriptions of the newread
andspeak
properties. This will help users understand the full range of available functionalities.
Line range hint
453-570
: Version class implementation and future plans.The
Version
class provides a flexible mechanism for version-specific client instantiation, which is crucial for maintaining backwards compatibility while allowing for future API updates. The commented-out code for potential future versioning shows foresight in API design.Consider adding a TODO comment or documentation note about the future versioning plans. This will help other developers understand the intended direction for API versioning and potentially contribute to its implementation.
deepgram/clients/speak/v1/rest/response.py (1)
Line range hint
24-29
: Properly deprecate thestream
attributeThe
stream
attribute is marked for deprecation in a future release, as indicated by the TODO comment. To clearly communicate this deprecation to users and developers, consider using thewarnings
module to emit aDeprecationWarning
when thestream
attribute is accessed. This will help users transition to usingstream_memory
and prevent unexpected issues whenstream
is eventually removed.Here is how you might implement this:
import warnings # ... @dataclass class SpeakRESTResponse(BaseResponse): # Existing fields... _stream: Optional[io.BytesIO] = field( default=None, metadata=dataclass_config(exclude=lambda f: True), ) @property def stream(self): warnings.warn( "The 'stream' attribute is deprecated and will be removed in a future release. Please use 'stream_memory' instead.", DeprecationWarning, stacklevel=2 ) return self._stream @stream.setter def stream(self, value): warnings.warn( "Setting the 'stream' attribute is deprecated and will be removed in a future release. Please use 'stream_memory' instead.", DeprecationWarning, stacklevel=2 ) self._stream = valuedeepgram/clients/analyze/v1/response.py (3)
Line range hint
47-58
: Simplify the__getitem__
method in theMetadata
class for improved efficiencyThe current implementation of the
__getitem__
method converts the entire object to a dictionary and reconstructs certain fields, which may introduce unnecessary overhead. Consider simplifying the method to directly access attributes.Apply this diff to streamline the method:
def __getitem__(self, key): - _dict = self.to_dict() - if "intents_info" in _dict: - _dict["intents_info"] = IntentsInfo.from_dict(_dict["intents_info"]) - if "sentiment_info" in _dict: - _dict["sentiment_info"] = SentimentInfo.from_dict(_dict["sentiment_info"]) - if "summary_info" in _dict: - _dict["summary_info"] = SummaryInfo.from_dict(_dict["summary_info"]) - if "topics_info" in _dict: - _dict["topics_info"] = TopicsInfo.from_dict(_dict["topics_info"]) - return _dict[key] + return getattr(self, key)This change simplifies the method by directly accessing the attribute using
getattr
, reducing overhead and improving performance.
Line range hint
71-81
: Simplify the__getitem__
method in theResults
classSimilar to the
Metadata
class, the__getitem__
method in theResults
class can be optimized for better performance by directly accessing attributes.Apply this diff to simplify the method:
def __getitem__(self, key): - _dict = self.to_dict() - if "summary" in _dict: - _dict["summary"] = Summary.from_dict(_dict["summary"]) - if "sentiments" in _dict: - _dict["sentiments"] = Sentiments.from_dict(_dict["sentiments"]) - if "topics" in _dict: - _dict["topics"] = Topics.from_dict(_dict["topics"]) - if "intents" in _dict: - _dict["intents"] = Intents.from_dict(_dict["intents"]) - return _dict[key] + return getattr(self, key)This refactoring enhances code readability and reduces unnecessary processing.
Line range hint
96-105
: Optimize the__getitem__
method in theAnalyzeResponse
classTo maintain consistency and improve efficiency, consider simplifying the
__getitem__
method in theAnalyzeResponse
class as well.Apply this diff:
def __getitem__(self, key): - _dict = self.to_dict() - if "metadata" in _dict: - _dict["metadata"] = Metadata.from_dict(_dict["metadata"]) - if "results" in _dict: - _dict["results"] = Results.from_dict(_dict["results"]) - return _dict[key] + return getattr(self, key)This change aligns the method with the simplified versions in other classes, improving overall consistency and performance.
deepgram/clients/listen/v1/websocket/response.py (1)
Line range hint
73-81
: Refactor duplicate__getitem__
methods to eliminate code duplication.The
__getitem__
methods in bothLiveResultResponse
andMetadataResponse
classes have similar implementations. To adhere to the DRY (Don't Repeat Yourself) principle, consider abstracting this method into theBaseResponse
class or creating a utility function that both classes can utilize. This refactoring will reduce code redundancy and simplify future maintenance.Also applies to: 123-134
deepgram/clients/common/v1/rest_response.py (4)
5-5
: Remove unused imports for cleaner codeThe imports
Dict
andAny
from thetyping
module are not used in this file. Removing unused imports helps maintain code cleanliness and reduces potential confusion.Apply this diff to remove the unused imports:
-from typing import List, Optional, Dict, Any +from typing import List, Optional
8-8
: Clarify aliasing of importedconfig
functionYou have imported
config
fromdataclasses_json
asdataclass_config
. This alias might be misleading since it suggests a relation to the standarddataclasses
module. For clarity, consider using the original name or a different alias.Apply this diff to use the original name:
-from dataclasses_json import config as dataclass_config +from dataclasses_json import configAnd update all references accordingly.
17-59
: Enhance class docstrings for better clarityThe docstrings for the
IntentsInfo
,SentimentInfo
,SummaryInfo
, andTopicsInfo
classes currently only repeat the class names. Providing more descriptive docstrings improves code readability and helps other developers understand the purpose of each class.For example, update the docstring for
IntentsInfo
:class IntentsInfo(BaseResponse): - """ - Intents Info - """ + """ + Contains metadata information for intents analysis, including model UUID and token counts. + """
1-181
: Add comprehensive unit tests for new classesThe addition of multiple new data classes warrants thorough unit testing to ensure they behave as expected, especially given the custom
__getitem__
methods and serialization logic.Would you like assistance in generating unit tests for these classes or to open a new GitHub issue to track this task?
deepgram/clients/manage/v1/options.py (1)
Line range hint
100-169
: Consider refactoringUsageSummaryOptions
to improve maintainabilityThe
UsageSummaryOptions
class has a large number of attributes (over 20), which may affect readability and maintainability. Consider grouping related fields into nested data classes or refactoring the class to adhere to the Single Responsibility Principle.deepgram/clients/listen/client.py (2)
88-101
: Redundant aliasing of shared entitiesThe direct assignment of entities like
Average = AverageLatest
may be unnecessary if only one version is in use. Consider importing these entities without aliasing or implementing a versioning mechanism if multiple versions are expected.
Line range hint
118-121
: Incorrect assignment ofAsyncLiveClient
The
AsyncLiveClient
is currently assigned toListenWebSocketClientLatest
, which is the synchronous client. This could cause confusion or errors when attempting to use asynchronous methods.Apply this diff to correct the assignment:
-AsyncLiveClient = ListenWebSocketClientLatest +AsyncLiveClient = AsyncListenWebSocketClientLatest
Comments failed to post (27)
deepgram/clients/speak/v1/__init__.py (1)
20-22:
⚠️ Potential issueRemove duplicate imports.
The imports on lines 20-22 are duplicates of the imports on lines 8-9. To maintain clean and efficient code, it's advisable to remove these duplicate imports.
Apply this diff to remove the duplicate imports:
-from .rest import ( - SpeakRESTOptions, - SpeakOptions, -)Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
deepgram/clients/listen/v1/websocket/options.py (1)
13-17: 💡 Codebase verification
Base class
BaseResponse
does not provide theto_dict
method.Changing
LiveOptions
to inherit fromBaseResponse
removes theto_dict
functionality, which may affect existing implementations that rely on this method. Please ensure that:
- The
to_dict
method is no longer required forLiveOptions
.- If
to_dict
is needed, consider adding it toBaseResponse
or implementing it withinLiveOptions
.- Existing consumers of
LiveOptions
are updated to handle the absence of theto_dict
method if necessary.Analysis chain
Verify the impact of changing the base class to
BaseResponse
.The
LiveOptions
class now inherits fromBaseResponse
instead ofDataClassJsonMixin
. This change aligns with the PR objective of exposing all types at the top level. However, please ensure that:
BaseResponse
provides all necessary functionality previously offered byDataClassJsonMixin
.- This change doesn't introduce any breaking changes for existing users of the
LiveOptions
class.- The
@dataclass
decorator is still compatible with the new base class.To confirm the compatibility, run the following script:
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the usage and functionality of LiveOptions after the base class change. # Test 1: Check if LiveOptions is still being used as expected rg --type python -A 5 'LiveOptions' # Test 2: Verify that BaseResponse provides necessary functionality ast-grep --lang python --pattern 'class BaseResponse: $$$ def to_dict(self): $$$ $$$ 'Length of output: 221
Script:
#!/bin/bash # Description: Re-verify the usage and functionality of LiveOptions after the base class change without specifying file types. # Test 1: Check if LiveOptions is still being used as expected across all Python files rg 'LiveOptions' --glob '*.py' -A 5 # Test 2: Verify that BaseResponse provides necessary functionality by searching for the to_dict method ast-grep --lang python --pattern 'class BaseResponse: $$$ def to_dict(self): $$$ $$$ 'Length of output: 25238
deepgram/clients/__init__.py (1)
201-214:
⚠️ Potential issueApproved with a minor issue: Text-to-speech REST imports reorganization
The reorganization of text-to-speech REST imports is well-structured and aligns with the PR objectives. However, there's a minor issue to address:
- Lines 213-214 contain a duplicate import of
SpeakRESTSource
with different capitalizations:SpeakRestSource, SpeakRESTSource,Please remove one of these imports, preferably keeping the one that matches the capitalization used elsewhere in the codebase (likely
SpeakRESTSource
).Otherwise, the changes improve code organization and readability while expanding the SDK's capabilities.
deepgram/clients/speak/v1/websocket/response.py (1)
21-24: 🛠️ Refactor suggestion
Consider moving shared attributes to
BaseResponse
The
type
attribute is common across multiple response classes (MetadataResponse
,FlushedResponse
,ClearedResponse
,WarningResponse
). To adhere to the DRY principle and enhance maintainability, consider moving thetype
attribute to theBaseResponse
class.deepgram/clients/common/v1/shared_response.py (6)
123-128: 🛠️ Refactor suggestion
Optimize
__getitem__
inSearch
class to improve performance.The
__getitem__
method in theSearch
class also serializes and deserializes the entire object. Accessing attributes directly can enhance efficiency.Modify the method as follows:
def __getitem__(self, key): - _dict = self.to_dict() - if "hits" in _dict: - _dict["hits"] = [Hit.from_dict(hits) for hits in _dict["hits"]] - return _dict[key] + return getattr(self, key)Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def __getitem__(self, key): return getattr(self, key)
141-150: 🛠️ Refactor suggestion
Optimize
__getitem__
inChannel
class to improve performance.Similarly, the
__getitem__
method in theChannel
class can be optimized to avoid unnecessary serialization.Modify the method to access attributes directly:
def __getitem__(self, key): - _dict = self.to_dict() - if "search" in _dict: - _dict["search"] = [Search.from_dict(search) for search in _dict["search"]] - if "alternatives" in _dict: - _dict["alternatives"] = [ - Alternative.from_dict(alternatives) - for alternatives in _dict["alternatives"] - ] - return _dict[key] + return getattr(self, key)Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def __getitem__(self, key): return getattr(self, key)
95-100: 🛠️ Refactor suggestion
Optimize
__getitem__
inAlternative
class to improve performance.The
__getitem__
method in theAlternative
class serializes and deserializes the entire object, which may impact performance. Consider accessing attributes directly without converting to and from dictionaries.Modify the method to access attributes directly:
def __getitem__(self, key): - _dict = self.to_dict() - if "words" in _dict: - _dict["words"] = [Word.from_dict(words) for words in _dict["words"]] - return _dict[key] + return getattr(self, key)Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def __getitem__(self, key): return getattr(self, key)
2-2:
⚠️ Potential issueCorrect grammatical error in the license header.
In the license comment on line 2, "a MIT license" should be "an MIT license" for grammatical correctness.
Apply this diff to fix the typo:
-# Use of this source code is governed by a MIT license that can be found in the LICENSE file. +# Use of this source code is governed by an MIT license that can be found in the LICENSE file.Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.# Use of this source code is governed by an MIT license that can be found in the LICENSE file.
31-44:
⚠️ Potential issueConsider handling missing keys differently in the
get_nested_value
method.Currently, the method returns an empty string if the key is not found, which might not clearly indicate that the key is missing. Consider returning
None
or raising aKeyError
to better convey the absence of a value.Modify the method to return
None
when a key is not found:else: - return "" + return NoneAlternatively, raise a
KeyError
:else: - return "" + raise KeyError(f"Key '{key}' not found in the response object.")Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def eval(self, key: str) -> Optional[str]: """ This method is used to evaluate a key in the response object using a dot notation style method. """ keys = key.split(".") result: Dict[Any, Any] = self.to_dict() for k in keys: if isinstance(result, dict) and k in result: result = result[k] elif isinstance(result, list) and k.isdigit() and int(k) < len(result): result = result[int(k)] else: return None return str(result)
31-44: 🛠️ Refactor suggestion
Rename the
eval
method to avoid shadowing built-in functions and potential confusion.The method
eval
shadows Python's built-ineval
function, which could lead to confusion or unintended behavior. Consider renaming it to something more descriptive likeget_nested_value
orresolve_key
.Apply this diff to rename the method:
-def eval(self, key: str) -> str: +def get_nested_value(self, key: str) -> str: """ - This method is used to evaluate a key in the response object using a dot notation style method. + This method is used to retrieve a value from the response object using dot notation. """Also, update any internal references to this method accordingly.
Committable suggestion was skipped due to low confidence.
deepgram/clients/common/v1/rest_response.py (7)
17-181: 🛠️ Refactor suggestion
Consider abstracting redundant
__getitem__
methodsThe
__getitem__
methods in multiple classes (Average
,Segment
,Sentiments
,Topics
,Intents
) share similar patterns. To adhere to the DRY (Don't Repeat Yourself) principle, consider creating a base class method or utility function to handle this logic.By abstracting this functionality, you reduce code duplication and simplify future maintenance.
70-75:
⚠️ Potential issueReview the implementation of
__getitem__
method inAverage
classThe
__getitem__
method attempts to convertsentiment
usingSentiment.from_dict()
. SinceSentiment
is likely anEnum
, it might not have afrom_dict()
method, leading to anAttributeError
.Consider removing or adjusting the conversion:
def __getitem__(self, key): _dict = self.to_dict() - if "sentiment" in _dict: - _dict["sentiment"] = Sentiment.from_dict(_dict["sentiment"]) return _dict[key]If custom deserialization is needed, ensure that
Sentiment
provides a suitable method.Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.def __getitem__(self, key): _dict = self.to_dict() return _dict[key]
62-69: 🛠️ Refactor suggestion
Reconsider default value for
sentiment_score
In the
Average
class,sentiment_score
is initialized to0
. If a sentiment score of0
is meaningful in your context, it's fine. However, if0
could be confused with an uninitialized state, consider usingNone
as the default value to indicate the absence of a score.Adjust the default value:
sentiment_score: float = 0 + sentiment_score: Optional[float] = None
Don't forget to import
Optional
if it's not already imported.Committable suggestion was skipped due to low confidence.
106-117:
⚠️ Potential issueIncorrect usage of
dataclass_config
in field metadataIn the
Segment
class, you usemetadata=dataclass_config(exclude=lambda f: f is None)
. Theexclude
parameter expects a boolean, not a function. This might not behave as intended during serialization.Use the correct syntax for excluding fields when they are
None
:from dataclasses_json import config ... sentiment: Optional[Sentiment] = field( default=None, metadata=config(exclude=lambda x: x is None) )Ensure you import
config
directly and adjust the lambda function parameter tox
, representing the field's value.Committable suggestion was skipped due to low confidence.
140-148:
⚠️ Potential issueEnsure correctness of
__getitem__
method inSentiments
classSimilar to previous comments, check that
Segment
andAverage
classes have afrom_dict()
method. The current implementation may result in errors if these methods do not exist.Review and adjust the code:
def __getitem__(self, key): _dict = self.to_dict() - if "segments" in _dict: - _dict["segments"] = [ - Segment.from_dict(segment) for segment in _dict["segments"] - ] - if "average" in _dict: - _dict["average"] = Average.from_dict(_dict["average"]) return _dict[key]Ensure that the deserialization process is correctly handled elsewhere if needed.
Committable suggestion was skipped due to low confidence.
158-165:
⚠️ Potential issueValidate
__getitem__
method inTopics
classEnsure that the
Segment
class has afrom_dict()
method if you intend to use it here. Otherwise, this code may raise anAttributeError
.Adjust the method accordingly:
def __getitem__(self, key): _dict = self.to_dict() - if "segments" in _dict: - _dict["segments"] = [ - Segment.from_dict(segment) for segment in _dict["segments"] - ] return _dict[key]Provide proper deserialization if necessary.
Committable suggestion was skipped due to low confidence.
119-128:
⚠️ Potential issuePotential issues in
__getitem__
method ofSegment
classThe
__getitem__
method tries to convert fields usingfrom_dict()
, but it's unclear ifSentiment
,Intent
, andTopic
classes have this method. Additionally, modifying_dict
may lead to unexpected behavior.Verify that these classes have a
from_dict()
method. If they do not, you may need to implement them or adjust the code accordingly.def __getitem__(self, key): _dict = self.to_dict() - if "sentiment" in _dict: - _dict["sentiment"] = Sentiment.from_dict(_dict["sentiment"]) - if "intents" in _dict: - _dict["intents"] = [Intent.from_dict(intent) for intent in _dict["intents"]] - if "topics" in _dict: - _dict["topics"] = [Topic.from_dict(topic) for topic in _dict["topics"]] return _dict[key]Consider whether overriding
__getitem__
is necessary for your use case.Committable suggestion was skipped due to low confidence.
deepgram/clients/manage/v1/options.py (1)
173-174:
⚠️ Potential issueSet default values to
None
forOptional[str]
fieldsIn
UsageFieldsOptions
, the fieldsstart
andend
are declared asOptional[str]
but default to an empty string""
. For consistency and to properly represent optional fields, it's preferable to set the default toNone
and usedataclass_config
to exclude them when they areNone
, as done in other classes.Apply this diff to update the defaults and metadata:
class UsageFieldsOptions(BaseResponse): """ Usage Fields Options """ - start: Optional[str] = "" - end: Optional[str] = "" + start: Optional[str] = field( + default=None, metadata=dataclass_config(exclude=lambda f: f is None) + ) + end: Optional[str] = field( + default=None, metadata=dataclass_config(exclude=lambda f: f is None) + )Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.class UsageFieldsOptions(BaseResponse): """ Usage Fields Options """ start: Optional[str] = field( default=None, metadata=dataclass_config(exclude=lambda f: f is None) ) end: Optional[str] = field( default=None, metadata=dataclass_config(exclude=lambda f: f is None) )
deepgram/clients/listen/v1/rest/response.py (3)
351-351:
⚠️ Potential issueEnsure consistent naming conventions for class
ListenRESTChannel
Similar to previous classes, the class name
ListenRESTChannel
should follow the same naming pattern. Consider renaming it toListenRestChannel
for consistency.Apply this diff to correct the class name:
-class ListenRESTChannel(Channel): +class ListenRestChannel(Channel):Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.class ListenRestChannel(Channel):
252-252:
⚠️ Potential issueAvoid redefining the built-in
Warning
classDefining a class named
Warning
can overshadow Python's built-inWarning
class, leading to unexpected behavior. It's advisable to rename this class to prevent conflicts.Apply this diff to rename the class:
-class Warning(BaseResponse): # pylint: disable=used-before-assignment,redefined-builtin +class ListenRestWarning(BaseResponse):Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.class ListenRestWarning(BaseResponse):
308-310:
⚠️ Potential issueEnsure consistent naming conventions for class
ListenRESTAlternative
The class name
ListenRESTAlternative
uses uppercaseREST
, whereasListenRestWord
usesRest
with only the 'R' capitalized. For consistency and readability, consider renaming the class toListenRestAlternative
.Apply this diff to correct the class name:
-class ListenRESTAlternative( +class ListenRestAlternative(Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.class ListenRestAlternative( Alternative ): # pylint: disable=too-many-instance-attributes
deepgram/clients/manage/v1/response.py (6)
10-12: 🛠️ Refactor suggestion
Consider using absolute imports for clarity
Using triple-dot (
...
) relative imports can be less clear and more error-prone, especially if the module hierarchy changes in the future. Consider using absolute imports to enhance readability and maintainability.
61-63: 🛠️ Refactor suggestion
Avoid disabling pylint warnings; consider refactoring
STTDetails
The comment
# pylint: disable=too-many-instance-attributes
suppresses a pylint warning about having too many instance attributes in theSTTDetails
class. To improve code quality, consider refactoring the class to reduce complexity, possibly by grouping related attributes into nested classes or using composition.
84-86:
⚠️ Potential issueInconsistency between class name
TTSMetadata
and its usageThe class
TTSMetadata
is named as if it's specific to TTS models, but the docstring mentions it's used for both STT and TTS models. This could cause confusion.Consider one of the following actions:
- Rename the class to something more general like
ModelMetadata
if it represents metadata for both STT and TTS models.- Update the docstring to accurately reflect that
TTSMetadata
is specific to TTS models if that's the case.
110-110:
⚠️ Potential issueInconsistency in
metadata
type between declaration and usage inTTSDetails
The
metadata
field is declared asOptional[TTSMetadata]
, indicating it should be either aTTSMetadata
instance orNone
. However, in the__getitem__
method,metadata
is being iterated over as if it were a list:if "metadata" in _dict: _dict["metadata"] = [ TTSMetadata.from_dict(metadata) for metadata in _dict["metadata"] ]This inconsistency could lead to runtime errors.
Recommendation:
If
metadata
should be a single instance, modify the__getitem__
method to handle it as such:if "metadata" in _dict: _dict["metadata"] = TTSMetadata.from_dict(_dict["metadata"])If
metadata
should be a list, update the field declaration:metadata: Optional[List[TTSMetadata]] = field(...)
138-138:
⚠️ Potential issueInconsistency in
metadata
type between declaration and usage inModelResponse
Similar to the issue in
TTSDetails
, themetadata
field inModelResponse
is declared asOptional[TTSMetadata]
, but used as a list in the__getitem__
method:if "metadata" in _dict: _dict["metadata"] = [ TTSMetadata.from_dict(metadata) for metadata in _dict["metadata"] ]Recommendation:
- Align the field type and usage by either changing the field to a list or adjusting the
__getitem__
method to handle a single instance.
352-352: 🛠️ Refactor suggestion
Avoid disabling pylint warnings; consider refactoring
STTUsageDetails
The
# pylint: disable=too-many-instance-attributes
comment indicates thatSTTUsageDetails
has too many attributes. Refactoring the class could improve maintainability.Suggestions:
- Group related attributes into nested data classes.
- Use dictionaries or other data structures to encapsulate related properties.
Units tests pass as well! |
b2c6dce
to
7973bcb
Compare
Proposed changes
Addresses: #457
This exposes all types/classes in the top-level result results. Users should be able to access any object in a response by name or ref. This explicitly lists the objects and also explicitly state which ones are being used as "common" objects; you can see these as commented out items that are contained in the imports. This is to easily see what is being exported where. Example:
This is backward compatible, and no modification of client code is required. I manually ran each example to ensure the appropriate response.
As a consequence of doing this PR, there was a (much needed) consolidation of the BaseResponse class. This in turn deleted a bunch of code that is now inherited.
Created a test build
3.7.0-dev.2
to verify all types are exposed. This checks out.Types of changes
What types of changes does your code introduce to the community Python SDK?
Put an
x
in the boxes that applyChecklist
Put an
x
in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
NA
Summary by CodeRabbit
New Features
SpeakWSMetadataResponse
to improve WebSocket response handling.Refactor
BaseResponse
for a more consistent response structure.Bug Fixes
Chores