Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
429 changes: 365 additions & 64 deletions docs/TrendAnalysis_example.ipynb

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion docs/nbval_sanitization_rules.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@
regex: .*: UserWarning:
replace: NBVAL-FILEPATH: UserWarning:

# sanitize the specific line of code shown in warning tracebacks
# since stacklevel changes will alter which line is reported
[regex2]
regex: ^ .*$
replace: CODE-LINE

[regex3]
regex: \d{1,2}/\d{1,2}/\d{2,4}
replace: DATE-STAMP

[regex3]
[regex4]
regex: \d{2}:\d{2}:\d{2}
replace: TIME-STAMP
4 changes: 4 additions & 0 deletions docs/sphinx/source/changelog/pending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ Enhancements
* Added frequency validation for ``clip_filter`` in ``TrendAnalysis._filter()`` that
raises a ``ValueError`` if the time series has a median time step greater than 60
minutes, as clipping detection requires higher resolution data.
* Added ``stacklevel`` parameter to all ``warnings.warn()`` calls so that warning
messages point to user code rather than rdtools internals. Affected modules:
``analysis_chains``, ``filtering``, ``soiling``, ``plotting``, ``normalization``,
``availability``, and ``clearsky_temperature``.


Warnings
Expand Down
18 changes: 12 additions & 6 deletions rdtools/analysis_chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,8 @@ def _pvwatts_norm(self, poa_global, temperature_cell):
if self.gamma_pdc is None:
warnings.warn(
"Temperature coefficient not passed in to TrendAnalysis. "
"No temperature correction will be conducted."
"No temperature correction will be conducted.",
stacklevel=3,
)
pvwatts_kws = {
"poa_global": poa_global,
Expand Down Expand Up @@ -619,15 +620,17 @@ def _call_clearsky_filter(filter_string):

if ad_hoc_filter.isnull().any():
warnings.warn(
"ad_hoc_filter contains NaN values; setting to False (excluding)"
"ad_hoc_filter contains NaN values; setting to False (excluding)",
stacklevel=3,
)
ad_hoc_filter.loc[ad_hoc_filter.isnull()] = False

if not filter_components.index.equals(ad_hoc_filter.index):
warnings.warn(
"ad_hoc_filter index does not match index of other filters; missing "
"values will be set to True (kept). Align the index with the index "
"of the filter_components attribute to prevent this warning"
"of the filter_components attribute to prevent this warning",
stacklevel=3,
)
ad_hoc_filter = ad_hoc_filter.reindex(filter_components.index)
ad_hoc_filter.loc[ad_hoc_filter.isnull()] = True
Expand Down Expand Up @@ -709,7 +712,8 @@ def _aggregated_filter(self, aggregated, case):

if ad_hoc_filter_aggregated.isnull().any():
warnings.warn(
"aggregated ad_hoc_filter contains NaN values; setting to False (excluding)"
"aggregated ad_hoc_filter contains NaN values; setting to False (excluding)",
stacklevel=3,
)
ad_hoc_filter_aggregated.loc[ad_hoc_filter_aggregated.isnull()] = False

Expand All @@ -720,7 +724,8 @@ def _aggregated_filter(self, aggregated, case):
"Aggregated ad_hoc_filter index does not match index of other "
"filters; missing values will be set to True (kept). "
"Align the index with the index of the "
"filter_components_aggregated attribute to prevent this warning"
"filter_components_aggregated attribute to prevent this warning",
stacklevel=3,
)
ad_hoc_filter_aggregated = ad_hoc_filter_aggregated.reindex(
filter_components_aggregated.index
Expand Down Expand Up @@ -963,7 +968,8 @@ def _clearsky_preprocess(self):
"""Clear-sky analysis is performed but `power_expected` was passed in by user.
In this case, the power normalization is not tied to the modeled clear-sky
irradiance and the clear-sky workflow may provide similar results to
the sensor workflow."""
the sensor workflow.""",
stacklevel=2,
)
self._filter(cs_normalized, "clearsky")
cs_aggregated, cs_aggregated_insolation = self._aggregate(
Expand Down
2 changes: 1 addition & 1 deletion rdtools/availability.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ def _combine_losses(self, rollup_period="ME"):
'levels. This is unexpected and could indicate a problem with '
'the input time series data.'
)
warnings.warn(msg, UserWarning)
warnings.warn(msg, UserWarning, stacklevel=3)

self.loss_total = self.loss_system + self.loss_subsystem

Expand Down
6 changes: 4 additions & 2 deletions rdtools/clearsky_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ def get_clearsky_tamb(times, latitude, longitude, window_size=40,
# workaround from https://github.com/pandas-dev/pandas/issues/55794
freq_actual = pd.infer_freq(times[:10])
warnings.warn("Input 'times' has no frequency attribute. "
"Inferring frequency from first 10 timestamps.")
"Inferring frequency from first 10 timestamps.",
stacklevel=2)
else:
freq_actual = times.freq

Expand Down Expand Up @@ -121,7 +122,8 @@ def solar_noon_offset(utc_offset):
df['solar_noon_offset'].values)
if df['Clear Sky Temperature (C)'].isna().any():
warnings.warn("Clear Sky Temperature includes NaNs, "
"possibly invalid Lat/Lon coordinates.", UserWarning)
"possibly invalid Lat/Lon coordinates.", UserWarning,
stacklevel=2)
return df['Clear Sky Temperature (C)']


Expand Down
6 changes: 4 additions & 2 deletions rdtools/filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,8 @@ def _format_clipping_time_series(power_ac, mounting_type):
warnings.warn(
"Function expects timestamps in local time. "
"For best results pass a time-zone-localized "
"time series localized to the correct local time zone."
"time series localized to the correct local time zone.",
stacklevel=3,
)
# Check the other input variables to ensure that they are the
# correct format
Expand Down Expand Up @@ -448,7 +449,8 @@ def _check_data_sampling_frequency(power_ac):
"Variable sampling frequency across time series. "
"Less than 95% of the time series is sampled at the "
"same interval. This function was not tested "
"on variable frequency data--use at your own risk!"
"on variable frequency data--use at your own risk!",
stacklevel=3,
)
return

Expand Down
2 changes: 1 addition & 1 deletion rdtools/normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ def _interpolate_series(time_series, target_index, max_timedelta=None,
warnings.warn("Fraction of excluded data "
f"({100*fraction_excluded:0.02f}%) "
"exceeded threshold",
UserWarning)
UserWarning, stacklevel=3)

# put data on index that includes both original and target indices
target_timestamps = pd.Index((target_index - epoch).total_seconds())
Expand Down
6 changes: 3 additions & 3 deletions rdtools/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def soiling_monte_carlo_plot(soiling_info, normalized_yield, point_alpha=0.5,
warnings.warn(
'The soiling module is currently experimental. The API, results, '
'and default behaviors may change in future releases (including MINOR '
'and PATCH releases) as the code matures.'
'and PATCH releases) as the code matures.', stacklevel=2
)

fig, ax = plt.subplots()
Expand Down Expand Up @@ -233,7 +233,7 @@ def soiling_interval_plot(soiling_info, normalized_yield, point_alpha=0.5,
warnings.warn(
'The soiling module is currently experimental. The API, results, '
'and default behaviors may change in future releases (including MINOR '
'and PATCH releases) as the code matures.'
'and PATCH releases) as the code matures.', stacklevel=2
)

sratio = soiling_info['soiling_ratio_perfect_clean']
Expand Down Expand Up @@ -273,7 +273,7 @@ def soiling_rate_histogram(soiling_info, bins=None):
warnings.warn(
'The soiling module is currently experimental. The API, results, '
'and default behaviors may change in future releases (including MINOR '
'and PATCH releases) as the code matures.'
'and PATCH releases) as the code matures.', stacklevel=2
)

soiling_summary = soiling_info['soiling_interval_summary']
Expand Down
11 changes: 7 additions & 4 deletions rdtools/soiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
warnings.warn(
'The soiling module is currently experimental. The API, results, '
'and default behaviors may change in future releases (including MINOR '
'and PATCH releases) as the code matures.'
'and PATCH releases) as the code matures.', stacklevel=2
)


Expand Down Expand Up @@ -123,7 +123,8 @@ def _calc_daily_df(self, day_scale=13, clean_threshold='infer',
warnings.warn('An even value of day_scale was passed. An odd value is '
'recommended, otherwise, consecutive days may be erroneously '
'flagged as cleaning events. '
'See https://github.com/NREL/rdtools/issues/189')
'See https://github.com/NREL/rdtools/issues/189',
stacklevel=2)

df = self.pm.to_frame()
df.columns = ['pi']
Expand Down Expand Up @@ -382,7 +383,8 @@ def _calc_monte(self, monte, method='half_norm_clean'):
'validity criteria such as increasing "max_relative_slope_error" '
'and/or "max_negative_step" and/or decreasing "min_interval_length".'
' Alternatively, consider using method="perfect_clean". For more'
' info see https://github.com/NREL/rdtools/issues/272'
' info see https://github.com/NREL/rdtools/issues/272',
stacklevel=2
)
monte_losses = []
random_profiles = []
Expand Down Expand Up @@ -906,7 +908,8 @@ def annual_soiling_ratios(stochastic_soiling_profiles,
'The indexes of stochastic_soiling_profiles are not entirely '
'contained within the index of insolation_daily. Every day in '
'stochastic_soiling_profiles should be represented in '
'insolation_daily. This may cause erroneous results.')
'insolation_daily. This may cause erroneous results.',
stacklevel=2)

insolation_daily = insolation_daily.reindex(all_profiles.index)

Expand Down