Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/fable-library-py/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,6 @@ impl FSharpArray {
/// For Int8/UInt8 arrays, the result is a direct byte representation.
/// For larger types (Int16, Int32, Float64, etc.), each element occupies
/// multiple bytes in native byte order.
///
/// Returns NotImplemented for String and PyObject arrays.
pub fn __bytes__(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
match &self.storage {
// For UInt8/Int8 arrays, we can create bytes directly
Expand Down Expand Up @@ -756,8 +754,15 @@ impl FSharpArray {
});
Ok(bytes.into())
}
// For non-numeric types, return NotImplemented
_ => Ok(py.NotImplemented()),
NativeArray::PyObject(vec) => {
let list = PyList::new(py, vec.iter().map(|item| item.bind(py)))?;
Ok(py.get_type::<PyBytes>().call1((list,))?.unbind())
}
NativeArray::Bool(vec) => {
let bytes =
PyBytes::new(py, &vec.iter().map(|b| u8::from(*b)).collect::<Vec<u8>>());
Ok(bytes.into())
}
}
}

Expand Down
35 changes: 35 additions & 0 deletions src/fable-library-py/tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1646,3 +1646,38 @@ def test_generic_copy_round_trip(elements: list[int]) -> None:
if elements:
copied[0] = "changed"
assert list(arr) == list(elements)


def test_bytes_from_generic_array() -> None:
arr = Array(array_type="Generic", elements=[byte(1), byte(2), byte(255)])
assert bytes(arr) == b"\x01\x02\xff"


def test_bytes_from_empty_generic_array() -> None:
assert bytes(Array(array_type="Generic", elements=[])) == b""


@pytest.mark.parametrize(
"elements, error",
[
(["a"], TypeError),
([None], TypeError),
([1.5], TypeError),
([300], ValueError),
([-1], ValueError),
],
)
def test_bytes_from_generic_array_rejects_non_bytes(elements: list[Any], error: type[Exception]) -> None:
arr = Array(array_type="Generic", elements=elements)
with pytest.raises(error):
bytes(arr)


def test_bytes_from_bool_array() -> None:
arr = Array(array_type="Bool", elements=[True, False, True])
assert bytes(arr) == b"\x01\x00\x01"


def test_bytes_from_bool_array_matches_generic_array() -> None:
elements = [True, False, True]
assert bytes(Array(array_type="Bool", elements=elements)) == bytes(Array(array_type="Generic", elements=elements))
8 changes: 8 additions & 0 deletions tests/Python/TestConvert.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,14 @@ let ``test Convert.ToBase64String works`` () =
Convert.ToBase64String(bytes)
|> equal "AgQGCAoMDhASFA=="

let private genericOfList<'T> (xs: 'T list) : 'T[] = Array.ofList xs

[<Fact>]
let ``test Convert.ToBase64String works on an array built by a generic function`` () =
let bytes = genericOfList [ 2uy; 4uy; 6uy; 8uy; 10uy; 12uy; 14uy; 16uy; 18uy; 20uy ]
Convert.ToBase64String(bytes)
|> equal "AgQGCAoMDhASFA=="

[<Fact>]
let ``test Convert.FromBase64String works`` () =
Convert.FromBase64String("AgQGCAoMDhASFA==")
Expand Down
10 changes: 10 additions & 0 deletions tests/Python/TestGuid.fs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ let ``test Convert byte array built from a list or seq to Guid works`` () =
Guid(Array.ofList bytes).ToString() |> equal "96258006-c4ba-4a7f-80c4-de7f2b2898c5"
Guid(Array.ofSeq (Seq.ofList bytes)).ToString() |> equal "96258006-c4ba-4a7f-80c4-de7f2b2898c5"

let private genericOfList<'T> (xs: 'T list) : 'T[] = Array.ofList xs

let private genericOfSeq<'T> (xs: 'T seq) : 'T[] = Array.ofSeq xs

[<Fact>]
let ``test Convert byte array built by a generic function to Guid works`` () =
let bytes = id [6uy; 128uy; 37uy; 150uy; 186uy; 196uy; 127uy; 74uy; 128uy; 196uy; 222uy; 127uy; 43uy; 40uy; 152uy; 197uy]
Guid(genericOfList bytes).ToString() |> equal "96258006-c4ba-4a7f-80c4-de7f2b2898c5"
Guid(genericOfSeq (Seq.ofList bytes)).ToString() |> equal "96258006-c4ba-4a7f-80c4-de7f2b2898c5"

// [<Fact>]
// let ``Guid.ToString works with formats`` () =
// let g = Guid.Parse("96258006-c4ba-4a7f-80c4-de7f2b2898c5")
Expand Down
Loading