Skip to content

Move template-field validation/transformation out of operator __init__ (exemption-list burn-down) #70296

Description

@shahar1

Background

Template fields are rendered after an operator's constructor runs. Any logic applied to a template-field parameter inside __init__ — validation, type checks, transformation, string interpolation — therefore operates on the un-rendered Jinja expression, not the real value. This is documented in Creating a custom Operator and contributing-docs/05_pull_requests.rst, and it causes real bugs: #69813 (SSHRemoteJobOperator validated a templated remote_base_dir in __init__, so cleanup validation failed for any custom base) is a recent example.

The validate-operators-init prek hook previously only verified that template fields are assigned verbatim at the top level of __init__; it could not see validation calls, conditionals, or transformations (and it did not cover sensors, AwsBaseOperator[...] subclasses, or aws_template_fields(...)-based classes at all). The hook has been extended to detect any non-sanctioned read of a template field in __init__ (PR to follow).

The exemption ratchet

Existing violations are listed in scripts/ci/prek/validate_operators_init_exemptions.txt as path::ClassName entries so the hook can enforce the rule on new code immediately.

  • A PR that fixes a class must remove its entry in the same PR — the hook fails on stale exemptions, so this cannot be forgotten.
  • New violations cannot be added: only files listed in the exemption file are suppressed.
  • This issue is done when the exemption file is empty.

How to fix a class: move the validation / transformation from __init__ into execute() (or the first method that runs after rendering), keep __init__ down to plain self.field = field assignments (defaulting via field or default is fine). Don't forget the corresponding tests.

Please do not open sub-issues for individual entries — comment here or just open a PR referencing this issue.

Current exemption list (snapshot)

The authoritative list is the exemptions file; this checklist is the snapshot at the time the check was introduced. 83 classes across 22 providers.

amazon

  • AppflowBaseOperatorappflow.py — logic in __init__
  • AwsToAwsBaseOperatorbase.py — logic in __init__
  • BedrockCreateKnowledgeBaseOperatorbedrock.py — logic in __init__
  • BedrockRaGOperatorbedrock.py — transformed assignment, logic in __init__, missing assignment
  • DataSyncOperatordatasync.py — logic in __init__
  • DmsModifyTaskOperatordms.py — logic in __init__
  • DmsStartReplicationOperatordms.py — logic in __init__
  • EcsRunTaskOperatorecs.py — logic in __init__
  • EmrAddStepsOperatoremr.py — logic in __init__
  • GCSToS3Operatorgcs_to_s3.py — logic in __init__
  • GlueDataQualityOperatorglue.py — transformed assignment, logic in __init__, missing assignment
  • MongoToS3Operatormongo_to_s3.py — logic in __init__
  • NeptuneStartDbClusterOperatorneptune.py — transformed assignment, missing assignment
  • NeptuneStopDbClusterOperatorneptune.py — transformed assignment, missing assignment
  • S3DeleteObjectsOperators3.py — logic in __init__
  • S3ToRedshiftOperators3_to_redshift.py — logic in __init__
  • SageMakerCreateNotebookOperatorsagemaker.py — logic in __init__
  • SageMakerProcessingOperatorsagemaker.py — logic in __init__
  • StepFunctionStartExecutionOperatorstep_function.py — transformed assignment, missing assignment

anthropic

  • AnthropicAgentSessionOperatoragent.py — logic in __init__

apache/hive

apache/kafka

  • ProduceToTopicOperatorproduce.py — logic in __init__

apache/spark

cncf/kubernetes

  • KubernetesInstallKueueOperatorkueue.py — logic in __init__
  • KubernetesPodOperatorpod.py — logic in __init__
  • KubernetesResourceBaseOperatorresource.py — logic in __init__

cohere

  • CohereEmbeddingOperatorembedding.py — logic in __init__

common/ai

databricks

dbt/cloud

  • DbtCloudGetJobRunArtifactOperatordbt.py — logic in __init__

docker

  • DockerOperatordocker.py — logic in __init__

google

  • AzureFileShareToGCSOperatorazure_fileshare_to_gcs.py — logic in __init__
  • BigQueryDataTransferServiceTransferRunSensorbigquery_dts.py — transformed assignment, logic in __init__, missing assignment
  • BigQueryInsertJobOperatorbigquery.py — logic in __init__
  • BigQueryToMsSqlOperatorbigquery_to_mssql.py — logic in __init__
  • CloudBatchSubmitJobOperatorcloud_batch.py — logic in __init__
  • CloudBuildCreateBuildOperatorcloud_build.py — logic in __init__
  • CloudComposerExternalTaskSensorcloud_composer.py — logic in __init__
  • CloudDataTransferServiceCreateJobOperatorcloud_storage_transfer_service.py — logic in __init__
  • CloudFunctionDeployFunctionOperatorfunctions.py — logic in __init__
  • ComputeEngineCopyInstanceTemplateOperatorcompute.py — logic in __init__
  • ComputeEngineDeleteInstanceGroupManagerOperatorcompute.py — logic in __init__
  • ComputeEngineDeleteInstanceOperatorcompute.py — logic in __init__
  • ComputeEngineDeleteInstanceTemplateOperatorcompute.py — logic in __init__
  • ComputeEngineInsertInstanceFromTemplateOperatorcompute.py — logic in __init__
  • ComputeEngineInsertInstanceGroupManagerOperatorcompute.py — logic in __init__
  • ComputeEngineInsertInstanceOperatorcompute.py — logic in __init__
  • ComputeEngineInsertInstanceTemplateOperatorcompute.py — logic in __init__
  • ComputeEngineInstanceGroupUpdateManagerTemplateOperatorcompute.py — logic in __init__
  • ComputeEngineSetMachineTypeOperatorcompute.py — logic in __init__
  • DataprocCreateClusterOperatordataproc.py — logic in __init__
  • DataprocSubmitJobOperatordataproc.py — logic in __init__
  • GCSDeleteObjectsOperatorgcs.py — logic in __init__
  • GCSFileTransformOperatorgcs.py — logic in __init__
  • GCSListObjectsOperatorgcs.py — logic in __init__
  • GCSToBigQueryOperatorgcs_to_bigquery.py — logic in __init__
  • GCSToGCSOperatorgcs_to_gcs.py — logic in __init__
  • GCSToLocalFilesystemOperatorgcs_to_local.py — logic in __init__
  • GenAIGeminiCreateBatchJobOperatorgen_ai.py — logic in __init__
  • GenAIGeminiCreateEmbeddingsBatchJobOperatorgen_ai.py — logic in __init__
  • GoogleCampaignManagerDeleteReportOperatorcampaign_manager.py — logic in __init__

microsoft/azure

microsoft/psrp

  • PsrpOperatorpsrp.py — logic in __init__

neo4j

  • Neo4jOperatorneo4j.py — logic in __init__

oracle

papermill

snowflake

ssh

standard

  • BashOperatorbash.py — logic in __init__
  • DateTimeSensordate_time.py — logic in __init__, missing assignment
  • HITLOperatorhitl.py — logic in __init__
  • TriggerDagRunOperatortrigger_dagrun.py — logic in __init__

teradata

weaviate

  • WeaviateIngestOperatorweaviate.py — logic in __init__

Drafted-by: Claude Code (Opus 4.8) (no human review before posting)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions