stuart23 commented on code in PR #54702:
URL: https://github.com/apache/airflow/pull/54702#discussion_r2292573747
##########
airflow-core/src/airflow/cli/commands/dag_command.py:
##########
@@ -648,6 +649,149 @@ def dag_test(args, dag: DAG | None = None, session:
Session = NEW_SESSION) -> No
raise SystemExit("DagRun failed")
+def _get_schedule_info(dag) -> str | None:
+ """Extract and format schedule information from a DAG."""
+ try:
+ # Try to get schedule from different possible attributes
+ schedule = getattr(dag, 'schedule', None) or getattr(dag,
'schedule_interval', None)
+
+ if schedule is None:
+ return "Manual (no schedule)"
+
+ # Handle different schedule types
+ if isinstance(schedule, str):
+ # Cron expressions or preset schedules
+ if schedule.startswith('@'):
+ # Preset schedules like @daily, @hourly
+ preset_map = {
+ '@once': 'Once',
+ '@hourly': 'Hourly (0 * * * *)',
+ '@daily': 'Daily (0 0 * * *)',
+ '@weekly': 'Weekly (0 0 * * 0)',
+ '@monthly': 'Monthly (0 0 1 * *)',
+ '@yearly': 'Yearly (0 0 1 1 *)',
+ '@annually': 'Annually (0 0 1 1 *)',
+ }
+ return preset_map.get(schedule, schedule)
+ else:
+ # Cron expression
+ return f"Cron: `{schedule}`"
+
+ # Handle timedelta objects
+ if hasattr(schedule, 'total_seconds'):
+ seconds = schedule.total_seconds()
+ if seconds >= 86400: # 24 hours
+ days = int(seconds // 86400)
+ return f"Every {days} day{'s' if days > 1 else ''}"
+ elif seconds >= 3600: # 1 hour
+ hours = int(seconds // 3600)
+ return f"Every {hours} hour{'s' if hours > 1 else ''}"
+ elif seconds >= 60: # 1 minute
+ minutes = int(seconds // 60)
+ return f"Every {minutes} minute{'s' if minutes > 1 else ''}"
+ else:
+ return f"Every {int(seconds)} second{'s' if seconds > 1 else
''}"
+
+ # Handle timetable objects
+ if hasattr(dag, 'timetable') and dag.timetable:
+ timetable = dag.timetable
+ # Try to get a description from the timetable
+ if hasattr(timetable, 'description'):
+ return timetable.description
+ elif hasattr(timetable, 'summary'):
+ return timetable.summary
+ else:
+ return str(timetable.__class__.__name__)
+
+ # Handle dataset schedules
+ if hasattr(schedule, '__iter__') and not isinstance(schedule, str):
+ # Likely a dataset schedule (list/set of datasets)
+ try:
+ datasets = list(schedule)
+ if datasets:
+ dataset_names = [str(ds) for ds in datasets[:3]] # Show
first 3
+ if len(datasets) > 3:
+ return f"Dataset-triggered: {',
'.join(dataset_names)}, ..."
+ else:
+ return f"Dataset-triggered: {', '.join(dataset_names)}"
+ except (TypeError, AttributeError):
Review Comment:
I've changed it to just TypeError, which may be thrown when casting to list
##########
airflow-core/src/airflow/cli/commands/dag_command.py:
##########
@@ -648,6 +649,149 @@ def dag_test(args, dag: DAG | None = None, session:
Session = NEW_SESSION) -> No
raise SystemExit("DagRun failed")
+def _get_schedule_info(dag) -> str | None:
+ """Extract and format schedule information from a DAG."""
+ try:
+ # Try to get schedule from different possible attributes
+ schedule = getattr(dag, 'schedule', None) or getattr(dag,
'schedule_interval', None)
+
+ if schedule is None:
+ return "Manual (no schedule)"
+
+ # Handle different schedule types
+ if isinstance(schedule, str):
+ # Cron expressions or preset schedules
+ if schedule.startswith('@'):
+ # Preset schedules like @daily, @hourly
+ preset_map = {
+ '@once': 'Once',
+ '@hourly': 'Hourly (0 * * * *)',
+ '@daily': 'Daily (0 0 * * *)',
+ '@weekly': 'Weekly (0 0 * * 0)',
+ '@monthly': 'Monthly (0 0 1 * *)',
+ '@yearly': 'Yearly (0 0 1 1 *)',
+ '@annually': 'Annually (0 0 1 1 *)',
+ }
+ return preset_map.get(schedule, schedule)
+ else:
+ # Cron expression
+ return f"Cron: `{schedule}`"
+
+ # Handle timedelta objects
+ if hasattr(schedule, 'total_seconds'):
+ seconds = schedule.total_seconds()
+ if seconds >= 86400: # 24 hours
+ days = int(seconds // 86400)
+ return f"Every {days} day{'s' if days > 1 else ''}"
+ elif seconds >= 3600: # 1 hour
+ hours = int(seconds // 3600)
+ return f"Every {hours} hour{'s' if hours > 1 else ''}"
+ elif seconds >= 60: # 1 minute
+ minutes = int(seconds // 60)
+ return f"Every {minutes} minute{'s' if minutes > 1 else ''}"
+ else:
+ return f"Every {int(seconds)} second{'s' if seconds > 1 else
''}"
+
+ # Handle timetable objects
+ if hasattr(dag, 'timetable') and dag.timetable:
+ timetable = dag.timetable
+ # Try to get a description from the timetable
+ if hasattr(timetable, 'description'):
+ return timetable.description
+ elif hasattr(timetable, 'summary'):
+ return timetable.summary
+ else:
+ return str(timetable.__class__.__name__)
+
+ # Handle dataset schedules
+ if hasattr(schedule, '__iter__') and not isinstance(schedule, str):
+ # Likely a dataset schedule (list/set of datasets)
+ try:
+ datasets = list(schedule)
+ if datasets:
+ dataset_names = [str(ds) for ds in datasets[:3]] # Show
first 3
Review Comment:
Changed to show all
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]