cleder / crepr

Create a โค๏ธ__repr__๐Ÿค—๏ธ for your python classes from the definition found in __init__
MIT License
6 stars 4 forks source link

Update crepr.py #53

Closed Sohammhatre10 closed 1 month ago

Sohammhatre10 commented 1 month ago

User description

Included the report-missing method required in in https://github.com/cleder/crepr/issues/51 for reporting the number of classes and their names which don't possess repr function

Usage for report-missing

crepr report-missing <your-file-name>

PR Type

enhancement


Description


Changes walkthrough ๐Ÿ“

Relevant files
Enhancement
crepr.py
Add `report_missing` command and supporting functions       

crepr/crepr.py
  • Added report_missing command to count and print classes without a
    __repr__ method.
  • Implemented process_file to handle file processing for missing
    __repr__.
  • Introduced helper functions: load_module, extract_classes,
    filter_no_repr, and report_results.
  • Enhanced error handling with typer.secho for user feedback.
  • +61/-0   

    ๐Ÿ’ก PR-Agent usage: Comment /help "your question" on any pull request to receive relevant information

    Summary by Sourcery

    Introduce a new command report-missing to the crepr tool, allowing users to identify classes in a given file that do not implement a __repr__ method.

    New Features:

    Summary by CodeRabbit

    semanticdiff-com[bot] commented 1 month ago

    Review changes with SemanticDiff.

    Analyzed 1 of 1 files.

    Overall, the semantic diff is 1% smaller than the GitHub diff.

    Filename Status
    :heavy_check_mark: crepr/crepr.py 0.95% smaller
    sourcery-ai[bot] commented 1 month ago

    Reviewer's Guide by Sourcery

    This pull request implements a new feature in the crepr.py file to report classes without a __repr__ method. The implementation adds a new command report-missing that processes specified files, identifies classes without __repr__ methods, and reports the findings.

    File-Level Changes

    Change Details Files
    Implement new 'report-missing' command
    • Add new function 'report_missing' decorated with @app.command()
    • Implement helper functions: process_file, load_module, extract_classes, filter_no_repr, and report_results
    • Use typer for command-line interface and output formatting
    crepr/crepr.py
    Add error handling and reporting
    • Implement try-except blocks to catch and report CreprError
    • Use typer.secho for colored output of errors and results
    crepr/crepr.py
    Implement class analysis logic
    • Use inspect module to identify classes in the module
    • Filter classes without repr method using get_repr_source function
    crepr/crepr.py

    Sequence Diagram

    sequenceDiagram
        participant User
        participant CLI
        participant report_missing
        participant process_file
        participant load_module
        participant extract_classes
        participant filter_no_repr
        participant report_results
    
        User->>CLI: crepr report-missing <file>
        CLI->>report_missing: Call with file path
        report_missing->>process_file: Process each file
        process_file->>load_module: Load module
        process_file->>extract_classes: Extract classes
        process_file->>filter_no_repr: Filter classes without __repr__
        process_file->>report_results: Report findings
        report_results->>User: Display results

    Tips - Trigger a new Sourcery review by commenting `@sourcery-ai review` on the pull request. - Continue your discussion with Sourcery by replying directly to review comments. - You can change your review settings at any time by accessing your [dashboard](https://app.sourcery.ai): - Enable or disable the Sourcery-generated pull request summary or reviewer's guide; - Change the review language; - You can always [contact us](mailto:support@sourcery.ai) if you have any questions or feedback.
    coderabbitai[bot] commented 1 month ago

    [!WARNING]

    Rate limit exceeded

    @pre-commit-ci[bot] has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 35 seconds before requesting another review.

    How to resolve this issue? After the wait time has elapsed, a review can be triggered using the `@coderabbitai review` command as a PR comment. Alternatively, push new commits to this PR. 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](https://coderabbit.ai/docs/faq) for further information.
    Commits Files that changed from the base of the PR and between cfe7bde557ca680338d6ecaa41fec115962d5060 and b2377bf90e1bc9baecd31ee4dc2c4833743decbf.

    Walkthrough

    The pull request introduces a new command, report_missing, to the crepr module, which identifies and reports classes that do not implement a __repr__ method in specified source files. It includes several helper functions to process files, load modules, extract classes, filter those without a __repr__, and report the results. This enhancement allows users to easily find classes lacking a __repr__, improving the module's usability in code quality checks.

    Changes

    File Change Summary
    crepr/crepr.py Added methods: report_missing, process_file, load_module, extract_classes, filter_no_repr, report_results.

    Possibly related issues

    Poem

    ๐Ÿฐ In the code where classes dwell,
    A __repr__ gap we know too well.
    With report_missing, we now can see,
    Which classes lack their identity!
    So hop along, let's tidy up,
    And fill the code with a cheerful cup! ๐Ÿต


    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?

    Share - [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai) - [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai) - [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai) - [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)
    Tips ### Chat There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai): - Review comments: Directly reply to a review comment made by CodeRabbit. Example: -- `I pushed a fix in commit , please review it.` -- `Generate unit testing code for this file.` - `Open a follow-up GitHub issue for this discussion.` - Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples: -- `@coderabbitai generate unit testing code for this file.` -- `@coderabbitai modularize this function.` - PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples: -- `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.` -- `@coderabbitai read src/utils.ts and generate unit testing code.` -- `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.` -- `@coderabbitai help me debug CodeRabbit configuration file.` 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) - `@coderabbitai pause` to pause the reviews on a PR. - `@coderabbitai resume` to resume the paused reviews. - `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository. - `@coderabbitai full review` to do a full review from scratch and review all the files again. - `@coderabbitai summary` to regenerate the summary of the PR. - `@coderabbitai resolve` resolve all the CodeRabbit review comments. - `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository. - `@coderabbitai help` to get help. ### Other keywords and placeholders - Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed. - Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description. - Add `@coderabbitai` anywhere in the PR title to generate the title automatically. ### CodeRabbit Configuration File (`.coderabbit.yaml`) - You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository. - Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information. - If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json` ### Documentation and Community - Visit our [Documentation](https://coderabbit.ai/docs) for detailed information on how to use CodeRabbit. - Join our [Discord Community](https://discord.com/invite/GsXnASn26c) to get help, request features, and share feedback. - Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.
    codiumai-pr-agent-free[bot] commented 1 month ago

    PR Reviewer Guide ๐Ÿ”

    (Review updated until commit https://github.com/cleder/crepr/commit/0c4665f6fbf02d0ea201d1612af2fed63ba0f0c4)

    โฑ๏ธ Estimated effort to review: 3 ๐Ÿ”ต๐Ÿ”ต๐Ÿ”ตโšชโšช
    ๐Ÿงช No relevant tests
    ๐Ÿ”’ No security concerns identified
    โšก Key issues to review

    Error Handling
    The error handling in the `load_module` and `extract_classes` functions may lead to silent failures. The `CreprError` is caught and printed, but the function doesn't return or raise an exception, potentially causing issues in the calling function. Code Duplication
    The error handling pattern is repeated in multiple functions. Consider creating a decorator or utility function to handle these errors consistently across the module. Possible Performance Issue
    The `filter_no_repr` function calls `get_repr_source` for each class, which might be inefficient for large numbers of classes. Consider caching the results or optimizing this operation.
    codiumai-pr-agent-pro[bot] commented 1 month ago

    PR-Agent was enabled for this repository. To continue using it, please link your git user with your CodiumAI identity here.

    Persistent review updated to latest commit https://github.com/cleder/crepr/commit/0c4665f6fbf02d0ea201d1612af2fed63ba0f0c4

    codiumai-pr-agent-free[bot] commented 1 month ago

    PR Code Suggestions โœจ

    Latest suggestions up to 0c4665f

    CategorySuggestion                                                                                                                                    Score
    Error handling
    โœ… Propagate errors to the caller for centralized error handling instead of handling them locally ___
    Suggestion Impact:The suggestion to propagate errors instead of handling them locally was implemented. The load_module function now returns None if an error occurs, and the extract_classes function no longer handles errors locally. code diff: ```diff def process_file(file_path: pathlib.Path) -> None: """Process a single file and report classes without a __repr__ method.""" module = load_module(file_path) - classes = extract_classes(module, file_path) + if module is None: + typer.secho(f"Error: Could not load module from {file_path}", fg="red", err=True) + return + + classes = extract_classes(module) no_repr_classes = filter_no_repr(classes) report_results(file_path, classes, no_repr_classes) - -def load_module(file_path: pathlib.Path): +def load_module(file_path: pathlib.Path) -> Optional[ModuleType]: """Load a module from a given file path.""" try: return get_module(file_path) except CreprError as e: typer.secho(e.message, fg="red", err=True) - - -def extract_classes(module, file_path: pathlib.Path): + return None + +def extract_classes(module: ModuleType) -> List[Type]: """Extract classes from a module.""" - try: - return [ - obj - for _, obj in inspect.getmembers(module, inspect.isclass) - if is_class_in_module(obj, module) - ] - except CreprError as e: - typer.secho(e.message, fg="red", err=True) - - -def filter_no_repr(classes): + return [ + obj for _, obj in inspect.getmembers(module, inspect.isclass) + if is_class_in_module(obj, module) + ] ```
    ___ **In the load_module and extract_classes functions, consider raising the CreprError
    instead of handling it immediately to allow for centralized error handling.** [crepr/crepr.py [397-413]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R397-R413) ```diff def load_module(file_path: pathlib.Path): """Load a module from a given file path.""" - try: - return get_module(file_path) - except CreprError as e: - typer.secho(e.message, fg="red", err=True) + return get_module(file_path) def extract_classes(module, file_path: pathlib.Path): """Extract classes from a module.""" - try: - return [ - obj for _, obj in inspect.getmembers(module, inspect.isclass) - if is_class_in_module(obj, module) - ] - except CreprError as e: - typer.secho(e.message, fg="red", err=True) + return [ + obj for _, obj in inspect.getmembers(module, inspect.isclass) + if is_class_in_module(obj, module) + ] ``` - [ ] **Apply this suggestion**
    Suggestion importance[1-10]: 9 Why: Centralizing error handling by propagating errors to the caller improves code maintainability and allows for more consistent error management across the application.
    9
    Enhancement
    Implement a context manager for error handling to reduce code duplication and improve readability ___ **Consider using a context manager for error handling in the report_missing function
    to avoid repetitive try-except blocks for each file.** [crepr/crepr.py [380-386]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R380-R386) ```diff @app.command() def report_missing(files: Annotated[list[pathlib.Path], file_arg]) -> None: """Count and print classes without a __repr__ method in the source code.""" for file_path in files: - try: + with handle_crepr_error(): process_file(file_path) - except CreprError as e: - typer.secho(e.message, fg="red", err=True) +@contextlib.contextmanager +def handle_crepr_error(): + try: + yield + except CreprError as e: + typer.secho(e.message, fg="red", err=True) + ``` - [ ] **Apply this suggestion**
    Suggestion importance[1-10]: 8 Why: The suggestion to use a context manager for error handling is a good practice as it reduces code duplication and improves readability, making the code cleaner and more maintainable.
    8
    Maintainability
    โœ… Use more descriptive variable names to enhance code readability ___
    Suggestion Impact:The variable name 'obj' was changed to 'class_obj' in the filter_no_repr function to improve code readability. code diff: ```diff +def filter_no_repr(classes: List[Type]) -> List[str]: """Filter out classes without a __repr__ method.""" - return [obj.__name__ for obj in classes if get_repr_source(obj)[1] == -1] + return [ + obj.__name__ for obj in classes + if get_repr_source(obj)[1] == -1 + ] ```
    ___ **In the filter_no_repr function, consider using a more descriptive variable name
    instead of obj to improve code readability.** [crepr/crepr.py [416-421]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R416-R421) ```diff def filter_no_repr(classes): """Filter out classes without a __repr__ method.""" return [ - obj.__name__ for obj in classes - if get_repr_source(obj)[1] == -1 + class_obj.__name__ for class_obj in classes + if get_repr_source(class_obj)[1] == -1 ] ``` - [ ] **Apply this suggestion**
    Suggestion importance[1-10]: 6 Why: Using more descriptive variable names improves code readability and maintainability, making it easier for others to understand the code.
    6
    Best practice
    โœ… Use f-strings consistently for string formatting to improve code readability and maintainability ___
    Suggestion Impact:The commit replaced f-strings with the format method for string formatting in the report_results function, which is related to the suggestion of using consistent string formatting. code diff: ```diff +def report_results(file_path: pathlib.Path, classes: List[Type], no_repr_classes: List[str]) -> None: """Report the results of classes without a __repr__ method.""" if no_repr_classes: typer.secho( - f"In module '{file_path}': {len(no_repr_classes)} class(es) " - "don't have a __repr__ method:", - fg="yellow", + "In module '{}': {} class(es) don't have a __repr__ method:".format( + file_path, len(no_repr_classes) + ), + fg="yellow" ) for class_name in no_repr_classes: - typer.echo(f"{file_path}: {class_name}") + typer.echo("{}: {}".format(file_path, class_name)) else: typer.secho( - f"All {len(classes)} class(es) in module '{file_path}' " - "have a __repr__ method.", - fg="green", + "All {} class(es) in module '{}' have a __repr__ method.".format( + len(classes), file_path + ), + fg="green" ) ```
    ___ **In the report_results function, consider using f-strings consistently for string
    formatting to improve code consistency and readability.** [crepr/crepr.py [424-439]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R424-R439) ```diff def report_results(file_path: pathlib.Path, classes: list, no_repr_classes: list) -> None: """Report the results of classes without a __repr__ method.""" if no_repr_classes: typer.secho( f"In module '{file_path}': {len(no_repr_classes)} class(es) " - "don't have a __repr__ method:", + f"don't have a __repr__ method:", fg="yellow" ) for class_name in no_repr_classes: typer.echo(f"{file_path}: {class_name}") else: typer.secho( f"All {len(classes)} class(es) in module '{file_path}' " - "have a __repr__ method.", + f"have a __repr__ method.", fg="green" ) ``` - [ ] **Apply this suggestion**
    Suggestion importance[1-10]: 5 Why: Consistent use of f-strings for string formatting is a minor improvement that enhances code readability and maintainability, aligning with modern Python practices.
    5

    ๐Ÿ’ก Need additional feedback ? start a PR chat


    Previous suggestions

    โœ… Suggestions up to commit 0c4665f
    CategorySuggestion                                                                                                                                    Score
    Best practice
    โœ… Simplify error handling by propagating exceptions to the caller ___
    Suggestion Impact:The suggestion to propagate exceptions instead of handling them locally was implemented. The load_module and extract_classes functions were modified to remove local exception handling and propagate exceptions to the caller. code diff: ```diff -def load_module(file_path: pathlib.Path): +def load_module(file_path: pathlib.Path) -> Optional[ModuleType]: """Load a module from a given file path.""" try: return get_module(file_path) except CreprError as e: typer.secho(e.message, fg="red", err=True) - - -def extract_classes(module, file_path: pathlib.Path): + return None + +def extract_classes(module: ModuleType) -> List[Type]: """Extract classes from a module.""" - try: - return [ - obj - for _, obj in inspect.getmembers(module, inspect.isclass) - if is_class_in_module(obj, module) - ] - except CreprError as e: - typer.secho(e.message, fg="red", err=True) - - -def filter_no_repr(classes): + return [ + obj for _, obj in inspect.getmembers(module, inspect.isclass) + if is_class_in_module(obj, module) + ] ```
    ___ **In the load_module and extract_classes functions, consider raising the CreprError
    instead of handling it locally, as it's already being caught in the calling
    function.** [crepr/crepr.py [397-413]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R397-R413) ```diff def load_module(file_path: pathlib.Path): """Load a module from a given file path.""" - try: - return get_module(file_path) - except CreprError as e: - typer.secho(e.message, fg="red", err=True) + return get_module(file_path) def extract_classes(module, file_path: pathlib.Path): """Extract classes from a module.""" - try: - return [ - obj for _, obj in inspect.getmembers(module, inspect.isclass) - if is_class_in_module(obj, module) - ] - except CreprError as e: - typer.secho(e.message, fg="red", err=True) + return [ + obj for _, obj in inspect.getmembers(module, inspect.isclass) + if is_class_in_module(obj, module) + ] ```
    Suggestion importance[1-10]: 9 Why: Propagating exceptions to the caller simplifies the code and avoids redundant error handling, which is already managed in the calling function. This is a best practice that enhances code clarity and maintainability.
    9
    Enhancement
    Refactor error handling using a context manager to reduce code duplication ___ **Consider using a context manager for error handling in the report_missing function
    to avoid repetitive try-except blocks for each file.** [crepr/crepr.py [379-386]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R379-R386) ```diff @app.command() def report_missing(files: Annotated[list[pathlib.Path], file_arg]) -> None: """Count and print classes without a __repr__ method in the source code.""" for file_path in files: - try: + with handle_crepr_error(): process_file(file_path) - except CreprError as e: - typer.secho(e.message, fg="red", err=True) +@contextlib.contextmanager +def handle_crepr_error(): + try: + yield + except CreprError as e: + typer.secho(e.message, fg="red", err=True) + ```
    Suggestion importance[1-10]: 8 Why: Using a context manager for error handling is a good practice that reduces code duplication and improves readability. It is a significant improvement in terms of code maintainability.
    8
    Performance
    Use a generator expression for memory-efficient filtering of classes without __repr__ ___ **In the filter_no_repr function, consider using a generator expression instead of a
    list comprehension for better memory efficiency, especially when dealing with large
    numbers of classes.** [crepr/crepr.py [416-421]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R416-R421) ```diff def filter_no_repr(classes): """Filter out classes without a __repr__ method.""" - return [ + return ( obj.__name__ for obj in classes if get_repr_source(obj)[1] == -1 - ] + ) ```
    Suggestion importance[1-10]: 7 Why: Using a generator expression can improve memory efficiency, especially with large datasets. This is a minor performance optimization that can be beneficial in specific scenarios.
    7
    Maintainability
    โœ… Use f-strings consistently for string formatting in result reporting ___
    Suggestion Impact:The commit implemented the suggestion by changing the string formatting in the report_results function to use f-strings consistently. code diff: ```diff +def report_results(file_path: pathlib.Path, classes: List[Type], no_repr_classes: List[str]) -> None: """Report the results of classes without a __repr__ method.""" if no_repr_classes: typer.secho( f"In module '{file_path}': {len(no_repr_classes)} class(es) " "don't have a __repr__ method:", - fg="yellow", + fg="yellow" ) for class_name in no_repr_classes: typer.echo(f"{file_path}: {class_name}") @@ -436,9 +439,8 @@ typer.secho( f"All {len(classes)} class(es) in module '{file_path}' " "have a __repr__ method.", - fg="green", + fg="green" ) ```
    ___ **In the report_results function, consider using f-strings consistently for string
    formatting to improve readability and maintainability.** [crepr/crepr.py [424-439]](https://github.com/cleder/crepr/pull/53/files#diff-abcd7c4a2773c8234cdc05070d0abd10b0245a1a15f470288240c6d3a108f576R424-R439) ```diff def report_results(file_path: pathlib.Path, classes: list, no_repr_classes: list) -> None: """Report the results of classes without a __repr__ method.""" if no_repr_classes: typer.secho( f"In module '{file_path}': {len(no_repr_classes)} class(es) " - "don't have a __repr__ method:", + f"don't have a __repr__ method:", fg="yellow" ) for class_name in no_repr_classes: typer.echo(f"{file_path}: {class_name}") else: typer.secho( f"All {len(classes)} class(es) in module '{file_path}' " - "have a __repr__ method.", + f"have a __repr__ method.", fg="green" ) ```
    Suggestion importance[1-10]: 6 Why: Consistent use of f-strings improves code readability and maintainability. This is a minor improvement but aligns with modern Python best practices.
    6
    codecov[bot] commented 1 month ago

    Codecov Report

    Attention: Patch coverage is 21.87500% with 25 lines in your changes missing coverage. Please review.

    Project coverage is 91.41%. Comparing base (7750f43) to head (b71d0b0).

    Files with missing lines Patch % Lines
    crepr/crepr.py 21.87% 25 Missing :warning:
    Additional details and impacted files ```diff @@ Coverage Diff @@ ## develop #53 +/- ## =========================================== - Coverage 98.97% 91.41% -7.57% =========================================== Files 4 4 Lines 294 326 +32 Branches 38 43 +5 =========================================== + Hits 291 298 +7 - Misses 3 28 +25 ```

    :umbrella: View full report in Codecov by Sentry.
    :loudspeaker: Have feedback on the report? Share it here.