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

Fix parsing issues in TextStyle and *Event classes #3551

Merged
merged 4 commits into from
Jul 23, 2024
Merged

Conversation

ndonkoHenri
Copy link
Contributor

@ndonkoHenri ndonkoHenri commented Jun 26, 2024

Fixes #3532

Summary by Sourcery

This pull request addresses parsing issues in multiple event classes by using the get method for dictionary access to handle missing keys. Additionally, it refactors theme parsing functions to use textStyleFromJson directly, enhancing code consistency.

  • Bug Fixes:
    • Fixed parsing issues in various event classes by replacing dictionary key access with the get method to handle missing keys gracefully.
  • Enhancements:
    • Refactored parseTextStyle function usage in theme parsing functions to use textStyleFromJson directly, improving code consistency.

Copy link
Contributor

sourcery-ai bot commented Jun 26, 2024

Reviewer's Guide by Sourcery

This pull request addresses and fixes issues related to TextStyle parsing in theme-related functions by replacing the parseTextStyle function with textStyleFromJson. Additionally, it removes redundant parseTextStyle functions to enhance code maintainability. It also updates various event classes to use the get method for JSON parsing to handle missing keys gracefully.

File-Level Changes

Files Changes
sdk/python/packages/flet-core/src/flet_core/gesture_detector.py
sdk/python/packages/flet-core/src/flet_core/map/map_configuration.py
sdk/python/packages/flet-core/src/flet_core/scrollable_control.py
sdk/python/packages/flet-core/src/flet_core/drag_target.py
sdk/python/packages/flet-core/src/flet_core/file_picker.py
sdk/python/packages/flet-core/src/flet_core/dismissible.py
sdk/python/packages/flet-core/src/flet_core/charts/bar_chart.py
sdk/python/packages/flet-core/src/flet_core/charts/pie_chart.py
sdk/python/packages/flet-core/src/flet_core/container.py
sdk/python/packages/flet-core/src/flet_core/page.py
sdk/python/packages/flet-core/src/flet_core/canvas/canvas.py
sdk/python/packages/flet-core/src/flet_core/charts/line_chart.py
sdk/python/packages/flet-core/src/flet_core/datatable.py
sdk/python/packages/flet-core/src/flet_core/auto_complete.py
Replaced dictionary key access with get method in various event classes to handle missing keys gracefully.
packages/flet/lib/src/utils/theme.dart Replaced parseTextStyle function with textStyleFromJson in theme parsing functions and removed redundant parseTextStyle function.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @ndonkoHenri - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @ndonkoHenri - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 7 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

Comment on lines +701 to +705
self.local_x: float = d.get("lx")
self.local_y: float = d.get("ly")
self.global_x: float = d.get("gx")
self.global_y: float = d.get("gy")
self.kind: str = d.get("kind")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Potential issue with default values

Using d.get() will return None if the key is not found. This might cause issues if the attributes are expected to be non-null. Consider providing default values to d.get(), e.g., d.get('lx', 0.0).

self.local_y: float = d.get("ly")
self.global_x: float = d.get("gx")
self.global_y: float = d.get("gy")
self.timestamp: Optional[int] = d.get("ts")
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Inconsistent use of Optional

The use of Optional is inconsistent across the code. For example, self.timestamp is marked as Optional[int] but self.local_x is not marked as Optional[float]. Consider making the use of Optional consistent.

Suggested change
self.timestamp: Optional[int] = d.get("ts")
self.local_y: Optional[float] = d.get("ly")
self.global_x: Optional[float] = d.get("gx")
self.global_y: Optional[float] = d.get("gy")
self.timestamp: Optional[int] = d.get("ts")

