◐ Shell
clean mode source ↗

Py new by youknowone · Pull Request #6402 · RustPython/RustPython

🧩 Analysis chain

🏁 Script executed:

# Find the PyBytesInner::try_from_borrowed_object implementation
rg -A 20 "fn try_from_borrowed_object" crates/vm/src/builtins/bytes.rs

Repository: RustPython/RustPython

Length of output: 238


🏁 Script executed:

# Search for __bytes__ related tests or comments
rg -B 3 -A 3 "__bytes__" crates/vm/src/builtins/bytes.rs

Repository: RustPython/RustPython

Length of output: 856


🏁 Script executed:

# Check if there are any tests for bytes constructor with __bytes__
fd -e rs -x rg -l "__bytes__" {} \; | head -20

Repository: RustPython/RustPython

Length of output: 222


🏁 Script executed:

# Look at the downcast usage pattern in this file
rg "downcast" crates/vm/src/builtins/bytes.rs

Repository: RustPython/RustPython

Length of output: 794


🏁 Script executed:

# Find PyBytesInner definition and try_from_borrowed_object impl
rg -B 5 -A 20 "impl.*PyBytesInner" crates/vm/src/builtins/bytes.rs | head -80

Repository: RustPython/RustPython

Length of output: 527


🏁 Script executed:

# Search for PyBytesInner enum/struct definition
rg "^(pub )?struct PyBytesInner|^(pub )?enum PyBytesInner" crates/vm/src/builtins/bytes.rs

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Find where PyBytesInner::try_from_borrowed_object is actually implemented
ast-grep --pattern 'impl PyBytesInner {
  $$$
  fn try_from_borrowed_object($$$) {
    $$$
  }
  $$$
}'

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Look for the actual implementation - search more broadly
rg "fn try_from_borrowed_object" crates/vm/src/builtins/bytes.rs -B 2 -A 30 | head -100

Repository: RustPython/RustPython

Length of output: 288


🏁 Script executed:

# Look at the beginning/middle of bytes.rs for PyBytesInner impl
head -300 crates/vm/src/builtins/bytes.rs | tail -200

Repository: RustPython/RustPython

Length of output: 5642


🏁 Script executed:

# Search for PyBytesInner impl with try_from_borrowed_object more carefully
rg -B 3 "PyBytesInner::try_from_borrowed_object" crates/vm/src/builtins/bytes.rs

Repository: RustPython/RustPython

Length of output: 812


🏁 Script executed:

# Look at the entire impl block for PyBytesInner
sed -n '/^impl PyBytesInner/,/^impl /p' crates/vm/src/builtins/bytes.rs | head -100

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search across entire vm/src for PyBytesInner::try_from_borrowed_object implementation
rg -B 2 -A 20 "impl.*PyBytesInner.*\{" crates/vm/src/builtins/bytes.rs | grep -A 25 "try_from_borrowed_object"

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# PyBytesInner might be defined as a type alias - search for its definition
rg "type PyBytesInner|struct PyBytesInner|enum PyBytesInner" crates/vm/src/

Repository: RustPython/RustPython

Length of output: 119


🏁 Script executed:

# Search in function/buffer.rs since learnings mention it
rg -B 2 -A 25 "try_from_borrowed_object" crates/vm/src/function/buffer.rs | head -80

Repository: RustPython/RustPython

Length of output: 2557


🏁 Script executed:

# Look at PyBytesInner implementation in bytes_inner.rs
rg -B 2 -A 25 "fn try_from_borrowed_object" crates/vm/src/bytes_inner.rs

Repository: RustPython/RustPython

Length of output: 881


🏁 Script executed:

# Get context around PyBytesInner impl
rg -B 5 -A 30 "impl PyBytesInner" crates/vm/src/bytes_inner.rs | head -100

Repository: RustPython/RustPython

Length of output: 1354


🏁 Script executed:

# Find bytes_from_object function
rg -B 3 -A 40 "fn bytes_from_object" crates/vm/src/bytes_inner.rs

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search entire codebase for bytes_from_object
rg -B 3 -A 40 "fn bytes_from_object"

Repository: RustPython/RustPython

Length of output: 1345


🏁 Script executed:

# Check if it's imported in bytes_inner.rs
rg "bytes_from_object" crates/vm/src/bytes_inner.rs

Repository: RustPython/RustPython

Length of output: 201


🌐 Web query:

CPython bytes constructor __bytes__ return type error message TypeError

💡 Result:

When you call bytes(x), CPython will call x.bytes() (if present) and that method must return a bytes object. If it returns some other type, CPython raises a TypeError such as:

  • "TypeError: bytes returned non-bytes (type X)" (e.g. X == int or str). [1][2]

Fix: make bytes return a bytes object (e.g. return b"..." or return some_str.encode('utf-8')). [3]

Sources:

  • object.bytes doc / pydoc requirement that bytes should return bytes. [1]
  • Python tracker / example error message showing "bytes returned non-bytes (type ...)". [2]
  • Explanation and example usage showing the TypeError and correct return type. [3]

🏁 Script executed:

# Search for tests of __bytes__ returning non-bytes
rg -B 5 -A 10 "__bytes__.*non" crates/

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Look for __bytes__ error tests
fd -e py -x rg -l "__bytes__" {} \; | xargs rg -l "TypeError" | head -5

Repository: RustPython/RustPython

Length of output: 731


🏁 Script executed:

# Check the test file for __bytes__ tests
cat extra_tests/snippets/builtin_bytes.py

Repository: RustPython/RustPython

Length of output: 20952


🏁 Script executed:

# Look at lines 120-137 more carefully with context
sed -n '115,145p' crates/vm/src/builtins/bytes.rs

Repository: RustPython/RustPython

Length of output: 1364


🏁 Script executed:

# Check if there's specific __bytes__ error validation
rg -B 5 -A 5 "returned non-bytes" crates/

Repository: RustPython/RustPython

Length of output: 47


The downcast usage on line 129 is correct; consider adding a specific error for __bytes__ returning non-bytes.

Line 129 correctly uses downcast::<PyBytes>() (which accepts subclasses) rather than downcast_exact. This matches CPython semantics: bytes() returns the __bytes__ result directly if it's any bytes instance, including subclasses.

However, when __bytes__ returns a non-bytes type, the current code delegates to PyBytesInner::try_from_borrowed_object, which raises a generic error: "can assign only bytes, buffers, or iterables of ints in range(0, 256)". CPython raises a more specific error: "TypeError: bytes returned non-bytes (type X)". Consider adding explicit validation to match CPython's error message.