The "error" says that it is expecting byte
rather than a str
. What you're seeing here isn't really an error, it's the pyright typechecker telling you that the function definition and your input are misaligned. It could be that the function signature is incorrect and it actually can take a string, or it could be that this string works as the functions down the line just happen to work with that string. Another string might not. You can fix this by encoding the string with b"my string"
or "my string".encode("utf-8")
. I may have got the syntax wrong as i'm not able to test it at the moment.
Remember that type hints are just hints, so python will run the code regardless of whether the input matches the signature. If you're coming from a compiled language this can seem a bit strange as you might expect the types to be enforced but python is duck typed so it will try to run the code anyway. If a function said it only needed an int (def my_func(input: int) -> int:
), and you passed in a string, you may not get an error if said function only runs code on the string input that overlaps with the int functionality (I.e. both ints and strings can be muliplied, 2*2
becomes 4 but "4"*2
becomes "4"), but you might see some unexpected behaviour. So you may not notice the error until the code hits a branch that doesn't have overlap. If you'd passed a float in this case that was 2.0 you would get 4.0 out which could work fine as 4 and 4.0 would behave the same in your code (assuming there's no floating point imprecisions) until you try to use it to index into a list, my_list[4.0]
, so the type signature is correct but the value you used just happened to work in that context.
Python strings are Unicode encoded, as opposed to byte encoded (none of the characters you've used use more than one byte, so maybe this would error, or cause unexpected behaviour, if you tried a character that uses more than one byte 🤷, but i'm really just guessing at this point) https://stackoverflow.com/questions/10060411/byte-string-vs-unicode-string-python
We use something similar where I work. Not having a clear seperation between the parts of the name feels a bit noisy and hard to parse, so we use:
test_<function>__<context>[__<result>]
(pytest, Python, looks for functions starting withtest_
).So something like
test_clean_accounts__client_name_missing__fill_from_organisation_name
ortest_open_chest__unlocked_and_has_items__items_collected
.The double underscores make the linter unhappy, so that check is disabled for test names. It's helped guide how people with how they write their tests, shifting towards more BDD type testing, as the article points out as well it's also kept tests smaller and focused, and made our codebases more self documented. No one enjoyed adding docstrings and this seems to have encouraged slightly for TDD style work (we don't necessarily push TDD but there are use cases where it just makes sense, yet developers were avoiding it). It was a small changed that upped the general quality of tests and code, leaning into developer laziness rather than trying to fight against it.
It's also been useful for working with more junior engineers. On established projects they can just read through the tests. On newer projects we might pair code a wireframe of the program, get some test names written down, wrap them with
@pytest.mark.todo
markers, and let them have at it. The todo markers mean they can go more at their own pace without it feeling overwhelming with fails. We also sometimes do this when a bug, enhancement, or feature request comes in, we just create the test with the name then add atodo
(feature
,bug
, ...) so it doesn't break the flow, but is documented, and someone can pick it up later (people weren't always recording these in tickets.. So it's an improvement).