Skip to content

Drop bytes input in 2.0; require str #245

Description

@derek73

Summary

2.0 should stop accepting bytes anywhere and require str, making decoding the caller's job. The bytes tolerance is a Python 2 legacy, and — verified below — it is already inconsistent to the point of being half-broken: bytes input currently gets a different behavior depending on which door it walks through.

Current state (verified)

Entry point Behavior with bytes
HumanName(b'John Smith') works — decoded with the encoding kwarg; emits DeprecationWarning since 1.3.0
hn.first = b'Jane' / HumanName(first=b'Jane') crashes_set_list explicitly accepts bytes, then parse_pieces fails deep inside with the confusing inverse error TypeError: a bytes-like object is required, not 'str' (bytes.split(' '))
SetManager.add(b'esq') works — decoded, but see the stdin sniffing below; emits DeprecationWarning since 1.3.0
SetManager(b'esq') / SetManager([b'esq']) already rejected loudly with a decode hint (1.3.0: #238, PR #240)

So the "feature" is: two paths that decode, one that crashes confusingly despite an isinstance check that promises support, and one that's already banned. Nobody can be relying on the full surface, because part of it doesn't function.

Additional defect: environment-dependent decoding

SetManager.add_with_encoding resolves the encoding as encoding or sys.stdin.encoding or DEFAULT_ENCODING. The encoding of the process's stdin has no relationship to an arbitrary bytes argument, so the same call can decode differently depending on how the process was launched (terminal vs. pipe vs. embedded with sys.stdin = None). Library behavior should not vary with the runtime environment.

What's removed in 2.0

  • full_name: str | bytes and original: str | bytes become str
  • The encoding constructor kwarg and self.encoding attribute
  • The bytes branch in _set_list and the bytes tolerance in parse_pieces (accepting what later crashes)
  • add_with_encoding()add() becomes str-only, raising the same decode-hint TypeError the constructor already raises; the stdin sniffing goes with it

Migration

One line at the boundary: HumanName(raw.decode('utf-8')) — the caller knows the real encoding; the library never did. Everything else is the same call with str.

Bridge

Metadata

Metadata

Assignees

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions