Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codegen/IDL 7: handwritten Python tests and extensions for Points2D #2410

Merged
merged 68 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
6b18956
more build tools
teh-cmc Jun 11, 2023
1dd116a
self-review
teh-cmc Jun 11, 2023
cc3e464
addressing PR comments
teh-cmc Jun 13, 2023
4424160
introduce re_types_builder
teh-cmc Jun 11, 2023
d02415a
generate reflection code
teh-cmc Jun 11, 2023
d3feee9
unindent 0.1 everywhere
teh-cmc Jun 11, 2023
3064e4c
self-review
teh-cmc Jun 11, 2023
241a667
adhering to py38+ style guide
teh-cmc Jun 12, 2023
fb7f248
vscode flatbuffer things. Fix comment typo
Wumpf Jun 12, 2023
386a62e
turn the inner from_similar into _from_similar to appease linters
teh-cmc Jun 13, 2023
f7f97c9
generate __all__ everywhere to make python tools behave
teh-cmc Jun 13, 2023
2ad0695
make sure __all__ manifests are lexically sorted
teh-cmc Jun 13, 2023
d4bf7c5
adressing PR comments
teh-cmc Jun 14, 2023
8138d62
introduce re_types
teh-cmc Jun 11, 2023
22f6677
self-review
teh-cmc Jun 11, 2023
70220db
python shall output to rerun_py/rerun_sdk/rerun2
teh-cmc Jun 12, 2023
e23c608
addressing PR comments
teh-cmc Jun 14, 2023
75251a7
Rerun attributes' definitions
teh-cmc Jun 11, 2023
f394106
Rerun datatypes' definitions
teh-cmc Jun 11, 2023
8634406
Rerun components' definitions
teh-cmc Jun 11, 2023
1f269c6
Rerun archetypes' definitions
teh-cmc Jun 11, 2023
ce2e4a2
fixing typo in re_types_builder doc
teh-cmc Jun 11, 2023
cf684ce
self-review
teh-cmc Jun 11, 2023
c5e53b0
fix DrawOrder missing PartialEq & PartialOrd
teh-cmc Jun 12, 2023
41728fe
addressing PR comments
teh-cmc Jun 14, 2023
bc35933
fixing typo in re_types_builder doc
teh-cmc Jun 11, 2023
c1447b7
autogenerated python code
teh-cmc Jun 11, 2023
019aa55
freshly autogenerated python code for new py38+ style guide
teh-cmc Jun 12, 2023
8361e0a
python shall go into rerun_py/rerun_sdk/rerun2
teh-cmc Jun 12, 2023
a816bdf
setting up pyproject and runtime redirections apropriately
teh-cmc Jun 12, 2023
18ee660
regen after rebase
teh-cmc Jun 13, 2023
d9d2363
regen post rebase
teh-cmc Jun 13, 2023
6c4f1cb
addressing PR comments
teh-cmc Jun 14, 2023
28b9354
force regen this so the PR train makes sense
teh-cmc Jun 14, 2023
ed59c9a
fixed wrong indent in python codegen
teh-cmc Jun 14, 2023
a857211
left a dbg didnt i
teh-cmc Jun 14, 2023
48df2d5
autogenerated rust code
teh-cmc Jun 12, 2023
a440e4e
{Datatype,Component,Archetype}Name
teh-cmc Jun 14, 2023
72e4ce9
regen post rebase
teh-cmc Jun 14, 2023
c767df7
regen hash post rebase
teh-cmc Jun 14, 2023
5aa37ae
fixing typo in re_types_builder doc
teh-cmc Jun 11, 2023
6fbe9f9
autogenerated rust code
teh-cmc Jun 12, 2023
969a65f
regen post rebase
teh-cmc Jun 13, 2023
b967a1b
add datatypes.Vec2D extensions
teh-cmc Jun 13, 2023
e1aab5d
tests and extensions for components.Point2D
teh-cmc Jun 13, 2023
1bb25df
tests and extensions for components.Radius
teh-cmc Jun 13, 2023
02201ae
pytest -vv so we actually get diffs
teh-cmc Jun 13, 2023
9a3853b
tests and extensions for components.Label
teh-cmc Jun 13, 2023
8c281e0
tests and extensions for components.DrawOrder
teh-cmc Jun 13, 2023
9ec1edf
tests and extensions for components.ClassId
teh-cmc Jun 13, 2023
872cfe4
tests and extensions for components.KeypointId
teh-cmc Jun 13, 2023
2fa5283
tests and extensions for components.InstanceKey
teh-cmc Jun 13, 2023
d156759
switch to a zip-longest rather than a product so python doesnt die on us
teh-cmc Jun 13, 2023
2fd016d
tests and extensions for components.Color
teh-cmc Jun 13, 2023
246fb8b
back to prod imports
teh-cmc Jun 13, 2023
497b368
fmt
teh-cmc Jun 13, 2023
df4eb93
ignore weird inheritance lint -- whatever
teh-cmc Jun 13, 2023
cc4f910
types are types, but type aliases are Types with a T
teh-cmc Jun 13, 2023
e3d5be3
regen post rebase
teh-cmc Jun 14, 2023
14aa58b
addressing PR comments
teh-cmc Jun 14, 2023
0bada80
regen hash post rebase
teh-cmc Jun 14, 2023
7bdcbc7
fighting mypy, round #2345235923523099834
teh-cmc Jun 14, 2023
39951aa
oh for the love of god do whatever you want but stop complaining ffs
teh-cmc Jun 14, 2023
e676518
fighting mypy, round #2345235923523099835
teh-cmc Jun 14, 2023
231a146
make sure black and ruff use the right config no matter what
teh-cmc Jun 14, 2023
f758038
fighting mypy, round #2345235923523099836
teh-cmc Jun 14, 2023
d0524b6
fighting mypy, round #2345235923523099837
teh-cmc Jun 14, 2023
6529880
broke git
teh-cmc Jun 14, 2023
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
25 changes: 23 additions & 2 deletions crates/re_types/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Generates Rust & Python code from flatbuffers definitions.

