Skip to content

Fix UnboundLocalError in newick read_props when a required value is missing (#799) - #815

Open
youdie006 wants to merge 1 commit into
etetoolkit:ete4from
youdie006:fix/799-newick-unboundlocal-p1str
Open

Fix UnboundLocalError in newick read_props when a required value is missing (#799)#815
youdie006 wants to merge 1 commit into
etetoolkit:ete4from
youdie006:fix/799-newick-unboundlocal-p1str

Conversation

@youdie006

Copy link
Copy Markdown

Fixes #799.

Problem

import ete4
ete4.Tree("(A);", parser=3)

crashes with:

UnboundLocalError: local variable 'p1_str' referenced before assignment

in ete4.parser.newick.read_props, on ete4 4.4.0 and current ete4 HEAD.

Root cause

In read_props (ete4/parser/newick.pyx), the second try block only binds p1_str inside its if branch (when a :-separated value is present). When a strict parser requires that value but it is absent, the elif check_req and p1_req branch raises AssertionError('missing required value') while p1_str is still unbound. The except handler then references p1_str (raise NewickError('parsing %r: %s' % (p1_str, e))), so instead of the intended NewickError the caller gets an UnboundLocalError. This fires for every strict parser with a required second field (parsers 2, 3, 5, 6, 7) when a required dist/support value is missing.

Fix

Initialize p1_str = '' before the try, mirroring how p0_str is always defined earlier in the same function. The error message now reads sensibly: parsing '': missing required value.

This is deliberately narrow: it does not make the invalid input parse. parser=3 still correctly rejects (A); (as @dengzq1234 notes in the issue) -- the change only ensures the parser raises the intended, catchable NewickError described in its documented error contract instead of crashing with an UnboundLocalError, which is exactly the reporter's open complaint ("that doesn't return an error, it just blows up").

Test

Added test_newick_missing_required_value to tests/test_tree.py, mirroring the existing newick error-test style, asserting Tree('(A);', parser=3) raises NewickError. Verified red-green against the rebuilt Cython extension: before the fix the test fails with UnboundLocalError; after it passes. Full tests/test_tree.py and adjacent newick-parsing modules pass with no regressions.

Thanks to @terrycojones for the clear report.


This change was prepared with AI assistance and reviewed by me before submission.

…issing

In read_props (ete4/parser/newick.pyx), the second try block only binds p1_str
inside its if branch (when a :-separated value is present). When a strict parser
requires that value but it is absent, the elif check_req and p1_req branch raises
AssertionError('missing required value') while p1_str is still unbound. The
except handler then references p1_str, so instead of the intended NewickError the
caller gets an UnboundLocalError. This fires for every strict parser with a
required second field (parsers 2, 3, 5, 6, 7).

Initialize p1_str = '' before the try, mirroring how p0_str is always defined
earlier in the same function. Parsing behavior is unchanged - parser=3 still
rejects (A); - only the exception type on the required-value-missing path
changes, so the parser raises the intended, catchable NewickError instead of
crashing.

Fixes etetoolkit#799.
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.

ete4 Newick parser read_props: local variable 'p1_str' referenced before assignment

1 participant