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

Merge main #4920

Closed
wants to merge 5 commits into from
Closed

Merge main #4920

wants to merge 5 commits into from

Conversation

benjaminpkane
Copy link
Contributor

@benjaminpkane benjaminpkane commented Oct 11, 2024

Summary by CodeRabbit

  • New Features

    • Updated version to 1.1.7 for improved package management.
    • Enhanced logic for Linux download URLs to support a wider range of distributions.
    • Video playback now supports the timeline API.
    • Added utilities to support a rerun panel.
  • Bug Fixes

    • Fixed an issue with Auth0 connections for deployments behind proxies.
    • Resolved a bug preventing |Classifications| labels from rendering.
    • Fixed a bug that hindered the fiftyone quickstart and fiftyone app launch commands from launching the App.
    • Addressed a bug related to the classes argument when loading specific classes in COCO format.

findtopher and others added 4 commits October 10, 2024 16:19
* move modal looker state to use-looker

* fix video update sample

* linting
* ID_LIKE fallback

* bump db
Copy link
Contributor

coderabbitai bot commented Oct 11, 2024

Walkthrough

The pull request modifies the setup.py file for the fiftyone-db package, updating the version from 1.1.6 to 1.1.7. It enhances the logic for determining the Linux download URL by adding a fallback mechanism to support a wider range of Linux distributions. The _get_linux_download function is adjusted to implement this new logic. Additionally, the write_wheelfile method in the CustomBdistWheel class is updated to reflect the new versioning and download logic, while error handling remains unchanged. Similar updates are made to the setup.py file for the FiftyOne package, incrementing its version from 1.0.0 to 1.0.1.

Changes

File Change Summary
package/db/setup.py - Updated version from 1.1.6 to 1.1.7.
- Enhanced logic for Linux download URL.
- Modified _get_linux_download function to support fallback mechanism.
- Updated write_wheelfile method to reflect new versioning and download logic.
app/packages/core/src/components/ColorModal/ColorFooter.tsx - Replaced useRecoilState with useRecoilValue for activeColorModalField.
- Simplified useEffect logic.
app/packages/core/src/components/Modal/ModalLooker.tsx - Removed state management hooks and simplified component logic.
app/packages/core/src/components/Modal/use-looker.ts - Added useSetRecoilState and useModalContext hooks.
- Introduced new useEffect calls for state management.
app/packages/looker/src/lookers/video.ts - Added VideoConfig type.
- Updated getInitialState, hasDefaultZoom, updateSample, and pluckOverlays methods for better encapsulation and clarity.
app/packages/looker/src/state.ts - Added buffers: Buffers; to VideoState interface for enhanced buffer management.
docs/source/release-notes.rst - Updated release dates for FiftyOne Teams 2.1.1 and FiftyOne 1.0.1.
- Documented changes in both releases.

Possibly related PRs

  • ID_LIKE fallback for fiftyone-db #4903: This PR directly relates to the changes in the main PR as it also modifies the setup.py file to enhance the _get_linux_download function, implementing a fallback mechanism for the ID_LIKE field, and updates the version number from 1.1.6 to 1.1.7.
  • release is now Monday #4919: This PR updates the release notes to reflect changes in version release dates, including those for FiftyOne 1.0.1, which is relevant to the version updates mentioned in the main PR.

Suggested reviewers

  • lanzhenw

Poem

🐰 In the burrow, changes hop,
From 1.1.6, we rise to the top!
With download links now more spry,
For Linux friends, we reach the sky!
A little tweak, a version new,
Hooray for updates, cheers to you! 🌟


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, 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.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
package/db/setup.py (2)

151-154: Improved Linux distribution detection logic

The added fallback mechanism enhances compatibility with a wider range of Linux distributions. This is a good improvement that should make the package more robust across different Linux environments.

Consider adding error handling for cases where neither "ID" nor "ID_LIKE" match any key in LINUX_DOWNLOADS. This could prevent potential KeyError exceptions:

key = d["ID"].lower()
if key not in LINUX_DOWNLOADS:
    key = d.get("ID_LIKE", "").lower()
    if not key or key not in LINUX_DOWNLOADS:
        raise ValueError(f"Unsupported Linux distribution: {d['ID']}")

Line range hint 1-324: Suggestions for improving error handling and logging

While the overall structure and functionality of the setup script are sound, there are a few areas where error handling and logging could be improved:

  1. In the _get_linux_download function, consider adding logging to track which distribution is being detected and which download URL is being selected.

  2. In the CustomBdistWheel.write_wheelfile method, the error handling could be more specific. Instead of catching all exceptions, catch specific exceptions that you expect might occur (e.g., URLError, IOError).

  3. Consider adding more detailed logging throughout the script, especially in areas where file operations or network requests are made. This will make debugging easier in case of issues.

Here's an example of how you could improve the error handling and logging in the write_wheelfile method:

import logging
from urllib.error import URLError

# ... (rest of the imports)

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# ... (in the CustomBdistWheel class)

def write_wheelfile(self, *args, **kwargs):
    # ... (existing code)

    try:
        if not os.path.exists(mongo_zip_dest):
            logger.info(f"Downloading MongoDB binary from {mongo_zip_url}")
            with urlopen(mongo_zip_url) as conn, open(mongo_zip_dest, "wb") as dest:
                shutil.copyfileobj(conn, dest)
            logger.info("Download completed successfully")
    except URLError as e:
        logger.error(f"Failed to download MongoDB binary: {e}")
        raise
    except IOError as e:
        logger.error(f"Failed to write MongoDB binary to disk: {e}")
        raise

    # ... (rest of the method)

This change will provide more specific error messages and log important steps in the process, making it easier to diagnose issues if they occur.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6f5a12c and 7e73fec.

📒 Files selected for processing (1)
  • package/db/setup.py (2 hunks)
🧰 Additional context used

package/db/setup.py Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (2)
app/packages/core/src/components/Modal/ModalLooker.tsx (1)

30-30: LGTM: ModalLookerNoTimeline component updated

The changes to the ModalLookerNoTimeline component improve type safety by using the generic type ImageLooker with the useLooker hook. The removal of the looker destructuring suggests a simplification of the component's logic.

Consider adding a type annotation to the props parameter for improved readability:

const ModalLookerNoTimeline = React.memo((props: LookerProps) => {
  const { id, ref } = useLooker<ImageLooker>(props);
  // ... rest of the component
});
setup.py (1)

Line range hint 19-30: New get_version() function looks good, with a minor suggestion.

The new get_version() function is well-implemented. It provides flexibility for version management across different environments while ensuring consistency with the VERSION constant. The error handling is appropriate.

Consider adding a comment explaining the purpose of this function and when RELEASE_VERSION might be used. This would improve code maintainability. For example:

def get_version():
    """
    Get the package version.
    
    If RELEASE_VERSION environment variable is set (e.g., in CI/CD pipelines),
    use it after verifying it starts with VERSION. Otherwise, use VERSION.
    """
    # ... rest of the function
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7e73fec and 1f5eaa8.

📒 Files selected for processing (7)
  • app/packages/core/src/components/ColorModal/ColorFooter.tsx (3 hunks)
  • app/packages/core/src/components/Modal/ModalLooker.tsx (2 hunks)
  • app/packages/core/src/components/Modal/use-looker.ts (2 hunks)
  • app/packages/looker/src/lookers/video.ts (6 hunks)
  • app/packages/looker/src/state.ts (1 hunks)
  • docs/source/release-notes.rst (2 hunks)
  • setup.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
