klauer / blark

Beckhoff TwinCAT ST (IEC 61131-3) code parsing in Python using Lark (Earley)
https://klauer.github.io/blark/
GNU General Public License v2.0
42 stars 5 forks source link

Feature/add continue statement to grammar #48

Closed engineerjoe440 closed 1 year ago

engineerjoe440 commented 1 year ago

Related Issues:

This should add support of the CONTINUE statement.

Notes: Seems that the tests are failing, but they appear to have been failing prior to changes, as well. Open to thoughts, there!

klauer commented 1 year ago

Thanks, @engineerjoe440!

Let me take a look into those test failures. (Actually I'll have to get back to you next week, sorry 'bout that...)

engineerjoe440 commented 1 year ago

Don't be sorry! That's how this stuff goes sometime. Let me know if there's anything you find that I can change to help get fixes in place all in one shot. :)

klauer commented 1 year ago

@engineerjoe440 much appreciated 👍

I did some CI fixes in #49 - Python 3.8 failing is a bit of a mystery, but we're going to ignore it for now. Would you mind rebasing this PR?

engineerjoe440 commented 1 year ago

Absolutely! Will do! Thanks @klauer

codecov-commenter commented 1 year ago

Codecov Report

Merging #48 (ea32b88) into master (336831c) will increase coverage by 0.2%. The diff coverage is 100.0%.

