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

Error when parsing strings containing digits and starting or ending with an 'e' #672

Closed
HubertPalo opened this issue Feb 6, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@HubertPalo
Copy link
Contributor

HubertPalo commented Feb 6, 2025

🐛 Bug report

ArgumentParser fails to parse strings that contains digits and a starting or ending 'e'. For example:

  • e5125
  • e852343
  • e96
  • 812743e
  • 7435e
  • 913264e

To reproduce

from jsonargparse import ArgumentParser

parser = ArgumentParser(prog="app", description="Description for my app.")
parser.add_argument("--opt", type=str, default='asdasd', help="Test")
cfg = parser.parse_args(["--opt", "913264e"])
print(type(cfg.opt))

It returns the following error:

usage: app [-h] [--opt OPT]
error: Parser key "opt":
  could not convert string to float: '913264e'

Expected behavior

The code should not throw an exception and parse the value into a string

Environment

  • jsonargparse version: 4.36.0
  • Python version: 3.10.6
  • How jsonargparse was installed: through 'pip install jsonargparse' and 'pip install jsonargparse --upgrade'
  • OS: Ubuntu
@HubertPalo HubertPalo added the bug Something isn't working label Feb 6, 2025
@HubertPalo
Copy link
Contributor Author

First, the logic of the load_basic function:

def load_basic(value):
    value = value.strip()
    if value == "true":
        return True
    if value == "false":
        return False
    if value == "null":
        return None
    if value.isdigit() or (value.startswith("-") and value[1:].isdigit()):
        return int(value)
    if value.replace(".", "", 1).replace("e", "", 1).replace("-", "", 2).isdigit() and ("e" in value or "." in value):
        return float(value)
    return not_loaded

The function considers as a float any string that comply with:

  • After deleting one '.' or one '-' or one 'e', all left characters are digits.
    AND
  • Contains at least one 'e' or at least one '.'

Unfortunately, following that logic results in the strings 'e7217418' and '12314e' being considered floats instead of strings.

To correct this, I propose two simple additional conditions: to check for initial or endings 'e':

def load_basic(value):
    value = value.strip()
    if value == "true":
        return True
    if value == "false":
        return False
    if value == "null":
        return None
    if value.isdigit() or (value.startswith("-") and value[1:].isdigit()):
        return int(value)
    if (
        not value.startswith("e")
        and not value.endswith("e")
        and value.replace(".", "", 1).replace("e", "", 1).replace("-", "", 2).isdigit()
        and ("e" in value or "." in value)
    ):
        return float(value)
    return not_loaded

Also an additional test:

def test_load_value_digits_and_e():
    with parser_context(load_value_mode="yaml"):
        assert "e123" == load_value("e123")
        assert "123e" == load_value("123e")

@mauvilsa
Copy link
Member

mauvilsa commented Feb 7, 2025

Fixed by #673

@mauvilsa mauvilsa closed this as completed Feb 7, 2025
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

No branches or pull requests

2 participants