Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
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
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/serialization/serialized_objects.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1345,6 +1345,9 @@ def __eq__(self, other: Any) -> bool:
getattr(self, c, None) == getattr(other, c, None) for c in BaseOperator._comps
)

def __hash__(self):
return hash((self.task_type, *[getattr(self, c, None) for c in BaseOperator._comps]))

def __repr__(self) -> str:
return f"<SerializedTask({self.task_type}): {self.task_id}>"

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/task/priority_strategy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.serialize() == other.serialize()

def __hash__(self):
return hash(self.serialize())


class _AbsolutePriorityWeightStrategy(PriorityWeightStrategy):
"""Priority weight strategy that uses the task's priority weight directly."""
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/_cron.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,6 +128,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._expression == other._expression and self._timezone == other._timezone

def __hash__(self):
return hash((self._expression, self._timezone))

@property
def summary(self) -> str:
return self._expression
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/interval.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self._delta == other._delta

def __hash__(self):
return hash(self._delta)

def serialize(self) -> dict[str, Any]:
from airflow.serialization.serialized_objects import encode_relativedelta

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/timetables/simple.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,6 +50,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return True

def __hash__(self):
return hash(self.__class__.__name__)

def serialize(self) -> dict[str, Any]:
return {}

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/src/airflow/utils/db.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,6 +1596,9 @@ def __eq__(self, other: object) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash(tuple(x for x in iter(self)))

def __reversed__(self) -> Iterator[T]:
return iter(self._process_row(r) for r in self._session.execute(self._select_desc))

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/models/test_renderedtifields.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,6 +70,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -1339,6 +1339,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/serialization/test_serde.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -142,6 +142,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@attr.define
class Y:
Expand Down
3 changes: 3 additions & 0 deletions airflow-core/tests/unit/utils/test_json.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def deserialize(data: dict, version: int):
def __eq__(self, other):
return self.x == other.x

def __hash__(self):
return hash(self.x)


@dataclass
class U:
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/tests/unit/utils/test_sqlalchemy.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -264,7 +264,7 @@ def test_compare_values(self):
under older kubernetes library version.
"""

class MockAttrError:
class MockAttrError: # noqa: PLW1641
def __eq__(self, other):
raise AttributeError("hello")

Expand Down
3 changes: 3 additions & 0 deletions dev/airflow_perf/sql_queries.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,9 @@ def __eq__(self, other):
and self.file == other.file
)

def __hash__(self):
return hash((self.function, self.sql, self.location, self.file))

def to_dict(self):
"""
Convert selected attributes of the instance into a dictionary.
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/errors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other):
right = (other.file_path, other.line_no, other.message)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/sphinx_exts/docs_build/spelling_checks.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,6 +61,9 @@ def __eq__(self, other):
)
return left == right

def __hash__(self):
return hash((self.file_path, self.line_no, self.spelling, self.context_line, self.message))

def __ne__(self, other):
return not self == other

Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/test_utils/timetables.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,9 @@ def __eq__(self, other) -> bool:
return False
return self.value == other.value

def __hash__(self):
return hash(self.value)

def serialize(self):
return {"value": self.value}

Expand Down
3 changes: 3 additions & 0 deletions kubernetes-tests/tests/kubernetes_tests/test_base.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,9 @@ class StringContainingId(str):
def __eq__(self, other):
return self in other.strip() or self in other

def __hash__(self):
return hash(self)


class BaseK8STest:
"""Base class for K8S Tests."""
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -312,6 +312,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -121,5 +121,8 @@ def __eq__(self, other):
and self.key == other.key
)

def __hash__(self):
return hash((self.deploy_type, self.deploy_target, self.secret, self.key))

def __repr__(self):
return f"Secret({self.deploy_type}, {self.deploy_target}, {self.secret}, {self.key})"
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,6 +134,9 @@ def __eq__(self, other: object) -> bool:
and self.state_message == other.state_message
)

def __hash__(self):
return hash((self.life_cycle_state, self.result_state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -183,6 +186,9 @@ def is_running(self) -> bool:
def __eq__(self, other) -> bool:
return self.state == other.state and self.state_message == other.state_message

def __hash__(self):
return hash((self.state, self.state_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand DownExpand Up@@ -244,6 +250,9 @@ def __eq__(self, other: object) -> bool:
and self.error_message == other.error_message
)

def __hash__(self):
return hash((self.state, self.error_code, self.error_message))

def __repr__(self) -> str:
return str(self.__dict__)

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,9 @@ class Resource(Model):
def __eq__(self, other):
return (isinstance(other, self.__class__)) and (self.name == other.name)

def __hash__(self):
return hash((self.id, self.name))

def __neq__(self, other):
return self.name != other.name

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,6 +42,9 @@ def __init__(self, **kwargs):
def __eq__(self, other):
return isinstance(other, MockRow) and self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return f"MockRow({self.__dict__})"

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,9 @@ def __eq__(self, other: object) -> bool:
return False
return self.properties == other.properties and self.uuid == other.uuid

def __hash__(self):
return hash((self.properties, self.uuid))


class TestWeaviateHook:
"""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -605,6 +605,7 @@ extend-select = [
"PLW1507", # Shallow copy of os.environ via copy.copy(os.environ)
"PLW1508", # Invalid type for environment variable default; expected str or None
"PLW1510", # subprocess.run without explicit check argument
"PLW1641", # Object does not implement __hash__ method
# Per rule enables
"RUF006", # Checks for asyncio dangling task
"RUF015", # Checks for unnecessary iterable allocation for first element
Expand Down
4 changes: 4 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/asset/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -426,6 +426,10 @@ def __eq__(self, other: Any) -> bool:
f = attrs.filters.include(*attrs.fields_dict(Asset))
return attrs.asdict(self, filter=f) == attrs.asdict(other, filter=f)

def __hash__(self):
f = attrs.filters.include(*attrs.fields_dict(Asset))
return hash(attrs.asdict(self, filter=f))

@property
def normalized_uri(self) -> str | None:
"""
Expand Down
6 changes: 6 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/operator_resources.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand DownExpand Up@@ -138,6 +141,9 @@ def __eq__(self, other: object) -> bool:
return NotImplemented
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __repr__(self):
return str(self.__dict__)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/definitions/param.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -159,6 +159,9 @@ def __eq__(self, other: Any) -> bool:
return self.dump() == other
return NotImplemented

def __hash__(self):
return hash(self.dump())

def __copy__(self) -> ParamsDict:
return ParamsDict(self.__dict, self.suppress_exception)

Expand Down
9 changes: 9 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/context.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -351,6 +351,9 @@ def __eq__(self, other):
# All instances of ConnectionAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def get(self, conn_id: str, default_conn: Any = None) -> Any:
from airflow.exceptions import AirflowNotFoundException

Expand All@@ -376,6 +379,9 @@ def __eq__(self, other):
# All instances of VariableAccessor are equal since it is a stateless dynamic accessor
return True

def __hash__(self):
return hash(self.__class__.__name__)

def __repr__(self) -> str:
return "<VariableAccessor (dynamic access)>"

Expand DownExpand Up@@ -412,6 +418,9 @@ def __eq__(self, other: object) -> bool:
return False
return True

def __hash__(self):
return hash(self.__class__.__name__)


class _AssetRefResolutionMixin:
_asset_ref_cache: dict[AssetRef, AssetUniqueKey] = {}
Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/execution_time/lazy_sequence.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,6 +81,9 @@ def __eq__(self, other: Any) -> bool:
z = itertools.zip_longest(iter(self), iter(other), fillvalue=object())
return all(x == y for x, y in z)

def __hash__(self):
return hash((*[item for item in iter(self)],))

def __iter__(self) -> Iterator[T]:
return LazyXComIterator(seq=self)

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/src/airflow/sdk/io/store.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ def __eq__(self, other: object) -> bool:
except ValueError:
return False

def __hash__(self):
return hash((self.conn_id, self.fsid))


_STORE_CACHE: dict[str, ObjectStore] = {}

Expand Down
3 changes: 3 additions & 0 deletions task-sdk/tests/task_sdk/bases/test_operator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,9 @@ def __repr__(self):
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __hash__(self):
return hash(self.__dict__)

def __ne__(self, other):
return not self.__eq__(other)

Expand Down