Skip to content

refactor(ia): use Any as argument instead of PyObject#33

Merged
cesarcoatl merged 1 commit into
8.3from
refactor/ia/PyObject-to-Any
May 28, 2026
Merged

refactor(ia): use Any as argument instead of PyObject#33
cesarcoatl merged 1 commit into
8.3from
refactor/ia/PyObject-to-Any

Conversation

@cesarcoatl
Copy link
Copy Markdown
Member

@cesarcoatl cesarcoatl commented May 28, 2026

Summary by Sourcery

Enhancements:

  • Relax type annotations from PyObject to Any for variadic arguments in common scripting, HTTP client, adapters, and collection utilities to better reflect actual usage and improve type compatibility.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 28, 2026

Reviewer's Guide

Refactors various Ignition/Jython scripting APIs and their stubs to use the more general Any type for variadic *args parameters instead of PyObject, keeping **kwargs types unchanged, and keeps runtime code behavior the same by only updating type comments and .pyi signatures.

File-Level Changes

Change Details Files
Loosened variadic argument types from PyObject to Any in common script builtin OPC and dataset utilities, in both runtime implementations and stubs.
  • Updated AbstractOPCUtilities.getServers, writeValue, and writeValues *args annotations/comments from PyObject to Any while preserving **kwargs as Union[str, unicode].
  • Updated DatasetUtilities.toCSV and toExcel static methods to use *args: Any in stubs and corresponding # type: comments in implementations.
  • Updated SystemUtilities.parseTranslateArguments *args parameter from PyObject to Any in stubs and implementation type comments.
stubs/stubs/com/inductiveautomation/ignition/common/script/builtin/__init__.pyi
src/com/inductiveautomation/ignition/common/script/builtin/__init__.py
Generalized variadic argument types to Any in HTTP client and Promise APIs, aligning stubs with implementation type comments.
  • Changed JythonHttpClient.delete, deleteAsync, get, and getAsync *args type from PyObject to Any in stubs and implementation comments.
  • Changed Promise.get *args type from PyObject to Any in stubs and implementation comments.
stubs/stubs/com/inductiveautomation/ignition/common/script/builtin/http/__init__.pyi
src/com/inductiveautomation/ignition/common/script/builtin/http/__init__.py
Updated abstract collection and adapter APIs to use Any for variadic parameters in map/sequence update and sort methods, in both .py and .pyi files including org.python.core.
  • Changed MutableJythonMap/AbstractMutableJythonMap.update and MutableJythonSequence/AbstractMutableJythonSequence.sort signatures from *args: PyObject to *args: Any in stubs, and corresponding methods in src abc module to use Any in type comments.
  • Adjusted PyJsonObjectAdapter.update to accept *args: Any in stubs and implementation.
  • Updated Jython abstract/adapter implementations in src abc and adapters modules so update/sort methods’ type comments use Any instead of PyObject.
  • Changed PyList.sort variadic parameter from PyObject to Any in org.python.core stubs and implementation type comments.
src/com/inductiveautomation/ignition/common/script/abc/__init__.py
stubs/stubs/com/inductiveautomation/ignition/common/script/abc/__init__.pyi
src/com/inductiveautomation/ignition/common/script/adapters/__init__.py
stubs/stubs/com/inductiveautomation/ignition/common/script/adapters/__init__.pyi
src/org/python/core/__init__.py
stubs/stubs/org/python/core/__init__.pyi
Aligned Vision/Window utilities’ variadic argument types with Any for desktop and transform helpers, in both runtime and stubs.
  • Changed VisionUtilities.openDesktop and WindowUtilities.openDesktop to accept *args: Any instead of *args: PyObject in stubs and corresponding implementation type comments.
  • Updated WindowUtilities.transform to use *args: Any instead of *args: PyObject in stubs and implementation type comments, leaving return type as PyObject.
src/com/inductiveautomation/factorypmi/application/script/builtin/__init__.py
stubs/stubs/com/inductiveautomation/factorypmi/application/script/builtin/__init__.pyi

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
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 - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="stubs/stubs/com/inductiveautomation/ignition/common/script/abc/__init__.pyi" line_range="38" />
<code_context>
         self, pyKey: PyObject, def_: Optional[PyObject] = ...
     ) -> PyObject: ...
-    def update(self, *args: PyObject, **kwargs: Union[str, unicode]) -> None: ...
+    def update(self, *args: Any, **kwargs: Union[str, unicode]) -> None: ...
     def __setitem__(self, pyKey: PyObject, pyValue: PyObject) -> None: ...
     def __delitem__(self, pyKey: PyObject) -> None: ...
</code_context>
<issue_to_address>
**suggestion:** The `kwargs` type on `update` is narrower than Python `dict.update` semantics.

Since `*args` is now `Any`, consider widening `**kwargs` from `Union[str, unicode]` to `Any` as well to better match `dict.update` semantics. Callers may reasonably pass non-string keyword values (numbers, booleans, nested structures), and the current text-only type could cause unnecessary type-checking issues for valid usages.

```suggestion
    def update(self, *args: Any, **kwargs: Any) -> None: ...
```
</issue_to_address>

### Comment 2
<location path="stubs/stubs/com/inductiveautomation/ignition/common/script/abc/__init__.pyi" line_range="48" />
<code_context>
     def pop(self, index: Optional[int] = ...) -> PyObject: ...
     def remove(self, element: PyObject) -> None: ...
-    def sort(self, *args: PyObject, **kwargs: Union[str, unicode]) -> None: ...
+    def sort(self, *args: Any, **kwargs: Union[str, unicode]) -> None: ...
     def __add__(self, other: PyObject) -> PyObject: ...
     def __imul__(self, other: PyObject) -> PyObject: ...
</code_context>
<issue_to_address>
**suggestion:** Consider loosening `kwargs` for `sort` to better reflect typical Python `list.sort` usage.

For `MutableJythonSequence.sort`, `**kwargs: Union[str, unicode]` doesn’t match typical `list.sort` usage (e.g. `sort(key=..., reverse=True)`), where values aren’t limited to strings. Consider `**kwargs: Any`, or explicitly typing parameters (`key: Optional[Callable[..., Any]] = ..., reverse: bool = ...`) to better reflect Python semantics and improve typing usability.

Suggested implementation:

```
    def insert(self, index: int, element: PyObject) -> None: ...
    def pop(self, index: Optional[int] = ...) -> PyObject: ...
    def remove(self, element: PyObject) -> None: ...
    def sort(
        self,
        key: Optional[Callable[..., Any]] = ...,
        reverse: bool = ...,
    ) -> None: ...
    def __add__(self, other: PyObject) -> PyObject: ...
    def __imul__(self, other: PyObject) -> PyObject: ...

```

If `Callable` is not already imported in this stub file, add it to the existing `from typing import ...` line, e.g.:

- `from typing import Any, Optional, Union`  
+ `from typing import Any, Optional, Union, Callable`

This will ensure the new `Callable` annotation for `sort` is properly recognized.
</issue_to_address>

### Comment 3
<location path="stubs/stubs/com/inductiveautomation/ignition/common/script/builtin/http/__init__.pyi" line_range="15-18" />
<code_context>
-    ) -> Promise: ...
-    def get(self, *args: PyObject, **kwargs: Union[str, unicode]) -> Response: ...
-    def getAsync(self, *args: PyObject, **kwargs: Union[str, unicode]) -> Promise: ...
+    def delete(self, *args: Any, **kwargs: Union[str, unicode]) -> Response: ...
+    def deleteAsync(self, *args: Any, **kwargs: Union[str, unicode]) -> Promise: ...
+    def get(self, *args: Any, **kwargs: Union[str, unicode]) -> Response: ...
+    def getAsync(self, *args: Any, **kwargs: Union[str, unicode]) -> Promise: ...
     def getConnectTimeout(self) -> long: ...
     def getCookieManager(self) -> CookieManager: ...
</code_context>
<issue_to_address>
**suggestion:** `kwargs` for HTTP methods may be too strictly typed as `Union[str, unicode]`.

Given common kwargs like `timeout`, `headers`, `data`, or `json` are often non-strings (e.g., numbers, dicts), constraining `**kwargs` to `Union[str, unicode]` is likely too narrow for an HTTP client. Consider widening to `Any` or a more appropriate mapping type to better match real usage and avoid unnecessary type-checker complaints.

Suggested implementation:

```
class JythonHttpClient(Object):
    def delete(self, *args: Any, **kwargs: Any) -> Response: ...
    def deleteAsync(self, *args: Any, **kwargs: Any) -> Promise: ...
    def get(self, *args: Any, **kwargs: Any) -> Response: ...
    def getAsync(self, *args: Any, **kwargs: Any) -> Promise: ...

```