Additional details and impacted files [![Impacted file tree graph](https://codecov.io/gh/klauer/blark/pull/48/graphs/tree.svg?width=650&height=150&src=pr&token=QZDTKF30TH&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=K+Lauer)](https://codecov.io/gh/klauer/blark/pull/48?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=K+Lauer) ```diff @@ Coverage Diff @@ ## master #48 +/- ## ======================================== + Coverage 71.7% 72.0% +0.2% ======================================== Files 18 18 Lines 3760 3766 +6 ======================================== + Hits 2698 2713 +15 + Misses 1062 1053 -9 ``` | [Impacted Files](https://codecov.io/gh/klauer/blark/pull/48?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=K+Lauer) | Coverage Δ | | |---|---|---| | [blark/tests/test\_transformer.py](https://codecov.io/gh/klauer/blark/pull/48?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=K+Lauer#diff-YmxhcmsvdGVzdHMvdGVzdF90cmFuc2Zvcm1lci5weQ==) | `100.0% <ø> (ø)` | | | [blark/transform.py](https://codecov.io/gh/klauer/blark/pull/48?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=K+Lauer#diff-YmxhcmsvdHJhbnNmb3JtLnB5) | `98.9% <100.0%> (+<0.1%)` | :arrow_up: | ... and [1 file with indirect coverage changes](https://codecov.io/gh/klauer/blark/pull/48/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=K+Lauer)
engineerjoe440 commented 1 year ago

Well, I can see the same failures when I don't have apischema installed. I do see everything load properly when I run the tests locally (with apischema installed, mind you). So, I wonder if it might be beneficial to have that module installed in the 3.8 test? Maybe that could be broken out as a separate test for its uniqueness?

Thoughts?

Thanks again, @klauer :tada: !!!!

klauer commented 1 year ago

Well, I can see the same failures when I don't have apischema installed.

Hmm, can you paste the failure output? What I see in CI is it failing on import of apischema - which is installed there, by the way, as a dev dependency in requirements-dev.txt

Edit: also, I'm going to push one additional test and then merge this. It looks good to me. PLC programmers may balk at the idea of "CONTINUE" outside of a loop, but I think that check could/should happen at a higher level and not fail during parsing outright, I think.

engineerjoe440 commented 1 year ago

Sorry, I might have made that even more confusing. I was seeing the apischema errors when I didn't have that package installed. Notably, I'm running on Python 3.11, so it's a bit odd.

Errors ``` λ pytest ================================================================================================== test session starts ================================================================================================== platform win32 -- Python 3.11.1, pytest-7.2.0, pluggy-1.0.0 rootdir: C:\Users\joestan\Documents\Python RTAC Projects\blark plugins: anyio-3.6.2, cov-4.0.0, markdown-docs-0.4.1, xdoctest-1.1.0 collected 430 items blark\tests\test_cli.py .F..F..F..F..F..F..F....................F....F....F....F....F....F....F.. [ 16%] blark\tests\test_parsing.py ..........x..............................x [ 26%] blark\tests\test_transformer.py ..............................................................................................................................................................................x... [ 68%] .x...x........................................................................................................x.x...... [ 95%] blark\tests\test_util.py ....x............. [100%] ======================================================================================================= FAILURES ======================================================================================================== ______________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU-json] ______________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/POUs/F_SetStateParams.TcPOU'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError _______________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU-json] _______________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/POUs/global_version.TcPOU'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ______________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st-json] _______________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/and_then_or_else.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ______________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st-json] _______________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/array_of_objects.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError _______________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st-json] ________________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/commas_in_case.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError _____________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st-json] ______________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/fb_w_public_access.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ____________________________________________ test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st-json] ____________________________________________ input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st', kwargs = {'use_json': True} @pytest.mark.parametrize( "kwargs", [ param( dict(), id="defaults" ), param( dict(use_json=True), id="json", ), param( dict(verbose=3, summary=True, debug=True), id="verbose", ), ] ) def test_parse_cli(input_filename: str, kwargs: Dict[str, Any]): > parse_main(input_filename, **kwargs) blark\tests\test_cli.py:43: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/pointer_to_pointer_to.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError __________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU-parse-json] ___________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DAD883410>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/POUs/F_SetStateParams.TcPOU'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ___________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU-parse-json] ____________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DAD7D3A50>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/POUs/global_version.TcPOU'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ___________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st-parse-json] ___________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DAD7D6D10>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/and_then_or_else.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ___________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st-parse-json] ___________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DAD33C910>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/array_of_objects.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ____________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st-parse-json] ____________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DADAAE150>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/commas_in_case.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError __________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st-parse-json] __________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DAD7E8090>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/fb_w_public_access.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ________________________________________ test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st-parse-json] _________________________________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x0000027DAD8A21D0>, input_filename = 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st' args = ['parse', '--json', 'C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st'] @pytest.mark.parametrize( "args", [ param( ["parse", "filename"], id="basic-parse", ), param( ["parse", "-vvvs", "--debug", "filename"], id="parse-verbose", ), param( ["parse", "--json", "filename"], id="parse-json", ), param( ["format", "filename"], id="format-basic", ), param( ["format", "--debug", "filename"], id="format-debug", ), ] ) def test_blark_main(monkeypatch, input_filename: str, args: List[str]): def replace_filename(arg: str) -> str: if arg == "filename": return input_filename return arg args = [replace_filename(arg) for arg in args] monkeypatch.setattr(sys, "argv", ["blark", *args]) try: > blark_main() blark\tests\test_cli.py:123: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ blark\main.py:96: in main func(**kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ filename = WindowsPath('C:/Users/joestan/Documents/Python RTAC Projects/blark/blark/tests/source/pointer_to_pointer_to.st'), verbose = 0, debug = False, interactive = False, summary = False, use_json = True def main( filename: Union[str, pathlib.Path], verbose: int = 0, debug: bool = False, interactive: bool = False, summary: bool = False, use_json: bool = False, ): """ Parse the given source code/project. """ result_by_filename = {} failures = [] print_filenames = sys.stdout if verbose > 0 else None filename = pathlib.Path(filename) if use_json: print_filenames = False if apischema is None: > raise RuntimeError( "Optional dependency apischema is required to output a JSON " "representation of source code." ) E RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. blark\parse.py:308: RuntimeError ================================================================================================ short test summary info ================================================================================================ FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_parse_cli[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\F_SetStateParams.TcPOU-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\POUs\\global_version.TcPOU-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\and_then_or_else.st-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\array_of_objects.st-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\commas_in_case.st-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\fb_w_public_access.st-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. FAILED blark/tests/test_cli.py::test_blark_main[C:\\Users\\joestan\\Documents\\Python RTAC Projects\\blark\\blark\\tests\\source\\pointer_to_pointer_to.st-parse-json] - RuntimeError: Optional dependency apischema is required to output a JSON representation of source code. ====================================================================================== 14 failed, 408 passed, 8 xfailed in 12.95s ======================================================================================= ```
engineerjoe440 commented 1 year ago

Thank you, @klauer!!! This is very exciting, and will free up some of my work on a linter! :heart: :tada:

klauer commented 1 year ago

Your continued contributions are very much appreciated! Glad it has been of use to you. 👍

Ah, I see - the errors are a bit different from what you pasted.

The test suite requires apischema to be run completely, so those errors you pasted above are legitimate. The docs are very likely lacking, but requirements-dev.txt is considered a necessity for running the full test suite.

The weird/unexpected failure is the Python 3.8 job which shows:

```python blark/__init__.py:4: in from .parse import get_parser, parse_project, parse_source_code blark/parse.py:17: in from . import summary blark/summary.py:10: in from . import transform as tf blark/transform.py:22: in import apischema /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/__init__.py:29: in from . import ( # noqa: F401 /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/json_schema/__init__.py:8: in from .schema import definitions_schema, deserialization_schema, serialization_schema /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/json_schema/schema.py:46: in from apischema.json_schema.types import JsonSchema, JsonType, json_schema /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/json_schema/types.py:71: in serializer(Conversion(dict, source=JsonSchema)) /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/conversions/converters.py:165: in serializer resolved = resolve_conversion(serializer) /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/conversions/conversions.py:73: in resolve_conversion source, target = converter_types( /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/conversions/utils.py:35: in converter_types if target is None and is_type(converter): /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/typing.py:250: in is_type return isinstance(tp, type) and not get_args(tp) /opt/hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/apischema/typing.py:54: in get_args res = tp.__args__ E AttributeError: type object 'dict' has no attribute '__args__' ```

So, an on-import failure inside of apischema before anything blark gets run. That makes it extremely likely to be an upstream issue, but it's difficult to confirm without being able to reproduce just yet.