use std::path::PathBuf;

use xshell::{cmd, Shell};

use re_build_tools::{
Expand Down Expand Up @@ -84,6 +86,15 @@ fn main() {
"./definitions/rerun/archetypes.fbs",
);

let pyproject_path = PathBuf::from(PYTHON_OUTPUT_DIR_PATH)
.parent()
.unwrap()
.parent()
.unwrap()
.join("pyproject.toml")
.to_string_lossy()
.to_string();

// NOTE: This requires both `black` and `ruff` to be in $PATH, but only for contributors,
// not end users.
// Even for contributors, `black` and `ruff` won't be needed unless they edit some of the
Expand All @@ -96,15 +107,25 @@ fn main() {
// the build.
//
// The CI will catch the unformatted files at PR time and complain appropriately anyhow.
cmd!(sh, "black {PYTHON_OUTPUT_DIR_PATH}").run().ok();
cmd!(
sh,
"black --config {pyproject_path} {PYTHON_OUTPUT_DIR_PATH}"
)
.run()
.ok();

// NOTE: We're purposefully ignoring the error here.
//
// If the user doesn't have `ruff` in their $PATH, there's still no good reason to fail
// the build.
//
// The CI will catch the unformatted files at PR time and complain appropriately anyhow.
cmd!(sh, "ruff --fix {PYTHON_OUTPUT_DIR_PATH}").run().ok();
cmd!(
sh,
"ruff --config {pyproject_path} --fix {PYTHON_OUTPUT_DIR_PATH}"
)
.run()
.ok();

write_versioning_hash(SOURCE_HASH_PATH, new_hash);
}
4 changes: 2 additions & 2 deletions crates/re_types/definitions/rerun/components/class_id.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ namespace rerun.components;
/// \rs Used to look up a `crate::components::ClassDescription` within the `crate::components::AnnotationContext`.
struct ClassId (
"attr.arrow.transparent",
"attr.python.aliases": "float",
"attr.python.array_aliases": "npt.NDArray[np.uint8], npt.NDArray[np.uint16], npt.NDArray[np.uint32]",
"attr.python.aliases": "int",
"attr.python.array_aliases": "npt.NDArray[np.uint8], npt.NDArray[np.uint16], npt.NDArray[np.uint32], npt.NDArray[np.uint64]",
"attr.rust.derive": "Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash",
"attr.rust.tuple_struct",
order: 100
Expand Down
8 changes: 6 additions & 2 deletions crates/re_types/definitions/rerun/components/color.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ namespace rerun.components;
// ---

/// An RGBA color tuple with unmultiplied/separate alpha, in sRGB gamma space with linear alpha.
///
/// \py Float colors are assumed to be in 0-1 gamma sRGB space.
/// \py All other colors are assumed to be in 0-255 gamma sRGB space.
/// \py If there is an alpha, we assume it is in linear space, and separate (NOT pre-multiplied).
struct Color (
"attr.arrow.transparent",
"attr.python.aliases": "Sequence[int], Sequence[float], npt.NDArray[np.uint8], npt.NDArray[np.float32], npt.NDArray[np.float64]",
"attr.python.array_aliases": "Sequence[int], Sequence[float], npt.NDArray[np.uint8], npt.NDArray[np.float32], npt.NDArray[np.float64]",
"attr.python.aliases": "int, npt.NDArray[np.uint8], npt.NDArray[np.uint32], npt.NDArray[np.float32], npt.NDArray[np.float64]",
"attr.python.array_aliases": "Sequence[int], npt.NDArray[np.uint8], npt.NDArray[np.uint32], npt.NDArray[np.float32], npt.NDArray[np.float64]",
"attr.rust.derive": "Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, bytemuck::Pod, bytemuck::Zeroable",
"attr.rust.repr": "transparent",
"attr.rust.tuple_struct",
Expand Down
2 changes: 1 addition & 1 deletion crates/re_types/source_hash.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This is a sha256 hash for all direct and indirect dependencies of this crate's build script.
# It can be safely removed at anytime to force the build script to run again.
# Check out build.rs to see how it's computed.
2d611d0d686a6314da94b1797472e7690413465d16a611aae3560a847668d53d
184f79acfe7c0608f9ec2bb5f6a6783dc2270f5cae0edb147ad08ad4ee89c825
12 changes: 6 additions & 6 deletions crates/re_types_builder/src/codegen/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ fn quote_str_repr_from_obj(obj: &Object) -> String {

unindent::unindent(
r#"
def __str__(self):
def __str__(self) -> str:
s = f"rr.{type(self).__name__}(\n"

from dataclasses import fields
Expand All @@ -482,7 +482,7 @@ fn quote_str_repr_from_obj(obj: &Object) -> String {

return s

def __repr__(self):
def __repr__(self) -> str:
return str(self)

"#,
Expand Down Expand Up @@ -510,7 +510,7 @@ fn quote_array_method_from_obj(objects: &Objects, obj: &Object) -> String {
let field_name = &obj.fields[0].name;
unindent::unindent(&format!(
"
def __array__(self):
def __array__(self) -> npt.ArrayLike:
return np.asarray(self.{field_name})
",
))
Expand All @@ -535,7 +535,7 @@ fn quote_str_method_from_obj(objects: &Objects, obj: &Object) -> String {
let field_name = &obj.fields[0].name;
unindent::unindent(&format!(
"
def __str__(self):
def __str__(self) -> str:
return self.{field_name}
",
))
Expand Down Expand Up @@ -771,7 +771,7 @@ fn quote_arrow_support_from_obj(arrow_registry: &ArrowRegistry, obj: &Object) ->

from .{pkg}_ext import {many}Ext # noqa: E402

class {arrow}(pa.ExtensionType):
class {arrow}(pa.ExtensionType): # type: ignore[misc]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what error are se suppressing here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some non-sense about inheriting Any or something.

I don't remember exactly and didn't bother any further because this is just a verbatim port of what we already do today.

def __init__(self: type[pa.ExtensionType]) -> None:
pa.ExtensionType.__init__(
self, {datatype}, "{fqname}"
Expand All @@ -795,7 +795,7 @@ fn quote_arrow_support_from_obj(arrow_registry: &ArrowRegistry, obj: &Object) ->

class {many}(pa.ExtensionArray, {many}Ext): # type: ignore[misc]
@staticmethod
def from_similar(data: {many_aliases} | None):
def from_similar(data: {many_aliases} | None) -> pa.Array:
if data is None:
return {arrow}().wrap_array(pa.array([], type={arrow}().storage_type))
else:
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ py-lint:

# Run fast unittests
py-test:
python -m pytest rerun_py/tests/unit/
python -m pytest -vv rerun_py/tests/unit/

# Serve the python docs locally
py-docs-serve:
Expand Down
4 changes: 2 additions & 2 deletions rerun_py/rerun_sdk/rerun2/archetypes/points2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class Points2D:
Unique identifiers for each individual point in the batch.
"""

def __str__(self):
def __str__(self) -> str:
s = f"rr.{type(self).__name__}(\n"

from dataclasses import fields
Expand All @@ -86,7 +86,7 @@ def __str__(self):

return s

def __repr__(self):
def __repr__(self) -> str:
return str(self)

def __init__(
Expand Down
15 changes: 10 additions & 5 deletions rerun_py/rerun_sdk/rerun2/components/class_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@ class ClassId:

id: int

def __array__(self):
def __array__(self) -> npt.ArrayLike:
return np.asarray(self.id)


ClassIdLike = Union[ClassId, float]
ClassIdLike = Union[ClassId, int]

ClassIdArrayLike = Union[
ClassIdLike, Sequence[ClassIdLike], npt.NDArray[np.uint8], npt.NDArray[np.uint16], npt.NDArray[np.uint32]
ClassIdLike,
Sequence[ClassIdLike],
npt.NDArray[np.uint8],
npt.NDArray[np.uint16],
npt.NDArray[np.uint32],
npt.NDArray[np.uint64],
]


Expand All @@ -34,7 +39,7 @@ def __array__(self):
from rerun2.components.class_id_ext import ClassIdArrayExt # noqa: E402


class ClassIdType(pa.ExtensionType):
class ClassIdType(pa.ExtensionType): # type: ignore[misc]
def __init__(self: type[pa.ExtensionType]) -> None:
pa.ExtensionType.__init__(self, pa.uint16(), "rerun.components.ClassId")

Expand All @@ -58,7 +63,7 @@ def __arrow_ext_class__(self: type[pa.ExtensionType]) -> type[pa.ExtensionArray]

class ClassIdArray(pa.ExtensionArray, ClassIdArrayExt): # type: ignore[misc]
@staticmethod
def from_similar(data: ClassIdArrayLike | None):
def from_similar(data: ClassIdArrayLike | None) -> pa.Array:
if data is None:
return ClassIdType().wrap_array(pa.array([], type=ClassIdType().storage_type))
else:
Expand Down
21 changes: 21 additions & 0 deletions rerun_py/rerun_sdk/rerun2/components/class_id_ext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from __future__ import annotations

__all__ = ["ClassIdArrayExt"]

from typing import Any, Sequence

import numpy as np
import pyarrow as pa


class ClassIdArrayExt:
@staticmethod
def _from_similar(
data: Any | None, *, mono: type, mono_aliases: Any, many: type, many_aliases: Any, arrow: type
) -> pa.Array:
if isinstance(data, Sequence) and (len(data) > 0 and isinstance(data[0], mono)):
teh-cmc marked this conversation as resolved.
Show resolved Hide resolved
array = np.asarray([class_id.id for class_id in data], np.uint16)
else:
array = np.asarray(data, dtype=np.uint16).flatten()

return arrow().wrap_array(pa.array(array, type=arrow().storage_type))
18 changes: 12 additions & 6 deletions rerun_py/rerun_sdk/rerun2/components/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,30 @@

@dataclass
class Color:
"""An RGBA color tuple with unmultiplied/separate alpha, in sRGB gamma space with linear alpha."""
"""
An RGBA color tuple with unmultiplied/separate alpha, in sRGB gamma space with linear alpha.

Float colors are assumed to be in 0-1 gamma sRGB space.
All other colors are assumed to be in 0-255 gamma sRGB space.
If there is an alpha, we assume it is in linear space, and separate (NOT pre-multiplied).
"""

rgba: int

def __array__(self):
def __array__(self) -> npt.ArrayLike:
return np.asarray(self.rgba)


ColorLike = Union[
Color, Sequence[int], Sequence[float], npt.NDArray[np.uint8], npt.NDArray[np.float32], npt.NDArray[np.float64]
Color, int, npt.NDArray[np.uint8], npt.NDArray[np.uint32], npt.NDArray[np.float32], npt.NDArray[np.float64]
]

ColorArrayLike = Union[
ColorLike,
Sequence[ColorLike],
Sequence[int],
Sequence[float],
npt.NDArray[np.uint8],
npt.NDArray[np.uint32],
npt.NDArray[np.float32],
npt.NDArray[np.float64],
]
Expand All @@ -42,7 +48,7 @@ def __array__(self):
from rerun2.components.color_ext import ColorArrayExt # noqa: E402


class ColorType(pa.ExtensionType):
class ColorType(pa.ExtensionType): # type: ignore[misc]
def __init__(self: type[pa.ExtensionType]) -> None:
pa.ExtensionType.__init__(self, pa.uint32(), "rerun.components.Color")

Expand All @@ -66,7 +72,7 @@ def __arrow_ext_class__(self: type[pa.ExtensionType]) -> type[pa.ExtensionArray]

class ColorArray(pa.ExtensionArray, ColorArrayExt): # type: ignore[misc]
@staticmethod
def from_similar(data: ColorArrayLike | None):
def from_similar(data: ColorArrayLike | None) -> pa.Array:
if data is None:
return ColorType().wrap_array(pa.array([], type=ColorType().storage_type))
else:
Expand Down
42 changes: 42 additions & 0 deletions rerun_py/rerun_sdk/rerun2/components/color_ext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations

__all__ = ["ColorArrayExt"]

from typing import Any, Sequence

import numpy as np
import pyarrow as pa
from rerun.color_conversion import u8_array_to_rgba


class ColorArrayExt:
@staticmethod
def _from_similar(
data: Any | None, *, mono: type, mono_aliases: Any, many: type, many_aliases: Any, arrow: type
) -> pa.Array:
"""
Normalize flexible colors arrays.

Float colors are assumed to be in 0-1 gamma sRGB space.
All other colors are assumed to be in 0-255 gamma sRGB space.

If there is an alpha, we assume it is in linear space, and separate (NOT pre-multiplied).
"""
Comment on lines +17 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to surface this comment somehow to the user where appropriate. Here it won't be all that useful

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add this blurb as tagged docs.

Though again, this is just an alpha preview, we'll give the doc much more love when backporting.

if isinstance(data, Sequence) and len(data) == 0:
array = np.array([], np.uint32)
elif isinstance(data, Sequence) and (len(data) > 0 and isinstance(data[0], mono)):
array = np.asarray([color.rgba for color in data], np.uint32)
elif isinstance(data, Sequence) and (len(data) > 0 and isinstance(data[0], int)):
array = np.asarray(data, np.uint32)
else:
array = np.asarray(data)
# Rust expects colors in 0-255 uint8
if array.dtype.type in [np.float32, np.float64]:
# Assume gamma-space colors
array = u8_array_to_rgba(np.asarray(np.round(np.asarray(data).reshape((-1, 4)) * 255.0), np.uint8))
elif array.dtype.type == np.uint32:
array = np.asarray(data).flatten()
else:
array = u8_array_to_rgba(np.asarray(data, dtype=np.uint8).reshape((-1, 4)))

return arrow().wrap_array(pa.array(array, type=arrow().storage_type))
6 changes: 3 additions & 3 deletions rerun_py/rerun_sdk/rerun2/components/draw_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class DrawOrder:

value: float

def __array__(self):
def __array__(self) -> npt.ArrayLike:
return np.asarray(self.value)


Expand All @@ -40,7 +40,7 @@ def __array__(self):
from rerun2.components.draw_order_ext import DrawOrderArrayExt # noqa: E402


class DrawOrderType(pa.ExtensionType):
class DrawOrderType(pa.ExtensionType): # type: ignore[misc]
def __init__(self: type[pa.ExtensionType]) -> None:
pa.ExtensionType.__init__(self, pa.float32(), "rerun.components.DrawOrder")

Expand All @@ -64,7 +64,7 @@ def __arrow_ext_class__(self: type[pa.ExtensionType]) -> type[pa.ExtensionArray]

class DrawOrderArray(pa.ExtensionArray, DrawOrderArrayExt): # type: ignore[misc]
@staticmethod
def from_similar(data: DrawOrderArrayLike | None):
def from_similar(data: DrawOrderArrayLike | None) -> pa.Array:
if data is None:
return DrawOrderType().wrap_array(pa.array([], type=DrawOrderType().storage_type))
else:
Expand Down
21 changes: 21 additions & 0 deletions rerun_py/rerun_sdk/rerun2/components/draw_order_ext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from __future__ import annotations

__all__ = ["DrawOrderArrayExt"]

from typing import Any, Sequence

import numpy as np
import pyarrow as pa


class DrawOrderArrayExt:
@staticmethod
def _from_similar(
data: Any | None, *, mono: type, mono_aliases: Any, many: type, many_aliases: Any, arrow: type
) -> pa.Array:
if isinstance(data, Sequence) and (len(data) > 0 and isinstance(data[0], mono)):
array = np.asarray([draw_order.value for draw_order in data], np.float32)
else:
array = np.require(np.asarray(data), np.float32).flatten()

return arrow().wrap_array(pa.array(array, type=arrow().storage_type))
Loading
Loading