core-lens 0.1.dev150__tar.gz → 0.1.dev152__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.dev150 → core_lens-0.1.dev152}/PKG-INFO +1 -1
  2. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/_version.py +2 -2
  3. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/entity.py +16 -1
  4. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/result.py +25 -6
  5. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/ISSUE_TEMPLATE/blank-proposal.yaml +0 -0
  6. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
  7. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
  8. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/pull_request_template.md +0 -0
  9. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/workflows/ci.yml +0 -0
  10. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/workflows/gh-pages.yml +0 -0
  11. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/workflows/pre-release.yml +0 -0
  12. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.github/workflows/release.yml +0 -0
  13. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.gitignore +0 -0
  14. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.gitmessage +0 -0
  15. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.pre-commit-config.yaml +0 -0
  16. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/.python-version +0 -0
  17. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/CONTRIBUTING.md +0 -0
  18. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/LICENSE +0 -0
  19. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/README.md +0 -0
  20. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/SKILLS.md +0 -0
  21. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/README.md +0 -0
  22. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_aoi.py +0 -0
  23. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_export.py +0 -0
  24. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_polars_utils.py +0 -0
  25. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_result.py +0 -0
  26. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_schema.py +0 -0
  27. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_season.py +0 -0
  28. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_spatial.py +0 -0
  29. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/bench_view.py +0 -0
  30. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/benchmarks/run_all.sh +0 -0
  31. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/Makefile +0 -0
  32. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/make.bat +0 -0
  33. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/concepts.md +0 -0
  34. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/conf.py +0 -0
  35. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/export.md +0 -0
  36. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/index.rst +0 -0
  37. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/intro.md +0 -0
  38. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/logging.md +0 -0
  39. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/plots.md +0 -0
  40. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/plugins.md +0 -0
  41. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/queries.md +0 -0
  42. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/quickstart.md +0 -0
  43. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/docs/source/stats.md +0 -0
  44. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/examples/demo_mws.py +0 -0
  45. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/examples/demo_tehsil.py +0 -0
  46. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/hooks/mypy.sh +0 -0
  47. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/hooks/no-parquet-outside-fixtures.sh +0 -0
  48. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/hooks/pytest.sh +0 -0
  49. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/pyproject.toml +0 -0
  50. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/__init__.py +0 -0
  51. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/__main__.py +0 -0
  52. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/aoi.py +0 -0
  53. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/__init__.py +0 -0
  54. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/namespaces/__init__.py +0 -0
  55. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/namespaces/plot.py +0 -0
  56. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/namespaces/stats.py +0 -0
  57. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/base/view.py +0 -0
  58. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/entities/__init__.py +0 -0
  59. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/entities/mws.py +0 -0
  60. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/entities/tehsil.py +0 -0
  61. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/entities/waterbody.py +0 -0
  62. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/export/__init__.py +0 -0
  63. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/export/formats.py +0 -0
  64. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/py.typed +0 -0
  65. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/schema/__init__.py +0 -0
  66. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/schema/detection.py +0 -0
  67. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/schema/profile.py +0 -0
  68. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/utils/__init__.py +0 -0
  69. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/utils/paths.py +0 -0
  70. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/utils/polars_utils.py +0 -0
  71. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/utils/season.py +0 -0
  72. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/src/core_lens/utils/spatial.py +0 -0
  73. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/fixtures/generate_fixtures.py +0 -0
  74. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/conftest.py +0 -0
  75. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_aoi.py +0 -0
  76. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_entities.py +0 -0
  77. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_entity.py +0 -0
  78. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_export.py +0 -0
  79. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_main.py +0 -0
  80. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_plot.py +0 -0
  81. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_polars_utils.py +0 -0
  82. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_profile.py +0 -0
  83. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_result.py +0 -0
  84. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_schema_detection.py +0 -0
  85. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_schema_profile.py +0 -0
  86. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_season.py +0 -0
  87. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_season_config.py +0 -0
  88. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_spatial.py +0 -0
  89. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_stats.py +0 -0
  90. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/tests/unit/test_view.py +0 -0
  91. {core_lens-0.1.dev150 → core_lens-0.1.dev152}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-lens
