Skip to content

[BUG] TypeError: 'builtin_function_or_method' object does not support the context manager protocol #2082

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

Closed
17Reset opened this issue Mar 11, 2025 · 8 comments
Labels

Comments

@17Reset
Copy link

17Reset commented Mar 11, 2025

Base info:

D:\***\***\***\***\***\***>pyarmor -v
Pyarmor 9.0.8 (group), 006040, non-profits

License Type    : pyarmor-group
License No.     : pyarmor-vax-006040
License To      : *****
License Product : non-profits

BCC Mode        : Yes
RFT Mode        : Yes
CI/CD Mode      : No

Notes
* Offline obfuscation
447.15

Windows 11 Enterprise Edition LTSC
Python 3.13.1

When I packaged the code after obfuscating it with Pyarmor, I can start the program normally, but when executing a specific function, an error occurs (the original code does not have this problem) with the error message shown below:

D:\***\***\***\***\***\***>main.exe
TypeError: 'builtin_function_or_method' object does not support the context manager protocol

I then replaced the obfuscated python source file with the obfuscated file in order of precedence, and found the function that had been obfuscated by Pyarmor with an error:

D:\***\***\***\***\***\***>xAries.exe
Traceback (most recent call last):
  File "D:\***\***\***\***\***\***\_internal\app\poseidon\navigator\navigator_function.py", line 460, in _context_menu
    self._single_selection_menu(menu, indexes)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "D:\***\***\***\***\***\***\_internal\app\poseidon\navigator\navigator_function.py", line 880, in _single_selection_menu
    self._subproject_menu(menu, selected_item)
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
  File "D:\***\***\***\***\***\***\_internal\app\poseidon\navigator\navigator_function.py", line 1072, in _subproject_menu
    self.subproject_rtl.rtl_menu(menu, selected_item)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
  File "D:\***\***\***\***\***\***\_internal\app\poseidon\navigator\rtl\rtl.py", line 115, in rtl_menu
    self.design.design_menu(menu, selected_item)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
  File "D:\***\***\***\***\***\***\_internal\app\poseidon\navigator\rtl\desgin\design.py", line 77, in design_menu
    folder_data = get_folder_data(selected_item)
TypeError: 'builtin_function_or_method' object does not support the context manager protocol
def get_catalog_item(selected_item: QStandardItem) -> QStandardItem:
    current_item = selected_item

    while current_item:
        if current_item.data(ItemDataRole.ITEM_TYPE) == NavigatorType.CATALOG:
            return current_item

        current_item = current_item.parent()

    return current_item if current_item else selected_item


def get_folder_data(selected_item: QStandardItem) -> dict:
    """
    Retrieve folder data for the selected item.

    This function collects folder data by traversing the tree structure starting
    from the selected item. It includes the catalog item and its child folders.

    :param selected_item: The selected item in the tree.
    :type selected_item: QStandardItem
    :return: A dictionary containing folder data.
    :rtype: dict
    """
    catalog_item = get_catalog_item(selected_item)
    folder_data = {}
    if catalog_item is None:
        return folder_data

    parent_item = selected_item.parent()
    if parent_item is None:
        return folder_data

    if parent_item != catalog_item:
        folder_data[catalog_item.text()] = catalog_item

    def get_folder_data_recursive(item: QStandardItem):
        """
        Recursively collect folder data.

        This inner function traverses the tree structure to collect folder data
        from the child items of the given item.

        :param item: The current item in the tree.
        :type item: QStandardItem
        """
        for row in range(item.rowCount()):
            child_item = item.child(row)
            if child_item is None:
                continue
            if child_item == parent_item or child_item == selected_item:
                continue
            if child_item.data(ItemDataRole.ITEM_TYPE) == NavigatorType.FOLDER:
                folder_data[child_item.text()] = child_item
                get_folder_data_recursive(child_item)

    get_folder_data_recursive(catalog_item)

    return folder_data
@17Reset 17Reset added the bug label Mar 11, 2025
@17Reset
Copy link
Author

17Reset commented Mar 11, 2025

When I replace the above recursion code with something like this, it will work fine after Pyarmor obfuscation:

def _collect_folder_data_recursive(item, folder_data, parent_item, selected_item):
    for row in range(item.rowCount()):
        child_item = item.child(row)
        if child_item is None or child_item == parent_item or child_item == selected_item:
            continue
        if child_item.data(ItemDataRole.ITEM_TYPE) == NavigatorType.FOLDER:
            folder_data[child_item.text()] = child_item
            _collect_folder_data_recursive(child_item, folder_data, parent_item, selected_item)

def get_folder_data(selected_item: QStandardItem) -> dict:
    catalog_item = get_catalog_item(selected_item)
    folder_data = {}
    if catalog_item is None or (parent_item := selected_item.parent()) is None:
        return folder_data
    if parent_item != catalog_item:
        folder_data[catalog_item.text()] = catalog_item
    _collect_folder_data_recursive(catalog_item, folder_data, parent_item, selected_item)
    return folder_data

@jondy
Copy link
Contributor

jondy commented Mar 11, 2025

Please provide full options to generate the obfuscated scripts, do not pack but only run the obfuscated scripts, and which line is 77 in the snapshot code?

@17Reset
Copy link
Author

17Reset commented Mar 12, 2025

Pyarmor full cmd:

pyarmor cfg data_files=* encoding utf-8
pyarmor gen --recursive --enable-bcc --obf-code 2 --output dist_pyarmor

Line 77 of the report is a call to the function folder_data = get_folder_data(selected_item), and the function in question is the one shown below:

def get_folder_data(selected_item: QStandardItem) -> dict:
    catalog_item = get_catalog_item(selected_item)
    folder_data = {}
    if catalog_item is None:
        return folder_data

    parent_item = selected_item.parent()
    if parent_item is None:
        return folder_data

    if parent_item != catalog_item:
        folder_data[catalog_item.text()] = catalog_item

    def get_folder_data_recursive(item: QStandardItem):
        for row in range(item.rowCount()):
            child_item = item.child(row)
            if child_item is None:
                continue
            if child_item == parent_item or child_item == selected_item:
                continue
            if child_item.data(ItemDataRole.ITEM_TYPE) == NavigatorType.FOLDER:
                folder_data[child_item.text()] = child_item
                get_folder_data_recursive(child_item)

    get_folder_data_recursive(catalog_item)

    return folder_data

@17Reset
Copy link
Author

17Reset commented Mar 12, 2025

The following example minimally reproduces the above problem, which is the error caused by inline functions:

Source Code:

def main():
    a = 1
    b = 2
    def add(x):
        return x + a
    
    c = 3
    num = add(c)
    
    return num
    
    
if __name__ == '__main__':
    print(main())
    
D:\Download>python pyarmor_demo.py
4

D:\Download>pyarmor gen --recursive --enable-bcc --obf-code 2 pyarmor_demo.py
INFO     Python 3.13.1
INFO     Pyarmor 9.0.8 (group), 006040, non-profits
INFO     Platform windows.x86_64
INFO     search inputs ...
INFO     find script pyarmor_demo.py
INFO     find 1 top resources
INFO     start to generate runtime files
INFO     target platforms {'windows.amd64'}
INFO     write dist\pyarmor_runtime_006040\pyarmor_runtime.pyd
INFO     generate runtime files OK
INFO     start to obfuscate scripts
INFO     process resource "pyarmor_demo"
INFO     obfuscating file pyarmor_demo.py
INFO     write dist\pyarmor_demo.py
INFO     obfuscate scripts OK

D:\Download>cd D:\Download\dist

D:\Download\dist>python pyarmor_demo.py
Traceback (most recent call last):
  File "<frozen __main__>", line 3, in <module>
TypeError: 'builtin_function_or_method' object does not support the context manager protocol

@17Reset
Copy link
Author

17Reset commented Mar 12, 2025

@jondy This error occurs if the inline function uses the function's variables.

@jondy
Copy link
Contributor

jondy commented Mar 12, 2025

Reproduced, I'll check it.

@jondy
Copy link
Contributor

jondy commented Mar 13, 2025

This bug will be fixed in next release (v9.1.2)

The pre-release version could be downloaded from

https://pyarmor.dashingsoft.com/downloads/temp/pyarmor-9.1.2.tar.gz

@jondy
Copy link
Contributor

jondy commented Mar 23, 2025

Fixed in v9.1.2

@jondy jondy closed this as completed Mar 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants