diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index 3304483283e7..15bf430ac588 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -409,8 +409,8 @@ impl PythonCodeGenerator { } // rerun/{datatypes|components|archetypes}/__init__.py - write_init(&kind_path, &mods, files_to_write); - write_init(&test_kind_path, &test_mods, files_to_write); + write_init_file(&kind_path, &mods, files_to_write); + write_init_file(&test_kind_path, &test_mods, files_to_write); } fn write_files(&self, files_to_write: &BTreeMap) { @@ -458,7 +458,7 @@ impl PythonCodeGenerator { } } -fn write_init( +fn write_init_file( kind_path: &Utf8PathBuf, mods: &HashMap>, files_to_write: &mut BTreeMap, @@ -603,11 +603,7 @@ fn code_for_struct( 2, 4, ); - } else if !obj.is_delegating_component() { - // In absence of a an extension class __init__ method, we don't *need* an __init__ method here. - // But if we don't generate one, LSP will show the class's doc string instead of parameter documentation. - code.push_text(quote_init_method(obj, ext_class, objects), 2, 4); - } else { + } else if obj.is_delegating_component() { code.push_text( format!( "# You can define your own __init__ function as a member of {} in {}", @@ -616,6 +612,10 @@ fn code_for_struct( 2, 4, ); + } else { + // In absence of a an extension class __init__ method, we don't *need* an __init__ method here. + // But if we don't generate one, LSP will show the class's doc string instead of parameter documentation. + code.push_text(quote_init_method(obj, ext_class, objects), 2, 4); } if obj.is_delegating_component() { @@ -1510,7 +1510,7 @@ fn quote_arrow_support_from_obj( } } -fn quote_argument_type_alias( +fn quote_parameter_type_alias( arg_type_fqname: &str, class_fqname: &str, objects: &Objects, @@ -1535,13 +1535,13 @@ fn quote_argument_type_alias( } } -fn quote_init_argument_from_field( +fn quote_init_parameter_from_field( field: &ObjectField, objects: &Objects, current_obj_fqname: &str, ) -> String { let type_annotation = if let Some(fqname) = field.typ.fqname() { - quote_argument_type_alias(fqname, current_obj_fqname, objects, field.typ.is_plural()) + quote_parameter_type_alias(fqname, current_obj_fqname, objects, field.typ.is_plural()) } else { let type_annotation = quote_field_type_from_field(objects, field, false).0; // Relax type annotation for numpy arrays. @@ -1563,29 +1563,47 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects // If the type is fully transparent (single non-nullable field and not an archetype), // we have to use the "{obj.name}Like" type directly since the type of the field itself might be too narrow. // -> Whatever type aliases there are for this type, we need to pick them up. - let arguments: Vec<_> = + let parameters: Vec<_> = if obj.kind != ObjectKind::Archetype && obj.fields.len() == 1 && !obj.fields[0].is_nullable { vec![format!( "{}: {}", obj.fields[0].name, - quote_argument_type_alias(&obj.fqname, &obj.fqname, objects, false) + quote_parameter_type_alias(&obj.fqname, &obj.fqname, objects, false) )] } else if obj.is_union() { vec![format!( "inner: {} | None = None", - quote_argument_type_alias(&obj.fqname, &obj.fqname, objects, false) + quote_parameter_type_alias(&obj.fqname, &obj.fqname, objects, false) )] } else { - obj.fields + let required = obj + .fields .iter() - .sorted_by_key(|field| field.is_nullable) - .map(|field| quote_init_argument_from_field(field, objects, &obj.fqname)) - .collect() + .filter(|field| !field.is_nullable) + .map(|field| quote_init_parameter_from_field(field, objects, &obj.fqname)) + .collect_vec(); + + let optional = obj + .fields + .iter() + .filter(|field| field.is_nullable) + .map(|field| quote_init_parameter_from_field(field, objects, &obj.fqname)) + .collect_vec(); + + if optional.is_empty() { + required + } else { + required + .into_iter() + .chain(std::iter::once("*".to_owned())) // Force kw-args for all optional arguments + .chain(optional) + .collect() + } }; - let head = format!("def __init__(self: Any, {}):", arguments.join(", ")); + let head = format!("def __init__(self: Any, {}):", parameters.join(", ")); - let argument_docs = if obj.is_union() { + let parameter_docs = if obj.is_union() { Vec::new() } else { obj.fields @@ -1614,11 +1632,11 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects r#"""""#.to_owned(), format!("Create a new instance of the {} {doc_typedesc}.", obj.name), ]; - if !argument_docs.is_empty() { + if !parameter_docs.is_empty() { doc_string_lines.push("\n".to_owned()); doc_string_lines.push("Parameters".to_owned()); doc_string_lines.push("----------".to_owned()); - for doc in argument_docs { + for doc in parameter_docs { doc_string_lines.push(doc); } }; diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index 1d4d30042a0b..091a8a1c4437 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -76,6 +76,7 @@ class Asset3D(Asset3DExt, Archetype): def __init__( self: Any, data: components.BlobLike, + *, media_type: datatypes.Utf8Like | None = None, transform: datatypes.Transform3DLike | None = None, ): diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 18f86e4928fe..59c7a4751f06 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -90,6 +90,7 @@ class DepthImage(DepthImageExt, Archetype): def __init__( self: Any, data: datatypes.TensorDataLike, + *, meter: components.DepthMeterLike | None = None, draw_order: components.DrawOrderLike | None = None, ): diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index aa4709f0afcd..4712fde46810 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -54,7 +54,7 @@ class Image(ImageExt, Archetype): """ - def __init__(self: Any, data: datatypes.TensorDataLike, draw_order: components.DrawOrderLike | None = None): + def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: components.DrawOrderLike | None = None): """ Create a new instance of the Image archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index 3424f61d77c5..e8ffd80d4e7b 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -98,6 +98,7 @@ class LineStrips2D(Archetype): def __init__( self: Any, strips: components.LineStrip2DArrayLike, + *, radii: components.RadiusArrayLike | None = None, colors: datatypes.ColorArrayLike | None = None, labels: datatypes.Utf8ArrayLike | None = None, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index 04f010435641..cb963d15a517 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -124,6 +124,7 @@ class LineStrips3D(Archetype): def __init__( self: Any, strips: components.LineStrip3DArrayLike, + *, radii: components.RadiusArrayLike | None = None, colors: datatypes.ColorArrayLike | None = None, labels: datatypes.Utf8ArrayLike | None = None, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index 12c62fb7a84a..b07582c04db3 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -68,6 +68,7 @@ class Points2D(Archetype): def __init__( self: Any, positions: datatypes.Vec2DArrayLike, + *, radii: components.RadiusArrayLike | None = None, colors: datatypes.ColorArrayLike | None = None, labels: datatypes.Utf8ArrayLike | None = None, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 6ed732189a2b..324e0f1337b0 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -62,6 +62,7 @@ class Points3D(Archetype): def __init__( self: Any, positions: datatypes.Vec3DArrayLike, + *, radii: components.RadiusArrayLike | None = None, colors: datatypes.ColorArrayLike | None = None, labels: datatypes.Utf8ArrayLike | None = None, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index 14aa62473ef5..cde92b6c29c6 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -55,7 +55,7 @@ class SegmentationImage(SegmentationImageExt, Archetype): """ - def __init__(self: Any, data: datatypes.TensorDataLike, draw_order: components.DrawOrderLike | None = None): + def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: components.DrawOrderLike | None = None): """ Create a new instance of the SegmentationImage archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index 8f33ffb557bd..2429f7d5a8d2 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -19,7 +19,7 @@ class TextDocument(Archetype): """A text element intended to be displayed in its own text-box.""" - def __init__(self: Any, body: datatypes.Utf8Like, media_type: datatypes.Utf8Like | None = None): + def __init__(self: Any, body: datatypes.Utf8Like, *, media_type: datatypes.Utf8Like | None = None): """ Create a new instance of the TextDocument archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index 43f958ba0d15..8caa0f3930b4 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -22,6 +22,7 @@ class TextLog(Archetype): def __init__( self: Any, body: datatypes.Utf8Like, + *, level: datatypes.Utf8Like | None = None, color: datatypes.ColorLike | None = None, ): diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index c4707239133b..bd8b9423ae7d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -63,6 +63,7 @@ class TimeSeriesScalar(Archetype): def __init__( self: Any, scalar: components.ScalarLike, + *, radius: components.RadiusLike | None = None, color: datatypes.ColorLike | None = None, label: datatypes.Utf8Like | None = None, diff --git a/rerun_py/rerun_sdk/rerun/datatypes/annotation_info.py b/rerun_py/rerun_sdk/rerun/datatypes/annotation_info.py index c1b24643d033..dc2fc392b7e4 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/annotation_info.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/annotation_info.py @@ -50,7 +50,9 @@ class AnnotationInfo(AnnotationInfoExt): The id refers either to a class or key-point id """ - def __init__(self: Any, id: int, label: datatypes.Utf8Like | None = None, color: datatypes.ColorLike | None = None): + def __init__( + self: Any, id: int, *, label: datatypes.Utf8Like | None = None, color: datatypes.ColorLike | None = None + ): """ Create a new instance of the AnnotationInfo datatype. diff --git a/rerun_py/rerun_sdk/rerun/datatypes/material.py b/rerun_py/rerun_sdk/rerun/datatypes/material.py index f29608701141..d606cd13a041 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/material.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/material.py @@ -28,7 +28,7 @@ def _material__albedo_factor__special_field_converter_override(x: datatypes.Colo @define(init=False) class Material(MaterialExt): - def __init__(self: Any, albedo_factor: datatypes.ColorLike | None = None): + def __init__(self: Any, *, albedo_factor: datatypes.ColorLike | None = None): """ Create a new instance of the Material datatype. diff --git a/rerun_py/rerun_sdk/rerun/datatypes/mesh_properties.py b/rerun_py/rerun_sdk/rerun/datatypes/mesh_properties.py index 828e7740daa9..43547598afe3 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/mesh_properties.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/mesh_properties.py @@ -29,7 +29,7 @@ @define(init=False) class MeshProperties(MeshPropertiesExt): - def __init__(self: Any, indices: npt.ArrayLike | None = None): + def __init__(self: Any, *, indices: npt.ArrayLike | None = None): """ Create a new instance of the MeshProperties datatype. diff --git a/rerun_py/rerun_sdk/rerun/datatypes/tensor_dimension.py b/rerun_py/rerun_sdk/rerun/datatypes/tensor_dimension.py index cb64693dfc6b..cfb993a255e8 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/tensor_dimension.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/tensor_dimension.py @@ -28,7 +28,7 @@ class TensorDimension: """A single dimension within a multi-dimensional tensor.""" - def __init__(self: Any, size: int, name: str | None = None): + def __init__(self: Any, size: int, *, name: str | None = None): """Create a new instance of the TensorDimension datatype.""" # You can define your own __init__ function as a member of TensorDimensionExt in tensor_dimension_ext.py diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index df31d1ac404e..b3170480b7c2 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -19,6 +19,7 @@ class AffixFuzzer3(Archetype): def __init__( self: Any, + *, fuzz2001: datatypes.AffixFuzzer1Like | None = None, fuzz2002: datatypes.AffixFuzzer1Like | None = None, fuzz2003: datatypes.AffixFuzzer1Like | None = None, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index 493b0963371e..7006598163a0 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -19,6 +19,7 @@ class AffixFuzzer4(Archetype): def __init__( self: Any, + *, fuzz2101: datatypes.AffixFuzzer1ArrayLike | None = None, fuzz2102: datatypes.AffixFuzzer1ArrayLike | None = None, fuzz2103: datatypes.AffixFuzzer1ArrayLike | None = None, diff --git a/rerun_py/tests/test_types/components/affix_fuzzer10.py b/rerun_py/tests/test_types/components/affix_fuzzer10.py index b0f7b2c0bbaa..0bad9fea65ef 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer10.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer10.py @@ -19,7 +19,7 @@ @define(init=False) class AffixFuzzer10: - def __init__(self: Any, single_string_optional: str | None = None): + def __init__(self: Any, *, single_string_optional: str | None = None): """Create a new instance of the AffixFuzzer10 component.""" # You can define your own __init__ function as a member of AffixFuzzer10Ext in affix_fuzzer10_ext.py diff --git a/rerun_py/tests/test_types/components/affix_fuzzer11.py b/rerun_py/tests/test_types/components/affix_fuzzer11.py index 94e8eabd8325..b57649b64430 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer11.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer11.py @@ -21,7 +21,7 @@ @define(init=False) class AffixFuzzer11: - def __init__(self: Any, many_floats_optional: npt.ArrayLike | None = None): + def __init__(self: Any, *, many_floats_optional: npt.ArrayLike | None = None): """Create a new instance of the AffixFuzzer11 component.""" # You can define your own __init__ function as a member of AffixFuzzer11Ext in affix_fuzzer11_ext.py diff --git a/rerun_py/tests/test_types/components/affix_fuzzer13.py b/rerun_py/tests/test_types/components/affix_fuzzer13.py index adebc8d7ff05..03a8a6a72425 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer13.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer13.py @@ -16,7 +16,7 @@ @define(init=False) class AffixFuzzer13: - def __init__(self: Any, many_strings_optional: list[str] | None = None): + def __init__(self: Any, *, many_strings_optional: list[str] | None = None): """Create a new instance of the AffixFuzzer13 component.""" # You can define your own __init__ function as a member of AffixFuzzer13Ext in affix_fuzzer13_ext.py diff --git a/rerun_py/tests/test_types/components/affix_fuzzer17.py b/rerun_py/tests/test_types/components/affix_fuzzer17.py index 07a893add15d..da9c2ff4ee46 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer17.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer17.py @@ -18,7 +18,7 @@ @define(init=False) class AffixFuzzer17: - def __init__(self: Any, many_optional_unions: datatypes.AffixFuzzer3ArrayLike | None = None): + def __init__(self: Any, *, many_optional_unions: datatypes.AffixFuzzer3ArrayLike | None = None): """Create a new instance of the AffixFuzzer17 component.""" # You can define your own __init__ function as a member of AffixFuzzer17Ext in affix_fuzzer17_ext.py diff --git a/rerun_py/tests/test_types/components/affix_fuzzer18.py b/rerun_py/tests/test_types/components/affix_fuzzer18.py index b8fe9ade3a84..203faef306d2 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer18.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer18.py @@ -18,7 +18,7 @@ @define(init=False) class AffixFuzzer18: - def __init__(self: Any, many_optional_unions: datatypes.AffixFuzzer4ArrayLike | None = None): + def __init__(self: Any, *, many_optional_unions: datatypes.AffixFuzzer4ArrayLike | None = None): """Create a new instance of the AffixFuzzer18 component.""" # You can define your own __init__ function as a member of AffixFuzzer18Ext in affix_fuzzer18_ext.py diff --git a/rerun_py/tests/test_types/components/affix_fuzzer7.py b/rerun_py/tests/test_types/components/affix_fuzzer7.py index 78f28b541261..fd899795247e 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer7.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer7.py @@ -18,7 +18,7 @@ @define(init=False) class AffixFuzzer7: - def __init__(self: Any, many_optional: datatypes.AffixFuzzer1ArrayLike | None = None): + def __init__(self: Any, *, many_optional: datatypes.AffixFuzzer1ArrayLike | None = None): """Create a new instance of the AffixFuzzer7 component.""" # You can define your own __init__ function as a member of AffixFuzzer7Ext in affix_fuzzer7_ext.py diff --git a/rerun_py/tests/test_types/components/affix_fuzzer8.py b/rerun_py/tests/test_types/components/affix_fuzzer8.py index 5125259f4dc7..87e4cd44d8fe 100644 --- a/rerun_py/tests/test_types/components/affix_fuzzer8.py +++ b/rerun_py/tests/test_types/components/affix_fuzzer8.py @@ -21,7 +21,7 @@ @define(init=False) class AffixFuzzer8: - def __init__(self: Any, single_float_optional: float | None = None): + def __init__(self: Any, *, single_float_optional: float | None = None): """Create a new instance of the AffixFuzzer8 component.""" # You can define your own __init__ function as a member of AffixFuzzer8Ext in affix_fuzzer8_ext.py diff --git a/rerun_py/tests/test_types/datatypes/affix_fuzzer1.py b/rerun_py/tests/test_types/datatypes/affix_fuzzer1.py index 217734e8c0c9..12886fddf81a 100644 --- a/rerun_py/tests/test_types/datatypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/datatypes/affix_fuzzer1.py @@ -41,6 +41,7 @@ def __init__( many_strings_required: list[str], flattened_scalar: float, almost_flattened_scalar: datatypes.FlattenedScalarLike, + *, single_float_optional: float | None = None, single_string_optional: str | None = None, many_floats_optional: npt.ArrayLike | None = None, diff --git a/rerun_py/tests/test_types/datatypes/affix_fuzzer2.py b/rerun_py/tests/test_types/datatypes/affix_fuzzer2.py index 04e8196a2a0c..5000b2872676 100644 --- a/rerun_py/tests/test_types/datatypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/datatypes/affix_fuzzer2.py @@ -21,7 +21,7 @@ @define(init=False) class AffixFuzzer2: - def __init__(self: Any, single_float_optional: float | None = None): + def __init__(self: Any, *, single_float_optional: float | None = None): """Create a new instance of the AffixFuzzer2 datatype.""" # You can define your own __init__ function as a member of AffixFuzzer2Ext in affix_fuzzer2_ext.py diff --git a/rerun_py/tests/test_types/datatypes/affix_fuzzer5.py b/rerun_py/tests/test_types/datatypes/affix_fuzzer5.py index 7de8a98f1b11..7ed57589e5fb 100644 --- a/rerun_py/tests/test_types/datatypes/affix_fuzzer5.py +++ b/rerun_py/tests/test_types/datatypes/affix_fuzzer5.py @@ -29,7 +29,7 @@ def _affix_fuzzer5__single_optional_union__special_field_converter_override( @define(init=False) class AffixFuzzer5: - def __init__(self: Any, single_optional_union: datatypes.AffixFuzzer4Like | None = None): + def __init__(self: Any, *, single_optional_union: datatypes.AffixFuzzer4Like | None = None): """Create a new instance of the AffixFuzzer5 datatype.""" # You can define your own __init__ function as a member of AffixFuzzer5Ext in affix_fuzzer5_ext.py