```
class Promise(Object):
    def cancel(self) -> bool: ...
    def get(self, *args: Any, **kwargs: Any) -> Any: ...
    def getFuture(self) -> CompletableFuture: ...
    def handleException(self, callback: PyObject) -> Promise: ...
    def isDone(self) -> bool: ...

```
</issue_to_address>

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 and I'll use the feedback to improve your reviews.

self, pyKey: PyObject, def_: Optional[PyObject] = ...
) -> PyObject: ...
def update(self, *args: PyObject, **kwargs: Union[str, unicode]) -> None: ...
def update(self, *args: Any, **kwargs: Union[str, unicode]) -> None: ...
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: The kwargs type on update is narrower than Python dict.update semantics.

Since *args is now Any, consider widening **kwargs from Union[str, unicode] to Any as well to better match dict.update semantics. Callers may reasonably pass non-string keyword values (numbers, booleans, nested structures), and the current text-only type could cause unnecessary type-checking issues for valid usages.

Suggested change
def update(self, *args: Any, **kwargs: Union[str, unicode]) -> None: ...
def update(self, *args: Any, **kwargs: Any) -> None: ...

def pop(self, index: Optional[int] = ...) -> PyObject: ...
def remove(self, element: PyObject) -> None: ...
def sort(self, *args: PyObject, **kwargs: Union[str, unicode]) -> None: ...
def sort(self, *args: Any, **kwargs: Union[str, unicode]) -> None: ...
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider loosening kwargs for sort to better reflect typical Python list.sort usage.

For MutableJythonSequence.sort, **kwargs: Union[str, unicode] doesn’t match typical list.sort usage (e.g. sort(key=..., reverse=True)), where values aren’t limited to strings. Consider **kwargs: Any, or explicitly typing parameters (key: Optional[Callable[..., Any]] = ..., reverse: bool = ...) to better reflect Python semantics and improve typing usability.

Suggested implementation:

    def insert(self, index: int, element: PyObject) -> None: ...
    def pop(self, index: Optional[int] = ...) -> PyObject: ...
    def remove(self, element: PyObject) -> None: ...
    def sort(
        self,
        key: Optional[Callable[..., Any]] = ...,
        reverse: bool = ...,
    ) -> None: ...
    def __add__(self, other: PyObject) -> PyObject: ...
    def __imul__(self, other: PyObject) -> PyObject: ...

If Callable is not already imported in this stub file, add it to the existing from typing import ... line, e.g.:

  • from typing import Any, Optional, Union
  • from typing import Any, Optional, Union, Callable

This will ensure the new Callable annotation for sort is properly recognized.

Comment on lines +15 to +18
def delete(self, *args: Any, **kwargs: Union[str, unicode]) -> Response: ...
def deleteAsync(self, *args: Any, **kwargs: Union[str, unicode]) -> Promise: ...
def get(self, *args: Any, **kwargs: Union[str, unicode]) -> Response: ...
def getAsync(self, *args: Any, **kwargs: Union[str, unicode]) -> Promise: ...
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: kwargs for HTTP methods may be too strictly typed as Union[str, unicode].

Given common kwargs like timeout, headers, data, or json are often non-strings (e.g., numbers, dicts), constraining **kwargs to Union[str, unicode] is likely too narrow for an HTTP client. Consider widening to Any or a more appropriate mapping type to better match real usage and avoid unnecessary type-checker complaints.

Suggested implementation:

class JythonHttpClient(Object):
    def delete(self, *args: Any, **kwargs: Any) -> Response: ...
    def deleteAsync(self, *args: Any, **kwargs: Any) -> Promise: ...
    def get(self, *args: Any, **kwargs: Any) -> Response: ...
    def getAsync(self, *args: Any, **kwargs: Any) -> Promise: ...

class Promise(Object):
    def cancel(self) -> bool: ...
    def get(self, *args: Any, **kwargs: Any) -> Any: ...
    def getFuture(self) -> CompletableFuture: ...
    def handleException(self, callback: PyObject) -> Promise: ...
    def isDone(self) -> bool: ...

@cesarcoatl cesarcoatl merged commit 262a8c7 into 8.3 May 28, 2026
5 checks passed
@cesarcoatl cesarcoatl deleted the refactor/ia/PyObject-to-Any branch May 28, 2026 21:37
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.

1 participant