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

IfThenElse inside Select using context not working as intended #1038

Open
guilloulouis opened this issue Jul 28, 2023 · 5 comments
Open

IfThenElse inside Select using context not working as intended #1038

guilloulouis opened this issue Jul 28, 2023 · 5 comments

Comments

@guilloulouis
Copy link

Hello, I looked for a bit but was unable to find anything related to this.
I have this code snippet :

from construct import *

b1 = IfThenElse(lambda ctx: ctx._params.get('ctx') == 1, Int8ul, Int16ul)
a = Struct(
    "1" / Int8ul,
    "2" / Select(b1, Bit)
)
context = {"ctx": 1}

b = a.build({"1": 1, "2": 2}, **context)
print(len(b))  # Output: 3

I would expect to have the length of b to be 2 as my ctx provided is 1 but not it goes to the else part of the IfThenElse statement.
The behavior is correct when I remove the Select.

@arekbulski
Copy link
Member

Not sure why it is so but you cannot use Bit class outside of Bitwise context.

@guilloulouis
Copy link
Author

I added the Bit to make sure that the subcon would trigger an exception, removing it still shows the issue :

from construct import *

a = Struct(
    "1" / Int8ul,
    "2" / Select(IfThenElse(lambda ctx: ctx._params.get('ctx') == 1, Int8ul, Int16ul))
)
context = {"ctx": 1}

b = a.build({"1": 1, "2": 2}, **context)
print(len(b))  # Output: 3

@arekbulski
Copy link
Member

I cannot for the love of god find what is wrong with it. I added following test case. I also managed to workaround the issue by just using different construction:

@xfail(reason="unknown problem with Select")
def test_select_issue_1038():
    s = Struct(
        "value" / Select(IfThenElse(this._params.ctx == 1, Byte, Short)),
    )
    assert s.build(dict(value=9), ctx=1) == b"\x09"

def test_select_issue_1038_fixed():
    s = Struct(
        "value" / Select(If(this._.ctx == 1, Byte), If(this._.ctx == 2, Short)),
    )
    assert s.build(dict(value=9), ctx=1) == b"\x09"

@franzhaas
Copy link

franzhaas commented Jan 28, 2024

I looked at it, and using the compile feature yielded the same issue. This is expected as the compiled code just calls the uncompiled feature.

I added compilation feature.: https://github.com/franzhaas/construct and with that it works.

The changes are quite significant (among other things you cant use "1" as a name for a field anymore), and currently I have no idea why the testsuite doesn't run at all on github actions... but just for this bug... it looks promising.

from construct import *

a = Struct(
    "a" / Int8ul,
    "b" / Select(IfThenElse(lambda ctx: ctx._params.get('ctx') == 1, Int8ul, Int16ul))
)
context = {"ctx": 1}
s = a.compile()
b = s.build({"a": 1, "b": 2}, **context)
print(len(b))  # Output: 2
context = {"ctx": 0}
s = a.compile()
b = s.build({"a": 1, "b": 2}, **context)
print(len(b))  # Output: 3

Update.:

  • tests did not run due to pytest 8.0.0 update
  • one unit test is failing, repr/str mixup probably...

@franzhaas
Copy link

while my aproach changed a lot, the statements here remain valid...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants