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

Support for match-case statement: AttributeError: 'Unparser' object has no attribute '_Match' #28

Open
bjoernma opened this issue Oct 9, 2023 · 11 comments · Fixed by #29
Assignees
Labels
bug Something isn't working
Milestone

Comments

@bjoernma
Copy link

bjoernma commented Oct 9, 2023

As pyflowchart 0.3.1 used with python 3.11 and astunparse 1.6.3 throws an exception:
Traceback (most recent call last): File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "/usr/lib/python3.10/runpy.py", line 86, in _run_code exec(code, run_globals) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/__main__.py", line 115, in <module> main(args.code_file, args.field, args.inner, args.output, args.no_simplify, args.conds_align) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/__main__.py", line 85, in main flowchart = Flowchart.from_code(code, File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/flowchart.py", line 102, in from_code p = parse(f, simplify=simplify, conds_align=conds_align) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 659, in parse node = ast_node_class(ast_object, **kwargs) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 137, in __init__ self.body_head, self.body_tails = self.parse_func_body(**kwargs) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 158, in parse_func_body p = parse(self.ast_object.body, **kwargs) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 659, in parse node = ast_node_class(ast_object, **kwargs) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 463, in __init__ OperationNode.__init__(self, operation=self.ast_to_source()) File "/home/bjorn/.local/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 33, in ast_to_source return astunparse.unparse(self.ast_object).strip() File "/home/bjorn/.local/lib/python3.10/site-packages/astunparse/__init__.py", line 13, in unparse Unparser(tree, file=v) File "/home/bjorn/.local/lib/python3.10/site-packages/astunparse/unparser.py", line 38, in __init__ self.dispatch(tree) File "/home/bjorn/.local/lib/python3.10/site-packages/astunparse/unparser.py", line 65, in dispatch meth = getattr(self, "_"+tree.__class__.__name__) AttributeError: 'Unparser' object has no attribute '_Match'

I looked into a solution. It now seems that replacing astunparse with the inbuild package ast package (see e.g. simonpercivall/astunparse#56 (comment)) doesnt throw this and works atm.

@cdfmlr
Copy link
Owner

cdfmlr commented Oct 9, 2023

Thanks for reporting. I'm on it!

@cdfmlr cdfmlr self-assigned this Oct 9, 2023
@cdfmlr cdfmlr added the bug Something isn't working label Oct 9, 2023
@cdfmlr cdfmlr added this to the v0.3.2 milestone Oct 9, 2023
@cdfmlr
Copy link
Owner

cdfmlr commented Oct 9, 2023

@bjoernma would you mind to provide some more detailed information about how you triggered the exception. I think I've fixed it (by following the solution you mentioned), but I haven't been able to reproduce the problem to test it. So I am not sure if there are any further bugs that prevent you from using PyFlowchart freely.

@AzureArmageddon
Copy link

AzureArmageddon commented Oct 15, 2023

Able to replicate using python 3.10.11, pyflowchart 0.3.1, and astunparse 1.6.3 on a new Repl on Replit. Happened after adding a match-case block to my code. Traceback generated follows:

Traceback (most recent call last):
  File "/nix/store/xf54733x4chbawkh1qvy9i1i4mlscy1c-python3-3.10.11/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/nix/store/xf54733x4chbawkh1qvy9i1i4mlscy1c-python3-3.10.11/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/pyflowchart/__main__.py", line 115, in <module>
    main(args.code_file, args.field, args.inner, args.output, args.no_simplify, args.conds_align)
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/pyflowchart/__main__.py", line 85, in main
    flowchart = Flowchart.from_code(code,
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/pyflowchart/flowchart.py", line 102, in from_code
    p = parse(f, simplify=simplify, conds_align=conds_align)
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 659, in parse
    node = ast_node_class(ast_object, **kwargs)
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 463, in __init__
    OperationNode.__init__(self, operation=self.ast_to_source())
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/pyflowchart/ast_node.py", line 33, in ast_to_source
    return astunparse.unparse(self.ast_object).strip()
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/astunparse/__init__.py", line 13, in unparse
    Unparser(tree, file=v)
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/astunparse/unparser.py", line 38, in __init__
    self.dispatch(tree)
  File "/home/runner/Hollow-Knight-Charm-Build-Randomiser/.pythonlibs/lib/python3.10/site-packages/astunparse/unparser.py", line 65, in dispatch
    meth = getattr(self, "_"+tree.__class__.__name__)
AttributeError: 'Unparser' object has no attribute '_Match'

@cdfmlr
Copy link
Owner

cdfmlr commented Oct 16, 2023

Thanks, @AzureArmageddon. There seem to be more jobs to do aside the compatibility of astunparse package to support the new match statement. I am considering literal convert the match-case back into the if-else statement OR a new kind of AstNode would be required to support it.

Since a multi-branch condition node is not supported by flowchart.js (See #13 for details), even though we have introduced a conds-align feature which may be useful, supporting for match could be really hard. 😭

@cdfmlr
Copy link
Owner

cdfmlr commented Oct 16, 2023

As the match-case statement has been widely adopted today, I recommend that those encountering this problem consider a quick fix:

  • Make a copy of the code you want to create a flowchart for.
  • Rewrite your match-case code into an if-elif-else block.
  • Try running pyflowchart on the modified version.
  • The conds-align feature can help improve the readability of the generated flowchart.

@cdfmlr cdfmlr changed the title Exception in astunparse/unparser.py when using pyflowchart Support for match-case statement: AttributeError: 'Unparser' object has no attribute '_Match' Oct 16, 2023
@cdfmlr cdfmlr modified the milestones: v0.3.2, v0.4.0 Oct 23, 2023
@cdfmlr
Copy link
Owner

cdfmlr commented Oct 25, 2023

Progress:

With my latest commit 12fcc03, PyFlowchart is now able to read & parse the match sentences (with Python 3.10+).

As mentioned before,

Since a multi-branch condition node is not supported by flowchart.js (See #13 for details), even though we have introduced a conds-align feature which may be useful, supporting for match could be really hard. 😭

I have no choice but to make each case in the match a condition node (looks like a if without else) and connect them one by one.

For example:

def test_match(a, b, c):
    if a > 0:
        match b:
            case 1:
                print('ab')
            case 2:
                print('abc')
                c = 1 + b + a
            case 3:
                print('nested match')
                match c:
                    case["a"]:
                        print('a')
                    case["a", *other_items]:
                        print('a and others')
                    case[*first_items, "d"] | (*first_items, "d"):
                        print('d is the last item')
            case _:
                print('abcd')
        end_of_match()
    else:
        alez()
    end_of_ifs()

Excuse me, this code as a example is a bit verbose (but it covers common use cases, I assume). So the generated flowchart is "a bit" long:

match-case

It's definitely not ideal. I have tried to make it more readable (by reusing the conds-align and connection direction features), but it backfired on me:

failed to align match-cases

No one like this bad-routed maze. So I decide to remove all this programic "beautify" features. Just leave it "a bit long".

@cdfmlr cdfmlr linked a pull request Oct 25, 2023 that will close this issue
@AzureArmageddon
Copy link

AzureArmageddon commented Oct 26, 2023

So, in short, it would appear that astunparse's inability to parse match-case has been overcome, but flowchart.js is unable to handle multi-branching conditionals in the exact way we want so this temporary implementation must be used. Not ideal, but that means there is officially a new feature working! 🎉

Perhaps making an issue on flowchart.js would be appropriate. I don't suppose we can close this issue until flowchart.js makes changes (or mayhaps if an attractive alternative comes along as a viable replacement)?

@cdfmlr
Copy link
Owner

cdfmlr commented Oct 28, 2023

Perhaps making an issue on flowchart.js would be appropriate.

There's an existing one that has persisted for years: adrai/flowchart.js#60.

or mayhaps if an attractive alternative comes along as a viable replacement

This is exactly what I am trying to.

I am considering mermaid.js as a potential alternative. Lately, I've favored mermaid.js over flowchart.js. However, it's not a straightforward shift due to PyFlowchart's initial design being closely tied to flowchart.js.

Adopting mermaid.js will undoubtedly cause significant disruptions to our stable compatibility, which I take pride in since its initial release in 2020 for Python 3.6/3.7.

So I'm still seeking a way to make a refactor that not destroy the current flowchart.js features, but allow us to add a support for mermaid.js. (Maybe the silver bullet here is the visitor pattern?)

@cdfmlr cdfmlr reopened this Oct 30, 2023
@cdfmlr
Copy link
Owner

cdfmlr commented Nov 3, 2023

Anyway, I'm releasing a preview (not well tested) version v0.4.0-alpha.4 that contains current progress for match-case support. pip install pyflowchart==0.4.0a4 to use it.

Keep this issue open for seeking further enhancements.

@kaasima10
Copy link

As pyflowchart 0.3.1 used with python 3.11 and astunparse 1.6.3 throws an exception:

Traceback (most recent call last):
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\flowchart.py", line 12, in
fc = pfc.parse(code)
^^^^^^^^^^^^^^^
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\new_env\Lib\site-packages\pyflowchart\ast_node.py", line 659, in parse
node = ast_node_class(ast_object, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\new_env\Lib\site-packages\pyflowchart\ast_node.py", line 463, in init
OperationNode.init(self, operation=self.ast_to_source())
^^^^^^^^^^^^^^^^^^^^
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\new_env\Lib\site-packages\pyflowchart\ast_node.py", line 33, in ast_to_source
return astunparse.unparse(self.ast_object).strip()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\new_env\Lib\site-packages\astunparse_init_.py", line 13, in unparse
Unparser(tree, file=v)
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\new_env\Lib\site-packages\astunparse\unparser.py", line 38, in init
self.dispatch(tree)
File "C:\Downloads\sc-navigator-model-generation-cp\APO Input Workflow\src\new_env\Lib\site-packages\astunparse\unparser.py", line 65, in dispatch
meth = getattr(self, "_"+tree.class.name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Unparser' object has no attribute '_str'. Did you mean: '_Str'?

How do I resolve this issue?

@cdfmlr
Copy link
Owner

cdfmlr commented May 9, 2024

@kaasima10, it appears that your comment may not be related to this thread. Your issue will be traced in #32.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants