Skip to content

[py] Add properties (getter/setter) for service args #15889

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

Merged
merged 11 commits into from
Jun 13, 2025

Conversation

cgoldberg
Copy link
Contributor

@cgoldberg cgoldberg commented Jun 11, 2025

User description

🔗 Related Issues

Fixes #12760
Supersedes #14263
Supersedes #12767

💥 What does this PR do?

This PR adds properties (getter/setter) for service_args to the service classes as requested in #12760.

🔧 Implementation Notes

Service args can be any sequence, not just a list.

🔄 Types of changes

  • Bug fix (backwards compatible)
  • New feature (non-breaking change which adds functionality and tests!)

PR Type

Enhancement


Description

• Add getter/setter properties for service_args across all WebDriver service classes
• Change parameter type from list[str] to Sequence[str] for better flexibility
• Implement private _service_args attribute with validation in setters
• Update documentation strings to reflect sequence type change


Changes walkthrough 📝

Relevant files
Enhancement
8 files
service.py
Update service_args type to Sequence                                         
+3/-3     
service.py
Add service_args property with getter/setter                         
+17/-6   
service.py
Add service_args property with validation                               
+14/-4   
service.py
Implement service_args property and private attribute       
+19/-8   
service.py
Add service_args property with type validation                     
+22/-9   
service.py
Implement service_args getter/setter properties                   
+16/-7   
service.py
Add service_args property with sequence validation             
+16/-5   
service.py
Implement service_args property and private storage           
+15/-4   
Formatting
1 files
service.py
Add blank line formatting                                                               
+1/-0     

Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • @selenium-ci selenium-ci added the C-py Python Bindings label Jun 11, 2025
    @cgoldberg cgoldberg requested a review from shbenzer June 11, 2025 18:06
    Copy link
    Contributor

    qodo-merge-pro bot commented Jun 11, 2025

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    @cgoldberg cgoldberg requested a review from titusfortner June 11, 2025 18:06
    Copy link
    Contributor

    qodo-merge-pro bot commented Jun 11, 2025

    PR Code Suggestions ✨

    Latest suggestions up to e54bffe

    CategorySuggestion                                                                                                                                    Impact
    Incremental [*]
    Validate sequence element types

    Add validation to ensure the sequence contains only string elements to prevent
    runtime errors when the service arguments are used in subprocess calls.

    py/selenium/webdriver/chrome/service.py [61-65]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
         if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    +    if not all(isinstance(arg, str) for arg in value):
    +        raise TypeError("All service_args must be strings")
         self._service_args = list(value)
    • Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly identifies a missing validation step. While the type hint is Sequence[str], there is no runtime check to ensure all elements in the sequence are strings. Adding this check prevents potential TypeError exceptions when constructing command-line arguments for the subprocess, thus improving the code's robustness.

    Medium
    Possible issue
    Fix string validation logic
    Suggestion Impact:The commit directly implements the suggested fix by changing the validation condition from "not isinstance(value, Sequence) or isinstance(value, str)" to "isinstance(value, str) or not isinstance(value, Sequence)" on line 6.

    code diff:

    -        if not isinstance(value, Sequence) or isinstance(value, str):
    +        if isinstance(value, str) or not isinstance(value, Sequence):

    The validation logic incorrectly rejects strings because strings are sequences
    in Python. The condition should use isinstance(value, str) first to exclude
    strings, then check if it's a sequence. This prevents valid non-string sequences
    from being rejected.

    py/selenium/webdriver/chrome/service.py [61-65]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
    -    if not isinstance(value, Sequence) or isinstance(value, str):
    +    if isinstance(value, str) or not isinstance(value, Sequence):
             raise TypeError("service_args must be a sequence")
         self._service_args = list(value)

    [Suggestion processed]

    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly identifies that the original validation logic not isinstance(value, Sequence) or isinstance(value, str) is flawed because a string is a sequence, causing the first part of the or to be false and the second to be true, thus always raising an error for strings. The proposed change isinstance(value, str) or not isinstance(value, Sequence) correctly handles this by checking for strings first.

    Medium
    • Update

    Previous suggestions

    ✅ Suggestions up to commit 64a0768
    CategorySuggestion                                                                                                                                    Impact
    General
    Convert sequence to list consistently
    Suggestion Impact:The suggestion was directly implemented - the setter now converts the sequence to a list using list(value) instead of storing the sequence directly

    code diff:

    -        self._service_args = value
    +        self._service_args = list(value)

    The setter should convert the sequence to a list to maintain consistency with
    the internal storage format. The current implementation stores the sequence
    directly, which could lead to issues if a non-list sequence is provided.

    py/selenium/webdriver/chromium/service.py [75-79]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
         if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    -    self._service_args = value
    +    self._service_args = list(value)

    [Suggestion processed]

    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly points out an inconsistency. The __init__ method initializes self._service_args as a list and uses .append(), but the setter allows any Sequence to be assigned. This could lead to runtime errors if a non-list sequence (like a tuple) is assigned and subsequent code expects a list. Converting to a list in the setter ensures type consistency for the internal attribute.

    Medium
    ✅ Suggestions up to commit ac0f6e5
    CategorySuggestion                                                                                                                                    Impact
    General
    Add string exclusion validation consistency
    Suggestion Impact:The suggestion's first part was implemented - the validation logic was updated to exclude strings by adding "or isinstance(value, str)" to the condition

    code diff:

    -        if not isinstance(value, Sequence):
    +        if not isinstance(value, Sequence) or isinstance(value, str):

    The setter validation is inconsistent with other service classes. It should also
    exclude strings from being accepted as valid sequences, since strings are
    sequences but not the intended type for service arguments.

    py/selenium/webdriver/chrome/service.py [61-65]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
    -    if not isinstance(value, Sequence):
    +    if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    -    self._service_args = value
    +    self._service_args = list(value)

    [Suggestion processed]

    Suggestion importance[1-10]: 9

    __

    Why: This suggestion correctly points out two issues: the inconsistent validation that allows strings, and the need to convert the input to a list. Fixing this prevents potential errors and aligns the chrome service's behavior with all other service classes modified in this PR, improving overall consistency and robustness.

    High
    Convert sequence to list consistently
    Suggestion Impact:The suggestion was directly implemented - the setter now converts the sequence to a list using list(value) instead of storing the sequence directly

    code diff:

    -        self._service_args = value
    +        self._service_args = list(value)

    The setter should convert the sequence to a list to maintain consistency with
    the internal storage format. The current implementation directly assigns the
    sequence, which could lead to type inconsistencies since _service_args is
    expected to be a list.

    py/selenium/webdriver/chromium/service.py [75-79]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
         if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    -    self._service_args = value
    +    self._service_args = list(value)
    Suggestion importance[1-10]: 8

    __

    Why: The suggestion correctly identifies that _service_args should consistently be a list, as it is initialized as one and other parts of the codebase may rely on its mutability (e.g., using .append()). Assigning a generic Sequence like a tuple could lead to runtime errors.

    Medium
    Incremental [*]
    Convert sequence to list assignment
    Suggestion Impact:The suggestion was directly implemented - the setter now converts the input sequence to a list before assignment

    code diff:

    -        self._service_args = value
    +        self._service_args = list(value)

    Convert the sequence to a list before assignment to maintain consistency with
    the internal storage format and avoid potential issues with immutable sequences

    py/selenium/webdriver/edge/service.py [64-68]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
         if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    -    self._service_args = value
    +    self._service_args = list(value)
    Suggestion importance[1-10]: 6

    __

    Why: The suggestion correctly points out a potential issue. The __init__ method initializes _service_args as a list, and other methods in related classes mutate it using methods like .append(). The setter should also convert the incoming sequence to a list to maintain internal type consistency and prevent potential AttributeError if an immutable sequence (like a tuple) is passed.

    Low
    ✅ Suggestions up to commit c657676
    CategorySuggestion                                                                                                                                    Impact
    General
    Add string exclusion validation consistency
    Suggestion Impact:The suggestion's first part was implemented - the validation logic was updated to exclude strings by adding "or isinstance(value, str)" to the condition

    code diff:

    -        if not isinstance(value, Sequence):
    +        if not isinstance(value, Sequence) or isinstance(value, str):

    The setter validation is inconsistent with other service classes. It should also
    exclude strings from being accepted as valid sequences, since strings are
    sequences but not the intended type.

    py/selenium/webdriver/chrome/service.py [61-65]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
    -    if not isinstance(value, Sequence):
    +    if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    -    self._service_args = value
    +    self._service_args = list(value)
    Suggestion importance[1-10]: 8

    __

    Why: The suggestion correctly identifies two issues: the validation for service_args is incomplete as it allows strings, and the assigned value is not converted to a list. The proposed change aligns the implementation with other service classes in the PR, improving both robustness and consistency.

    Medium
    Improve validation and conversion consistency
    Suggestion Impact:The commit partially implemented the suggestion by adding string exclusion to the validation logic, but did not include the list conversion part

    code diff:

    -        if not isinstance(value, Sequence):
    +        if not isinstance(value, Sequence) or isinstance(value, str):

    The setter validation should exclude strings and convert the sequence to a list
    for consistency with other service classes and internal storage format.

    py/selenium/webdriver/edge/service.py [64-68]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
    -    if not isinstance(value, Sequence):
    +    if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
    -    self._service_args = value
    +    self._service_args = list(value)

    [Suggestion processed]

    Suggestion importance[1-10]: 8

    __

    Why: The suggestion correctly identifies that the service_args setter is missing validation to exclude strings and does not convert the input sequence to a list. Applying this change makes the setter more robust and consistent with other service classes modified in this PR.

    Medium
    Incremental [*]
    Ensure service_args mutability

    Convert the service_args to a list to ensure mutability since the property
    setter expects to assign a new value to this attribute, and sequences like
    tuples are immutable.

    py/selenium/webdriver/chrome/service.py [46]

    -self._service_args = service_args or []
    +self._service_args = list(service_args or [])
    Suggestion importance[1-10]: 6

    __

    Why: The suggestion correctly points out an inconsistency. While the code in chrome/service.py does not mutate self._service_args, other service classes in the PR convert service_args to a list to ensure mutability. Applying this change improves consistency across the codebase.

    Low
    Convert sequence to list
    Suggestion Impact:The suggestion was directly implemented - the code was changed from `self._service_args = value` to `self._service_args = list(value)` exactly as suggested

    code diff:

    -        self._service_args = value
    +        self._service_args = list(value)

    Convert the value to a list before assignment to ensure the internal storage is
    mutable and consistent with the initialization pattern used elsewhere in the
    codebase.

    py/selenium/webdriver/chromium/service.py [77-79]

     if not isinstance(value, Sequence) or isinstance(value, str):
         raise TypeError("service_args must be a sequence")
    -self._service_args = value
    +self._service_args = list(value)
    Suggestion importance[1-10]: 6

    __

    Why: The suggestion correctly identifies that self._service_args should be a mutable list, as it's modified in the __init__ method. Converting the assigned value to a list in the setter ensures this, improving robustness and consistency with the initialization logic.

    Low
    ✅ Suggestions up to commit e5ad858
    CategorySuggestion                                                                                                                                    Impact
    General
    Ensure service args mutability
    Suggestion Impact:The exact suggested change was implemented - wrapping service_args with list() to ensure mutability

    code diff:

    -        self._service_args = service_args or []
    +        self._service_args = list(service_args or [])

    Convert the input sequence to a list to ensure mutability for operations like
    append() used elsewhere in the code. This prevents potential issues when
    immutable sequences are passed.

    py/selenium/webdriver/chromium/service.py [48]

    -self._service_args = service_args or []
    +self._service_args = list(service_args or [])

    [Suggestion processed]

    Suggestion importance[1-10]: 8

    __

    Why: This is a valuable suggestion. The code later appends to self._service_args, which requires a mutable sequence. If an immutable sequence like a tuple is passed for service_args, it would cause a runtime AttributeError. Converting to a list ensures mutability and prevents this bug.

    Medium
    Prevent strings as sequence arguments
    Suggestion Impact:The suggestion was directly implemented - the exact code change was made to add isinstance(value, str) check to prevent strings from being treated as valid sequence arguments

    code diff:

    -        if not isinstance(value, Sequence):
    +        if not isinstance(value, Sequence) or isinstance(value, str):

    The type check should exclude strings since they are sequences but shouldn't be
    treated as argument lists. Add a check to prevent strings from being accepted as
    valid sequences.

    py/selenium/webdriver/chromium/service.py [75-79]

     @service_args.setter
     def service_args(self, value: Sequence[str]):
    -    if not isinstance(value, Sequence):
    +    if not isinstance(value, Sequence) or isinstance(value, str):
             raise TypeError("service_args must be a sequence")
         self._service_args = value

    [Suggestion processed]

    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly points out that a string, being a sequence, would pass the isinstance(value, Sequence) check but is likely not the intended input for a list of arguments. Adding a check for isinstance(value, str) makes the validation more robust and prevents potential runtime errors.

    Medium
    Possible issue
    Fix inconsistent attribute assignment
    Suggestion Impact:The suggestion was directly implemented - the line "self.service_args = service_args or []" was changed to "self._service_args = service_args or []" exactly as suggested

    code diff:

    -        self.service_args = service_args or []
    +        self._service_args = service_args or []

    The service_args assignment should use the private attribute _service_args to be
    consistent with the property implementation. This ensures the getter/setter
    pattern works correctly.

    py/selenium/webdriver/wpewebkit/service.py [40-49]

     def __init__(
         self,
         executable_path: str = DEFAULT_EXECUTABLE_PATH,
         port: int = 0,
         log_output: Optional[str] = None,
         service_args: Optional[Sequence[str]] = None,
         env: Optional[Mapping[str, str]] = None,
         **kwargs,
     ):
    -    self.service_args = service_args or []
    +    self._service_args = service_args or []
    Suggestion importance[1-10]: 5

    __

    Why: The suggestion correctly identifies an inconsistency in py/selenium/webdriver/wpewebkit/service.py where self.service_args is used in __init__ instead of self._service_args. While functionally correct due to the setter, changing it improves consistency with other modified files in the PR.

    Low

    @shbenzer
    Copy link
    Contributor

    I don't really see much benefit in allowing for sequences instead of forcing List as we have, but after looking into it every type in the Sequence library can be cast to List safely so LGTM.

    Edit: Was #12760 reopened in the Slack, I see it's marked as not planned on the ticket?

    @cgoldberg
    Copy link
    Contributor Author

    Was #12760 reopened in the Slack, I see it's marked as not planned on the ticket?

    It was marked "not planned" by the bot because it had no activity for a long time. It's still useful.

    @cgoldberg cgoldberg merged commit 4a6303e into SeleniumHQ:trunk Jun 13, 2025
    17 of 18 checks passed
    @cgoldberg cgoldberg deleted the py-service-args-properties branch June 13, 2025 17:45
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    [🚀 Feature]: Python Service class Properties
    3 participants