in jetstream/analysis.py [0:0]
def validate(self) -> None:
self.check_runnable()
assert self.config.experiment.start_date is not None # for mypy
dates_enrollment = self.config.experiment.enrollment_period + 1
if self.config.experiment.end_date is not None:
end_date = self.config.experiment.end_date
analysis_length_dates = (
(end_date - self.config.experiment.start_date).days - dates_enrollment + 1
)
else:
analysis_length_dates = 21 # arbitrary
end_date = self.config.experiment.start_date + timedelta(
days=analysis_length_dates + dates_enrollment - 1
)
if analysis_length_dates < 0:
logging.error(
"Proposed enrollment longer than analysis dates length:"
+ f"{self.config.experiment.normandy_slug}"
)
raise Exception("Cannot validate experiment")
limits = TimeLimits.for_single_analysis_window(
last_date_full_data=end_date.strftime("%Y-%m-%d"),
analysis_start_days=0,
analysis_length_dates=analysis_length_dates,
first_enrollment_date=self.config.experiment.start_date.strftime("%Y-%m-%d"),
num_dates_enrollment=dates_enrollment,
)
exp = mozanalysis.experiment.Experiment(
experiment_slug=self.config.experiment.normandy_slug,
start_date=self.config.experiment.start_date.strftime("%Y-%m-%d"),
app_id=self._app_id_to_bigquery_dataset(self.config.experiment.app_id),
analysis_unit=self.config.experiment.analysis_unit,
)
metrics = set()
for v in self.config.metrics.values():
for metric_config in v:
if metric_config.metric.select_expression:
metrics.add(
Metric.from_metric_config(metric_config.metric).to_mozanalysis_metric()
)
exposure_signal = None
if self.config.experiment.exposure_signal:
exposure_signal = ExposureSignal.from_exposure_signal_config(
self.config.experiment.exposure_signal
)
exposure_signal = exposure_signal.to_mozanalysis_exposure_signal(limits)
segments = []
for segment in self.config.experiment.segments:
segments.append(Segment.from_segment_config(segment).to_mozanalysis_segment())
enrollments_sql = exp.build_enrollments_query(
limits,
PLATFORM_CONFIGS[self.config.experiment.app_name].enrollments_query_type,
self.config.experiment.enrollment_query,
None,
exposure_signal,
segments,
self.config.experiment.sample_size or None,
)
self._write_sql_output(
f"enrollments_{bq_normalize_name(self.config.experiment.normandy_slug)}",
enrollments_sql,
)
dry_run_query(enrollments_sql)
print(f"Dry running enrollments query for {self.config.experiment.normandy_slug}:")
print(enrollments_sql)
metrics_sql = exp.build_metrics_query(
metrics, limits, "enrollments_table", AnalysisBasis.ENROLLMENTS
)
# enrollments_table doesn't get created when performing a dry run;
# the metrics SQL is modified to include a subquery for a mock enrollments_table
# A UNION ALL is required here otherwise the dry run fails with
# "cannot query over table without filter over columns"
metrics_sql = metrics_sql.replace(
"WITH analysis_windows AS (",