From 1211f6dc7c9553e2d252eeb299b5cf17d90a6967 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler <49431240+abey79@users.noreply.github.com> Date: Fri, 31 May 2024 09:56:59 +0200 Subject: [PATCH] Improve visibility of Python public APIs to type checkers (#6462) ### What - Closes #6459 #6117 removed many `__all__` statements, which cause problem for type checkers when using our public APIs (`rr.*` and `rr.blueprint.*`). This PR fixes this by using the `from X import Y as Y` pattern, which is easier to maintain than `__all__`. This required a ruff setting change, which rippled into additional (arguably good) formatting changes. ### Checklist * [x] I have read and agree to [Contributor Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and the [Code of Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md) * [x] I've included a screenshot or gif (if applicable) * [x] I have tested the web demo (if applicable): * Using examples from latest `main` build: [rerun.io/viewer](https://rerun.io/viewer/pr/6462?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [rerun.io/viewer](https://rerun.io/viewer/pr/6462?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG * [x] If applicable, add a new check to the [release checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)! - [PR Build Summary](https://build.rerun.io/pr/6462) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) To run all checks from `main`, comment on the PR with `@rerun-bot full-check`. --- rerun_py/pyproject.toml | 1 + rerun_py/rerun_sdk/rerun/__init__.py | 204 ++++++++++-------- .../rerun_sdk/rerun/blueprint/__init__.py | 77 ++++--- .../rerun/blueprint/views/spatial2d_view.py | 3 +- .../rerun/blueprint/views/spatial3d_view.py | 3 +- .../rerun/blueprint/views/time_series_view.py | 3 +- rerun_py/tests/unit/test_box2d.py | 8 - rerun_py/tests/unit/test_box3d.py | 8 - rerun_py/tests/unit/test_points2d.py | 4 - rerun_py/tests/unit/test_points3d.py | 4 - scripts/ci/build_and_upload_wheels.py | 3 +- scripts/ci/crates.py | 3 +- scripts/ci/publish_wheels.py | 3 +- 13 files changed, 169 insertions(+), 155 deletions(-) diff --git a/rerun_py/pyproject.toml b/rerun_py/pyproject.toml index 69336dd23cca..ed399b85d7b5 100644 --- a/rerun_py/pyproject.toml +++ b/rerun_py/pyproject.toml @@ -134,6 +134,7 @@ lint.unfixable = [ [tool.ruff.lint.isort] required-imports = ["from __future__ import annotations"] +combine-as-imports = true # needed so keep rerun_sdk/__init__.py clean [tool.maturin] # We use a python package from inside the rerun_sdk folder to avoid conflicting diff --git a/rerun_py/rerun_sdk/rerun/__init__.py b/rerun_py/rerun_sdk/rerun/__init__.py index cc0b2c147b52..eb8ceb495603 100644 --- a/rerun_py/rerun_sdk/rerun/__init__.py +++ b/rerun_py/rerun_sdk/rerun/__init__.py @@ -9,106 +9,139 @@ # ===================================== # API RE-EXPORTS +# Important: always us the `import _ as _` format to make it explicit to type-checkers that these are public APIs. +# Background: https://github.com/microsoft/pyright/blob/1.1.365/docs/typed-libraries.md#library-interface +# import rerun_bindings as bindings # type: ignore[attr-defined] -from ._image import ImageEncoded, ImageFormat +from . import ( + blueprint as blueprint, + experimental as experimental, +) +from ._image import ( + ImageEncoded as ImageEncoded, + ImageFormat as ImageFormat, +) from ._log import ( - AsComponents, - ComponentBatchLike, - IndicatorComponentBatch, - escape_entity_path_part, - log, - log_components, - log_file_from_contents, - log_file_from_path, - new_entity_path, + AsComponents as AsComponents, + ComponentBatchLike as ComponentBatchLike, + IndicatorComponentBatch as IndicatorComponentBatch, + escape_entity_path_part as escape_entity_path_part, + log as log, + log_components as log_components, + log_file_from_contents as log_file_from_contents, + log_file_from_path as log_file_from_path, + new_entity_path as new_entity_path, +) +from .any_value import ( + AnyValues as AnyValues, ) -from .any_value import AnyValues from .archetypes import ( - AnnotationContext, - Arrows2D, - Arrows3D, - Asset3D, - BarChart, - Boxes2D, - Boxes3D, - Clear, - DepthImage, - DisconnectedSpace, - Image, - LineStrips2D, - LineStrips3D, - Mesh3D, - Pinhole, - Points2D, - Points3D, - Scalar, - SegmentationImage, - SeriesLine, - SeriesPoint, - Tensor, - TextDocument, - TextLog, - Transform3D, - ViewCoordinates, + AnnotationContext as AnnotationContext, + Arrows2D as Arrows2D, + Arrows3D as Arrows3D, + Asset3D as Asset3D, + BarChart as BarChart, + Boxes2D as Boxes2D, + Boxes3D as Boxes3D, + Clear as Clear, + DepthImage as DepthImage, + DisconnectedSpace as DisconnectedSpace, + Image as Image, + LineStrips2D as LineStrips2D, + LineStrips3D as LineStrips3D, + Mesh3D as Mesh3D, + Pinhole as Pinhole, + Points2D as Points2D, + Points3D as Points3D, + Scalar as Scalar, + SegmentationImage as SegmentationImage, + SeriesLine as SeriesLine, + SeriesPoint as SeriesPoint, + Tensor as Tensor, + TextDocument as TextDocument, + TextLog as TextLog, + Transform3D as Transform3D, + ViewCoordinates as ViewCoordinates, +) +from .archetypes.boxes2d_ext import ( + Box2DFormat as Box2DFormat, +) +from .blueprint.api import ( + BlueprintLike as BlueprintLike, ) -from .archetypes.boxes2d_ext import Box2DFormat -from .blueprint.api import BlueprintLike from .components import ( - Material, - MediaType, - OutOfTreeTransform3D, - OutOfTreeTransform3DBatch, - TextLogLevel, + Material as Material, + MediaType as MediaType, + OutOfTreeTransform3D as OutOfTreeTransform3D, + OutOfTreeTransform3DBatch as OutOfTreeTransform3DBatch, + TextLogLevel as TextLogLevel, ) from .datatypes import ( - AnnotationInfo, - ClassDescription, - Quaternion, - RotationAxisAngle, - Scale3D, - TensorData, - TimeInt, - TimeRange, - TimeRangeBoundary, - TranslationAndMat3x3, - TranslationRotationScale3D, - VisibleTimeRange, + AnnotationInfo as AnnotationInfo, + ClassDescription as ClassDescription, + Quaternion as Quaternion, + RotationAxisAngle as RotationAxisAngle, + Scale3D as Scale3D, + TensorData as TensorData, + TimeInt as TimeInt, + TimeRange as TimeRange, + TimeRangeBoundary as TimeRangeBoundary, + TranslationAndMat3x3 as TranslationAndMat3x3, + TranslationRotationScale3D as TranslationRotationScale3D, + VisibleTimeRange as VisibleTimeRange, +) +from .error_utils import ( + set_strict_mode as set_strict_mode, +) +from .logging_handler import ( + LoggingHandler as LoggingHandler, +) +from .memory import ( + MemoryRecording as MemoryRecording, + memory_recording as memory_recording, +) +from .notebook import ( + notebook_show as notebook_show, ) -from .error_utils import set_strict_mode -from .logging_handler import LoggingHandler -from .memory import MemoryRecording, memory_recording -from .notebook import notebook_show from .recording_stream import ( - BinaryStream, - RecordingStream, - binary_stream, - get_application_id, - get_data_recording, - get_global_data_recording, - get_recording_id, - get_thread_local_data_recording, - is_enabled, - new_recording, - recording_stream_generator_ctx, - set_global_data_recording, - set_thread_local_data_recording, - thread_local_stream, + BinaryStream as BinaryStream, + RecordingStream as RecordingStream, + binary_stream as binary_stream, + get_application_id as get_application_id, + get_data_recording as get_data_recording, + get_global_data_recording as get_global_data_recording, + get_recording_id as get_recording_id, + get_thread_local_data_recording as get_thread_local_data_recording, + is_enabled as is_enabled, + new_recording as new_recording, + recording_stream_generator_ctx as recording_stream_generator_ctx, + set_global_data_recording as set_global_data_recording, + set_thread_local_data_recording as set_thread_local_data_recording, + thread_local_stream as thread_local_stream, +) +from .script_helpers import ( + script_add_args as script_add_args, + script_setup as script_setup, + script_teardown as script_teardown, +) +from .sinks import ( + connect as connect, + disconnect as disconnect, + save as save, + send_blueprint as send_blueprint, + serve as serve, + spawn as spawn, + stdout as stdout, ) -from .script_helpers import script_add_args, script_setup, script_teardown -from .sinks import connect, disconnect, save, send_blueprint, serve, spawn, stdout from .time import ( - disable_timeline, - reset_time, - set_time_nanos, - set_time_seconds, - set_time_sequence, + disable_timeline as disable_timeline, + reset_time as reset_time, + set_time_nanos as set_time_nanos, + set_time_seconds as set_time_seconds, + set_time_sequence as set_time_sequence, ) -# Import experimental last -from . import experimental # isort: skip -from . import blueprint - # ===================================== # UTILITIES @@ -321,7 +354,6 @@ def _register_on_fork() -> None: _register_on_fork() - _TFunc = TypeVar("_TFunc", bound=Callable[..., Any]) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/__init__.py index 0b0443378383..88274d2e327e 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/__init__.py @@ -1,45 +1,56 @@ from __future__ import annotations -# Re-export time range types for better discoverability. -from ..datatypes import ( - TimeRange, - TimeRangeBoundary, +# ===================================== +# API RE-EXPORTS +# Important: always us the `import _ as _` format to make it explicit to type-checkers that these are public APIs. +# +from ..datatypes import ( # Re-export time range types for better discoverability. + TimeRange as TimeRange, + TimeRangeBoundary as TimeRangeBoundary, +) +from . import ( + archetypes as archetypes, + components as components, ) -from . import archetypes, components from .api import ( - Blueprint, - BlueprintLike, - BlueprintPanel, - BlueprintPart, - Container, - ContainerLike, - PanelState, - PanelStateLike, - SelectionPanel, - SpaceView, - TimePanel, - TopPanel, + Blueprint as Blueprint, + BlueprintLike as BlueprintLike, + BlueprintPanel as BlueprintPanel, + BlueprintPart as BlueprintPart, + Container as Container, + ContainerLike as ContainerLike, + PanelState as PanelState, + PanelStateLike as PanelStateLike, + SelectionPanel as SelectionPanel, + SpaceView as SpaceView, + TimePanel as TimePanel, + TopPanel as TopPanel, ) from .archetypes import ( - Background, - PlotLegend, - ScalarAxis, + Background as Background, + PlotLegend as PlotLegend, + ScalarAxis as ScalarAxis, # VisibleTimeRanges, # Don't expose this mono-archetype directly - one can always use the component instead! - VisualBounds2D, + VisualBounds2D as VisualBounds2D, ) from .components import ( - BackgroundKind, - Corner2D, - LockRangeDuringZoom, - VisibleTimeRange, + BackgroundKind as BackgroundKind, + Corner2D as Corner2D, + LockRangeDuringZoom as LockRangeDuringZoom, + VisibleTimeRange as VisibleTimeRange, +) +from .containers import ( + Grid as Grid, + Horizontal as Horizontal, + Tabs as Tabs, + Vertical as Vertical, ) -from .containers import Grid, Horizontal, Tabs, Vertical from .views import ( - BarChartView, - Spatial2DView, - Spatial3DView, - TensorView, - TextDocumentView, - TextLogView, - TimeSeriesView, + BarChartView as BarChartView, + Spatial2DView as Spatial2DView, + Spatial3DView as Spatial3DView, + TensorView as TensorView, + TextDocumentView as TextDocumentView, + TextLogView as TextLogView, + TimeSeriesView as TimeSeriesView, ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/views/spatial2d_view.py b/rerun_py/rerun_sdk/rerun/blueprint/views/spatial2d_view.py index 511aa5d5874e..ab1526586792 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/views/spatial2d_view.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/views/spatial2d_view.py @@ -11,8 +11,7 @@ from ... import datatypes from ..._baseclasses import AsComponents from ...datatypes import EntityPathLike, Utf8Like -from .. import archetypes as blueprint_archetypes -from .. import components as blueprint_components +from .. import archetypes as blueprint_archetypes, components as blueprint_components from ..api import SpaceView, SpaceViewContentsLike diff --git a/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py b/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py index a164059b1804..3e995ddc4f56 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/views/spatial3d_view.py @@ -11,8 +11,7 @@ from ... import datatypes from ..._baseclasses import AsComponents from ...datatypes import EntityPathLike, Utf8Like -from .. import archetypes as blueprint_archetypes -from .. import components as blueprint_components +from .. import archetypes as blueprint_archetypes, components as blueprint_components from ..api import SpaceView, SpaceViewContentsLike diff --git a/rerun_py/rerun_sdk/rerun/blueprint/views/time_series_view.py b/rerun_py/rerun_sdk/rerun/blueprint/views/time_series_view.py index b6d69442d191..174b66ea6c0e 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/views/time_series_view.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/views/time_series_view.py @@ -11,8 +11,7 @@ from ... import datatypes from ..._baseclasses import AsComponents from ...datatypes import EntityPathLike, Utf8Like -from .. import archetypes as blueprint_archetypes -from .. import components as blueprint_components +from .. import archetypes as blueprint_archetypes, components as blueprint_components from ..api import SpaceView, SpaceViewContentsLike diff --git a/rerun_py/tests/unit/test_box2d.py b/rerun_py/tests/unit/test_box2d.py index a6dee157b0cd..1c016ba33c0d 100644 --- a/rerun_py/tests/unit/test_box2d.py +++ b/rerun_py/tests/unit/test_box2d.py @@ -27,17 +27,9 @@ labels_expected, radii_arrays, radii_expected, -) -from .common_arrays import ( vec2ds_arrays as centers_arrays, -) -from .common_arrays import ( vec2ds_arrays as half_sizes_arrays, -) -from .common_arrays import ( vec2ds_expected as centers_expected, -) -from .common_arrays import ( vec2ds_expected as half_sizes_expected, ) diff --git a/rerun_py/tests/unit/test_box3d.py b/rerun_py/tests/unit/test_box3d.py index d79c16d2e47a..653de41dfc2b 100644 --- a/rerun_py/tests/unit/test_box3d.py +++ b/rerun_py/tests/unit/test_box3d.py @@ -19,17 +19,9 @@ radii_arrays, radii_expected, rotations_arrays, -) -from .common_arrays import ( vec3ds_arrays as centers_arrays, -) -from .common_arrays import ( vec3ds_arrays as half_sizes_arrays, -) -from .common_arrays import ( vec3ds_expected as centers_expected, -) -from .common_arrays import ( vec3ds_expected as half_sizes_expected, ) diff --git a/rerun_py/tests/unit/test_points2d.py b/rerun_py/tests/unit/test_points2d.py index fd10f1b976a1..ca15f0f1bdf5 100644 --- a/rerun_py/tests/unit/test_points2d.py +++ b/rerun_py/tests/unit/test_points2d.py @@ -28,11 +28,7 @@ labels_expected, radii_arrays, radii_expected, -) -from .common_arrays import ( vec2ds_arrays as positions_arrays, -) -from .common_arrays import ( vec2ds_expected as positions_expected, ) diff --git a/rerun_py/tests/unit/test_points3d.py b/rerun_py/tests/unit/test_points3d.py index 0d4a7d5738a4..be4a76cd8f11 100644 --- a/rerun_py/tests/unit/test_points3d.py +++ b/rerun_py/tests/unit/test_points3d.py @@ -25,11 +25,7 @@ labels_expected, radii_arrays, radii_expected, -) -from .common_arrays import ( vec3ds_arrays as positions_arrays, -) -from .common_arrays import ( vec3ds_expected as positions_expected, ) diff --git a/scripts/ci/build_and_upload_wheels.py b/scripts/ci/build_and_upload_wheels.py index d2c681350ffb..c5de7319acb9 100755 --- a/scripts/ci/build_and_upload_wheels.py +++ b/scripts/ci/build_and_upload_wheels.py @@ -18,8 +18,7 @@ import subprocess from enum import Enum -from google.cloud.storage import Bucket -from google.cloud.storage import Client as Gcs +from google.cloud.storage import Bucket, Client as Gcs def run( diff --git a/scripts/ci/crates.py b/scripts/ci/crates.py index a80ae5b98fdc..d4039c9b790c 100755 --- a/scripts/ci/crates.py +++ b/scripts/ci/crates.py @@ -35,8 +35,7 @@ import git import requests import tomlkit -from colorama import Fore -from colorama import init as colorama_init +from colorama import Fore, init as colorama_init from dag import DAG, RateLimiter from semver import VersionInfo diff --git a/scripts/ci/publish_wheels.py b/scripts/ci/publish_wheels.py index 6790d2434e95..12216ed841ff 100755 --- a/scripts/ci/publish_wheels.py +++ b/scripts/ci/publish_wheels.py @@ -18,8 +18,7 @@ from pathlib import Path import wheel_utils -from google.cloud.storage import Blob -from google.cloud.storage import Client as Gcs +from google.cloud.storage import Blob, Client as Gcs from packaging.utils import canonicalize_version