valid_ip4 behaves differently for None
kajinamit opened this issue · comments
Before 1.0.0 release, both valid_ipv4 and vlaid_ipv6 return False in case None is passed.
>>> netaddr.valid_ipv4('192.168.0.1')
True
>>> netaddr.valid_ipv4(None)
False
>>> netaddr.valid_ipv6(None)
False
However this behavior has been changed in 1.0.0 and now valid_ipv4 raises raises AttributeError.
valid_ipv6 still returns False so the change is inconsistently made.
>>> netaddr.valid_ipv4('192.168.0.1')
True
>>> netaddr.valid_ipv4(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/tkajinam/venv/lib/python3.11/site-packages/netaddr/strategy/ipv4.py", line 99, in valid_str
str_to_int(addr, flags)
File "/home/tkajinam/venv/lib/python3.11/site-packages/netaddr/strategy/ipv4.py", line 119, in str_to_int
elif pton_mode and any(len(p) > 1 and p.startswith('0') for p in addr.split('.')):
^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'split'
>>>
>>> netaddr.valid_ipv6(None)
False
Hey @kajinamit, thank you for the report.
valid_ipv4
and valid_ipv6
have been defined for and expected to be called with strings:
:param addr: An IPv4 address in presentation (string) format.
:param addr: An IPv6 address in presentation (string) format.
Giving them anything other than a string should be considered an error – in the code that calls them – and there's no guarantee what happens when that happens.
I don't consider this a bug – if anything I'm rather unhappy with valid_ipv6(None)
returning False
.
Thanks @jstasiak for the thoughts.
I understand that interface documented, but as you know python does not enforce types and returning False for unexpected types could make sense to me. If this is not a desired behavior then I'm wondering if it should raise an explicit exception like TypeError, instead of raising the internal exception.
I understand that interface documented, but as you know python does not enforce types (...)
That depends on what do we mean by "enforce types".
Runtime enforcement? It very much does in many cases. One can't add a str
to an int
(not easily), one can't index a list with another list etc. 99 cases out of 100 as a user of an API I want an exception instead of a result if I provide a bad type somewhere.
Lint-time enforcement (static type checking)? I'd argue using Mypy or similar is table stakes these days. The library doesn't publish type definitions yet but that's planned.
If this is not a desired behavior then I'm wondering if it should raise an explicit exception like TypeError, instead of raising the internal exception.
Maybe, although here's why I'm against it:
- An explicit exception is likely to encourage the client code to keep providing bad types and catch that exception, while the client code shouldn't be providing bad types in the first place.
- I plan to add static types to the library which can eliminate this issue before the code can even be executed (as long as the client code uses Mypy or similar).
I'm not strongly opposed to raising TypeError
for the time being at least, if you create a PR I'll merge it.
What I meant by type enforcement is runtime one at interface level. It may be reasonable to get exception in case an unacceptable type is given, but if an exception is directly raised from an internal logic, it requires some effort to dig into the logic and find out at which point, at which layer they made mistake.
In the mean time, until type annotation is added, #371 may help people aware of the situation.
That's fair, we're on the same page.