0.1.8
Loading...
Searching...
No Matches
plugin_decorators.py
Go to the documentation of this file.
1"""
2Validation decorators for PyHelios plugin methods.
3
4This module provides validation decorators that ensure parameter validation
5for all plugin methods, maintaining consistency across the PyHelios API.
6"""
7
8from functools import wraps
9from typing import Any, Callable, List, Optional, Union
10from .plugins import (
11 validate_band_label, validate_source_id, validate_source_id_list,
12 validate_flux_value, validate_ray_count, validate_direction_vector,
13 validate_angle_degrees, validate_scaling_factor, validate_uuid_list,
14 validate_tree_id, validate_segment_resolution, validate_filename,
15 validate_recursion_level, validate_subdivision_count, validate_time_value,
16 # Photosynthesis validation functions
17 validate_species_name, validate_temperature, validate_co2_concentration,
18 validate_photosynthetic_rate, validate_conductance, validate_par_flux,
19 validate_empirical_coefficients, validate_farquhar_coefficients,
20 validate_vcmax, validate_jmax, validate_quantum_efficiency, validate_dark_respiration,
21 validate_oxygen_concentration, validate_temperature_response_params,
22 # Camera validation functions
23 validate_camera_label, validate_band_labels_list, validate_antialiasing_samples
24)
25from .datatypes import validate_vec3, validate_rgb_color
26from .core import validate_positive_value, validate_non_negative_value
27
28
29# RadiationModel decorators
30def validate_radiation_band_params(func: Callable) -> Callable:
31 """Validate parameters for radiation band operations."""
32 @wraps(func)
33 def wrapper(self, old_label: str, new_label: str, *args, **kwargs):
34 validate_band_label(old_label, "old_label", func.__name__)
35 validate_band_label(new_label, "new_label", func.__name__)
36 return func(self, old_label, new_label, *args, **kwargs)
37 return wrapper
38
39
40def validate_collimated_source_params(func: Callable) -> Callable:
41 """Validate parameters for collimated radiation source creation."""
42 @wraps(func)
43 def wrapper(self, direction=None, *args, **kwargs):
44 if direction is not None:
45 # RadiationModel handles multiple types (vec3, SphericalCoord, tuple)
46 # Let the method handle type conversion, but validate if it's vec3-like
47 if hasattr(direction, 'x') and hasattr(direction, 'y') and hasattr(direction, 'z'):
48 validate_direction_vector(direction, "direction", func.__name__)
49 return func(self, direction, *args, **kwargs)
50 return wrapper
51
52
53def validate_sphere_source_params(func: Callable) -> Callable:
54 """Validate parameters for sphere radiation source creation."""
55 @wraps(func)
56 def wrapper(self, position, radius: float, *args, **kwargs):
57 validate_vec3(position, "position", func.__name__)
58 validate_positive_value(radius, "radius", func.__name__)
59 return func(self, position, radius, *args, **kwargs)
60 return wrapper
61
62
63def validate_sun_sphere_params(func: Callable) -> Callable:
64 """Validate parameters for sun sphere radiation source."""
65 @wraps(func)
66 def wrapper(self, radius: float, zenith: float, azimuth: float,
67 position_scaling: float = 1.0, angular_width: float = 0.53,
68 flux_scaling: float = 1.0, *args, **kwargs):
69 validate_positive_value(radius, "radius", func.__name__)
70 validate_angle_degrees(zenith, "zenith", func.__name__)
71 validate_angle_degrees(azimuth, "azimuth", func.__name__)
72 validate_scaling_factor(position_scaling, param_name="position_scaling", function_name=func.__name__)
73 validate_positive_value(angular_width, "angular_width", func.__name__)
74 validate_scaling_factor(flux_scaling, param_name="flux_scaling", function_name=func.__name__)
75 return func(self, radius, zenith, azimuth, position_scaling, angular_width, flux_scaling, *args, **kwargs)
76 return wrapper
77
78
79def validate_source_flux_multiple_params(func: Callable) -> Callable:
80 """Validate parameters for setting multiple source flux."""
81 @wraps(func)
82 def wrapper(self, source_ids: List[int], label: str, flux: float, *args, **kwargs):
83 validate_source_id_list(source_ids, "source_ids", func.__name__)
84 validate_band_label(label, "label", func.__name__)
85 validate_flux_value(flux, "flux", func.__name__)
86 return func(self, source_ids, label, flux, *args, **kwargs)
87 return wrapper
88
89
90def validate_get_source_flux_params(func: Callable) -> Callable:
91 """Validate parameters for getting source flux."""
92 @wraps(func)
93 def wrapper(self, source_id: int, label: str, *args, **kwargs):
94 validate_source_id(source_id, "source_id", func.__name__)
95 validate_band_label(label, "label", func.__name__)
96 return func(self, source_id, label, *args, **kwargs)
97 return wrapper
98
99
100def validate_update_geometry_params(func: Callable) -> Callable:
101 """Validate parameters for geometry updates."""
102 @wraps(func)
103 def wrapper(self, uuids: Optional[List[int]] = None, *args, **kwargs):
104 if uuids is not None:
105 validate_uuid_list(uuids, "uuids", func.__name__, allow_empty=True)
106 return func(self, uuids, *args, **kwargs)
107 return wrapper
108
109
110def validate_run_band_params(func: Callable) -> Callable:
111 """Validate parameters for running radiation bands."""
112 @wraps(func)
113 def wrapper(self, band_label: Union[str, List[str]], *args, **kwargs):
114 if isinstance(band_label, str):
115 validate_band_label(band_label, "band_label", func.__name__)
116 elif isinstance(band_label, list):
117 if not band_label:
118 from .exceptions import create_validation_error
119 raise create_validation_error(
120 f"Parameter cannot be empty",
121 param_name="band_label",
122 function_name=func.__name__,
123 expected_type="non-empty list",
124 actual_value=band_label,
125 suggestion="Provide at least one band label."
126 )
127 for i, label in enumerate(band_label):
128 validate_band_label(label, f"band_label[{i}]", func.__name__)
129 else:
130 from .exceptions import create_validation_error
131 raise create_validation_error(
132 f"Parameter must be a string or list of strings, got {type(band_label).__name__}",
133 param_name="band_label",
134 function_name=func.__name__,
135 expected_type="string or list of strings",
136 actual_value=band_label,
137 suggestion="Provide a band label string or list of band labels."
138 )
139 return func(self, band_label, *args, **kwargs)
140 return wrapper
141
142
143def validate_scattering_depth_params(func: Callable) -> Callable:
144 """Validate parameters for scattering depth."""
145 @wraps(func)
146 def wrapper(self, label: str, depth: int, *args, **kwargs):
147 validate_band_label(label, "label", func.__name__)
148 if not isinstance(depth, int):
149 from .exceptions import create_validation_error
150 raise create_validation_error(
151 f"Parameter must be an integer, got {type(depth).__name__}",
152 param_name="depth",
153 function_name=func.__name__,
154 expected_type="integer",
155 actual_value=depth,
156 suggestion="Scattering depth must be an integer."
157 )
158 validate_non_negative_value(depth, "depth", func.__name__)
159 return func(self, label, depth, *args, **kwargs)
160 return wrapper
161
162
163def validate_min_scatter_energy_params(func: Callable) -> Callable:
164 """Validate parameters for minimum scatter energy."""
165 @wraps(func)
166 def wrapper(self, label: str, energy: float, *args, **kwargs):
167 validate_band_label(label, "label", func.__name__)
168 validate_positive_value(energy, "energy", func.__name__)
169 return func(self, label, energy, *args, **kwargs)
170 return wrapper
171
172
173# WeberPennTree decorators
174def validate_tree_uuid_params(func: Callable) -> Callable:
175 """Validate tree ID parameters for WeberPennTree methods."""
176 @wraps(func)
177 def wrapper(self, tree_id: int, *args, **kwargs):
178 validate_tree_id(tree_id, "tree_id", func.__name__)
179 return func(self, tree_id, *args, **kwargs)
180 return wrapper
181
182
183def validate_recursion_params(func: Callable) -> Callable:
184 """Validate recursion level parameters."""
185 @wraps(func)
186 def wrapper(self, level: int, *args, **kwargs):
187 validate_recursion_level(level, "level", func.__name__)
188 return func(self, level, *args, **kwargs)
189 return wrapper
190
191
192def validate_trunk_segment_params(func: Callable) -> Callable:
193 """Validate trunk segment resolution parameters."""
194 @wraps(func)
195 def wrapper(self, trunk_segs: int, *args, **kwargs):
196 validate_segment_resolution(trunk_segs, min_val=3, max_val=100, param_name="trunk_segs", function_name=func.__name__)
197 return func(self, trunk_segs, *args, **kwargs)
198 return wrapper
199
200
201def validate_branch_segment_params(func: Callable) -> Callable:
202 """Validate branch segment resolution parameters."""
203 @wraps(func)
204 def wrapper(self, branch_segs: int, *args, **kwargs):
205 validate_segment_resolution(branch_segs, min_val=3, max_val=100, param_name="branch_segs", function_name=func.__name__)
206 return func(self, branch_segs, *args, **kwargs)
207 return wrapper
208
209
210def validate_leaf_subdivisions_params(func: Callable) -> Callable:
211 """Validate leaf subdivision parameters."""
212 @wraps(func)
213 def wrapper(self, leaf_segs_x: int, leaf_segs_y: int, *args, **kwargs):
214 validate_subdivision_count(leaf_segs_x, "leaf_segs_x", func.__name__)
215 validate_subdivision_count(leaf_segs_y, "leaf_segs_y", func.__name__)
216 return func(self, leaf_segs_x, leaf_segs_y, *args, **kwargs)
217 return wrapper
218
219
220# EnergyBalance decorators
221def validate_energy_run_params(func: Callable) -> Callable:
222 """Validate parameters for energy balance run method."""
223 @wraps(func)
224 def wrapper(self, uuids: Optional[List[int]] = None, dt: Optional[float] = None, *args, **kwargs):
225 if uuids is not None:
226 validate_uuid_list(uuids, "uuids", func.__name__, allow_empty=False)
227 if dt is not None:
228 validate_positive_value(dt, "dt", func.__name__)
229 return func(self, uuids, dt, *args, **kwargs)
230 return wrapper
231
232
233def validate_energy_band_params(func: Callable) -> Callable:
234 """Validate parameters for energy balance band operations."""
235 @wraps(func)
236 def wrapper(self, band: Union[str, List[str]], *args, **kwargs):
237 if isinstance(band, str):
238 if not band.strip():
239 from .exceptions import create_validation_error
240 raise create_validation_error(
241 f"Parameter must be a non-empty string",
242 param_name="band",
243 function_name=func.__name__,
244 expected_type="non-empty string",
245 actual_value=repr(band),
246 suggestion="Provide a non-empty band name."
247 )
248 elif isinstance(band, list):
249 if not band:
250 from .exceptions import create_validation_error
251 raise create_validation_error(
252 f"Parameter cannot be empty",
253 param_name="band",
254 function_name=func.__name__,
255 expected_type="non-empty list",
256 actual_value=band,
257 suggestion="Provide at least one band name."
258 )
259 for i, b in enumerate(band):
260 if not isinstance(b, str) or not b.strip():
261 from .exceptions import create_validation_error
262 raise create_validation_error(
263 f"All band names must be non-empty strings, got {type(b).__name__} at index {i}",
264 param_name=f"band[{i}]",
265 function_name=func.__name__,
266 expected_type="non-empty string",
267 actual_value=b,
268 suggestion="All band names must be non-empty strings."
269 )
270 else:
271 from .exceptions import create_validation_error
272 raise create_validation_error(
273 f"Parameter must be a string or list of strings, got {type(band).__name__}",
274 param_name="band",
275 function_name=func.__name__,
276 expected_type="string or list of strings",
277 actual_value=band,
278 suggestion="Provide a band name string or list of band names."
279 )
280 return func(self, band, *args, **kwargs)
281 return wrapper
282
283
284def validate_air_energy_params(func: Callable) -> Callable:
285 """Validate parameters for air energy balance."""
286 @wraps(func)
287 def wrapper(self, canopy_height_m: Optional[float] = None, reference_height_m: Optional[float] = None, *args, **kwargs):
288 if canopy_height_m is not None:
289 validate_positive_value(canopy_height_m, "canopy_height_m", func.__name__)
290 if reference_height_m is not None:
291 validate_positive_value(reference_height_m, "reference_height_m", func.__name__)
292
293 # Check that both parameters are provided together or neither
294 if (canopy_height_m is None) != (reference_height_m is None):
295 from .exceptions import create_validation_error
296 raise create_validation_error(
297 f"Canopy height and reference height must be provided together or omitted together",
298 param_name="canopy_height_m, reference_height_m",
299 function_name=func.__name__,
300 expected_type="both parameters provided or both None",
301 actual_value=f"canopy_height_m={canopy_height_m}, reference_height_m={reference_height_m}",
302 suggestion="Provide both canopy_height_m and reference_height_m, or omit both for automatic detection."
303 )
304
305 return func(self, canopy_height_m, reference_height_m, *args, **kwargs)
306 return wrapper
307
308
309def validate_evaluate_air_energy_params(func: Callable) -> Callable:
310 """Validate parameters for evaluating air energy balance."""
311 @wraps(func)
312 def wrapper(self, dt_sec: float, time_advance_sec: float, UUIDs: Optional[List[int]] = None, *args, **kwargs):
313 validate_time_value(dt_sec, "dt_sec", func.__name__)
314 validate_time_value(time_advance_sec, "time_advance_sec", func.__name__)
315
316 if time_advance_sec < dt_sec:
317 from .exceptions import create_validation_error
318 raise create_validation_error(
319 f"Time advance ({time_advance_sec}) must be greater than or equal to time step ({dt_sec})",
320 param_name="time_advance_sec",
321 function_name=func.__name__,
322 expected_type=f"number >= {dt_sec}",
323 actual_value=time_advance_sec,
324 suggestion=f"Use time_advance_sec >= {dt_sec}."
325 )
326
327 if UUIDs is not None:
328 validate_uuid_list(UUIDs, "UUIDs", func.__name__, allow_empty=False)
329
330 return func(self, dt_sec, time_advance_sec, UUIDs, *args, **kwargs)
331 return wrapper
332
333
334def validate_output_data_params(func: Callable) -> Callable:
335 """Validate parameters for optional output data."""
336 @wraps(func)
337 def wrapper(self, label: str, *args, **kwargs):
338 if not isinstance(label, str):
339 from .exceptions import create_validation_error
340 raise create_validation_error(
341 f"Parameter must be a string, got {type(label).__name__}",
342 param_name="label",
343 function_name=func.__name__,
344 expected_type="string",
345 actual_value=label,
346 suggestion="Provide a string label for the output data."
347 )
348 if not label.strip():
349 from .exceptions import create_validation_error
350 raise create_validation_error(
351 f"Parameter cannot be empty or whitespace-only",
352 param_name="label",
353 function_name=func.__name__,
354 expected_type="non-empty string",
355 actual_value=repr(label),
356 suggestion="Provide a non-empty label for the output data."
357 )
358 return func(self, label, *args, **kwargs)
359 return wrapper
360
361
362def validate_print_report_params(func: Callable) -> Callable:
363 """Validate parameters for print report methods."""
364 @wraps(func)
365 def wrapper(self, UUIDs: Optional[List[int]] = None, *args, **kwargs):
366 if UUIDs is not None:
367 validate_uuid_list(UUIDs, "UUIDs", func.__name__, allow_empty=False)
368 return func(self, UUIDs, *args, **kwargs)
369 return wrapper
370
371
372# Visualizer decorators
373def validate_build_geometry_params(func: Callable) -> Callable:
374 """Validate parameters for building visualizer geometry."""
375 @wraps(func)
376 def wrapper(self, context, uuids: Optional[List[int]] = None, *args, **kwargs):
377 # Context validation - check it's the right type
378 # Use both isinstance and string-based checking to handle import ordering issues
379 from ..Context import Context
380 is_valid_context = (
381 isinstance(context, Context) or
382 (hasattr(context, '__class__') and
383 context.__class__.__name__ == 'Context' and
384 'pyhelios.Context' in context.__class__.__module__)
385 )
386
387 if not is_valid_context:
388 from .exceptions import create_validation_error
389 raise create_validation_error(
390 f"Parameter must be a Context instance, got {type(context).__name__}",
391 param_name="context",
392 function_name=func.__name__,
393 expected_type="Context",
394 actual_value=context,
395 suggestion="Provide a valid PyHelios Context instance."
396 )
397
398 if uuids is not None:
399 validate_uuid_list(uuids, "uuids", func.__name__, allow_empty=True)
400 return func(self, context, uuids, *args, **kwargs)
401 return wrapper
402
403
404def validate_print_window_params(func: Callable) -> Callable:
405 """Validate parameters for printing window to file."""
406 @wraps(func)
407 def wrapper(self, filename: str, *args, **kwargs):
408 validate_filename(filename, "filename", func.__name__,
409 allowed_extensions=['.png', '.jpg', '.jpeg', '.bmp', '.tga'])
410 return func(self, filename, *args, **kwargs)
411 return wrapper
412
413
414# Photosynthesis decorators
415def validate_photosynthesis_species_params(func: Callable) -> Callable:
416 """Validate photosynthesis species parameters."""
417 @wraps(func)
418 def wrapper(self, species: str, *args, **kwargs):
419 validate_species_name(species, "species", func.__name__)
420 return func(self, species, *args, **kwargs)
421 return wrapper
422
423
424def validate_photosynthesis_temperature_params(func: Callable) -> Callable:
425 """Validate temperature parameters for photosynthesis."""
426 @wraps(func)
427 def wrapper(self, temperature: float, *args, **kwargs):
428 validate_temperature(temperature, "temperature", func.__name__)
429 return func(self, temperature, *args, **kwargs)
430 return wrapper
431
432
433def validate_photosynthesis_co2_params(func: Callable) -> Callable:
434 """Validate CO2 concentration parameters."""
435 @wraps(func)
436 def wrapper(self, co2_concentration: float, *args, **kwargs):
437 validate_co2_concentration(co2_concentration, "co2_concentration", func.__name__)
438 return func(self, co2_concentration, *args, **kwargs)
439 return wrapper
440
441
442def validate_photosynthesis_par_params(func: Callable) -> Callable:
443 """Validate PAR flux parameters."""
444 @wraps(func)
445 def wrapper(self, par_flux: float, *args, **kwargs):
446 validate_par_flux(par_flux, "par_flux", func.__name__)
447 return func(self, par_flux, *args, **kwargs)
448 return wrapper
449
450
451def validate_photosynthesis_conductance_params(func: Callable) -> Callable:
452 """Validate conductance parameters."""
453 @wraps(func)
454 def wrapper(self, conductance: float, *args, **kwargs):
455 validate_conductance(conductance, "conductance", func.__name__)
456 return func(self, conductance, *args, **kwargs)
457 return wrapper
458
459
460def validate_empirical_model_params(func: Callable) -> Callable:
461 """Validate empirical model coefficient parameters."""
462 @wraps(func)
463 def wrapper(self, coefficients, *args, **kwargs):
464 validate_empirical_coefficients(coefficients, "coefficients", func.__name__)
465 return func(self, coefficients, *args, **kwargs)
466 return wrapper
467
468
469def validate_farquhar_model_params(func: Callable) -> Callable:
470 """Validate Farquhar model coefficient parameters."""
471 @wraps(func)
472 def wrapper(self, coefficients, *args, **kwargs):
473 validate_farquhar_coefficients(coefficients, "coefficients", func.__name__)
474 return func(self, coefficients, *args, **kwargs)
475 return wrapper
476
477
478def validate_vcmax_params(func: Callable) -> Callable:
479 """Validate Vcmax parameters for Farquhar model."""
480 @wraps(func)
481 def wrapper(self, vcmax: float, *args, **kwargs):
482 validate_vcmax(vcmax, "vcmax", func.__name__)
483 return func(self, vcmax, *args, **kwargs)
484 return wrapper
485
486
487def validate_jmax_params(func: Callable) -> Callable:
488 """Validate Jmax parameters for Farquhar model."""
489 @wraps(func)
490 def wrapper(self, jmax: float, *args, **kwargs):
491 validate_jmax(jmax, "jmax", func.__name__)
492 return func(self, jmax, *args, **kwargs)
493 return wrapper
494
495
496def validate_quantum_efficiency_params(func: Callable) -> Callable:
497 """Validate quantum efficiency parameters."""
498 @wraps(func)
499 def wrapper(self, efficiency: float, *args, **kwargs):
500 validate_quantum_efficiency(efficiency, "efficiency", func.__name__)
501 return func(self, efficiency, *args, **kwargs)
502 return wrapper
503
504
505def validate_dark_respiration_params(func: Callable) -> Callable:
506 """Validate dark respiration parameters."""
507 @wraps(func)
508 def wrapper(self, respiration: float, *args, **kwargs):
509 validate_dark_respiration(respiration, "respiration", func.__name__)
510 return func(self, respiration, *args, **kwargs)
511 return wrapper
512
513
514def validate_oxygen_concentration_params(func: Callable) -> Callable:
515 """Validate oxygen concentration parameters."""
516 @wraps(func)
517 def wrapper(self, o2_concentration: float, *args, **kwargs):
518 validate_oxygen_concentration(o2_concentration, "o2_concentration", func.__name__)
519 return func(self, o2_concentration, *args, **kwargs)
520 return wrapper
521
522
523def validate_temperature_response_params(func: Callable) -> Callable:
524 """Validate temperature response parameters."""
525 @wraps(func)
526 def wrapper(self, params, *args, **kwargs):
527 validate_temperature_response_params(params, "params", func.__name__)
528 return func(self, params, *args, **kwargs)
529 return wrapper
530
531
532def validate_photosynthesis_rate_params(func: Callable) -> Callable:
533 """Validate photosynthetic rate parameters."""
534 @wraps(func)
535 def wrapper(self, rate: float, *args, **kwargs):
536 validate_photosynthetic_rate(rate, "rate", func.__name__)
537 return func(self, rate, *args, **kwargs)
538 return wrapper
539
540
541def validate_photosynthesis_uuid_params(func: Callable) -> Callable:
542 """Validate UUID parameters for photosynthesis methods."""
543 @wraps(func)
544 def wrapper(self, uuids: Union[List[int], int], *args, **kwargs):
545 if isinstance(uuids, int):
546 # Single UUID - validate as non-negative integer (UUIDs start from 0)
547 validate_non_negative_value(uuids, "uuids", func.__name__)
548 elif isinstance(uuids, list):
549 validate_uuid_list(uuids, "uuids", func.__name__, allow_empty=False)
550 else:
551 from .exceptions import create_validation_error
552 raise create_validation_error(
553 f"Parameter must be an integer or list of integers, got {type(uuids).__name__}",
554 param_name="uuids",
555 function_name=func.__name__,
556 expected_type="integer or list of integers",
557 actual_value=uuids,
558 suggestion="Provide a UUID (integer) or list of UUIDs."
559 )
560 return func(self, uuids, *args, **kwargs)
561 return wrapper
562
563
564def validate_radiation_camera_params(func: Callable) -> Callable:
565 """
566 Validate parameters for addRadiationCamera method.
567
568 Handles validation and type conversion for camera creation parameters:
569 - camera_label: string validation
570 - band_labels: list of strings validation
571 - position: converts lists/tuples to vec3 if needed
572 - lookat_or_direction: handles vec3 or SphericalCoord
573 - antialiasing_samples: positive integer validation
574 """
575 @wraps(func)
576 def wrapper(self, camera_label, band_labels, position, lookat_or_direction,
577 camera_properties=None, antialiasing_samples: int = 100, *args, **kwargs):
578 from ..wrappers.DataTypes import vec3, SphericalCoord, make_vec3
579
580 # Validate basic parameters
581 validated_label = validate_camera_label(camera_label, "camera_label", func.__name__)
582 validated_bands = validate_band_labels_list(band_labels, "band_labels", func.__name__)
583 validated_samples = validate_antialiasing_samples(antialiasing_samples, "antialiasing_samples", func.__name__)
584
585 # Validate and convert position to vec3
586 validated_position = validate_vec3(position, "position", func.__name__)
587
588 # Validate lookat_or_direction (can be vec3, list/tuple, or SphericalCoord)
589 validated_direction = None
590 if hasattr(lookat_or_direction, 'radius') and hasattr(lookat_or_direction, 'elevation'):
591 # SphericalCoord - validate directly (already proper type)
592 validated_direction = lookat_or_direction
593 else:
594 # Assume vec3 or convertible to vec3
595 validated_direction = validate_vec3(lookat_or_direction, "lookat_or_direction", func.__name__)
596
597 # Validate camera properties if provided
598 if camera_properties is not None:
599 if not hasattr(camera_properties, 'to_array'):
600 from ..validation.exceptions import create_validation_error
601 raise create_validation_error(
602 f"camera_properties must be a CameraProperties instance or None, got {type(camera_properties).__name__}",
603 param_name="camera_properties",
604 function_name=func.__name__,
605 expected_type="CameraProperties or None",
606 actual_value=camera_properties,
607 suggestion="Use a CameraProperties instance or None for default properties."
608 )
609
610 return func(self, validated_label, validated_bands, validated_position, validated_direction,
611 camera_properties, validated_samples, *args, **kwargs)
612 return wrapper
Callable validate_branch_segment_params(Callable func)
Validate branch segment resolution parameters.
Callable validate_jmax_params(Callable func)
Validate Jmax parameters for Farquhar model.
Callable validate_radiation_camera_params(Callable func)
Validate parameters for addRadiationCamera method.
Callable validate_photosynthesis_co2_params(Callable func)
Validate CO2 concentration parameters.
Callable validate_recursion_params(Callable func)
Validate recursion level parameters.
Callable validate_quantum_efficiency_params(Callable func)
Validate quantum efficiency parameters.
Callable validate_collimated_source_params(Callable func)
Validate parameters for collimated radiation source creation.
Callable validate_print_window_params(Callable func)
Validate parameters for printing window to file.
Callable validate_min_scatter_energy_params(Callable func)
Validate parameters for minimum scatter energy.
Callable validate_update_geometry_params(Callable func)
Validate parameters for geometry updates.
Callable validate_tree_uuid_params(Callable func)
Validate tree ID parameters for WeberPennTree methods.
Callable validate_get_source_flux_params(Callable func)
Validate parameters for getting source flux.
Callable validate_energy_band_params(Callable func)
Validate parameters for energy balance band operations.
Callable validate_photosynthesis_temperature_params(Callable func)
Validate temperature parameters for photosynthesis.
Callable validate_evaluate_air_energy_params(Callable func)
Validate parameters for evaluating air energy balance.
Callable validate_sphere_source_params(Callable func)
Validate parameters for sphere radiation source creation.
Callable validate_trunk_segment_params(Callable func)
Validate trunk segment resolution parameters.
Callable validate_empirical_model_params(Callable func)
Validate empirical model coefficient parameters.
Callable validate_radiation_band_params(Callable func)
Validate parameters for radiation band operations.
Callable validate_dark_respiration_params(Callable func)
Validate dark respiration parameters.
Callable validate_photosynthesis_rate_params(Callable func)
Validate photosynthetic rate parameters.
Callable validate_leaf_subdivisions_params(Callable func)
Validate leaf subdivision parameters.
Callable validate_temperature_response_params(Callable func)
Validate temperature response parameters.
Callable validate_build_geometry_params(Callable func)
Validate parameters for building visualizer geometry.
Callable validate_photosynthesis_uuid_params(Callable func)
Validate UUID parameters for photosynthesis methods.
Callable validate_farquhar_model_params(Callable func)
Validate Farquhar model coefficient parameters.
Callable validate_oxygen_concentration_params(Callable func)
Validate oxygen concentration parameters.
Callable validate_print_report_params(Callable func)
Validate parameters for print report methods.
Callable validate_vcmax_params(Callable func)
Validate Vcmax parameters for Farquhar model.
Callable validate_photosynthesis_species_params(Callable func)
Validate photosynthesis species parameters.
Callable validate_energy_run_params(Callable func)
Validate parameters for energy balance run method.
Callable validate_run_band_params(Callable func)
Validate parameters for running radiation bands.
Callable validate_photosynthesis_conductance_params(Callable func)
Validate conductance parameters.
Callable validate_sun_sphere_params(Callable func)
Validate parameters for sun sphere radiation source.
Callable validate_air_energy_params(Callable func)
Validate parameters for air energy balance.
Callable validate_scattering_depth_params(Callable func)
Validate parameters for scattering depth.
Callable validate_photosynthesis_par_params(Callable func)
Validate PAR flux parameters.
Callable validate_output_data_params(Callable func)
Validate parameters for optional output data.
Callable validate_source_flux_multiple_params(Callable func)
Validate parameters for setting multiple source flux.