app/packages/core/src/components/ColorModal/ColorFooter.tsx (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/core/src/components/Modal/ModalLooker.tsx (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/core/src/components/Modal/use-looker.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/looker/src/lookers/video.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/looker/src/state.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

🔇 Additional comments (21)
app/packages/core/src/components/Modal/ModalLooker.tsx (1)

4-5: LGTM: Import statements cleaned up

The removal of unused imports (useCallback, useEffect, useState, and setActiveLookerRef) improves code cleanliness and aligns with React best practices. This change suggests a simplification of the component's logic.

setup.py (3)

16-16: Version update looks good.

The VERSION has been incremented from "1.0.0" to "1.0.1", which is appropriate for a minor update. This change correctly reflects the package's version progression.


Line range hint 138-138: Correct usage of get_version() in setup()

The setup() function correctly uses the new get_version() function for the version parameter. This ensures that the package will always use the appropriate version, whether it's defined by the VERSION constant or overridden by the RELEASE_VERSION environment variable.


Line range hint 1-185: Summary of changes

The updates to setup.py are focused and well-implemented:

  1. The VERSION has been incremented from "1.0.0" to "1.0.1".
  2. A new get_version() function has been added, allowing for flexible version management.
  3. The setup() function now uses get_version() to determine the package version.

These changes improve version management without affecting the rest of the setup script or introducing any risks. The implementation is solid and maintains backwards compatibility.

app/packages/core/src/components/ColorModal/ColorFooter.tsx (2)

6-6: LGTM: Import statement updated correctly

The import statement has been updated to only include useRecoilValue, which aligns with the changes in state management within the component. This is a good practice as it helps to keep the imports minimal and potentially reduces the bundle size.


17-17: Verify the impact of changing state management

The state management for activeColorModalField has been changed from useRecoilState to useRecoilValue. This shifts from a read-write approach to a read-only approach. Please verify:

  1. Is this change intentional?
  2. Are there any places in the component where setActiveColorModalField was previously used?
  3. How is the activeColorModalField state now being updated, if needed?

Ensure that this change doesn't unintentionally break any functionality within the component.

app/packages/looker/src/state.ts (1)

344-344: LGTM! Consider verifying the initialization and usage of the new buffers property.

The addition of the buffers property to the VideoState interface is a good enhancement for tracking multiple buffer ranges. This change is consistent with the existing video-related properties and doesn't break existing functionality.

To ensure proper implementation, please verify the following:

  1. The buffers property is correctly initialized wherever VideoState is created or updated.
  2. Any components or functions that rely on VideoState are updated to handle the new buffers property if necessary.

You can use the following script to check for potential usage:

✅ Verification successful

[/run_scripts]


[/run_scripts]


Verified! The buffers property is correctly initialized and utilized throughout the codebase. All relevant components handle it as expected, and existing tests confirm its proper functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for VideoState usage and initialization
rg --type typescript "VideoState" -A 10 -B 5

Length of output: 79


Script:

#!/bin/bash
# Search for VideoState usage and initialization in TypeScript files
rg "VideoState" --glob '*.ts' --glob '*.tsx' -A 10 -B 5

Length of output: 75120


Script:

#!/bin/bash
# Search for 'buffers' initialization and usage in TypeScript files
rg "buffers" --glob '*.ts' --glob '*.tsx' -A 10 -B 5

Length of output: 67643

docs/source/release-notes.rst (7)

Line range hint 8-19: Significant updates in v0.23.8

This release introduces several important features and improvements:

  1. A new Hugging Face Hub integration for publishing and downloading datasets.
  2. Support for visualizing grouped datasets in the App.
  3. Addition of a new Map panel for visualizing GeoLocation data.
  4. Initial support for custom App plugins.

These updates enhance FiftyOne's integration capabilities and visualization features, providing users with more flexibility in dataset management and analysis.


Line range hint 21-36: Core improvements in v0.23.8

Notable core improvements include:

  1. Support for point cloud samples in grouped datasets.
  2. New app_config property for per-dataset App configuration.
  3. Enhanced export functionality with new parameters like rel_dir and abs_paths.
  4. Improved COCO importer to load all available label types by default.

These changes provide more flexibility in dataset handling and improve interoperability with other formats and tools.


Line range hint 38-48: App enhancements in v0.23.8

Key App improvements:

  1. Support for visualizing clips views.
  2. New date and datetime field rendering and filtering.
  3. Improved error handling and display of stack traces.

These updates enhance the user experience and provide more robust data visualization and filtering capabilities in the App.


Line range hint 50-61: Brain and Zoo updates in v0.23.8

Significant updates:

  1. New Brain methods for finding unique and duplicate images or objects.
  2. Addition of CLIP and DINOv2 models to the Model Zoo.
  3. Support for applying Segment Anything models to video frames.

These additions expand FiftyOne's capabilities in image analysis and provide access to state-of-the-art models for various tasks.


Line range hint 63-73: Documentation improvements in v0.23.8

Notable documentation updates:

  1. New tutorials on clustering, small object detection, and monocular depth estimation.
  2. Updated popular tutorials for better clarity and relevance.
  3. New cheat sheets for pandas comparison, FiftyOne terminology, view stages, and filtering.

These documentation improvements make it easier for users to learn and effectively use FiftyOne's features.


Line range hint 1042-1062: Major updates in v0.23.0

This release introduces several significant features and integrations:

  1. New integrations for native text and image searches:

    • Redis integration
    • MongoDB integration
    • Milvus integration
    • LanceDB integration
  2. V7 integration for annotating FiftyOne datasets.

  3. App improvements:

    • New Lightning mode for optimized filtering on large datasets
    • Support for viewing image groups as a video
  4. Core enhancements:

    • Support for storing and visualizing cuboids and rotated bounding boxes
    • New aggregations framework for computing aggregate values

These updates significantly expand FiftyOne's capabilities in search, annotation, and data visualization, making it more powerful for large-scale dataset management and analysis.


Line range hint 1321-1340: Breaking changes and significant updates in v0.22.0 and earlier

  1. Breaking changes in v0.22.0:

    • Renamed all applicable API components that previously referenced "objects" to use "labels" instead. This affects attributes, classes, and methods related to label selection and manipulation.
  2. Major features and integrations in earlier versions:

    • v0.21.0: Added support for querying by arbitrary text prompts in the App.
    • v0.20.0: Introduced the Spaces framework and native support for visualizing embeddings in the App.
    • v0.19.0: Added support for storing frame labels on video samples.
    • v0.18.0: Introduced the Model Zoo with over 70 pretrained models for various tasks.
    • v0.17.0: Added support for grouped datasets and point cloud visualization.

These updates represent significant milestones in FiftyOne's development, expanding its capabilities in areas such as video analysis, model integration, and data visualization.

app/packages/core/src/components/Modal/use-looker.ts (2)

106-107: Appropriate use of Recoil's useSetRecoilState

The implementation correctly utilizes useSetRecoilState to manage the modalLooker state in Recoil, ensuring that the looker instance is properly stored.


108-109: Proper use of modal context with useModalContext

Destructuring setActiveLookerRef from useModalContext() allows effective interaction with the modal context.

app/packages/looker/src/lookers/video.ts (5)

18-18: Importing VideoConfig is appropriate

The addition of VideoConfig to the imports aligns with its usage in the code and ensures type consistency.


322-322: Initialize buffers using initialBuffers method enhances maintainability

Setting buffers in the initial state with this.initialBuffers(config) encapsulates buffer initialization logic, improving code readability and maintainability.


332-333: Use const for pan and scale to signify immutability

Changing let to const for the pan and scale variables is appropriate since their values are not reassigned, enhancing code clarity.


552-558: Proper cleanup when updating sample

Reinitializing this.frames and resetting this.state.buffers in updateSample clears outdated data, ensuring that the new sample loads correctly without residual state from previous samples.


572-576: Adding initialBuffers method improves code modularity

Introducing the initialBuffers method encapsulates the buffer initialization logic, promoting reusability and simplifying future modifications.

Comment on lines +28 to +29
() => foq.subscribe((_, { set }) => set(activeColorEntry, null)),
[]
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider the implications of the useEffect changes

The useEffect hook has been modified:

  1. The dependency array is now empty, meaning this effect will only run once on component mount.
  2. The callback now directly sets activeColorEntry to null using Recoil's set function.

While this simplifies the state update logic, consider the following:

  • Is it intentional to only reset activeColorEntry on component mount?
  • Are there any scenarios where activeColorEntry needs to be reset based on other state changes?

If the current behavior is intended, you might want to add a comment explaining why the effect only runs once. If not, consider adding appropriate dependencies to the dependency array.

Additionally, to improve code clarity, you could extract the subscription logic into a custom hook:

const useResetActiveColorEntry = () => {
  useEffect(() => foq.subscribe((_, { set }) => set(activeColorEntry, null)), []);
};

Then use it in the component:

const ColorFooter: React.FC = () => {
  // ... other code ...
  useResetActiveColorEntry();
  // ... rest of the component ...
};

This would make the component's logic more modular and easier to test.


useEffect(() => {
if (looker) {
setActiveLookerRef(looker as fos.Lookers);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid unnecessary type assertion

Using as fos.Lookers in setActiveLookerRef(looker as fos.Lookers); may mask potential type safety issues. Since looker is of type L extending fos.Lookers, the cast might be unnecessary. Consider ensuring that looker is correctly typed to eliminate the need for casting.

Adjust the code to avoid the type assertion:

- setActiveLookerRef(looker as fos.Lookers);
+ setActiveLookerRef(looker);
📝 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.

Suggested change
setActiveLookerRef(looker as fos.Lookers);
setActiveLookerRef(looker);

Comment on lines +110 to +113
useEffect(() => {
setModalLooker(looker);
}, [looker, setModalLooker]);

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider cleaning up modalLooker state on unmount

Currently, modalLooker is set when looker changes, but there is no cleanup when the component unmounts. To prevent potential stale references or memory leaks, consider resetting modalLooker when the component unmounts.

Add a cleanup function to the useEffect:

useEffect(() => {
  setModalLooker(looker);
+  return () => {
+    setModalLooker(null);
+  };
}, [looker, setModalLooker]);
📝 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.

Suggested change
useEffect(() => {
setModalLooker(looker);
}, [looker, setModalLooker]);
useEffect(() => {
setModalLooker(looker);
return () => {
setModalLooker(null);
};
}, [looker, setModalLooker]);

Comment on lines +114 to +119
useEffect(() => {
if (looker) {
setActiveLookerRef(looker as fos.Lookers);
}
}, [looker, setActiveLookerRef]);

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure activeLookerRef is cleaned up on unmount

In the useEffect, you set activeLookerRef when looker is available, but you should also reset it when the component unmounts to avoid holding onto stale references.

Modify the useEffect to include a cleanup function:

useEffect(() => {
  if (looker) {
    setActiveLookerRef(looker as fos.Lookers);
  }
+  return () => {
+    setActiveLookerRef(null);
+  };
}, [looker, setActiveLookerRef]);
📝 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.

Suggested change
useEffect(() => {
if (looker) {
setActiveLookerRef(looker as fos.Lookers);
}
}, [looker, setActiveLookerRef]);
useEffect(() => {
if (looker) {
setActiveLookerRef(looker as fos.Lookers);
}
return () => {
setActiveLookerRef(null);
};
}, [looker, setActiveLookerRef]);

Comment on lines +406 to +408
lookerWithReader?.pause();
lookerWithReader = this;
this.state.buffers = [[1, 1]];
this.setReader();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential race condition with shared lookerWithReader variable

Using the shared variable lookerWithReader may lead to unexpected behavior if multiple VideoLooker instances are active simultaneously. This can cause instances to pause or overwrite each other's readers.

Consider refactoring to avoid shared mutable state across instances. Encapsulating lookerWithReader within the class or managing instance-specific readers can prevent conflicts.

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.

2 participants