self.coordinates: MapLatitudeLongitude = MapLatitudeLongitude(
d["lat"], d["long"]
d.get("lat"), d.get("long")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Potential issue with default values in coordinates

If d.get('lat') or d.get('long') returns None, it might cause issues in MapLatitudeLongitude. Consider providing default values or handling None cases.

@@ -19,6 +19,7 @@ def __init__(
on_scroll_interval: OptionalNumber = None,
on_scroll: Optional[Callable[["OnScrollEvent"], None]] = None,
):
Control.__init__(self)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Redundant call to superclass constructor

The call to Control.__init__(self) is redundant if super().__init__() is already being called in the constructor. Consider removing it to avoid confusion.

Suggested change
Control.__init__(self)
super().__init__()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sourcery-ai explain this point more detaily

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, I'd be happy to explain this in more detail.

In Python, when you define a class that inherits from a superclass, you often need to call the constructor of the superclass to ensure that the superclass is properly initialized. This is typically done using the super() function.

For example, if you have a class Control and a subclass ScrollableControl, you would call the superclass constructor like this:

class ScrollableControl(Control):
    def __init__(self, ...):
        super().__init__()
        # additional initialization for ScrollableControl

The super().__init__() call ensures that the __init__ method of the Control class is executed, which sets up any necessary state or properties defined in Control.

In the diff hunk you provided, there is a call to Control.__init__(self):

class ScrollableControl(Control):
    def __init__(self, ...):
        Control.__init__(self)
        # additional initialization for ScrollableControl

This is a more explicit way of calling the superclass constructor, but it is generally considered less flexible and less idiomatic in modern Python code. The super() function is preferred because it automatically handles the correct method resolution order, especially in cases of multiple inheritance.

So, the suggestion to replace Control.__init__(self) with super().__init__() is to make the code more idiomatic and to avoid potential issues with method resolution order in more complex inheritance hierarchies.

Here's the revised code with the suggested change:

class ScrollableControl(Control):
    def __init__(self, ...):
        super().__init__()
        # additional initialization for ScrollableControl

This way, the superclass constructor is called in a more standard and flexible manner.

Comment on lines +296 to +305
self.direction: DismissDirection = DismissDirection(d.get("direction"))


class DismissibleUpdateEvent(ControlEvent):
def __init__(self, e: ControlEvent):
super().__init__(e.target, e.name, e.data, e.control, e.page)
d = json.loads(e.data)
self.direction = DismissDirection(d["direction"])
self.progress = d["progress"]
self.reached = d["reached"]
self.previous_reached = d["previous_reached"]
self.direction: DismissDirection = DismissDirection(d.get("direction"))
self.progress: float = d.get("progress")
self.reached: bool = d.get("reached")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Potential issue with default values in DismissibleUpdateEvent

Using d.get() without default values might cause issues if the keys are not present. Consider providing default values or handling None cases.

@@ -1116,7 +1116,7 @@ async def _authorize_callback_async(self, data: str) -> None:
async def __on_authorize_async(self, e) -> None:
assert self.__authorization
d = json.loads(e.data)
state = d["state"]
state = d.get("state")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Potential issue with state validation

If d.get('state') returns None, the subsequent assert might fail. Consider handling the None case explicitly.

Comment on lines +30 to +31
self.column_index: int = d.get("i")
self.ascending: bool = d.get("a")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Potential issue with default values in DataColumnSortEvent

Using d.get() without default values might cause issues if the keys are not present. Consider providing default values or handling None cases.

self.src_id: float = d["src_id"]
self.x: float = d["x"]
self.y: float = d["y"]
self.src_id: float = d.get("src_id")
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider explicitly handling missing keys instead of using get.

The new code introduces additional complexity by using the get method for dictionary access, which can silently assign None to attributes if keys are missing. This can mask issues and make debugging harder. The original code's direct dictionary access would raise a KeyError, providing a clear signal when expected keys are missing. If handling missing keys is necessary, it should be done explicitly with proper error handling. Here's a suggested approach:

class DragTargetAcceptEvent(ControlEvent):
    def __init__(self, e: ControlEvent):
        super().__init__(e.target, e.name, e.data, e.control, e.page)
        d = json.loads(e.data)
        warn(
            f"{self.__class__.__name__} is deprecated since version 0.22.0 "
            f"and will be removed in version 0.26.0. Use DragTargetEvent instead.",
            category=DeprecationWarning,
            stacklevel=2,
        )
        try:
            self.src_id: float = d["src_id"]
            self.x: float = d["x"]
            self.y: float = d["y"]
        except KeyError as key_error:
            raise ValueError(f"Missing expected key in data: {key_error}")

class DragTargetEvent(ControlEvent):
    def __init__(self, e: ControlEvent):
        super().__init__(e.target, e.name, e.data, e.control, e.page)
        d = json.loads(e.data)
        try:
            self.src_id: float = d["src_id"]
            self.x: float = d["x"]
            self.y: float = d["y"]
        except KeyError as key_error:
            raise ValueError(f"Missing expected key in data: {key_error}")

This maintains simplicity while explicitly handling missing keys, making the code more robust and easier to maintain.

@ndonkoHenri ndonkoHenri linked an issue Jul 6, 2024 that may be closed by this pull request
1 task
@ndonkoHenri ndonkoHenri linked an issue Jul 7, 2024 that may be closed by this pull request
1 task
@FeodorFitsner FeodorFitsner merged commit 01935d0 into main Jul 23, 2024
2 checks passed
@ndonkoHenri ndonkoHenri deleted the fix-theme branch July 23, 2024 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment