core-lens 0.1.dev169__tar.gz → 0.1.dev171__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/PKG-INFO +1 -1
  2. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/queries.md +3 -3
  3. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/pyproject.toml +3 -0
  4. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/__init__.py +2 -0
  5. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/__main__.py +12 -0
  6. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/_version.py +2 -2
  7. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/aoi.py +21 -1
  8. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/entity.py +2 -2
  9. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/namespaces/__init__.py +2 -0
  10. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/namespaces/plot.py +26 -0
  11. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/namespaces/stats.py +5 -0
  12. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/result.py +12 -0
  13. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/view.py +15 -0
  14. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/entities/__init__.py +2 -0
  15. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/entities/mws.py +2 -0
  16. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/entities/tehsil.py +2 -0
  17. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/entities/waterbody.py +2 -0
  18. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/export/__init__.py +2 -0
  19. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/export/formats.py +6 -7
  20. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/utils/__init__.py +2 -0
  21. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/utils/polars_utils.py +1 -1
  22. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/ISSUE_TEMPLATE/blank-proposal.yaml +0 -0
  23. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
  24. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
  25. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/pull_request_template.md +0 -0
  26. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/workflows/ci.yml +0 -0
  27. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/workflows/gh-pages.yml +0 -0
  28. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/workflows/pre-release.yml +0 -0
  29. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.github/workflows/release.yml +0 -0
  30. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.gitignore +0 -0
  31. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.gitmessage +0 -0
  32. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.pre-commit-config.yaml +0 -0
  33. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/.python-version +0 -0
  34. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/CONTRIBUTING.md +0 -0
  35. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/LICENSE +0 -0
  36. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/README.md +0 -0
  37. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/SKILLS.md +0 -0
  38. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/README.md +0 -0
  39. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_aoi.py +0 -0
  40. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_export.py +0 -0
  41. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_polars_utils.py +0 -0
  42. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_result.py +0 -0
  43. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_schema.py +0 -0
  44. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_season.py +0 -0
  45. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_spatial.py +0 -0
  46. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/bench_view.py +0 -0
  47. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/benchmarks/run_all.sh +0 -0
  48. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/Makefile +0 -0
  49. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/make.bat +0 -0
  50. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/concepts.md +0 -0
  51. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/conf.py +0 -0
  52. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/export.md +0 -0
  53. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/index.rst +0 -0
  54. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/intro.md +0 -0
  55. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/logging.md +0 -0
  56. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/plots.md +0 -0
  57. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/plugins.md +0 -0
  58. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/quickstart.md +0 -0
  59. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/docs/source/stats.md +0 -0
  60. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/examples/demo_mws.py +0 -0
  61. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/examples/demo_tehsil.py +0 -0
  62. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/hooks/mypy.sh +0 -0
  63. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/hooks/no-parquet-outside-fixtures.sh +0 -0
  64. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/hooks/pytest.sh +0 -0
  65. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/base/__init__.py +0 -0
  66. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/py.typed +0 -0
  67. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/schema/__init__.py +0 -0
  68. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/schema/detection.py +0 -0
  69. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/schema/profile.py +0 -0
  70. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/utils/paths.py +0 -0
  71. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/utils/season.py +0 -0
  72. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/src/core_lens/utils/spatial.py +0 -0
  73. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/fixtures/generate_fixtures.py +0 -0
  74. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/conftest.py +0 -0
  75. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_aoi.py +0 -0
  76. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_entities.py +0 -0
  77. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_entity.py +0 -0
  78. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_export.py +0 -0
  79. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_main.py +0 -0
  80. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_plot.py +0 -0
  81. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_polars_utils.py +0 -0
  82. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_profile.py +0 -0
  83. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_result.py +0 -0
  84. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_schema_detection.py +0 -0
  85. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_schema_profile.py +0 -0
  86. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_season.py +0 -0
  87. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_season_config.py +0 -0
  88. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_spatial.py +0 -0
  89. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_stats.py +0 -0
  90. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/tests/unit/test_view.py +0 -0
  91. {core_lens-0.1.dev169 → core_lens-0.1.dev171}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-lens
3
- Version: 0.1.dev169
3
+ Version: 0.1.dev171
4
4
  Summary: Query, analyse, and visualise CoreStack's microwatershed and Earth science data through a clean, composable Python API.
5
5
  Project-URL: Homepage, https://github.com/ApoorvaKashyap/core-lens
6
6
  Project-URL: Issues, https://github.com/ApoorvaKashyap/core-lens/issues
@@ -54,10 +54,10 @@ joined_view = aoi.mws.spatial_join(
54
54
  }
55
55
  )
56
56
 
57
- # Materialise (Note: spatial join materialisation raises NotImplementedError in this release)
58
- # res = joined_view.annual
57
+ # Materialise the joined view
58
+ res = joined_view.annual
59
59
  ```
60
60
 
61
61
  ```{note}
62
- Cross-entity spatial join execution (materialisation) is currently under development and will be added in a subsequent release. Calling materialisation methods (like `.annual`, `.static`, or `.sub_annual`) on a joined view will raise a `NotImplementedError` in the current version.
62
+ Cross-entity spatial join execution (materialisation) is fully supported. Calling materialisation methods (like `.annual`, `.static`, or `.sub_annual`) on a joined view will evaluate the deferred join and execute it.
63
63
  ```
@@ -139,3 +139,6 @@ ignore = [
139
139
  [tool.ruff.lint.per-file-ignores]
140
140
  "tests/*" = ["S"]
141
141
  "examples/*" = ["S"]
142
+
143
+ [tool.ruff.lint.pydocstyle]
144
+ convention = "google"
@@ -1,3 +1,5 @@
1
+ """Core Lens package."""
2
+
1
3
  try:
2
4
  from ._version import __version__
3
5
  except ImportError:
@@ -1,7 +1,14 @@
1
+ """Module for Core Lens."""
2
+
1
3
  from . import __version__
2
4
 
3
5
 
4
6
  def hello() -> str:
7
+ """Return hello message.
8
+
9
+ Returns:
10
+ A welcome string describing core-lens capabilities.
11
+ """
5
12
  hello_str = """Hello from core-lens!
6
13
 
7
14
  The following primary capabilities are available:
@@ -28,6 +35,11 @@ Visualisation (via `result.plot`):
28
35
 
29
36
 
30
37
  def version() -> str:
38
+ """Return version string.
39
+
40
+ Returns:
41
+ The current core-lens package version.
42
+ """
31
43
  return str(__version__)
32
44
 
33
45
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.1.dev169'
22
- __version_tuple__ = version_tuple = (0, 1, 'dev169')
21
+ __version__ = version = '0.1.dev171'
22
+ __version_tuple__ = version_tuple = (0, 1, 'dev171')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -56,6 +56,13 @@ class SeasonConfig:
56
56
  zaid: tuple[str, str] = ("04-01", "06-30")
57
57
 
58
58
  def __post_init__(self) -> None:
59
+ """Initialize after dataclass creation.
60
+
61
+ Validates that all configured seasons have valid MM-DD ranges.
62
+
63
+ Raises:
64
+ ValueError: If a season date format is invalid.
65
+ """
59
66
  from datetime import datetime
60
67
 
61
68
  for attr in ("kharif", "rabi", "zaid"):
@@ -151,7 +158,7 @@ def _cached_resolve_boundary(
151
158
  storage_options_key: tuple[tuple[str, Any], ...],
152
159
  entity_kwargs_key: tuple[tuple[str, Any], ...],
153
160
  ) -> tuple[bytes, str, tuple[tuple[Any, ...], ...]]:
154
- """Cached boundary resolution: return ``(geometry_wkb, entity_name, key_rows)``.
161
+ """Return cached boundary resolution: ``(geometry_wkb, entity_name, key_rows)``.
155
162
 
156
163
  All arguments must be hashable. ``entity_kwargs`` must be converted to a
157
164
  sorted tuple of ``(key, value)`` pairs before calling this function.
@@ -542,6 +549,19 @@ class AoI:
542
549
  self._get_entity(name)
543
550
 
544
551
  def __getattr__(self, name: str) -> "View":
552
+ """Get view by entity name.
553
+
554
+ Resolves and caches a scoped view for a registered entity on first access.
555
+
556
+ Args:
557
+ name: The registered entity name (e.g. 'mws').
558
+
559
+ Returns:
560
+ The scoped View for the entity.
561
+
562
+ Raises:
563
+ AttributeError: If the entity is not registered.
564
+ """
545
565
  # Called only when normal attribute lookup has already failed, so this
546
566
  # never shadows real attributes. Maps entity names to their scoped Views.
547
567
  if name in _REGISTRY:
@@ -80,7 +80,7 @@ def _cached_detect(
80
80
  sub_annual_path: str | None,
81
81
  storage_options_key: tuple[tuple[str, Any], ...],
82
82
  ) -> "SchemaProfile":
83
- """Cached wrapper around :func:`~core_lens.schema.detection.detect`.
83
+ """Wrap :func:`~core_lens.schema.detection.detect` with caching.
84
84
 
85
85
  All arguments must be hashable so they can form the cache key. Pass
86
86
  ``storage_options`` through :func:`_so_key` before calling this function.
@@ -110,7 +110,7 @@ def _cached_build_index(
110
110
  geometry_type: str,
111
111
  storage_options_key: tuple[tuple[str, Any], ...],
112
112
  ) -> pl.DataFrame:
113
- """Cached wrapper around :func:`~core_lens.utils.spatial.build_bbox_index`.
113
+ """Wrap :func:`~core_lens.utils.spatial.build_bbox_index` with caching.
114
114
 
115
115
  All arguments must be hashable so they can form the cache key. Pass
116
116
  ``storage_options`` through :func:`_so_key` before calling this function.
@@ -1,3 +1,5 @@
1
+ """Core Lens package."""
2
+
1
3
  __module__: str = "core_lens.base.namespaces"
2
4
 
3
5
  from core_lens.base.namespaces.plot import PlotNamespace
@@ -231,6 +231,17 @@ class MapWithLegend:
231
231
  clamped_min: bool = False,
232
232
  clamped_max: bool = False,
233
233
  ) -> None:
234
+ """Initialize MapWithLegend.
235
+
236
+ Args:
237
+ map_widget: The underlying Lonboard map instance.
238
+ cmap: The colormap applied to the map.
239
+ v_min: Minimum value of the color scale.
240
+ v_max: Maximum value of the color scale.
241
+ column_name: Name of the visualized column.
242
+ clamped_min: True if values below v_min were clamped.
243
+ clamped_max: True if values above v_max were clamped.
244
+ """
234
245
  self._map = map_widget
235
246
  self._cmap = cmap
236
247
  self._v_min = v_min
@@ -240,6 +251,14 @@ class MapWithLegend:
240
251
  self._clamped_max = clamped_max
241
252
 
242
253
  def __getattr__(self, name: str) -> Any:
254
+ """Get map attribute.
255
+
256
+ Args:
257
+ name: The attribute name to look up on the underlying map.
258
+
259
+ Returns:
260
+ The requested attribute from the map widget.
261
+ """
243
262
  return getattr(self._map, name)
244
263
 
245
264
  def _generate_legend_div(self, absolute: bool = True) -> str:
@@ -336,6 +355,11 @@ class PlotNamespace:
336
355
  """
337
356
 
338
357
  def __init__(self, result: "Result") -> None:
358
+ """Initialize PlotNamespace.
359
+
360
+ Args:
361
+ result: The parent Result object this namespace is bound to.
362
+ """
339
363
  self.result = result
340
364
 
341
365
  def choropleth(
@@ -355,6 +379,8 @@ class PlotNamespace:
355
379
  subplot_on (SubplotOn | None, optional): Optional temporal dimension to split data across.
356
380
  A :class:`~core_lens.base.namespaces.plot.SubplotOn` enum value. When set, one layer is rendered per unique
357
381
  value of ``subplot_on`` in the data.
382
+ v_min (float | None, optional): Minimum value for color scale.
383
+ v_max (float | None, optional): Maximum value for color scale.
358
384
 
359
385
  Returns:
360
386
  lonboard.Map: A Lonboard Map object.
@@ -158,6 +158,11 @@ class StatsNamespace:
158
158
  """
159
159
 
160
160
  def __init__(self, result: "Result") -> None:
161
+ """Initialize StatsNamespace.
162
+
163
+ Args:
164
+ result: The parent Result object this namespace is bound to.
165
+ """
161
166
  self._r = result
162
167
 
163
168
  def _numeric_cols(self, df: pl.DataFrame) -> list[str]:
@@ -67,6 +67,17 @@ class Result:
67
67
  entity: "BaseEntity",
68
68
  metadata: dict[str, Any] | None = None,
69
69
  ) -> None:
70
+ """Initialize Result.
71
+
72
+ Args:
73
+ data: The underlying dataframe or lazyframe.
74
+ resolution: The spatial and temporal resolution of the data.
75
+ has_geometry: True if the geometry column is populated.
76
+ key_cols: Primary key columns linking back to the entity.
77
+ entity_name: Registered name of the parent entity.
78
+ entity: The BaseEntity object that produced this result.
79
+ metadata: Additional metadata dictionary to store.
80
+ """
70
81
  self.data = data.lazy() if isinstance(data, pl.DataFrame) else data
71
82
  self.resolution = resolution
72
83
  self.has_geometry = has_geometry
@@ -94,6 +105,7 @@ class Result:
94
105
 
95
106
  Returns:
96
107
  Result: A new Result with the data cached as an in-memory LazyFrame.
108
+
97
109
  """
98
110
  return self._replace(data=self.df().lazy())
99
111
 
@@ -24,6 +24,11 @@ if TYPE_CHECKING:
24
24
 
25
25
 
26
26
  class Season(Enum):
27
+ """Season enum.
28
+
29
+ Enumerates standard agronomic seasons used across Core Lens for temporal filtering.
30
+ """
31
+
27
32
  KHARIF = "kharif"
28
33
  RABI = "rabi"
29
34
  ZAID = "zaid"
@@ -78,6 +83,16 @@ class View:
78
83
  join_spec: dict[str, Any] | None = None,
79
84
  season_config: SeasonConfig | None = None,
80
85
  ) -> None:
86
+ """Initialize View.
87
+
88
+ Args:
89
+ keys: Polars LazyFrame or DataFrame containing the resolved IDs.
90
+ entity: Parent BaseEntity instance defining the schema and paths.
91
+ entity_name: Registered string name of the entity.
92
+ time_filter: Active time filter conditions, if any.
93
+ join_spec: Active spatial join spec, if any.
94
+ season_config: Optional season date configuration overrides.
95
+ """
81
96
  self.keys = keys.lazy() if isinstance(keys, pl.DataFrame) else keys
82
97
  self.entity = entity
83
98
  self.entity_name = entity_name
@@ -1,3 +1,5 @@
1
+ """Core Lens package."""
2
+
1
3
  __module__: str = "core_lens.entities"
2
4
 
3
5
  from core_lens.entities.tehsil import TehsilEntity
@@ -1,3 +1,5 @@
1
+ """Module for Core Lens."""
2
+
1
3
  from core_lens.base.entity import BaseEntity
2
4
 
3
5
 
@@ -1,3 +1,5 @@
1
+ """Module for Core Lens."""
2
+
1
3
  from core_lens.base.entity import BaseEntity
2
4
  from core_lens.schema.profile import SchemaProfile
3
5
 
@@ -1,3 +1,5 @@
1
+ """Module for Core Lens."""
2
+
1
3
  from core_lens.base.entity import BaseEntity
2
4
 
3
5
 
@@ -1,3 +1,5 @@
1
+ """Core Lens package."""
2
+
1
3
  __module__: str = "core_lens.export"
2
4
 
3
5
  from core_lens.export.formats import csv, geojson, geoparquet, json, parquet
@@ -1,3 +1,5 @@
1
+ """Module for Core Lens."""
2
+
1
3
  import pathlib
2
4
  from typing import TYPE_CHECKING, Any
3
5
 
@@ -166,17 +168,14 @@ def geoparquet(result: "Result", path: str | pathlib.Path, **kwargs: Any) -> Non
166
168
  def geojson(result: "Result", path: str | pathlib.Path, **kwargs: Any) -> None:
167
169
  """Export the result data to a GeoJSON file.
168
170
 
169
- This function uses GeoPandas to write the data frame. It prefers the
170
- ``pyogrio`` engine (faster, C-backed) when available and falls back to
171
- ``fiona`` automatically. The ``engine`` kwarg can override this:
172
- ``engine="fiona"`` or ``engine="pyogrio"``.
171
+ This function natively streams the data directly from Polars and Shapely
172
+ without invoking GDAL or DuckDB, making it fast for large datasets.
173
173
 
174
174
  Args:
175
175
  result (Result): The Result object to export.
176
176
  path (str | pathlib.Path): Destination path for the GeoJSON file.
177
- **kwargs (Any): Additional options forwarded to
178
- ``GeoDataFrame.to_file()`` (e.g. ``driver="GeoJSON"``,
179
- ``engine="pyogrio"``).
177
+ **kwargs (Any): Driver-specific kwargs are currently ignored.
178
+ The `driver` keyword argument supports `GeoJSONSeq` for newline-delimited GeoJSON.
180
179
 
181
180
  Example:
182
181
  >>> from core_lens.export import geojson
@@ -1 +1,3 @@
1
+ """Core Lens package."""
2
+
1
3
  __module__: str = "core_lens.utils"
@@ -22,7 +22,7 @@ def _cached_schema_internal(path: str, so_key: tuple[tuple[str, Any], ...]) -> A
22
22
 
23
23
 
24
24
  def cached_read_schema(path: str, storage_options: dict[str, Any] | None = None) -> Any:
25
- """Cached wrapper around pl.read_parquet_schema.
25
+ """Wrap pl.read_parquet_schema with caching.
26
26
 
27
27
  Avoids repeated Parquet footer reads for schema resolution in hot paths.
28
28
  """
File without changes
File without changes
File without changes
File without changes