3
- Version: 0.1.dev150
3
+ Version: 0.1.dev152
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
@@ -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.dev150'
22
- __version_tuple__ = version_tuple = (0, 1, 'dev150')
21
+ __version__ = version = '0.1.dev152'
22
+ __version_tuple__ = version_tuple = (0, 1, 'dev152')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -474,7 +474,22 @@ class BaseEntity(ABC):
474
474
  if attr_kwargs:
475
475
  filter_expr = pl.lit(True)
476
476
  for col, val in attr_kwargs.items():
477
- filter_expr = filter_expr & (pl.col(col) == val)
477
+ dtype = schema[col]
478
+ is_list_col = isinstance(dtype, pl.List) or dtype == pl.List
479
+ is_val_list = isinstance(val, (list, tuple, set))
480
+
481
+ if is_list_col:
482
+ if is_val_list:
483
+ filter_expr = filter_expr & (
484
+ pl.col(col).list.set_intersection(list(val)).list.len() > 0
485
+ )
486
+ else:
487
+ filter_expr = filter_expr & pl.col(col).list.contains(val)
488
+ else:
489
+ if is_val_list:
490
+ filter_expr = filter_expr & pl.col(col).is_in(list(val))
491
+ else:
492
+ filter_expr = filter_expr & (pl.col(col) == val)
478
493
  lf = lf.filter(filter_expr)
479
494
 
480
495
  if not entity_kwargs:
@@ -89,6 +89,14 @@ class Result:
89
89
  """
90
90
  return collect_lf(self.data)
91
91
 
92
+ def materialise(self) -> "Result":
93
+ """Evaluate the lazy computation graph and cache it in memory.
94
+
95
+ Returns:
96
+ Result: A new Result with the data cached as an in-memory LazyFrame.
97
+ """
98
+ return self._replace(data=self.df().lazy())
99
+
92
100
  def gdf(self) -> "gpd.GeoDataFrame":
93
101
  """Return the data as a ``GeoDataFrame``.
94
102
 
@@ -156,13 +164,24 @@ class Result:
156
164
 
157
165
  key_cols = self.key_cols
158
166
 
159
- # We use a direct left join here instead of a semi-join intermediate step.
160
- # A semi-join creates a "diamond" query graph where `self.data` must be evaluated
161
- # twice by Polars. Because `self.data` can be an expensive aggregation pipeline,
162
- # this caused execution times to double.
163
- joined = self.data.join(self.entity.geometry_lazy, on=key_cols, how="left")
167
+ # 1. Evaluate the heavy aggregation graph ONCE to prevent Polars from
168
+ # evaluating it twice during the geometry extraction and join.
169
+ res = self.materialise()
170
+ keys_df = res.df().select(key_cols)
171
+
172
+ # 2. Push down the geometry filter into the Parquet reader using is_in
173
+ # so we don't scan the entire static geometry file (which takes ~0.4s).
174
+ geo_lf = self.entity.geometry_lazy
175
+ if len(key_cols) == 1 and keys_df.height < 50000:
176
+ key = key_cols[0]
177
+ geo_lf = geo_lf.filter(pl.col(key).is_in(keys_df[key]))
178
+ else:
179
+ geo_lf = geo_lf.join(keys_df.lazy(), on=key_cols, how="semi")
180
+
181
+ joined = res.data.join(geo_lf, on=key_cols, how="left")
164
182
 
165
- return self._replace(data=joined, has_geometry=True)
183
+ # 3. Cache the joined geometry so multiple plots are instant.
184
+ return res._replace(data=joined, has_geometry=True).materialise()
166
185
 
167
186
  def derive(self, name: str, expr: pl.Expr) -> "Result":
168
187
  """Return a new ``Result`` with a computed column appended.
File without changes
File without changes
File without changes
File without changes