From 3a2bdd8383d720b1b2052213d71542e4f44ad792 Mon Sep 17 00:00:00 2001 From: Christopher DeCarolis Date: Wed, 11 Dec 2024 16:13:08 -0800 Subject: [PATCH 01/94] Handle adding and removing deps in AssetsDefinition.map_asset_specs (#26144) # Background This PR changes `AssetsDefinition.map_asset_specs` to allow adding additional deps to an `AssetSpec`. To do this, we create `Nothing` inputs under the hood which map to the asset dependency in question. This is important mostly for integration cases where we use the decorator pattern `@dbt_assets`, `@fivetran_assets`, etc. If you want to link an asset dependency to assets defined with those decorators, it's currently not feasible for users. # Caveats **Only supports op-backed assets** This PR adds support only for op-backed assets, not graph-backed assets. I attempted to add support and found myself blocked since graph-backed assets currently do not support non-argument deps (at least from what I could gather). I added a linear issue to track this and referenced it in the relevant place in code. **Doesn't work for argument-based deps** This PR adds support for the deletion of non-argument based deps; but does not support the deletion of argument-based deps. I think deletion of argument-based deps is impossible, since you would have nothing to pass to the underlying function. We error cleanly instead, and I think that's the best we can do. # Testing A bunch of tests for every case that I could think of: - add additional dependencies - add the same dependency multiple times - remove a dependency - add dependencies with partition mappings - add dependencies to a non-executable assets def - attempt to add deps to a graph-backed asset --- .../dbt_example/dagster_defs/utils.py | 4 +- .../dagster/_core/definitions/assets.py | 83 +++++++++-- .../decorator_assets_definition_builder.py | 5 +- .../_core/definitions/op_definition.py | 12 +- .../dagster/dagster/_utils/merger.py | 10 ++ .../definitions_tests/test_asset_spec.py | 129 +++++++++++++++++- 6 files changed, 218 insertions(+), 25 deletions(-) diff --git a/examples/starlift-demo/dbt_example/dagster_defs/utils.py b/examples/starlift-demo/dbt_example/dagster_defs/utils.py index ea4fa0740c2e4..1087a7d454573 100644 --- a/examples/starlift-demo/dbt_example/dagster_defs/utils.py +++ b/examples/starlift-demo/dbt_example/dagster_defs/utils.py @@ -2,9 +2,7 @@ from dagster import AssetsDefinition, AssetSpec, AutomationCondition, Definitions, Nothing from dagster._core.definitions.asset_key import AssetKey -from dagster._core.definitions.decorators.decorator_assets_definition_builder import ( - stringify_asset_key_to_input_name, -) +from dagster._core.definitions.assets import stringify_asset_key_to_input_name from dagster._core.definitions.input import In diff --git a/python_modules/dagster/dagster/_core/definitions/assets.py b/python_modules/dagster/dagster/_core/definitions/assets.py index d616fb0361f8d..064507025685d 100644 --- a/python_modules/dagster/dagster/_core/definitions/assets.py +++ b/python_modules/dagster/dagster/_core/definitions/assets.py @@ -74,7 +74,7 @@ ) from dagster._core.errors import DagsterInvalidDefinitionError, DagsterInvariantViolationError from dagster._utils import IHasInternalInit -from dagster._utils.merger import merge_dicts +from dagster._utils.merger import merge_dicts, reverse_dict from dagster._utils.security import non_secure_md5_hash_str from dagster._utils.tags import normalize_tags from dagster._utils.warnings import ExperimentalWarning, disable_dagster_warnings @@ -85,6 +85,10 @@ ASSET_SUBSET_INPUT_PREFIX = "__subset_input__" +def stringify_asset_key_to_input_name(asset_key: AssetKey) -> str: + return "_".join(asset_key.path).replace("-", "_") + + class AssetsDefinition(ResourceAddable, IHasInternalInit): """Defines a set of assets that are produced by the same op or graph. @@ -932,6 +936,10 @@ def node_keys_by_input_name(self) -> Mapping[str, AssetKey]: """AssetKey for each input on the underlying NodeDefinition.""" return self._computation.keys_by_input_name if self._computation else {} + @property + def input_names_by_node_key(self) -> Mapping[AssetKey, str]: + return {key: input_name for input_name, key in self.node_keys_by_input_name.items()} + @property def node_check_specs_by_output_name(self) -> Mapping[str, AssetCheckSpec]: """AssetCheckSpec for each output on the underlying NodeDefinition.""" @@ -1293,20 +1301,10 @@ def map_asset_specs(self, fn: Callable[[AssetSpec], AssetSpec]) -> "AssetsDefini f"Asset key {spec.key.to_user_string()} was changed to " f"{mapped_spec.key.to_user_string()}. Mapping function must not change keys." ) - if ( - # check reference equality first for performance - mapped_spec.deps is not spec.deps and mapped_spec.deps != spec.deps - ): - raise DagsterInvalidDefinitionError( - f"Asset deps {spec.deps} were changed to {mapped_spec.deps}. Mapping function " - "must not change deps." - ) mapped_specs.append(mapped_spec) - return self.__class__.dagster_internal_init( - **{**self.get_attributes_dict(), "specs": mapped_specs} - ) + return replace_specs_on_asset(self, mapped_specs) def subset_for( self, @@ -1897,3 +1895,64 @@ def unique_id_from_asset_and_check_keys(entity_keys: Iterable["EntityKey"]) -> s """ sorted_key_strs = sorted(str(key) for key in entity_keys) return non_secure_md5_hash_str(json.dumps(sorted_key_strs).encode("utf-8"))[:8] + + +def replace_specs_on_asset( + assets_def: AssetsDefinition, replaced_specs: Sequence[AssetSpec] +) -> "AssetsDefinition": + from dagster._builtins import Nothing + from dagster._core.definitions.input import In + + new_deps = set().union(*(spec.deps for spec in replaced_specs)) + previous_deps = set().union(*(spec.deps for spec in assets_def.specs)) + added_deps = new_deps - previous_deps + removed_deps = previous_deps - new_deps + remaining_original_deps = previous_deps - removed_deps + original_key_to_input_mapping = reverse_dict(assets_def.node_keys_by_input_name) + + # If there are no changes to the dependency structure, we don't need to make any changes to the underlying node. + if not assets_def.is_executable or (not added_deps and not removed_deps): + return assets_def.__class__.dagster_internal_init( + **{**assets_def.get_attributes_dict(), "specs": replaced_specs} + ) + + # Otherwise, there are changes to the dependency structure. We need to update the node_def. + # Graph-backed assets do not currently support non-argument-based deps. Every argument to a graph-backed asset + # must map to an an input on an internal asset node in the graph structure. + # IMPROVEME BUILD-529 + check.invariant( + isinstance(assets_def.node_def, OpDefinition), + "Can only add additional deps to an op-backed asset.", + ) + # for each deleted dep, we need to make sure it is not an argument-based dep. Argument-based deps cannot be removed. + for dep in removed_deps: + input_name = original_key_to_input_mapping[dep.asset_key] + input_def = assets_def.node_def.input_def_named(input_name) + check.invariant( + input_def.dagster_type.is_nothing, + f"Attempted to remove argument-backed dependency {dep.asset_key} (mapped to argument {input_name}) from the asset. Only non-argument dependencies can be changed or removed using map_asset_specs.", + ) + + remaining_original_deps_by_key = {dep.asset_key: dep for dep in remaining_original_deps} + remaining_ins = { + input_name: the_in + for input_name, the_in in assets_def.node_def.input_dict.items() + if assets_def.node_keys_by_input_name[input_name] in remaining_original_deps_by_key + } + all_ins = merge_dicts( + remaining_ins, + { + stringify_asset_key_to_input_name(dep.asset_key): In(dagster_type=Nothing) + for dep in new_deps + }, + ) + + return assets_def.__class__.dagster_internal_init( + **{ + **assets_def.get_attributes_dict(), + "node_def": assets_def.op.with_replaced_properties( + name=assets_def.op.name, ins=all_ins + ), + "specs": replaced_specs, + } + ) diff --git a/python_modules/dagster/dagster/_core/definitions/decorators/decorator_assets_definition_builder.py b/python_modules/dagster/dagster/_core/definitions/decorators/decorator_assets_definition_builder.py index db4b32a374dbe..0eab760bc93e7 100644 --- a/python_modules/dagster/dagster/_core/definitions/decorators/decorator_assets_definition_builder.py +++ b/python_modules/dagster/dagster/_core/definitions/decorators/decorator_assets_definition_builder.py @@ -34,6 +34,7 @@ ASSET_SUBSET_INPUT_PREFIX, AssetsDefinition, get_partition_mappings_from_deps, + stringify_asset_key_to_input_name, ) from dagster._core.definitions.backfill_policy import BackfillPolicy from dagster._core.definitions.decorators.op_decorator import _Op @@ -55,10 +56,6 @@ ) -def stringify_asset_key_to_input_name(asset_key: AssetKey) -> str: - return "_".join(asset_key.path).replace("-", "_") - - def get_function_params_without_context_or_config_or_resources( fn: Callable[..., Any], ) -> List[Parameter]: diff --git a/python_modules/dagster/dagster/_core/definitions/op_definition.py b/python_modules/dagster/dagster/_core/definitions/op_definition.py index 58bdfcb9b1c2f..c70a520409654 100644 --- a/python_modules/dagster/dagster/_core/definitions/op_definition.py +++ b/python_modules/dagster/dagster/_core/definitions/op_definition.py @@ -367,12 +367,14 @@ def with_replaced_properties( ) -> "OpDefinition": return OpDefinition.dagster_internal_init( name=name, - ins=ins - or {input_def.name: In.from_definition(input_def) for input_def in self.input_defs}, - outs=outs - or { + ins={input_def.name: In.from_definition(input_def) for input_def in self.input_defs} + if ins is None + else ins, + outs={ output_def.name: Out.from_definition(output_def) for output_def in self.output_defs - }, + } + if outs is None + else outs, compute_fn=self.compute_fn, config_schema=config_schema or self.config_schema, description=description or self.description, diff --git a/python_modules/dagster/dagster/_utils/merger.py b/python_modules/dagster/dagster/_utils/merger.py index dc0e6401cde86..9995315a294a1 100644 --- a/python_modules/dagster/dagster/_utils/merger.py +++ b/python_modules/dagster/dagster/_utils/merger.py @@ -59,3 +59,13 @@ def merge_dicts(*args: Mapping[Any, Any]) -> Dict[Any, Any]: for arg in args: result.update(arg) return result + + +def reverse_dict(d: Mapping[V, K]) -> Dict[K, V]: + """Returns a new dictionary with the keys and values of the input dictionary swapped. + + If the input dictionary has duplicate values, the returned dictionary will have the value from + the last key that maps to it. + """ + check.dict_param(d, "d") + return {v: k for k, v in d.items()} diff --git a/python_modules/dagster/dagster_tests/definitions_tests/test_asset_spec.py b/python_modules/dagster/dagster_tests/definitions_tests/test_asset_spec.py index ddbe373d04b22..a47062ec3a623 100644 --- a/python_modules/dagster/dagster_tests/definitions_tests/test_asset_spec.py +++ b/python_modules/dagster/dagster_tests/definitions_tests/test_asset_spec.py @@ -2,7 +2,14 @@ import dagster as dg import pytest -from dagster import AssetSpec, AutoMaterializePolicy, AutomationCondition +from dagster import ( + AssetSpec, + AutoMaterializePolicy, + AutomationCondition, + IdentityPartitionMapping, + LastPartitionMapping, +) +from dagster._check import CheckError from dagster._core.definitions.asset_dep import AssetDep from dagster._core.definitions.asset_key import AssetKey from dagster._core.definitions.assets import AssetsDefinition @@ -230,3 +237,123 @@ def my_other_multi_asset(): assert all( spec.owners == ["ben@dagsterlabs.com"] for asset in mapped_assets for spec in asset.specs ) + + +def test_map_asset_specs_additional_deps() -> None: + @dg.multi_asset(specs=[AssetSpec(key="a")]) + def my_asset(): + pass + + @dg.multi_asset(specs=[AssetSpec(key="c", deps=["a"])]) + def my_other_asset(): + pass + + assets = [my_asset, my_other_asset] + + mapped_assets = dg.map_asset_specs( + lambda spec: spec.merge_attributes(deps=["b"]) if spec.key == my_other_asset.key else spec, + assets, + ) + + c_asset = next(iter(asset for asset in mapped_assets if asset.key == my_other_asset.key)) + assert set(next(iter(c_asset.specs)).deps) == {AssetDep("a"), AssetDep("b")} + + +def test_map_asset_specs_multiple_deps_same_key() -> None: + @dg.multi_asset(specs=[AssetSpec(key="a", deps=[AssetDep("b")])]) + def my_asset(): + pass + + # This works because the dep is coerced to an identical object. + + dg.map_asset_specs(lambda spec: spec.merge_attributes(deps=[AssetKey("b")]), [my_asset]) + + # This doesn't work because we change the object. + with pytest.raises(DagsterInvariantViolationError): + dg.map_asset_specs( + lambda spec: spec.merge_attributes( + deps=[AssetDep(AssetKey("b"), partition_mapping=LastPartitionMapping())] + ), + [my_asset], + ) + + +def test_map_asset_specs_nonarg_dep_removal() -> None: + @dg.multi_asset(specs=[AssetSpec(key="a", deps=[AssetDep("b")])]) + def my_asset(): + pass + + new_asset = next( + iter(dg.map_asset_specs(lambda spec: spec.replace_attributes(deps=[]), [my_asset])) + ) + new_spec = next(iter(new_asset.specs)) + assert new_spec.deps == [] + # Ensure that dep removal propogated to the underlying op + assert new_asset.keys_by_input_name == {} + assert len(new_asset.op.input_defs) == 0 + + +def test_map_asset_specs_arg_dep_removal() -> None: + @dg.asset(key="a") + def my_asset(b): + pass + + with pytest.raises(CheckError): + dg.map_asset_specs(lambda spec: spec.replace_attributes(deps=[]), [my_asset]) + + +def test_map_additional_deps_partition_mapping() -> None: + @dg.multi_asset( + specs=[AssetSpec(key="a", deps=[AssetDep("b", partition_mapping=LastPartitionMapping())])] + ) + def my_asset(): + pass + + a_asset = next( + iter( + dg.map_asset_specs( + lambda spec: spec.merge_attributes( + deps=[AssetDep("c", partition_mapping=IdentityPartitionMapping())] + ), + [my_asset], + ) + ) + ) + a_spec = next(iter(a_asset.specs)) + b_dep = next(iter(dep for dep in a_spec.deps if dep.asset_key == AssetKey("b"))) + assert b_dep.partition_mapping == LastPartitionMapping() + c_dep = next(iter(dep for dep in a_spec.deps if dep.asset_key == AssetKey("c"))) + assert c_dep.partition_mapping == IdentityPartitionMapping() + assert a_asset.get_partition_mapping(AssetKey("c")) == IdentityPartitionMapping() + assert a_asset.get_partition_mapping(AssetKey("b")) == LastPartitionMapping() + + +def test_add_specs_non_executable_asset() -> None: + assets_def = ( + dg.Definitions(assets=[AssetSpec(key="foo")]) + .get_repository_def() + .assets_defs_by_key[AssetKey("foo")] + ) + foo_spec = next( + iter( + next( + iter( + dg.map_asset_specs(lambda spec: spec.merge_attributes(deps=["a"]), [assets_def]) + ) + ).specs + ) + ) + assert foo_spec.deps == [AssetDep("a")] + + +def test_graph_backed_asset_additional_deps() -> None: + @dg.op + def foo_op(): + pass + + @dg.graph_asset() + def foo(): + return foo_op() + + with pytest.raises(CheckError): + dg.map_asset_specs(lambda spec: spec.merge_attributes(deps=["baz"]), [foo]) From 6b70b14908fc28a53a444c4ed9dc96d3d3c91523 Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Wed, 11 Dec 2024 18:17:05 -0600 Subject: [PATCH 02/94] fix pyright (#26420) fixes for pyright issues that manifested with updated pins ## How I Tested These Changes bk --- .../guides/migrations/migrating_airflow_to_dagster.py | 1 + .../airlift/operator_migration/kubernetes_pod_operator.py | 1 + examples/experimental/external_assets/airflow_example.py | 1 + python_modules/dagster/dagster/_generate/download.py | 1 + .../pythonic_config_tests/test_basic_pythonic_config.py | 4 ++-- .../dagster_tests/storage_tests/test_upath_io_manager.py | 2 +- .../libraries/dagster-airbyte/dagster_airbyte/resources.py | 2 +- .../dagster-databricks/dagster_databricks/databricks.py | 4 ++-- .../libraries/dagster-databricks/dagster_databricks/ops.py | 4 ++-- .../dagster-deltalake/dagster_deltalake/io_manager.py | 6 ++++-- .../dagster-fivetran/dagster_fivetran/resources.py | 4 +--- python_modules/libraries/dagster-ge/dagster_ge/factory.py | 2 +- .../dagster-prometheus/dagster_prometheus/resources.py | 2 +- .../libraries/dagster-pyspark/dagster_pyspark/resources.py | 4 ++-- python_modules/libraries/dagster-shell/dagster_shell/ops.py | 2 +- .../libraries/dagster-tableau/dagster_tableau/assets.py | 2 +- 16 files changed, 23 insertions(+), 19 deletions(-) diff --git a/examples/docs_snippets/docs_snippets/guides/migrations/migrating_airflow_to_dagster.py b/examples/docs_snippets/docs_snippets/guides/migrations/migrating_airflow_to_dagster.py index c546978f13096..e88e8c01e467a 100644 --- a/examples/docs_snippets/docs_snippets/guides/migrations/migrating_airflow_to_dagster.py +++ b/examples/docs_snippets/docs_snippets/guides/migrations/migrating_airflow_to_dagster.py @@ -1,5 +1,6 @@ # ruff: isort: skip_file # ruff: noqa: T201,D415 +# type: ignore # problematic imports in example code def scope_simple_airflow_task(): diff --git a/examples/docs_snippets/docs_snippets/integrations/airlift/operator_migration/kubernetes_pod_operator.py b/examples/docs_snippets/docs_snippets/integrations/airlift/operator_migration/kubernetes_pod_operator.py index bde2a3e5b1a86..aeafe9c74b84f 100644 --- a/examples/docs_snippets/docs_snippets/integrations/airlift/operator_migration/kubernetes_pod_operator.py +++ b/examples/docs_snippets/docs_snippets/integrations/airlift/operator_migration/kubernetes_pod_operator.py @@ -1,3 +1,4 @@ +# type: ignore from airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator k8s_hello_world = KubernetesPodOperator( diff --git a/examples/experimental/external_assets/airflow_example.py b/examples/experimental/external_assets/airflow_example.py index 9585d06d701f6..b326ea323bfbc 100644 --- a/examples/experimental/external_assets/airflow_example.py +++ b/examples/experimental/external_assets/airflow_example.py @@ -1,3 +1,4 @@ +# type: ignore from airflow import DAG from airflow.providers.cncf.kubernetes.operators.kubernetes_pod import KubernetesPodOperator from pendulum import datetime diff --git a/python_modules/dagster/dagster/_generate/download.py b/python_modules/dagster/dagster/_generate/download.py index c8b7ca7223f81..c0365830c1954 100644 --- a/python_modules/dagster/dagster/_generate/download.py +++ b/python_modules/dagster/dagster/_generate/download.py @@ -37,6 +37,7 @@ "feature_graph_backed_assets", "getting_started_etl_tutorial", "project_analytics", + "project_dagster_modal_pipes", "project_dagster_university_start", "project_du_dbt_starter", "project_fully_featured", diff --git a/python_modules/dagster/dagster_tests/core_tests/pythonic_config_tests/test_basic_pythonic_config.py b/python_modules/dagster/dagster_tests/core_tests/pythonic_config_tests/test_basic_pythonic_config.py index 0098cb7588ac2..9e7941ed83a15 100644 --- a/python_modules/dagster/dagster_tests/core_tests/pythonic_config_tests/test_basic_pythonic_config.py +++ b/python_modules/dagster/dagster_tests/core_tests/pythonic_config_tests/test_basic_pythonic_config.py @@ -707,7 +707,7 @@ def test_structured_run_config_optional() -> None: class ANewConfigOpConfig(Config): a_string: Optional[str] an_int: Optional[int] = None - a_float: float = PyField(None) + a_float: float = PyField(None) # type: ignore executed = {} @@ -805,7 +805,7 @@ def my_asset(config: AnAssetConfig): def test_structured_run_config_assets_optional() -> None: class AnAssetConfig(Config): - a_string: str = PyField(None) + a_string: str = PyField(None) # type: ignore an_int: Optional[int] = None executed = {} diff --git a/python_modules/dagster/dagster_tests/storage_tests/test_upath_io_manager.py b/python_modules/dagster/dagster_tests/storage_tests/test_upath_io_manager.py index da3b9ee155a37..be3858701e26f 100644 --- a/python_modules/dagster/dagster_tests/storage_tests/test_upath_io_manager.py +++ b/python_modules/dagster/dagster_tests/storage_tests/test_upath_io_manager.py @@ -464,7 +464,7 @@ def my_asset() -> Any: class AsyncJSONIOManager(ConfigurableIOManager, UPathIOManager): - base_dir: str = PydanticField(None, description="Base directory for storing files.") + base_dir: str = PydanticField(None, description="Base directory for storing files.") # type: ignore _base_path: UPath = PrivateAttr() diff --git a/python_modules/libraries/dagster-airbyte/dagster_airbyte/resources.py b/python_modules/libraries/dagster-airbyte/dagster_airbyte/resources.py index 0625b7c1073b0..d17f975d3586a 100644 --- a/python_modules/libraries/dagster-airbyte/dagster_airbyte/resources.py +++ b/python_modules/libraries/dagster-airbyte/dagster_airbyte/resources.py @@ -1018,7 +1018,7 @@ class AirbyteCloudWorkspace(ConfigurableResource): description="Time (in seconds) after which the requests to Airbyte are declared timed out.", ) - _client: AirbyteCloudClient = PrivateAttr(default=None) + _client: AirbyteCloudClient = PrivateAttr(default=None) # type: ignore @cached_method def get_client(self) -> AirbyteCloudClient: diff --git a/python_modules/libraries/dagster-databricks/dagster_databricks/databricks.py b/python_modules/libraries/dagster-databricks/dagster_databricks/databricks.py index afbd41a4a8786..9a5c6656c6c44 100644 --- a/python_modules/libraries/dagster-databricks/dagster_databricks/databricks.py +++ b/python_modules/libraries/dagster-databricks/dagster_databricks/databricks.py @@ -374,7 +374,7 @@ def wait_for_run_to_complete( logger: logging.Logger, databricks_run_id: int, poll_interval_sec: float, - max_wait_time_sec: int, + max_wait_time_sec: float, verbose_logs: bool = True, ) -> None: logger.info(f"Waiting for Databricks run `{databricks_run_id}` to complete...") @@ -413,7 +413,7 @@ def __init__( azure_client_secret: Optional[str] = None, azure_tenant_id: Optional[str] = None, poll_interval_sec: float = 5, - max_wait_time_sec: int = DEFAULT_RUN_MAX_WAIT_TIME_SEC, + max_wait_time_sec: float = DEFAULT_RUN_MAX_WAIT_TIME_SEC, ): self.host = check.opt_str_param(host, "host") self.token = check.opt_str_param(token, "token") diff --git a/python_modules/libraries/dagster-databricks/dagster_databricks/ops.py b/python_modules/libraries/dagster-databricks/dagster_databricks/ops.py index 56d70045daae9..bb0afabb36e54 100644 --- a/python_modules/libraries/dagster-databricks/dagster_databricks/ops.py +++ b/python_modules/libraries/dagster-databricks/dagster_databricks/ops.py @@ -93,7 +93,7 @@ class DatabricksRunNowOpConfig(Config): default=_poll_interval_seconds, description="Check whether the Databricks Job is done at this interval, in seconds.", ) - max_wait_time_seconds: int = Field( + max_wait_time_seconds: float = Field( default=_max_wait_time_seconds, description=( "If the Databricks Job is not complete after this length of time, in seconds," @@ -205,7 +205,7 @@ class DatabricksSubmitRunOpConfig(Config): default=_poll_interval_seconds, description="Check whether the Databricks Job is done at this interval, in seconds.", ) - max_wait_time_seconds: int = Field( + max_wait_time_seconds: float = Field( default=_max_wait_time_seconds, description=( "If the Databricks Job is not complete after this length of time, in seconds," diff --git a/python_modules/libraries/dagster-deltalake/dagster_deltalake/io_manager.py b/python_modules/libraries/dagster-deltalake/dagster_deltalake/io_manager.py index 17ce19d31c1af..131e1475a260f 100644 --- a/python_modules/libraries/dagster-deltalake/dagster_deltalake/io_manager.py +++ b/python_modules/libraries/dagster-deltalake/dagster_deltalake/io_manager.py @@ -125,11 +125,13 @@ def my_table_a(my_table: pd.DataFrame): root_uri: str = Field(description="Storage location where Delta tables are stored.") mode: WriteMode = Field( - default=WriteMode.overwrite.value, description="The write mode passed to save the output." + default=WriteMode.overwrite.value, # type: ignore + description="The write mode passed to save the output.", ) overwrite_schema: bool = Field(default=False) writer_engine: WriterEngine = Field( - default=WriterEngine.pyarrow.value, description="Engine passed to write_deltalake." + default=WriterEngine.pyarrow.value, # type: ignore + description="Engine passed to write_deltalake.", ) storage_options: Union[AzureConfig, S3Config, LocalConfig, GcsConfig] = Field( diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py index 01936211cc2ed..867c9e6a8a30c 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py @@ -30,7 +30,7 @@ from dagster._record import as_dict, record from dagster._utils.cached_method import cached_method from dagster._vendored.dateutil import parser -from pydantic import Field, PrivateAttr +from pydantic import Field from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException @@ -858,8 +858,6 @@ class FivetranWorkspace(ConfigurableResource): ), ) - _client: FivetranClient = PrivateAttr(default=None) - @cached_method def get_client(self) -> FivetranClient: return FivetranClient( diff --git a/python_modules/libraries/dagster-ge/dagster_ge/factory.py b/python_modules/libraries/dagster-ge/dagster_ge/factory.py index bf42e6e8a5310..b0313bc4d88df 100644 --- a/python_modules/libraries/dagster-ge/dagster_ge/factory.py +++ b/python_modules/libraries/dagster-ge/dagster_ge/factory.py @@ -27,7 +27,7 @@ class GEContextResource(ConfigurableResource, IAttachDifferentObjectToOpContext): - ge_root_dir: str = Field( + ge_root_dir: Optional[str] = Field( default=None, description="The root directory for your Great Expectations project.", ) diff --git a/python_modules/libraries/dagster-prometheus/dagster_prometheus/resources.py b/python_modules/libraries/dagster-prometheus/dagster_prometheus/resources.py index da9c1f202d493..993fccede5ddd 100644 --- a/python_modules/libraries/dagster-prometheus/dagster_prometheus/resources.py +++ b/python_modules/libraries/dagster-prometheus/dagster_prometheus/resources.py @@ -46,7 +46,7 @@ def my_job(): default=30, description="is how long delete will attempt to connect before giving up. Defaults to 30s.", ) - _registry: prometheus_client.CollectorRegistry = PrivateAttr(default=None) + _registry: prometheus_client.CollectorRegistry = PrivateAttr(default=None) # type: ignore @classmethod def _is_dagster_maintained(cls) -> bool: diff --git a/python_modules/libraries/dagster-pyspark/dagster_pyspark/resources.py b/python_modules/libraries/dagster-pyspark/dagster_pyspark/resources.py index 9a3c34df7f0d9..71fb888515d6b 100644 --- a/python_modules/libraries/dagster-pyspark/dagster_pyspark/resources.py +++ b/python_modules/libraries/dagster-pyspark/dagster_pyspark/resources.py @@ -132,12 +132,12 @@ def _init_session(self) -> None: @property def spark_session(self) -> Any: self._init_session() - return self._spark_session + return check.not_none(self._spark_session) @property def spark_context(self) -> Any: self._init_session() - return self._spark_session.sparkContext + return check.not_none(self._spark_session).sparkContext @dagster_maintained_resource diff --git a/python_modules/libraries/dagster-shell/dagster_shell/ops.py b/python_modules/libraries/dagster-shell/dagster_shell/ops.py index d22d49b41b1c3..ae0cbf32c6eb3 100644 --- a/python_modules/libraries/dagster-shell/dagster_shell/ops.py +++ b/python_modules/libraries/dagster-shell/dagster_shell/ops.py @@ -36,7 +36,7 @@ class ShellOpConfig(Config): description="An optional dict of environment variables to pass to the subprocess.", ) output_logging: OutputType = Field( - default=OutputType.BUFFER.value, + default=OutputType.BUFFER.value, # type: ignore ) cwd: Optional[str] = Field( default=None, description="Working directory in which to execute shell script" diff --git a/python_modules/libraries/dagster-tableau/dagster_tableau/assets.py b/python_modules/libraries/dagster-tableau/dagster_tableau/assets.py index 4ab7c99cf038b..55507697ee0a1 100644 --- a/python_modules/libraries/dagster-tableau/dagster_tableau/assets.py +++ b/python_modules/libraries/dagster-tableau/dagster_tableau/assets.py @@ -42,7 +42,7 @@ def build_tableau_materializable_assets_definition( def asset_fn(context: AssetExecutionContext): tableau = cast(BaseTableauWorkspace, getattr(context.resources, resource_key)) with tableau.get_client() as client: - yield from client.refresh_and_materialize_workbooks( # pyright: ignore[reportOptionalMemberAccess] + yield from client.refresh_and_materialize_workbooks( specs=specs, refreshable_workbook_ids=refreshable_workbook_ids ) From 4637108ebd5e2a3e4e43672a404ebff1913c19b7 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Wed, 11 Dec 2024 20:10:30 -0500 Subject: [PATCH 03/94] [components] Improve docstrings and clean up code in dagster-dg (#26406) ## Summary & Motivation Improve the docstrings for `dg` commands. Also convert them to use `Path` instead of `str` where possible. ## How I Tested These Changes Existing test suite. --- .../dagster-dg/dagster_dg/cli/generate.py | 81 ++++++++++++++++--- .../dagster-dg/dagster_dg/cli/list.py | 10 +-- .../dagster-dg/dagster_dg/generate.py | 10 +-- .../libraries/dagster-dg/dagster_dg/utils.py | 22 +++-- .../cli_tests/test_generate_commands.py | 4 +- .../cli_tests/test_list_commands.py | 6 +- 6 files changed, 93 insertions(+), 40 deletions(-) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index 5034c1b5943fd..a8c18bd490b86 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -25,9 +25,13 @@ def generate_cli() -> None: @generate_cli.command(name="deployment") -@click.argument("path", type=str) -def generate_deployment_command(path: str) -> None: - """Generate a Dagster deployment instance.""" +@click.argument("path", type=Path) +def generate_deployment_command(path: Path) -> None: + """Generate a Dagster deployment file structure. + + The deployment file structure includes a directory for code locations and configuration files + for deploying to Dagster Plus. + """ dir_abspath = os.path.abspath(path) if os.path.exists(dir_abspath): click.echo( @@ -42,15 +46,37 @@ def generate_deployment_command(path: str) -> None: @click.argument("name", type=str) @click.option("--use-editable-dagster", is_flag=True, default=False) def generate_code_location_command(name: str, use_editable_dagster: bool) -> None: - """Generate a Dagster code location inside a component.""" + """Generate a Dagster code location file structure and a uv-managed virtual environment scoped + to the code location. + + This command can be run inside or outside of a deployment directory. If run inside a deployment, + the code location will be created within the deployment directory's code location directory. + + The code location file structure defines a Python package with some pre-existing internal + structure: + + ├── + │ ├── __init__.py + │ ├── components + │ ├── definitions.py + │ └── lib + │ └── __init__.py + ├── _tests + │ └── __init__.py + └── pyproject.toml + + The `.components` directory holds components (which can be created with `dg generate + component`). The `.lib` directory holds custom component types scoped to the code + location (which can be created with `dg generate component-type`). + """ if is_inside_deployment_project(Path.cwd()): context = DeploymentProjectContext.from_path(Path.cwd()) if context.has_code_location(name): click.echo(click.style(f"A code location named {name} already exists.", fg="red")) sys.exit(1) - code_location_path = os.path.join(context.code_location_root_path, name) + code_location_path = context.code_location_root_path / name else: - code_location_path = os.path.join(Path.cwd(), name) + code_location_path = Path.cwd() / name if use_editable_dagster: if "DAGSTER_GIT_REPO_DIR" not in os.environ: @@ -71,11 +97,15 @@ def generate_code_location_command(name: str, use_editable_dagster: bool) -> Non @generate_cli.command(name="component-type") @click.argument("name", type=str) def generate_component_type_command(name: str) -> None: - """Generate a Dagster component instance.""" + """Generate a scaffold of a custom Dagster component type. + + This command must be run inside a Dagster code location directory. The component type scaffold + will be generated in submodule `.lib.`. + """ if not is_inside_code_location_project(Path.cwd()): click.echo( click.style( - "This command must be run inside a Dagster code location project.", fg="red" + "This command must be run inside a Dagster code location directory.", fg="red" ) ) sys.exit(1) @@ -85,13 +115,16 @@ def generate_component_type_command(name: str) -> None: click.echo(click.style(f"A component type named `{name}` already exists.", fg="red")) sys.exit(1) - generate_component_type(context.component_types_root_path, name) + generate_component_type(Path(context.component_types_root_path), name) @generate_cli.command(name="component") -@click.argument("component_type", type=str) +@click.argument( + "component_type", + type=str, +) @click.argument("component_name", type=str) -@click.option("--json-params", type=str, default=None) +@click.option("--json-params", type=str, default=None, help="JSON string of component parameters.") @click.argument("extra_args", nargs=-1, type=str) def generate_component_command( component_type: str, @@ -99,10 +132,32 @@ def generate_component_command( json_params: Optional[str], extra_args: Tuple[str, ...], ) -> None: + """Generate a scaffold of a Dagster component. + + This command must be run inside a Dagster code location directory. The component scaffold will be + generated in submodule `.components.`. + + The COMPONENT_TYPE must be a registered component type in the code location environment. + You can view all registered component types with `dg list component-types`. The COMPONENT_NAME + will be used to name the submodule created under .components. + + Components can optionally be passed generate parameters. There are two ways to do this: + + - Passing --json-params with a JSON string of parameters. For example: + + dg generate component foo.bar my_component --json-params '{"param1": "value", "param2": "value"}'`. + + - Passing key-value pairs as space-separated EXTRA_ARGS after `--`. For example: + + dg generate component foo.bar my_component -- param1=value param2=value + + When key-value pairs are used, the value type will be inferred from the + underlying component generation schema. + """ if not is_inside_code_location_project(Path.cwd()): click.echo( click.style( - "This command must be run inside a Dagster code location project.", fg="red" + "This command must be run inside a Dagster code location directory.", fg="red" ) ) sys.exit(1) @@ -120,7 +175,7 @@ def generate_component_command( sys.exit(1) generate_component_instance( - context.component_instances_root_path, + Path(context.component_instances_root_path), component_name, component_type, json_params, diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py index 1cb7f0a91d2de..3ad2e561b16af 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py @@ -21,7 +21,7 @@ def list_code_locations_command() -> None: """List code locations in the current deployment.""" if not is_inside_deployment_project(Path.cwd()): click.echo( - click.style("This command must be run inside a Dagster deployment project.", fg="red") + click.style("This command must be run inside a Dagster deployment directory.", fg="red") ) sys.exit(1) @@ -32,11 +32,11 @@ def list_code_locations_command() -> None: @list_cli.command(name="component-types") def list_component_types_command() -> None: - """List registered Dagster components.""" + """List registered Dagster components in the current code location environment.""" if not is_inside_code_location_project(Path.cwd()): click.echo( click.style( - "This command must be run inside a Dagster code location project.", fg="red" + "This command must be run inside a Dagster code location directory.", fg="red" ) ) sys.exit(1) @@ -48,11 +48,11 @@ def list_component_types_command() -> None: @list_cli.command(name="components") def list_components_command() -> None: - """List Dagster component instances in a code location.""" + """List Dagster component instances defined in the current code location.""" if not is_inside_code_location_project(Path.cwd()): click.echo( click.style( - "This command must be run inside a Dagster code location project.", fg="red" + "This command must be run inside a Dagster code location directory.", fg="red" ) ) sys.exit(1) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index 1ca5c72bad6be..f469b9c824e94 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -13,7 +13,7 @@ ) -def generate_deployment(path: str) -> None: +def generate_deployment(path: Path) -> None: click.echo(f"Creating a Dagster deployment at {path}.") generate_subtree( @@ -25,7 +25,7 @@ def generate_deployment(path: str) -> None: ) -def generate_code_location(path: str, editable_dagster_root: Optional[str] = None) -> None: +def generate_code_location(path: Path, editable_dagster_root: Optional[str] = None) -> None: click.echo(f"Creating a Dagster code location at {path}.") # Temporarily we always set an editable dagster root. This is needed while the packages are not @@ -65,7 +65,7 @@ def generate_code_location(path: str, editable_dagster_root: Optional[str] = Non execute_code_location_command(Path(path), ("uv", "sync")) -def generate_component_type(root_path: str, name: str) -> None: +def generate_component_type(root_path: Path, name: str) -> None: click.echo(f"Creating a Dagster component type at {root_path}/{name}.py.") generate_subtree( @@ -79,7 +79,7 @@ def generate_component_type(root_path: str, name: str) -> None: def generate_component_instance( - root_path: str, + root_path: Path, name: str, component_type: str, json_params: Optional[str], @@ -87,7 +87,7 @@ def generate_component_instance( ) -> None: click.echo(f"Creating a Dagster component instance at {root_path}/{name}.py.") - component_instance_root_path = os.path.join(root_path, name) + component_instance_root_path = root_path / name generate_subtree( path=component_instance_root_path, name_placeholder="COMPONENT_INSTANCE_NAME_PLACEHOLDER", diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index 2452d563fee9c..cef8b663368e3 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -72,7 +72,7 @@ def snakecase(string: str) -> str: # Copied from dagster._generate.generate def generate_subtree( - path: str, + path: Path, excludes: Optional[List[str]] = None, name_placeholder: str = PROJECT_NAME_PLACEHOLDER, templates_path: str = PROJECT_NAME_PLACEHOLDER, @@ -87,9 +87,7 @@ def generate_subtree( if not os.path.exists(normalized_path): os.mkdir(normalized_path) - project_template_path: str = os.path.join( - os.path.dirname(__file__), "templates", templates_path - ) + project_template_path = os.path.join(os.path.dirname(__file__), "templates", templates_path) loader: jinja2.loaders.FileSystemLoader = jinja2.FileSystemLoader( searchpath=project_template_path ) @@ -99,17 +97,17 @@ def generate_subtree( for root, dirs, files in os.walk(project_template_path): # For each subdirectory in the source template, create a subdirectory in the destination. for dirname in dirs: - src_dir_path: str = os.path.join(root, dirname) + src_dir_path = os.path.join(root, dirname) if _should_skip_file(src_dir_path, excludes): continue - src_relative_dir_path: str = os.path.relpath(src_dir_path, project_template_path) - dst_relative_dir_path: str = src_relative_dir_path.replace( + src_relative_dir_path = os.path.relpath(src_dir_path, project_template_path) + dst_relative_dir_path = src_relative_dir_path.replace( name_placeholder, project_name, 1, ) - dst_dir_path: str = os.path.join(normalized_path, dst_relative_dir_path) + dst_dir_path = os.path.join(normalized_path, dst_relative_dir_path) os.mkdir(dst_dir_path) @@ -119,20 +117,20 @@ def generate_subtree( if _should_skip_file(src_file_path, excludes): continue - src_relative_file_path: str = os.path.relpath(src_file_path, project_template_path) - dst_relative_file_path: str = src_relative_file_path.replace( + src_relative_file_path = os.path.relpath(src_file_path, project_template_path) + dst_relative_file_path = src_relative_file_path.replace( name_placeholder, project_name, 1, ) - dst_file_path: str = os.path.join(normalized_path, dst_relative_file_path) + dst_file_path = os.path.join(normalized_path, dst_relative_file_path) if dst_file_path.endswith(".jinja"): dst_file_path = dst_file_path[: -len(".jinja")] with open(dst_file_path, "w", encoding="utf8") as f: # Jinja template names must use the POSIX path separator "/". - template_name: str = src_relative_file_path.replace(os.sep, posixpath.sep) + template_name = src_relative_file_path.replace(os.sep, posixpath.sep) template: jinja2.environment.Template = env.get_template(name=template_name) f.write( template.render( diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 776d33f996bff..8275d839690cd 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -235,7 +235,7 @@ def test_generate_component_type_outside_code_location_fails() -> None: with isolated_example_deployment_foo(runner): result = runner.invoke(generate_component_type_command, ["baz"]) assert result.exit_code != 0 - assert "must be run inside a Dagster code location project" in result.output + assert "must be run inside a Dagster code location directory" in result.output @pytest.mark.parametrize("in_deployment", [True, False]) @@ -267,7 +267,7 @@ def test_generate_component_outside_code_location_fails() -> None: with isolated_example_deployment_foo(runner): result = runner.invoke(generate_component_command, ["bar.baz", "qux"]) assert result.exit_code != 0 - assert "must be run inside a Dagster code location project" in result.output + assert "must be run inside a Dagster code location directory" in result.output @pytest.mark.parametrize("in_deployment", [True, False]) diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py index 630d2ae2fa95b..f48f2e7d4ce6d 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py @@ -43,7 +43,7 @@ def test_list_code_locations_outside_deployment_fails() -> None: with runner.isolated_filesystem(): result = runner.invoke(list_code_locations_command) assert result.exit_code != 0 - assert "must be run inside a Dagster deployment project" in result.output + assert "must be run inside a Dagster deployment directory" in result.output def test_list_component_types_success(): @@ -69,7 +69,7 @@ def test_list_component_types_outside_code_location_fails() -> None: with runner.isolated_filesystem(): result = runner.invoke(list_component_types_command) assert result.exit_code != 0 - assert "must be run inside a Dagster code location project" in result.output + assert "must be run inside a Dagster code location directory" in result.output def test_list_components_succeeds(): @@ -87,4 +87,4 @@ def test_list_components_command_outside_code_location_fails() -> None: with runner.isolated_filesystem(): result = runner.invoke(list_components_command) assert result.exit_code != 0 - assert "must be run inside a Dagster code location project" in result.output + assert "must be run inside a Dagster code location directory" in result.output From 65751c78cd0e2d2a26b1ff9b04efe832630eb9e2 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Wed, 11 Dec 2024 20:11:41 -0500 Subject: [PATCH 04/94] [components] Error on passing both --json-params and EXTRA_ARGS to `dg generate component` (#26418) ## Summary & Motivation Have `dagster-dg` throw an error when both `--json-params` and `EXTRA_ARGS` are passed to `dg generate component`. These are mutually exclusive ways of specifying parameters. ## How I Tested These Changes New unit tests. --- .../dagster-dg/dagster_dg/cli/generate.py | 12 ++++ .../dagster-dg/dagster_dg/generate.py | 2 +- .../cli_tests/test_generate_commands.py | 72 +++++++++++++++++-- python_modules/libraries/dagster-dg/setup.py | 2 +- 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index a8c18bd490b86..be58f8b0284ea 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -153,6 +153,8 @@ def generate_component_command( When key-value pairs are used, the value type will be inferred from the underlying component generation schema. + + It is an error to pass both --json-params and EXTRA_ARGS. """ if not is_inside_code_location_project(Path.cwd()): click.echo( @@ -174,6 +176,16 @@ def generate_component_command( ) sys.exit(1) + if json_params is not None and extra_args: + click.echo( + click.style( + "Detected both --json-params and EXTRA_ARGS. These are mutually exclusive means of passing" + " component generation parameters. Use only one.", + fg="red", + ) + ) + sys.exit(1) + generate_component_instance( Path(context.component_instances_root_path), component_name, diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index f469b9c824e94..6bf0ee7f42b4a 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -103,7 +103,7 @@ def generate_component_instance( "component", component_type, name, - *([f"--json-params={json_params}"] if json_params else []), + *(["--json-params", json_params] if json_params else []), *(["--", *extra_args] if extra_args else []), ) execute_code_location_command(Path(component_instance_root_path), code_location_command) diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 8275d839690cd..2d99002b9da92 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -33,10 +33,10 @@ def _assert_module_imports(module_name: str): # This is a holder for code that is intended to be written to a file def _example_component_type_baz(): - from typing import Any - + import click from dagster import AssetExecutionContext, Definitions, PipesSubprocessClient, asset from dagster_components import Component, ComponentLoadContext, component + from pydantic import BaseModel _SAMPLE_PIPES_SCRIPT = """ from dagster_pipes import open_dagster_pipes @@ -45,11 +45,22 @@ def _example_component_type_baz(): context.report_asset_materialization({"alpha": "beta"}) """ + class BazGenerateParams(BaseModel): + filename: str = "sample.py" + + @staticmethod + @click.command + @click.option("--filename", type=str, default="sample.py") + def cli(filename: str) -> "BazGenerateParams": + return BazGenerateParams(filename=filename) + @component(name="baz") class Baz(Component): + generate_params_schema = BazGenerateParams + @classmethod - def generate_files(cls, params: Any): - with open("sample.py", "w") as f: + def generate_files(cls, params: BazGenerateParams): + with open(params.filename, "w") as f: f.write(_SAMPLE_PIPES_SCRIPT) def build_defs(self, context: ComponentLoadContext) -> Definitions: @@ -250,18 +261,67 @@ def test_generate_component_type_already_exists_fails(in_deployment: bool) -> No @pytest.mark.parametrize("in_deployment", [True, False]) -def test_generate_component_success(in_deployment: bool) -> None: +def test_generate_component_no_params_success(in_deployment: bool) -> None: runner = CliRunner() with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): result = runner.invoke(generate_component_command, ["bar.baz", "qux"]) assert result.exit_code == 0 assert Path("bar/components/qux").exists() - assert Path("bar/components/qux/sample.py").exists() + assert Path("bar/components/qux/sample.py").exists() # default filename + component_yaml_path = Path("bar/components/qux/component.yaml") + assert component_yaml_path.exists() + assert "type: bar.baz" in component_yaml_path.read_text() + + +@pytest.mark.parametrize("in_deployment", [True, False]) +def test_generate_component_json_params_success(in_deployment: bool) -> None: + runner = CliRunner() + with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): + result = runner.invoke( + generate_component_command, + ["bar.baz", "qux", "--json-params", '{"filename": "hello.py"}'], + ) + assert result.exit_code == 0 + assert Path("bar/components/qux").exists() + assert Path("bar/components/qux/hello.py").exists() + component_yaml_path = Path("bar/components/qux/component.yaml") + assert component_yaml_path.exists() + assert "type: bar.baz" in component_yaml_path.read_text() + + +@pytest.mark.parametrize("in_deployment", [True, False]) +def test_generate_component_extra_args_success(in_deployment: bool) -> None: + runner = CliRunner() + with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): + result = runner.invoke( + generate_component_command, ["bar.baz", "qux", "--", "--filename=hello.py"] + ) + assert result.exit_code == 0 + assert Path("bar/components/qux").exists() + assert Path("bar/components/qux/hello.py").exists() component_yaml_path = Path("bar/components/qux/component.yaml") assert component_yaml_path.exists() assert "type: bar.baz" in component_yaml_path.read_text() +def test_generate_component_json_params_and_extra_args_fails() -> None: + runner = CliRunner() + with isolated_example_code_location_bar_with_component_type_baz(runner): + result = runner.invoke( + generate_component_command, + [ + "bar.baz", + "qux", + "--json-params", + '{"filename": "hello.py"}', + "--", + "--filename=hello.py", + ], + ) + assert result.exit_code != 0 + assert "Detected both --json-params and EXTRA_ARGS" in result.output + + def test_generate_component_outside_code_location_fails() -> None: runner = CliRunner() with isolated_example_deployment_foo(runner): diff --git a/python_modules/libraries/dagster-dg/setup.py b/python_modules/libraries/dagster-dg/setup.py index 767da03708ef4..78f487255a4cc 100644 --- a/python_modules/libraries/dagster-dg/setup.py +++ b/python_modules/libraries/dagster-dg/setup.py @@ -46,6 +46,6 @@ def get_version() -> str: ] }, extras_require={ - "test": ["pytest"], + "test": ["click", "pydantic", "pytest"], }, ) From f523e338a9f6835dc23a5fae913a1b693b7f1fc7 Mon Sep 17 00:00:00 2001 From: Ian Jenkins Date: Thu, 12 Dec 2024 08:48:05 +0000 Subject: [PATCH 05/94] [dagster_aws][pipes] Don't cause an error when get_log_events raises certain exceptions (#26308) Sometimes CloudWatch returns an empty list instead of raising an error for missing log streams. This PR fixes the log stream readiness check in `PipesCloudWatchMessageReader` by taking this into account. Also, `get_log_events` now retries on throttling exceptions with an exponential backoff. ## Summary & Motivation Messages weren't showing from my ECS task due to an exception being thrown about the log stream not being ready. ## How I Tested These Changes Existing test suite ## Changelog * [dagster-aws] PipesCloudWatchMessageReader correctly identifies streams which are not ready yet and doesn't fail on ThrottlingException anymore (retries added) --- .../dagster_aws/pipes/message_readers.py | 59 ++++++++++++++++--- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/python_modules/libraries/dagster-aws/dagster_aws/pipes/message_readers.py b/python_modules/libraries/dagster-aws/dagster_aws/pipes/message_readers.py index b81f57f4d6894..7f857d94bce10 100644 --- a/python_modules/libraries/dagster-aws/dagster_aws/pipes/message_readers.py +++ b/python_modules/libraries/dagster-aws/dagster_aws/pipes/message_readers.py @@ -37,6 +37,7 @@ extract_message_or_forward_to_stdout, forward_only_logs_to_file, ) +from dagster._utils.backoff import backoff from dagster_pipes import PipesBlobStoreMessageWriter, PipesDefaultMessageWriter if TYPE_CHECKING: @@ -216,11 +217,41 @@ def no_messages_debug_text(self) -> str: ) +# Number of retries to attempt getting cloudwatch logs when faced with a throttling exception. +DEFAULT_CLOUDWATCH_LOGS_MAX_RETRIES = 10 + + +# Custom backoff delay_generator for get_log_events which adds some jitter +def get_log_events_delay_generator() -> Iterator[float]: + i = 0.5 + while True: + yield i + i *= 2 + i += random.uniform(0, 1) + + +def get_log_events( + client: "CloudWatchLogsClient", + max_retries: Optional[int] = DEFAULT_CLOUDWATCH_LOGS_MAX_RETRIES, + **log_params, +): + max_retries = max_retries or DEFAULT_CLOUDWATCH_LOGS_MAX_RETRIES + + return backoff( + fn=client.get_log_events, + kwargs=log_params, + retry_on=(client.exceptions.ThrottlingException,), + max_retries=max_retries, + delay_generator=get_log_events_delay_generator(), + ) + + def tail_cloudwatch_events( client: "CloudWatchLogsClient", log_group: str, log_stream: str, start_time: Optional[int] = None, + max_retries: Optional[int] = DEFAULT_CLOUDWATCH_LOGS_MAX_RETRIES, ) -> Generator[List["OutputLogEventTypeDef"], None, None]: """Yields events from a CloudWatch log stream.""" params: Dict[str, Any] = { @@ -231,7 +262,7 @@ def tail_cloudwatch_events( if start_time is not None: params["startTime"] = start_time - response = client.get_log_events(**params) + response = get_log_events(client=client, max_retries=max_retries, **params) while True: events = response.get("events") @@ -241,7 +272,7 @@ def tail_cloudwatch_events( params["nextToken"] = response["nextForwardToken"] - response = client.get_log_events(**params) + response = get_log_events(client=client, max_retries=max_retries, **params) @experimental @@ -254,6 +285,7 @@ def __init__( target_stream: Optional[IO[str]] = None, start_time: Optional[int] = None, debug_info: Optional[str] = None, + max_retries: Optional[int] = DEFAULT_CLOUDWATCH_LOGS_MAX_RETRIES, ): self.client = client or boto3.client("logs") self.log_group = log_group @@ -262,6 +294,7 @@ def __init__( self.thread = None self.start_time = start_time self._debug_info = debug_info + self.max_retries = max_retries @property def debug_info(self) -> Optional[str]: @@ -274,11 +307,15 @@ def target_is_readable(self, params: PipesParams) -> bool: if log_group is not None and log_stream is not None: # check if the stream actually exists try: - self.client.describe_log_streams( + resp = self.client.describe_log_streams( logGroupName=log_group, logStreamNamePrefix=log_stream, ) - return True + + if resp.get("logStreams", []): + return True + else: + return False except self.client.exceptions.ResourceNotFoundException: return False else: @@ -301,7 +338,7 @@ def _start(self, params: PipesParams, is_session_closed: Event) -> None: start_time = cast(int, self.start_time or params.get("start_time")) for events in tail_cloudwatch_events( - self.client, log_group, log_stream, start_time=start_time + self.client, log_group, log_stream, start_time=start_time, max_retries=self.max_retries ): for event in events: for line in event.get("message", "").splitlines(): @@ -328,6 +365,7 @@ def __init__( log_group: Optional[str] = None, log_stream: Optional[str] = None, log_readers: Optional[Sequence[PipesLogReader]] = None, + max_retries: Optional[int] = DEFAULT_CLOUDWATCH_LOGS_MAX_RETRIES, ): """Args: client (boto3.client): boto3 CloudWatch client. @@ -335,6 +373,7 @@ def __init__( self.client: "CloudWatchLogsClient" = client or boto3.client("logs") self.log_group = log_group self.log_stream = log_stream + self.max_retries = max_retries self.start_time = datetime.now() @@ -357,11 +396,15 @@ def messages_are_readable(self, params: PipesParams) -> bool: if self.log_group is not None and self.log_stream is not None: # check if the stream actually exists try: - self.client.describe_log_streams( + resp = self.client.describe_log_streams( logGroupName=self.log_group, logStreamNamePrefix=self.log_stream, ) - return True + + if resp.get("logStreams", []): + return True + else: + return False except self.client.exceptions.ResourceNotFoundException: return False else: @@ -379,7 +422,7 @@ def download_messages( if cursor is not None: params["nextToken"] = cursor - response = self.client.get_log_events(**params) + response = get_log_events(client=self.client, max_retries=self.max_retries, **params) events = response.get("events") From dac2fd2990a512527ac908798276c3ef17979b83 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Thu, 12 Dec 2024 08:21:38 -0500 Subject: [PATCH 06/94] [components] Add support for extras (conditional imports version) (#26440) ## Summary & Motivation Add support for extras in component discovery in `dagster-components`. Alternative to #26417 (conditional entry point loading) that instead uses conditional import statements: - Discovery mechanism has changed so that submodules of the target module of an entry point are no longer traversed. Instead we look only at the specified module for declared components. - Because we load everything coming from the entry point target, and we unconditionally load every declared entry point, we place the burden on component library authors to examine the environment and skip loading any components corresponding to uninstalled extras. - Implementation of this approach in `dagster_components.lib`, where we condition imports of components for the `dbt` and `sling` extras on the presence of `dagster-dbt` and `dagster-embedded-elt` packages in the environment. Basically we are just hardcoding in `dagster_components/lib/__init__.py` a repeat of the dependencies associated with each extra rather than reading them from package metadata (approach in #26417). ## How I Tested These Changes Unit tests confirming only the correct components are registered when each extra is installed. --- .../dagster_components/core/component.py | 14 +- .../dagster_components/lib/__init__.py | 16 ++ .../dagster_components/lib/dbt_project.py | 2 +- .../unit_tests/test_registry.py | 185 +++++++++++------- 4 files changed, 141 insertions(+), 76 deletions(-) diff --git a/python_modules/libraries/dagster-components/dagster_components/core/component.py b/python_modules/libraries/dagster-components/dagster_components/core/component.py index fe15ed559e48e..524bcd5f58766 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/component.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/component.py @@ -88,16 +88,12 @@ def __repr__(self) -> str: return f"" -def get_registered_components_in_module(root_module: ModuleType) -> Iterable[Type[Component]]: - from dagster._core.definitions.load_assets_from_modules import ( - find_modules_in_package, - find_subclasses_in_module, - ) +def get_registered_components_in_module(module: ModuleType) -> Iterable[Type[Component]]: + from dagster._core.definitions.load_assets_from_modules import find_subclasses_in_module - for module in find_modules_in_package(root_module): - for component in find_subclasses_in_module(module, (Component,)): - if is_registered_component(component): - yield component + for component in find_subclasses_in_module(module, (Component,)): + if is_registered_component(component): + yield component class ComponentLoadContext: diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/__init__.py b/python_modules/libraries/dagster-components/dagster_components/lib/__init__.py index e69de29bb2d1d..bc6a6f9f3e6d9 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/__init__.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/__init__.py @@ -0,0 +1,16 @@ +import importlib.util + +_has_dagster_dbt = importlib.util.find_spec("dagster_dbt") is not None +_has_dagster_embedded_elt = importlib.util.find_spec("dagster_embedded_elt") is not None + +if _has_dagster_dbt: + from dagster_components.lib.dbt_project import DbtProjectComponent as DbtProjectComponent + +if _has_dagster_embedded_elt: + from dagster_components.lib.sling_replication import ( + SlingReplicationComponent as SlingReplicationComponent, + ) + +from dagster_components.lib.pipes_subprocess_script_collection import ( + PipesSubprocessScriptCollection as PipesSubprocessScriptCollection, +) diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py index 6f11a5a21273a..9ce448ad9f569 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py @@ -6,9 +6,9 @@ import dagster._check as check from dagster._core.definitions.asset_key import AssetKey from dagster._core.definitions.definitions_class import Definitions +from dagster._core.execution.context.asset_execution_context import AssetExecutionContext from dagster._utils import pushd from dagster_dbt import DagsterDbtTranslator, DbtCliResource, DbtProject, dbt_assets -from dagster_embedded_elt.sling.resources import AssetExecutionContext from dbt.cli.main import dbtRunner from jinja2 import Template from pydantic import BaseModel, Field, TypeAdapter diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_registry.py b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_registry.py index 0c52535b44096..07f26ca1ed6f8 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_registry.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_registry.py @@ -1,16 +1,47 @@ import os import subprocess import sys +import tempfile +import textwrap +from contextlib import contextmanager from pathlib import Path +from typing import Iterator, List, Sequence + +@contextmanager +def _temp_venv(install_args: Sequence[str]) -> Iterator[Path]: + # Create venv + with tempfile.TemporaryDirectory() as tmpdir: + venv_dir = Path(tmpdir) / ".venv" + subprocess.check_call(["uv", "venv", str(venv_dir)]) + python_executable = ( + venv_dir + / ("Scripts" if sys.platform == "win32" else "bin") + / ("python.exe" if sys.platform == "win32" else "python") + ) + subprocess.check_call( + ["uv", "pip", "install", "--python", str(python_executable), *install_args] + ) + yield python_executable + + +COMPONENT_PRINT_SCRIPT = """ from dagster_components import ComponentRegistry +registry = ComponentRegistry.from_entry_point_discovery() +for component_name in list(registry.keys()): + print(component_name) +""" + -def test_components_from_dagster(): - registry = ComponentRegistry.from_entry_point_discovery() - assert registry.has("dagster_components.dbt_project") - assert registry.has("dagster_components.sling_replication") - assert registry.has("dagster_components.pipes_subprocess_script_collection") +def _get_component_types_in_python_environment(python_executable: Path) -> Sequence[str]: + with tempfile.NamedTemporaryFile(mode="w") as f: + f.write(COMPONENT_PRINT_SCRIPT) + f.flush() + result = subprocess.run( + [str(python_executable), f.name], capture_output=True, text=True, check=False + ) + return result.stdout.strip().split("\n") def _find_repo_root(): @@ -22,10 +53,66 @@ def _find_repo_root(): return current -repo_root = _find_repo_root() +def _generate_test_component_source(number: int) -> str: + return textwrap.dedent(f""" + from dagster_components import Component, component + @component(name="test_component_{number}") + class TestComponent{number}(Component): + pass + """) + + +_repo_root = _find_repo_root() + + +def _get_editable_package_root(pkg_name: str) -> str: + possible_locations = [ + _repo_root / "python_modules" / pkg_name, + _repo_root / "python_modules" / "libraries" / pkg_name, + ] + return next(str(loc) for loc in possible_locations if loc.exists()) + + +# ######################## +# ##### TESTS +# ######################## + + +def test_components_from_dagster(): + common_deps: List[str] = [] + for pkg_name in ["dagster", "dagster-pipes"]: + common_deps.extend(["-e", _get_editable_package_root(pkg_name)]) + + components_root = _get_editable_package_root("dagster-components") + dbt_root = _get_editable_package_root("dagster-dbt") + embedded_elt_root = _get_editable_package_root("dagster-embedded-elt") + + # No extras + with _temp_venv([*common_deps, "-e", components_root]) as python_executable: + component_types = _get_component_types_in_python_environment(python_executable) + assert "dagster_components.pipes_subprocess_script_collection" in component_types + assert "dagster_components.dbt_project" not in component_types + assert "dagster_components.sling_replication" not in component_types + + with _temp_venv( + [*common_deps, "-e", f"{components_root}[dbt]", "-e", dbt_root] + ) as python_executable: + component_types = _get_component_types_in_python_environment(python_executable) + assert "dagster_components.pipes_subprocess_script_collection" in component_types + assert "dagster_components.dbt_project" in component_types + assert "dagster_components.sling_replication" not in component_types + + with _temp_venv( + [*common_deps, "-e", f"{components_root}[sling]", "-e", embedded_elt_root] + ) as python_executable: + component_types = _get_component_types_in_python_environment(python_executable) + assert "dagster_components.pipes_subprocess_script_collection" in component_types + assert "dagster_components.dbt_project" not in component_types + assert "dagster_components.sling_replication" in component_types + # Our pyproject.toml installs local dagster components -PYPROJECT_TOML = f""" +DAGSTER_FOO_PYPROJECT_TOML = """ [build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" @@ -35,48 +122,20 @@ def _find_repo_root(): version = "0.1.0" description = "A simple example package" authors = [ - {{ name = "Your Name", email = "your.email@example.com" }} + { name = "Your Name", email = "your.email@example.com" } ] dependencies = [ - "dagster", "dagster-components", - "dagster-dbt", - "dagster-embedded-elt", ] -[tool.uv.sources] -dagster = {{ path = "{repo_root}/python_modules/dagster" }} -dagster-pipes = {{ path = "{repo_root}/python_modules/dagster-pipes" }} -dagster-components = {{ path = "{repo_root}/python_modules/libraries/dagster-components" }} -dagster-dbt = {{ path = "{repo_root}/python_modules/libraries/dagster-dbt" }} -dagster-embedded-elt = {{ path = "{repo_root}/python_modules/libraries/dagster-embedded-elt" }} - [project.entry-points] -"dagster.components" = {{ dagster_foo = "dagster_foo.lib"}} -""" - -TEST_COMPONENT_1 = """ -from dagster_components import Component, component - -@component(name="test_component_1") -class TestComponent1(Component): - pass -""" - -TEST_COMPONENT_2 = """ -from dagster_components import Component, component - -@component(name="test_component_2") -class TestComponent2(Component): - pass +"dagster.components" = { dagster_foo = "dagster_foo.lib"} """ -COMPONENT_PRINT_SCRIPT = """ -from dagster_components import ComponentRegistry +DAGSTER_FOO_LIB_ROOT = f""" +{_generate_test_component_source(1)} -registry = ComponentRegistry.from_entry_point_discovery() -for component_name in list(registry.keys()): - print(component_name) +from dagster_foo.lib.sub import TestComponent2 """ @@ -85,35 +144,29 @@ def test_components_from_third_party_lib(tmpdir): # Create test package that defines some components os.makedirs("dagster-foo") with open("dagster-foo/pyproject.toml", "w") as f: - f.write(PYPROJECT_TOML) + f.write(DAGSTER_FOO_PYPROJECT_TOML) os.makedirs("dagster-foo/dagster_foo/lib/sub") with open("dagster-foo/dagster_foo/lib/__init__.py", "w") as f: - f.write(TEST_COMPONENT_1) + f.write(DAGSTER_FOO_LIB_ROOT) with open("dagster-foo/dagster_foo/lib/sub/__init__.py", "w") as f: - f.write(TEST_COMPONENT_2) - - # Create venv - venv_dir = Path(".venv") - subprocess.check_call(["uv", "venv", str(venv_dir)]) - python_executable = ( - venv_dir - / ("Scripts" if sys.platform == "win32" else "bin") - / ("python.exe" if sys.platform == "win32" else "python") - ) - - # Script to print components - with open("print_components.py", "w") as f: - f.write(COMPONENT_PRINT_SCRIPT) - - # subprocess.check_call([pip_executable, "install", "-e", "dagster-foo"]) - subprocess.check_call( - ["uv", "pip", "install", "--python", str(python_executable), "-e", "dagster-foo"] - ) - result = subprocess.run( - [python_executable, "print_components.py"], capture_output=True, text=True, check=False - ) - assert "dagster_foo.test_component_1" in result.stdout - assert "dagster_foo.test_component_2" in result.stdout + f.write(_generate_test_component_source(2)) + + # Need pipes because dependency of dagster + deps = [ + "-e", + _get_editable_package_root("dagster"), + "-e", + _get_editable_package_root("dagster-components"), + "-e", + _get_editable_package_root("dagster-pipes"), + "-e", + "dagster-foo", + ] + + with _temp_venv(deps) as python_executable: + component_types = _get_component_types_in_python_environment(python_executable) + assert "dagster_foo.test_component_1" in component_types + assert "dagster_foo.test_component_2" in component_types From f5fb49f36030539632cd2e774979c14da34163bd Mon Sep 17 00:00:00 2001 From: Nick Schrock Date: Thu, 12 Dec 2024 09:42:19 -0500 Subject: [PATCH 07/94] [components] Simplify component folder creation (#26438) ## Summary & Motivation There were very confusion calls to `generate_project` and `generate_subtree` in our scaffolding code that did nothing but generate a folder, even though they referred to nonexistent templates. Turns out this worked because `os.walk` silent returns an empty generator when it points to a directory that does not exist. Just changing this to a `mkdir_p` call for clarity and simplicity. ## How I Tested These Changes Manual test. BK --- .../dagster_components/generate.py | 16 +++------------- .../libraries/dagster-dg/dagster_dg/generate.py | 14 ++------------ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/python_modules/libraries/dagster-components/dagster_components/generate.py b/python_modules/libraries/dagster-components/dagster_components/generate.py index dcda0cd58967b..89aaf2d073104 100644 --- a/python_modules/libraries/dagster-components/dagster_components/generate.py +++ b/python_modules/libraries/dagster-components/dagster_components/generate.py @@ -4,8 +4,7 @@ import click import yaml -from dagster._generate.generate import generate_project -from dagster._utils import pushd +from dagster._utils import mkdir_p, pushd from dagster_components.core.component import Component @@ -25,18 +24,9 @@ def generate_component_instance( component_type_name: str, generate_params: Any, ) -> None: - click.echo(f"Creating a Dagster component instance at {root_path}/{name}.py.") - component_instance_root_path = os.path.join(root_path, name) - generate_project( - path=component_instance_root_path, - name_placeholder="COMPONENT_INSTANCE_NAME_PLACEHOLDER", - templates_path=os.path.join( - os.path.dirname(__file__), "templates", "COMPONENT_INSTANCE_NAME_PLACEHOLDER" - ), - project_name=name, - component_type=component_type_name, - ) + click.echo(f"Creating a Dagster component instance folder at {component_instance_root_path}.") + mkdir_p(component_instance_root_path) with pushd(component_instance_root_path): component_params = component_type.generate_files(generate_params) component_data = {"type": component_type_name, "params": component_params or {}} diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index 6bf0ee7f42b4a..e9c26a58429b3 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -85,19 +85,9 @@ def generate_component_instance( json_params: Optional[str], extra_args: Tuple[str, ...], ) -> None: - click.echo(f"Creating a Dagster component instance at {root_path}/{name}.py.") - component_instance_root_path = root_path / name - generate_subtree( - path=component_instance_root_path, - name_placeholder="COMPONENT_INSTANCE_NAME_PLACEHOLDER", - templates_path=os.path.join( - os.path.dirname(__file__), "templates", "COMPONENT_INSTANCE_NAME_PLACEHOLDER" - ), - project_name=name, - component_type=component_type, - ) - + click.echo(f"Creating a Dagster component instance folder at {component_instance_root_path}.") + os.makedirs(component_instance_root_path, exist_ok=True) code_location_command = ( "generate", "component", From 18c283a452f1de3fc5fa388121900015357ddbbe Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:01:36 -0500 Subject: [PATCH 08/94] [dagster-embedded-elt][dlt] Subclass typing.Iterator in DltEventIterator (#26425) ## Summary & Motivation Same as #26424 but for `DltEventIterator` ## How I Tested These Changes Same tests with BK --- .../dagster_embedded_elt/dlt/dlt_event_iterator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py index 724791278a30e..3a640153b47ea 100644 --- a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py +++ b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py @@ -1,4 +1,3 @@ -from collections import abc from typing import Generic, Iterator, Optional, Union from dagster import AssetMaterialization, MaterializeResult @@ -58,7 +57,7 @@ def fetch_row_count_metadata( return TableMetadataSet(row_count=None) -class DltEventIterator(Generic[T], abc.Iterator): +class DltEventIterator(Generic[T], Iterator): """A wrapper around an iterator of Dlt events which contains additional methods for post-processing the events, such as fetching column metadata. """ From 59aaaedf5fd0c89dc96b99bcb1622ffad0f2a17b Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:01:45 -0500 Subject: [PATCH 09/94] [dagster-embedded-elt][sling] Subclass typing.Iterator in SlingEventIterator (#26426) ## Summary & Motivation Same as #26424 but for `SlingEventIterator` ## How I Tested These Changes Same tests with BK --- .../dagster_embedded_elt/sling/sling_event_iterator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py index 55ff4198785eb..f08b200473f21 100644 --- a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py +++ b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py @@ -1,5 +1,4 @@ import re -from collections import abc from typing import TYPE_CHECKING, Any, Dict, Generic, Iterator, Optional, Sequence, Union, cast from dagster import ( @@ -168,7 +167,7 @@ def fetch_column_metadata( return {} -class SlingEventIterator(Generic[T], abc.Iterator): +class SlingEventIterator(Generic[T], Iterator): """A wrapper around an iterator of Sling events which contains additional methods for post-processing the events, such as fetching column metadata. """ From 303625c7897b75565d1ddc3c0142eff5eea26a4b Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:01:57 -0500 Subject: [PATCH 10/94] [dagster-dbt] Subclass typing.Iterator in DbtEventIterator (#26424) ## Summary & Motivation Subclass `typing.Iterator` instead of `abc.Iterator` in `DbtEventIterator`. This is motivated by [this discussion](https://github.com/dagster-io/dagster/pull/26396#discussion_r1881167290). ## How I Tested These Changes Same tests with BK --- .../dagster-dbt/dagster_dbt/core/dbt_event_iterator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py b/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py index 508e90c00b95e..5ffa200a422fc 100644 --- a/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py +++ b/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py @@ -1,4 +1,3 @@ -from collections import abc from concurrent.futures import ThreadPoolExecutor from typing import TYPE_CHECKING, Any, Callable, Dict, Generic, Iterator, Optional, Union, cast @@ -186,7 +185,7 @@ def _fetch_row_count_metadata( return None -class DbtEventIterator(Generic[T], abc.Iterator): +class DbtEventIterator(Generic[T], Iterator): """A wrapper around an iterator of dbt events which contains additional methods for post-processing the events, such as fetching row counts for materialized tables. """ From d07b921575aa15ab9cc9d0f92db815c42c335d89 Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:07:24 -0500 Subject: [PATCH 11/94] [dagster-fivetran] Update custom translator example in docstrings for Fivetran asset decorator and factory (#26435) ## Summary & Motivation As title. The example should be using the new `AssetSpec.replace_attributes(...)` pattern. ## How I Tested These Changes Docs preview --- .../dagster-fivetran/dagster_fivetran/asset_decorator.py | 7 +++---- .../dagster-fivetran/dagster_fivetran/asset_defs.py | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_decorator.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_decorator.py index 12989283941f9..2f8fba289d00b 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_decorator.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_decorator.py @@ -74,10 +74,9 @@ def fivetran_connector_assets(context: dg.AssetExecutionContext, fivetran: Fivet class CustomDagsterFivetranTranslator(DagsterFivetranTranslator): def get_asset_spec(self, props: FivetranConnectorTableProps) -> dg.AssetSpec: - asset_spec = super().get_asset_spec(props) - return replace_attributes( - asset_spec, - key=asset_spec.key.with_prefix("my_prefix"), + default_spec = super().get_asset_spec(props) + return default_spec.replace_attributes( + key=default_spec.key.with_prefix("my_prefix"), ) diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_defs.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_defs.py index f746c6b3728ea..712ff5e8bad60 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_defs.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/asset_defs.py @@ -791,10 +791,9 @@ def build_fivetran_assets_definitions( class CustomDagsterFivetranTranslator(DagsterFivetranTranslator): def get_asset_spec(self, props: FivetranConnectorTableProps) -> dg.AssetSpec: - asset_spec = super().get_asset_spec(props) - return replace_attributes( - asset_spec, - key=asset_spec.key.with_prefix("my_prefix"), + default_spec = super().get_asset_spec(props) + return default_spec.replace_attributes( + key=default_spec.key.with_prefix("my_prefix"), ) From d077eab683ae4f65e8835a2c1c34a61c34a92f0e Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Thu, 12 Dec 2024 10:21:11 -0500 Subject: [PATCH 12/94] [components] Fix dagster-dg component type scaffold and tests (#26441) ## Summary & Motivation Tests for this were broken by the extras support PR, since components local to a code location now to be added to `lib/__init__.py`. This fixes the component-type scaffolding and tests. ## How I Tested These Changes Modified unit tests. --- .../libraries/dagster-dg/dagster_dg/cli/generate.py | 2 +- python_modules/libraries/dagster-dg/dagster_dg/generate.py | 7 ++++++- .../dagster_dg_tests/cli_tests/test_generate_commands.py | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index be58f8b0284ea..d525676b35201 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -115,7 +115,7 @@ def generate_component_type_command(name: str) -> None: click.echo(click.style(f"A component type named `{name}` already exists.", fg="red")) sys.exit(1) - generate_component_type(Path(context.component_types_root_path), name) + generate_component_type(context, name) @generate_cli.command(name="component") diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index e9c26a58429b3..dd99154c5e359 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -5,6 +5,7 @@ import click +from dagster_dg.context import CodeLocationProjectContext from dagster_dg.utils import ( camelcase, discover_git_root, @@ -65,7 +66,8 @@ def generate_code_location(path: Path, editable_dagster_root: Optional[str] = No execute_code_location_command(Path(path), ("uv", "sync")) -def generate_component_type(root_path: Path, name: str) -> None: +def generate_component_type(context: CodeLocationProjectContext, name: str) -> None: + root_path = Path(context.component_types_root_path) click.echo(f"Creating a Dagster component type at {root_path}/{name}.py.") generate_subtree( @@ -77,6 +79,9 @@ def generate_component_type(root_path: Path, name: str) -> None: component_type=name, ) + with open(root_path / "__init__.py", "a") as f: + f.write(f"from {context.component_types_root_module}.{name} import {camelcase(name)}\n") + def generate_component_instance( root_path: Path, diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 2d99002b9da92..76c753cb178ab 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -100,6 +100,8 @@ def isolated_example_code_location_bar_with_component_type_baz( runner: CliRunner, in_deployment: bool = True ) -> Iterator[None]: with isolated_example_code_location_bar(runner, in_deployment): + with open("bar/lib/__init__.py", "a") as f: + f.write("from bar.lib.baz import Baz\n") with open("bar/lib/baz.py", "w") as f: component_type_source = textwrap.dedent( inspect.getsource(_example_component_type_baz).split("\n", 1)[1] From d06e1aa200a31221369114390dc2e46d59803cef Mon Sep 17 00:00:00 2001 From: Oren Lederman Date: Thu, 12 Dec 2024 07:46:06 -0800 Subject: [PATCH 13/94] [bugfix] k8s client now waits for main container to be ready (#26422) ## Summary & Motivation A more complete fix for issue #23497. The recent change in PR #24432 exits the loop if all sidecar init containers are in a ready state, and doesn't wait until the regular (non init container). If the main (dagster) container takes longer to startup, for example if it's using a large image, the code fails when it attempts to read the log. ## How I Tested These Changes * Fixed the existing unit tests to represent the full state of the pod when we expect it to be ready. The existing tests did not ensure that the main container is ready, and instead returned when the init containers were ready (or terminated) * Tested locally with our k8s deployment and deployed to production to fix the issue for our jobs ## Changelog > Insert changelog entry or delete this section. --- .../dagster-k8s/dagster_k8s/client.py | 6 +- .../unit_tests/test_client.py | 62 ++++++++++++++++--- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/python_modules/libraries/dagster-k8s/dagster_k8s/client.py b/python_modules/libraries/dagster-k8s/dagster_k8s/client.py index 26c543f26f1e9..fbf2dfce2484c 100644 --- a/python_modules/libraries/dagster-k8s/dagster_k8s/client.py +++ b/python_modules/libraries/dagster-k8s/dagster_k8s/client.py @@ -673,7 +673,6 @@ def wait_for_pod( # State checks below, see: # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#containerstate-v1-core state = container_status.state - if state.running is not None: if wait_for_state == WaitForPodState.Ready: # ready is boolean field of container status @@ -684,6 +683,11 @@ def wait_for_pod( continue else: ready_containers.add(container_status.name) + if container_status.name in initcontainers: + self.logger( + f'Init container "{container_status.name}" is ready, waiting for non-init containers...' + ) + continue if initcontainers.issubset(exited_containers | ready_containers): self.logger(f'Pod "{pod_name}" is ready, done waiting') break diff --git a/python_modules/libraries/dagster-k8s/dagster_k8s_tests/unit_tests/test_client.py b/python_modules/libraries/dagster-k8s/dagster_k8s_tests/unit_tests/test_client.py index ad754885590bf..983a6d5707c2f 100644 --- a/python_modules/libraries/dagster-k8s/dagster_k8s_tests/unit_tests/test_client.py +++ b/python_modules/libraries/dagster-k8s/dagster_k8s_tests/unit_tests/test_client.py @@ -427,7 +427,10 @@ def test_retrieve_pod_logs(): assert mock_client.retrieve_pod_logs("pod", "namespace") == "a_string" -def _pod_list_for_container_status(*container_statuses, init_container_statuses=None): +def _pod_list_for_container_status( + *container_statuses, + init_container_statuses=None, +): return V1PodList( items=[ V1Pod( @@ -805,23 +808,42 @@ def test_waiting_for_pod_initialize_with_ignored_containers(): def test_waiting_for_pod_initialize_with_init_container(): - mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=3)) + mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=4)) waiting_container_status = _create_status( state=V1ContainerState( waiting=V1ContainerStateWaiting(reason=KubernetesWaitingReasons.PodInitializing) ), ready=False, ) + waiting_initcontainer_status = _create_status( + name="initcontainer", + state=V1ContainerState( + waiting=V1ContainerStateWaiting(reason=KubernetesWaitingReasons.PodInitializing) + ), + ready=False, + ) + + ready_initcontainer_status = _ready_running_status(name="initcontainer") + + # Initial status single_waiting_pod = _pod_list_for_container_status( - waiting_container_status, init_container_statuses=[waiting_container_status] + waiting_container_status, init_container_statuses=[waiting_initcontainer_status] + ) + + # Init container is ready, but not the main container + single_only_init_ready_pod = _pod_list_for_container_status( + waiting_container_status, init_container_statuses=[ready_initcontainer_status] ) + + # Main container is ready single_ready_running_pod = _pod_list_for_container_status( - waiting_container_status, init_container_statuses=[_ready_running_status()] + _ready_running_status(), init_container_statuses=[ready_initcontainer_status] ) mock_client.core_api.list_namespaced_pod.side_effect = [ single_waiting_pod, single_waiting_pod, + single_only_init_ready_pod, single_ready_running_pod, ] @@ -833,6 +855,7 @@ def test_waiting_for_pod_initialize_with_init_container(): [ f'Waiting for pod "{pod_name}"', f'Waiting for pod "{pod_name}" to initialize...', + f'Init container "{ready_initcontainer_status.name}" is ready, waiting for non-init containers...', f'Pod "{pod_name}" is ready, done waiting', ], ) @@ -841,7 +864,7 @@ def test_waiting_for_pod_initialize_with_init_container(): def test_wait_for_pod_initialize_with_multiple_init_containers(): - mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=4)) + mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=5)) waiting_container_status = _create_status( state=V1ContainerState( waiting=V1ContainerStateWaiting(reason=KubernetesWaitingReasons.PodInitializing) @@ -878,11 +901,17 @@ def test_wait_for_pod_initialize_with_multiple_init_containers(): init_container_statuses=[ready_initcontainer1_status, ready_initcontainer2_status], ) + all_ready_pod = _pod_list_for_container_status( + _ready_running_status(), + init_container_statuses=[ready_initcontainer1_status, ready_initcontainer2_status], + ) + mock_client.core_api.list_namespaced_pod.side_effect = [ two_waiting_inits_pod, two_waiting_inits_pod, single_init_ready_waiting_pod, both_init_ready_waiting_pod, + all_ready_pod, ] pod_name = "a_pod" @@ -893,6 +922,8 @@ def test_wait_for_pod_initialize_with_multiple_init_containers(): [ f'Waiting for pod "{pod_name}"', f'Waiting for pod "{pod_name}" to initialize...', + f'Init container "{ready_initcontainer1_status.name}" is ready, waiting for non-init containers...', + f'Init container "{ready_initcontainer2_status.name}" is ready, waiting for non-init containers...', f'Pod "{pod_name}" is ready, done waiting', ], ) @@ -901,7 +932,7 @@ def test_wait_for_pod_initialize_with_multiple_init_containers(): # Container states are evaluated in the order that they are in the pod manifest, but # it's possible that the second initcontainer can finish first and we test that here. def test_wait_for_pod_initialize_with_multiple_init_containers_backwards(): - mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=5)) + mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=6)) waiting_container_status = _create_status( state=V1ContainerState( waiting=V1ContainerStateWaiting(reason=KubernetesWaitingReasons.PodInitializing) @@ -937,6 +968,10 @@ def test_wait_for_pod_initialize_with_multiple_init_containers_backwards(): waiting_container_status, init_container_statuses=[ready_initcontainer1_status, ready_initcontainer2_status], ) + all_ready_pod = _pod_list_for_container_status( + _ready_running_status(), + init_container_statuses=[ready_initcontainer1_status, ready_initcontainer2_status], + ) # we need an extra side effect here compared to the above test since # there's an extra loop iteration @@ -946,17 +981,19 @@ def test_wait_for_pod_initialize_with_multiple_init_containers_backwards(): single_init_ready_waiting_pod, both_init_ready_waiting_pod, both_init_ready_waiting_pod, + all_ready_pod, ] pod_name = "a_pod" mock_client.wait_for_pod(pod_name=pod_name, namespace="namespace") - assert_logger_calls( mock_client.logger, [ f'Waiting for pod "{pod_name}"', f'Waiting for pod "{pod_name}" to initialize...', f'Waiting for pod "{pod_name}" to initialize...', + f'Init container "{ready_initcontainer1_status.name}" is ready, waiting for non-init containers...', + f'Init container "{ready_initcontainer2_status.name}" is ready, waiting for non-init containers...', f'Pod "{pod_name}" is ready, done waiting', ], ) @@ -964,7 +1001,7 @@ def test_wait_for_pod_initialize_with_multiple_init_containers_backwards(): # init containers may terminate quickly, so a ready state is never observed def test_wait_for_pod_initialize_with_fast_init_containers(): - mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=5)) + mock_client = create_mocked_client(timer=create_timing_out_timer(num_good_ticks=6)) waiting_container_status = _create_status( state=V1ContainerState( waiting=V1ContainerStateWaiting(reason=KubernetesWaitingReasons.PodInitializing) @@ -1007,12 +1044,20 @@ def test_wait_for_pod_initialize_with_fast_init_containers(): ready_initcontainer_slow_status, ], ) + ready_pod = _pod_list_for_container_status( + _ready_running_status(), + init_container_statuses=[ + terminated_initcontainer_fast_status, + ready_initcontainer_slow_status, + ], + ) mock_client.core_api.list_namespaced_pod.side_effect = [ two_waiting_inits_pod, two_waiting_inits_pod, term_and_ready_waiting_pod, term_and_ready_waiting_pod, + ready_pod, ] pod_name = "a_pod" @@ -1024,6 +1069,7 @@ def test_wait_for_pod_initialize_with_fast_init_containers(): f'Waiting for pod "{pod_name}"', f'Waiting for pod "{pod_name}" to initialize...', "Init container init_fast in a_pod has exited successfully", + f'Init container "{ready_initcontainer_slow_status.name}" is ready, waiting for non-init containers...', f'Pod "{pod_name}" is ready, done waiting', ], ) From 595ed019e2b6309858c57e402d052cabfd6fb57e Mon Sep 17 00:00:00 2001 From: gibsondan Date: Thu, 12 Dec 2024 10:29:11 -0600 Subject: [PATCH 14/94] Fix events fields on GrapheneRunStepStats (#26016) ## Summary & Motivation These were passing in the python object directly instead of constructing graphene objects, likely a longstanding issues. Test Plan: BK NOCHANGELOG --- .../dagster_graphql/implementation/events.py | 3 +- .../dagster_graphql/schema/logs/events.py | 19 ++++- .../graphql/test_assets.py | 31 ++++++++ .../graphql/test_expectations.py | 78 ++++++++++++++++++- 4 files changed, 126 insertions(+), 5 deletions(-) diff --git a/python_modules/dagster-graphql/dagster_graphql/implementation/events.py b/python_modules/dagster-graphql/dagster_graphql/implementation/events.py index a49b91447141a..7e8fd1be4dca6 100644 --- a/python_modules/dagster-graphql/dagster_graphql/implementation/events.py +++ b/python_modules/dagster-graphql/dagster_graphql/implementation/events.py @@ -232,6 +232,7 @@ def from_dagster_event_record(event_record: EventLogEntry, pipeline_name: str) - GrapheneExecutionStepStartEvent, GrapheneExecutionStepSuccessEvent, GrapheneExecutionStepUpForRetryEvent, + GrapheneExpectationResult, GrapheneHandledOutputEvent, GrapheneHookCompletedEvent, GrapheneHookErroredEvent, @@ -306,7 +307,7 @@ def from_dagster_event_record(event_record: EventLogEntry, pipeline_name: str) - elif dagster_event.event_type == DagsterEventType.STEP_EXPECTATION_RESULT: data = cast(StepExpectationResultData, dagster_event.event_specific_data) return GrapheneStepExpectationResultEvent( - expectation_result=data.expectation_result, **basic_params + expectation_result=GrapheneExpectationResult(data.expectation_result), **basic_params ) elif dagster_event.event_type == DagsterEventType.STEP_FAILURE: data = dagster_event.step_failure_data diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/logs/events.py b/python_modules/dagster-graphql/dagster_graphql/schema/logs/events.py index 24e54116e4e0e..46a1dbc8bf0e2 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/logs/events.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/logs/events.py @@ -2,6 +2,7 @@ import dagster._check as check import graphene +from dagster._core.definitions import ExpectationResult from dagster._core.events import AssetLineageInfo, DagsterEventType from dagster._core.events.log import EventLogEntry from dagster._core.execution.plan.objects import ErrorSource @@ -209,10 +210,18 @@ class Meta: interfaces = (GrapheneDisplayableEvent,) name = "ExpectationResult" + def __init__(self, expectation_result: ExpectationResult): + self._expectation_result = expectation_result + super().__init__( + success=expectation_result.success, + label=expectation_result.label, + description=expectation_result.description, + ) + def resolve_metadataEntries(self, _graphene_info: ResolveInfo): from dagster_graphql.implementation.events import _to_metadata_entries - return _to_metadata_entries(self.metadata) + return _to_metadata_entries(self._expectation_result.metadata) class GrapheneTypeCheck(graphene.ObjectType): @@ -635,8 +644,12 @@ def __init__(self, stats): status=stats.status.value, startTime=stats.start_time, endTime=stats.end_time, - materializations=stats.materialization_events, - expectationResults=stats.expectation_results, + materializations=[ + GrapheneMaterializationEvent(event) for event in stats.materialization_events + ], + expectationResults=[ + GrapheneExpectationResult(result) for result in stats.expectation_results + ], attempts=[ GrapheneRunMarker(startTime=attempt.start_time, endTime=attempt.end_time) for attempt in stats.attempts_list diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py index 0901f0b9af9da..06c3943b75d91 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py @@ -818,6 +818,29 @@ } """ +GET_MATERIALIZATIONS_FROM_STEP_STATS = """ +query MaterializationsFromStepStatsQuery($runId: ID!) { + runOrError(runId: $runId) { + ... on PythonError { + className + message + stack + } + ... on Run { + stepStats { + materializations { + eventType + message + assetLineage { + partitions + } + } + } + } + } +} +""" + def _create_run( graphql_context: WorkspaceRequestContext, @@ -2016,6 +2039,14 @@ def test_get_run_materialization(self, graphql_context: WorkspaceRequestContext, assert len(result.data["runsOrError"]["results"][0]["assetMaterializations"]) == 1 snapshot.assert_match(result.data) + def test_get_materializations_from_step_stats(self, graphql_context: WorkspaceRequestContext): + run_id = _create_run(graphql_context, "single_asset_job") + result = execute_dagster_graphql( + graphql_context, GET_MATERIALIZATIONS_FROM_STEP_STATS, {"runId": run_id} + ) + assert result.data + assert len(result.data["runOrError"]["stepStats"][0]["materializations"]) == 1 + def test_asset_selection_in_run(self, graphql_context: WorkspaceRequestContext): # Generate materializations for bar asset run_id = _create_run(graphql_context, "foo_job", asset_selection=[{"path": ["bar"]}]) diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_expectations.py b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_expectations.py index bb18319c94deb..2746be44f06c3 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_expectations.py +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_expectations.py @@ -1,14 +1,68 @@ import json +from dagster._core.test_utils import poll_for_finished_run from dagster._core.workspace.context import WorkspaceRequestContext from dagster._utils import file_relative_path -from dagster_graphql.test.utils import infer_job_selector +from dagster_graphql.client.query import LAUNCH_PIPELINE_EXECUTION_MUTATION +from dagster_graphql.test.utils import execute_dagster_graphql, infer_job_selector from dagster_graphql_tests.graphql.graphql_context_test_suite import ( ExecutingGraphQLContextTestMatrix, ) from dagster_graphql_tests.graphql.utils import sync_execute_get_events +GET_EXPECTATIONS_FROM_STEP_STATS = """ +query MaterializationsFromStepStatsQuery($runId: ID!) { + runOrError(runId: $runId) { + ... on PythonError { + className + message + stack + } + ... on Run { + stepStats { + expectationResults { + success + label + description + metadataEntries { + ... on TextMetadataEntry { + text + } + ... on JsonMetadataEntry { + jsonString + } + } + } + } + } + } +} +""" + + +def _create_run( + graphql_context: WorkspaceRequestContext, + pipeline_name: str, +) -> str: + selector = infer_job_selector( + graphql_context, + pipeline_name, + ) + result = execute_dagster_graphql( + graphql_context, + LAUNCH_PIPELINE_EXECUTION_MUTATION, + variables={ + "executionParams": { + "selector": selector, + } + }, + ) + assert result.data["launchPipelineExecution"]["__typename"] == "LaunchRunSuccess" + run_id = result.data["launchPipelineExecution"]["run"]["runId"] + poll_for_finished_run(graphql_context.instance, run_id) + return run_id + def get_expectation_results(logs, op_name: str): def _f(): @@ -70,6 +124,28 @@ def test_basic_expectations_within_compute_step_events( get_expectation_results(logs, "emit_successful_expectation_no_metadata") ) + def test_get_expectation_results_from_step_stats( + self, graphql_context: WorkspaceRequestContext + ): + run_id = _create_run(graphql_context, "job_with_expectations") + result = execute_dagster_graphql( + graphql_context, GET_EXPECTATIONS_FROM_STEP_STATS, {"runId": run_id} + ) + assert result.data + assert any( + len(step["expectationResults"]) > 0 + and step["expectationResults"][0] + == { + "success": False, + "label": "always_false", + "description": "Failure", + "metadataEntries": [ + {"jsonString": json.dumps({"reason": "Relentless pessimism."})} + ], + } + for step in result.data["runOrError"]["stepStats"] + ) + def test_basic_input_output_expectations( self, graphql_context: WorkspaceRequestContext, snapshot ): From 65479b87a2a632cbfdbadf3929fe9d006cc1783b Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Thu, 12 Dec 2024 11:32:47 -0500 Subject: [PATCH 15/94] [components] dagster-dg general code cleanup (#26442) ## Summary & Motivation General clean up of `dagster-dg` code-- standardizing names, removing some detritus, etc. No significant behavior changes. ## How I Tested These Changes Existing test suite. --- .../dagster-dg/dagster_dg/cli/__init__.py | 2 +- .../dagster-dg/dagster_dg/cli/generate.py | 20 ++-- .../dagster-dg/dagster_dg/cli/list.py | 26 ++--- .../dagster-dg/dagster_dg/component.py | 1 - .../dagster-dg/dagster_dg/context.py | 105 +++++++++--------- .../libraries/dagster-dg/dagster_dg/error.py | 2 + .../dagster-dg/dagster_dg/generate.py | 12 +- .../libraries/dagster-dg/dagster_dg/utils.py | 29 +++-- .../cli_tests/test_generate_commands.py | 30 +---- 9 files changed, 104 insertions(+), 123 deletions(-) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py index b2fbe3c69f6fc..ff14bee381e63 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py @@ -17,7 +17,7 @@ def create_dg_cli(): ) @click.version_option(__version__, "--version", "-v") def group(): - """CLI tools for working with Dagster.""" + """CLI tools for working with Dagster components.""" return group diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index d525676b35201..6f035d57db520 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -6,10 +6,10 @@ import click from dagster_dg.context import ( - CodeLocationProjectContext, - DeploymentProjectContext, - is_inside_code_location_project, - is_inside_deployment_project, + CodeLocationDirectoryContext, + DeploymentDirectoryContext, + is_inside_code_location_directory, + is_inside_deployment_directory, ) from dagster_dg.generate import ( generate_code_location, @@ -69,8 +69,8 @@ def generate_code_location_command(name: str, use_editable_dagster: bool) -> Non component`). The `.lib` directory holds custom component types scoped to the code location (which can be created with `dg generate component-type`). """ - if is_inside_deployment_project(Path.cwd()): - context = DeploymentProjectContext.from_path(Path.cwd()) + if is_inside_deployment_directory(Path.cwd()): + context = DeploymentDirectoryContext.from_path(Path.cwd()) if context.has_code_location(name): click.echo(click.style(f"A code location named {name} already exists.", fg="red")) sys.exit(1) @@ -102,14 +102,14 @@ def generate_component_type_command(name: str) -> None: This command must be run inside a Dagster code location directory. The component type scaffold will be generated in submodule `.lib.`. """ - if not is_inside_code_location_project(Path.cwd()): + if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( "This command must be run inside a Dagster code location directory.", fg="red" ) ) sys.exit(1) - context = CodeLocationProjectContext.from_path(Path.cwd()) + context = CodeLocationDirectoryContext.from_path(Path.cwd()) full_component_name = f"{context.name}.{name}" if context.has_component_type(full_component_name): click.echo(click.style(f"A component type named `{name}` already exists.", fg="red")) @@ -156,7 +156,7 @@ def generate_component_command( It is an error to pass both --json-params and EXTRA_ARGS. """ - if not is_inside_code_location_project(Path.cwd()): + if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( "This command must be run inside a Dagster code location directory.", fg="red" @@ -164,7 +164,7 @@ def generate_component_command( ) sys.exit(1) - context = CodeLocationProjectContext.from_path(Path.cwd()) + context = CodeLocationDirectoryContext.from_path(Path.cwd()) if not context.has_component_type(component_type): click.echo( click.style(f"No component type `{component_type}` could be resolved.", fg="red") diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py index 3ad2e561b16af..35c2b68f6073a 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py @@ -4,10 +4,10 @@ import click from dagster_dg.context import ( - CodeLocationProjectContext, - DeploymentProjectContext, - is_inside_code_location_project, - is_inside_deployment_project, + CodeLocationDirectoryContext, + DeploymentDirectoryContext, + is_inside_code_location_directory, + is_inside_deployment_directory, ) @@ -19,21 +19,21 @@ def list_cli(): @list_cli.command(name="code-locations") def list_code_locations_command() -> None: """List code locations in the current deployment.""" - if not is_inside_deployment_project(Path.cwd()): + if not is_inside_deployment_directory(Path.cwd()): click.echo( click.style("This command must be run inside a Dagster deployment directory.", fg="red") ) sys.exit(1) - context = DeploymentProjectContext.from_path(Path.cwd()) - for code_location in context.list_code_locations(): + context = DeploymentDirectoryContext.from_path(Path.cwd()) + for code_location in context.get_code_location_names(): click.echo(code_location) @list_cli.command(name="component-types") def list_component_types_command() -> None: """List registered Dagster components in the current code location environment.""" - if not is_inside_code_location_project(Path.cwd()): + if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( "This command must be run inside a Dagster code location directory.", fg="red" @@ -41,15 +41,15 @@ def list_component_types_command() -> None: ) sys.exit(1) - context = CodeLocationProjectContext.from_path(Path.cwd()) - for component_type in context.list_component_types(): + context = CodeLocationDirectoryContext.from_path(Path.cwd()) + for component_type in context.get_component_type_names(): click.echo(component_type) @list_cli.command(name="components") def list_components_command() -> None: """List Dagster component instances defined in the current code location.""" - if not is_inside_code_location_project(Path.cwd()): + if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( "This command must be run inside a Dagster code location directory.", fg="red" @@ -57,6 +57,6 @@ def list_components_command() -> None: ) sys.exit(1) - context = CodeLocationProjectContext.from_path(Path.cwd()) - for component_name in context.component_instances: + context = CodeLocationDirectoryContext.from_path(Path.cwd()) + for component_name in context.get_component_instance_names(): click.echo(component_name) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/component.py b/python_modules/libraries/dagster-dg/dagster_dg/component.py index 129c4d6c388ad..fc3567da3470a 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/component.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/component.py @@ -10,7 +10,6 @@ class RemoteComponentType: @property def key(self) -> str: return self.name - # return f"{self.package}.{self.name}" class RemoteComponentRegistry: diff --git a/python_modules/libraries/dagster-dg/dagster_dg/context.py b/python_modules/libraries/dagster-dg/dagster_dg/context.py index ee03ce9ab7552..bce491322d325 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/context.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/context.py @@ -1,7 +1,7 @@ import json import os from pathlib import Path -from typing import Final, Iterable, Mapping, Optional, Sequence +from typing import Final, Iterable, Mapping, Optional import tomli from typing_extensions import Self @@ -11,45 +11,45 @@ from dagster_dg.utils import execute_code_location_command -def is_inside_deployment_project(path: Path) -> bool: +def is_inside_deployment_directory(path: Path) -> bool: try: - _resolve_deployment_root_path(path) + _resolve_deployment_root_directory(path) return True except DgError: return False -def _resolve_deployment_root_path(path: Path) -> Path: +def _resolve_deployment_root_directory(path: Path) -> Path: current_path = path.absolute() - while not _is_deployment_root(current_path): + while not _is_deployment_root_directory(current_path): current_path = current_path.parent if str(current_path) == "/": raise DgError("Cannot find deployment root") return current_path -def is_inside_code_location_project(path: Path) -> bool: +def _is_deployment_root_directory(path: Path) -> bool: + return (path / "code_locations").exists() + + +def is_inside_code_location_directory(path: Path) -> bool: try: - _resolve_code_location_root_path(path) + _resolve_code_location_root_directory(path) return True except DgError: return False -def _resolve_code_location_root_path(path: Path) -> Path: +def _resolve_code_location_root_directory(path: Path) -> Path: current_path = path.absolute() - while not _is_code_location_root(current_path): + while not _is_code_location_root_directory(current_path): current_path = current_path.parent if str(current_path) == "/": raise DgError("Cannot find code location root") return current_path -def _is_deployment_root(path: Path) -> bool: - return (path / "code_locations").exists() - - -def _is_code_location_root(path: Path) -> bool: +def _is_code_location_root_directory(path: Path) -> bool: if (path / "pyproject.toml").exists(): with open(path / "pyproject.toml") as f: toml = tomli.loads(f.read()) @@ -65,16 +65,16 @@ def _is_code_location_root(path: Path) -> bool: _CODE_LOCATION_COMPONENT_INSTANCES_DIR: Final = "components" -class DeploymentProjectContext: +class DeploymentDirectoryContext: @classmethod def from_path(cls, path: Path) -> Self: - return cls(root_path=_resolve_deployment_root_path(path)) + return cls(root_path=_resolve_deployment_root_directory(path)) def __init__(self, root_path: Path): self._root_path = root_path @property - def deployment_root(self) -> Path: + def root_path(self) -> Path: return self._root_path @property @@ -82,39 +82,38 @@ def code_location_root_path(self) -> Path: return self._root_path / _DEPLOYMENT_CODE_LOCATIONS_DIR def has_code_location(self, name: str) -> bool: - return os.path.exists(os.path.join(self._root_path, "code_locations", name)) + return (self._root_path / "code_locations" / name).is_dir() - def list_code_locations(self) -> Iterable[str]: - return sorted(os.listdir(os.path.join(self._root_path, "code_locations"))) + def get_code_location_names(self) -> Iterable[str]: + return [loc.name for loc in sorted((self._root_path / "code_locations").iterdir())] -class CodeLocationProjectContext: +class CodeLocationDirectoryContext: _components_registry: Mapping[str, RemoteComponentType] = {} @classmethod def from_path(cls, path: Path) -> Self: - root_path = _resolve_code_location_root_path(path) - raw_component_registry = execute_code_location_command( + root_path = _resolve_code_location_root_directory(path) + component_registry_data = execute_code_location_command( root_path, ["list", "component-types"] ) - component_registry = RemoteComponentRegistry.from_dict(json.loads(raw_component_registry)) - deployment_context = ( - DeploymentProjectContext.from_path(path) if is_inside_deployment_project(path) else None - ) + component_registry = RemoteComponentRegistry.from_dict(json.loads(component_registry_data)) return cls( - deployment_context=deployment_context, root_path=root_path, name=path.name, component_registry=component_registry, + deployment_context=DeploymentDirectoryContext.from_path(path) + if is_inside_deployment_directory(path) + else None, ) def __init__( self, - deployment_context: Optional[DeploymentProjectContext], root_path: Path, name: str, component_registry: "RemoteComponentRegistry", + deployment_context: Optional[DeploymentDirectoryContext], ): self._deployment_context = deployment_context self._root_path = root_path @@ -126,20 +125,23 @@ def name(self) -> str: return self._name @property - def deployment_context(self) -> Optional[DeploymentProjectContext]: + def deployment_context(self) -> Optional[DeploymentDirectoryContext]: return self._deployment_context @property - def component_types_root_path(self) -> str: + def component_registry(self) -> "RemoteComponentRegistry": + return self._component_registry + + @property + def local_component_types_root_path(self) -> str: return os.path.join(self._root_path, self._name, _CODE_LOCATION_CUSTOM_COMPONENTS_DIR) @property - def component_types_root_module(self) -> str: + def local_component_types_root_module_name(self) -> str: return f"{self._name}.{_CODE_LOCATION_CUSTOM_COMPONENTS_DIR}" - @property - def component_registry(self) -> "RemoteComponentRegistry": - return self._component_registry + def get_component_type_names(self) -> Iterable[str]: + return sorted(self._component_registry.keys()) def has_component_type(self, name: str) -> bool: return self._component_registry.has(name) @@ -149,25 +151,24 @@ def get_component_type(self, name: str) -> RemoteComponentType: raise DgError(f"No component type named {name}") return self._component_registry.get(name) - def list_component_types(self) -> Sequence[str]: - return sorted(self._component_registry.keys()) - - def get_component_instance_path(self, name: str) -> str: - if name not in self.component_instances: - raise DgError(f"No component instance named {name}") - return os.path.join(self.component_instances_root_path, name) - @property - def component_instances_root_path(self) -> str: - return os.path.join(self._root_path, self._name, _CODE_LOCATION_COMPONENT_INSTANCES_DIR) + def component_instances_root_path(self) -> Path: + return self._root_path / self._name / _CODE_LOCATION_COMPONENT_INSTANCES_DIR @property - def component_instances(self) -> Iterable[str]: - return os.listdir( - os.path.join(self._root_path, self._name, _CODE_LOCATION_COMPONENT_INSTANCES_DIR) - ) + def component_instances_root_module_name(self) -> str: + return f"{self._name}.{_CODE_LOCATION_COMPONENT_INSTANCES_DIR}" + + def get_component_instance_names(self) -> Iterable[str]: + return [ + str(instance_path.name) + for instance_path in self.component_instances_root_path.iterdir() + ] + + def get_component_instance_path(self, name: str) -> Path: + if not self.has_component_instance(name): + raise DgError(f"No component instance named {name}") + return self.component_instances_root_path / name def has_component_instance(self, name: str) -> bool: - return os.path.exists( - os.path.join(self._root_path, self._name, _CODE_LOCATION_COMPONENT_INSTANCES_DIR, name) - ) + return (self.component_instances_root_path / name).is_dir() diff --git a/python_modules/libraries/dagster-dg/dagster_dg/error.py b/python_modules/libraries/dagster-dg/dagster_dg/error.py index a6cdf04a81995..4909e68682427 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/error.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/error.py @@ -1,2 +1,4 @@ class DgError(Exception): + """Base class for errors thrown by the dg CLI.""" + pass diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index dd99154c5e359..40632a8a19735 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -5,7 +5,7 @@ import click -from dagster_dg.context import CodeLocationProjectContext +from dagster_dg.context import CodeLocationDirectoryContext from dagster_dg.utils import ( camelcase, discover_git_root, @@ -34,7 +34,7 @@ def generate_code_location(path: Path, editable_dagster_root: Optional[str] = No editable_dagster_root = ( editable_dagster_root or os.environ.get("DAGSTER_GIT_REPO_DIR") - or discover_git_root(Path(__file__)) + or str(discover_git_root(Path(__file__))) ) editable_dagster_uv_sources = textwrap.dedent(f""" @@ -66,8 +66,8 @@ def generate_code_location(path: Path, editable_dagster_root: Optional[str] = No execute_code_location_command(Path(path), ("uv", "sync")) -def generate_component_type(context: CodeLocationProjectContext, name: str) -> None: - root_path = Path(context.component_types_root_path) +def generate_component_type(context: CodeLocationDirectoryContext, name: str) -> None: + root_path = Path(context.local_component_types_root_path) click.echo(f"Creating a Dagster component type at {root_path}/{name}.py.") generate_subtree( @@ -80,7 +80,9 @@ def generate_component_type(context: CodeLocationProjectContext, name: str) -> N ) with open(root_path / "__init__.py", "a") as f: - f.write(f"from {context.component_types_root_module}.{name} import {camelcase(name)}\n") + f.write( + f"from {context.local_component_types_root_module_name}.{name} import {camelcase(name)}\n" + ) def generate_component_instance( diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index cef8b663368e3..f9d7543467883 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -14,14 +14,6 @@ _CODE_LOCATION_COMMAND_PREFIX: Final = ["uv", "run", "dagster-components"] -def discover_git_root(path: Path) -> str: - while path != path.parent: - if (path / ".git").exists(): - return str(path) - path = path.parent - raise ValueError("Could not find git root") - - def execute_code_location_command(path: Path, cmd: Sequence[str]) -> str: with pushd(path): full_cmd = [*_CODE_LOCATION_COMMAND_PREFIX, *cmd] @@ -29,6 +21,14 @@ def execute_code_location_command(path: Path, cmd: Sequence[str]) -> str: return result.stdout.decode("utf-8") +def discover_git_root(path: Path) -> Path: + while path != path.parent: + if (path / ".git").exists(): + return path + path = path.parent + raise ValueError("Could not find git root") + + @contextlib.contextmanager def pushd(path: Union[str, Path]) -> Iterator[None]: old_cwd = os.getcwd() @@ -39,7 +39,6 @@ def pushd(path: Union[str, Path]) -> Iterator[None]: os.chdir(old_cwd) -# Adapted from https://github.com/okunishinishi/python-stringcase/blob/master/stringcase.py def camelcase(string: str) -> str: string = re.sub(r"^[\-_\.]", "", str(string)) if not string: @@ -57,7 +56,7 @@ def snakecase(string: str) -> str: return string -DEFAULT_EXCLUDES: List[str] = [ +_DEFAULT_EXCLUDES: List[str] = [ "__pycache__", ".pytest_cache", "*.egg-info", @@ -80,7 +79,7 @@ def generate_subtree( **other_template_vars: Any, ): """Renders templates for Dagster project.""" - excludes = DEFAULT_EXCLUDES if not excludes else DEFAULT_EXCLUDES + excludes + excludes = _DEFAULT_EXCLUDES if not excludes else _DEFAULT_EXCLUDES + excludes normalized_path = os.path.normpath(path) project_name = project_name or os.path.basename(normalized_path).replace("-", "_") @@ -88,10 +87,8 @@ def generate_subtree( os.mkdir(normalized_path) project_template_path = os.path.join(os.path.dirname(__file__), "templates", templates_path) - loader: jinja2.loaders.FileSystemLoader = jinja2.FileSystemLoader( - searchpath=project_template_path - ) - env: jinja2.environment.Environment = jinja2.Environment(loader=loader) + loader = jinja2.FileSystemLoader(searchpath=project_template_path) + env = jinja2.Environment(loader=loader) # merge custom skip_files with the default list for root, dirs, files in os.walk(project_template_path): @@ -146,7 +143,7 @@ def generate_subtree( click.echo(f"Generated files for Dagster project in {path}.") -def _should_skip_file(path: str, excludes: List[str] = DEFAULT_EXCLUDES): +def _should_skip_file(path: str, excludes: List[str] = _DEFAULT_EXCLUDES): """Given a file path `path` in a source template, returns whether or not the file should be skipped when generating destination files. diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 76c753cb178ab..36fd9e154fdf7 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -1,4 +1,3 @@ -import importlib import inspect import json import os @@ -17,18 +16,8 @@ generate_component_type_command, generate_deployment_command, ) -from dagster_dg.context import CodeLocationProjectContext -from dagster_dg.utils import pushd - - -def _ensure_cwd_on_sys_path(): - if sys.path[0] != "": - sys.path.insert(0, "") - - -def _assert_module_imports(module_name: str): - _ensure_cwd_on_sys_path() - assert importlib.import_module(module_name) +from dagster_dg.context import CodeLocationDirectoryContext +from dagster_dg.utils import discover_git_root, pushd # This is a holder for code that is intended to be written to a file @@ -184,19 +173,10 @@ def test_generate_code_location_outside_deployment_success() -> None: assert Path("bar/uv.lock").exists() -def _find_git_root(): - current = Path.cwd() - while current != current.parent: - if (current / ".git").exists(): - return current - current = current.parent - raise Exception("Could not find git root") - - def test_generate_code_location_editable_dagster_success(monkeypatch) -> None: runner = CliRunner() - dagster_git_repo_dir = _find_git_root() - monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", dagster_git_repo_dir) + dagster_git_repo_dir = discover_git_root(Path(__file__)) + monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", str(dagster_git_repo_dir)) with isolated_example_deployment_foo(runner): result = runner.invoke(generate_code_location_command, ["--use-editable-dagster", "bar"]) assert result.exit_code == 0 @@ -239,7 +219,7 @@ def test_generate_component_type_success(in_deployment: bool) -> None: result = runner.invoke(generate_component_type_command, ["baz"]) assert result.exit_code == 0 assert Path("bar/lib/baz.py").exists() - context = CodeLocationProjectContext.from_path(Path.cwd()) + context = CodeLocationDirectoryContext.from_path(Path.cwd()) assert context.has_component_type("bar.baz") From bf7ea98677d84c443acc92e816a77600fc4127c1 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Thu, 12 Dec 2024 11:33:59 -0500 Subject: [PATCH 16/94] [components] Fix `uv` error messages/warnings in dagster-dg tests (#26443) ## Summary & Motivation - `uv sync` was being incorrectly invoked using `uv run` - Now all `uv` commands are run in an environment with `VIRTUAL_ENV` unset, to get rid of the warnings about the uv-resolved environment not matching the shell `VIRTUAL_ENV` ## How I Tested These Changes Observed test output. --- .../libraries/dagster-dg/dagster_dg/generate.py | 6 +++++- .../libraries/dagster-dg/dagster_dg/utils.py | 13 +++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index 40632a8a19735..a0f93908a5e6f 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -1,4 +1,5 @@ import os +import subprocess import textwrap from pathlib import Path from typing import Optional, Tuple @@ -11,6 +12,8 @@ discover_git_root, execute_code_location_command, generate_subtree, + get_uv_command_env, + pushd, ) @@ -63,7 +66,8 @@ def generate_code_location(path: Path, editable_dagster_root: Optional[str] = No ) # Build the venv - execute_code_location_command(Path(path), ("uv", "sync")) + with pushd(path): + subprocess.run(["uv", "sync"], check=True, env=get_uv_command_env()) def generate_component_type(context: CodeLocationDirectoryContext, name: str) -> None: diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index f9d7543467883..c021337245409 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -4,7 +4,7 @@ import re import subprocess from pathlib import Path -from typing import Any, Final, Iterator, List, Optional, Sequence, Union +from typing import Any, Final, Iterator, List, Mapping, Optional, Sequence, Union import click import jinja2 @@ -17,10 +17,19 @@ def execute_code_location_command(path: Path, cmd: Sequence[str]) -> str: with pushd(path): full_cmd = [*_CODE_LOCATION_COMMAND_PREFIX, *cmd] - result = subprocess.run(full_cmd, stdout=subprocess.PIPE, check=False) + result = subprocess.run( + full_cmd, stdout=subprocess.PIPE, env=get_uv_command_env(), check=True + ) return result.stdout.decode("utf-8") +# uv commands should be executed in an environment with no pre-existing VIRTUAL_ENV set. If this +# variable is set (common during development) and does not match the venv resolved by uv, it prints +# undesireable warnings. +def get_uv_command_env() -> Mapping[str, str]: + return {k: v for k, v in os.environ.items() if not k == "VIRTUAL_ENV"} + + def discover_git_root(path: Path) -> Path: while path != path.parent: if (path / ".git").exists(): From a1c6d7e8198220f729bb6239ff69676e19f99ec3 Mon Sep 17 00:00:00 2001 From: jamiedemaria Date: Thu, 12 Dec 2024 11:41:12 -0500 Subject: [PATCH 17/94] Rename run group side bar to Re-executions instead of the job name (#26359) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary & Motivation During dogfooding of some changes to retry logic, @anuthebananu pointed out that the title for the lineage of retried runs was a bit confusing. It's currently the name of the job, which for asset jobs leaks the internal `__ASSET_JOB` name Screenshot 2024-12-09 at 3 01 30 PM This PR renames it `Re-executions`. Screenshot 2024-12-12 at 11 28 57 AM ## How I Tested These Changes ## Changelog Renamed the run lineage sidebar on the Run details page to `Re-executions`. --- .../dagster-ui/packages/ui-core/src/gantt/RunGroupPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/gantt/RunGroupPanel.tsx b/js_modules/dagster-ui/packages/ui-core/src/gantt/RunGroupPanel.tsx index 00f35180d3e53..6d65f30ae1767 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/gantt/RunGroupPanel.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/gantt/RunGroupPanel.tsx @@ -96,7 +96,7 @@ export const RunGroupPanel = ({ }); return ( - + <> {runs.map((g, idx) => g ? ( From b48ccbc17c7966807e2242c33da1abcd60c0cd6a Mon Sep 17 00:00:00 2001 From: Christopher DeCarolis Date: Thu, 12 Dec 2024 10:48:30 -0800 Subject: [PATCH 18/94] [freshness-checks][rfc] Retrieve latest completed check execution in summary records. (#26331) ## Summary & Motivation This is in preparation to make some fixes to the freshness check sensor, which needs to understand both when a check is in flight, and the last completed execution of the check. Previously, on an AssetCheckExecutionSummaryRecord, we were only storing the latest record regardless of status. For freshness checks, we additionally need to know the latest _completed_ execution of a check. This PR adds that behavior by making it possible to query check execution history based on status; a cloud PR companion will follow up if we think this is reasonable. Here's my intuition regarding perf: - In most cases, this will retrieve the latest 2 check executions at most. - In some degenerate cases, we could potentially have to scan many check execution records if there are many in flight checks at once for the same check key. But it's hard to imagine this happening reasonably often. ## How I Tested These Changes Added new assertions to event log storage tests, a new assertion in instance tests to show what the status behavior is for runless events. --- .../storage/asset_check_execution_record.py | 6 +++ .../dagster/_core/storage/event_log/base.py | 16 +++++++- .../_core/storage/event_log/sql_event_log.py | 32 ++++++++++++++-- .../dagster/_core/storage/legacy_storage.py | 19 +++++++++- .../instance_tests/test_instance.py | 19 +++++++++- .../storage_tests/utils/event_log_storage.py | 38 +++++++++++++++++++ 6 files changed, 123 insertions(+), 7 deletions(-) diff --git a/python_modules/dagster/dagster/_core/storage/asset_check_execution_record.py b/python_modules/dagster/dagster/_core/storage/asset_check_execution_record.py index 32f9d68a48a6f..8b233099eae33 100644 --- a/python_modules/dagster/dagster/_core/storage/asset_check_execution_record.py +++ b/python_modules/dagster/dagster/_core/storage/asset_check_execution_record.py @@ -29,6 +29,12 @@ class AssetCheckExecutionRecordStatus(enum.Enum): FAILED = "FAILED" # explicit fail result +COMPLETED_ASSET_CHECK_EXECUTION_RECORD_STATUSES = { + AssetCheckExecutionRecordStatus.SUCCEEDED, + AssetCheckExecutionRecordStatus.FAILED, +} + + class AssetCheckExecutionResolvedStatus(enum.Enum): IN_PROGRESS = "IN_PROGRESS" SUCCEEDED = "SUCCEEDED" diff --git a/python_modules/dagster/dagster/_core/storage/event_log/base.py b/python_modules/dagster/dagster/_core/storage/event_log/base.py index 96ce375465ccf..80b90313e6d39 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/base.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/base.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from typing import ( TYPE_CHECKING, + AbstractSet, Iterable, Mapping, NamedTuple, @@ -35,7 +36,10 @@ ) from dagster._core.instance import MayHaveInstanceWeakref, T_DagsterInstance from dagster._core.loader import LoadableBy, LoadingContext -from dagster._core.storage.asset_check_execution_record import AssetCheckExecutionRecord +from dagster._core.storage.asset_check_execution_record import ( + AssetCheckExecutionRecord, + AssetCheckExecutionRecordStatus, +) from dagster._core.storage.dagster_run import DagsterRunStatsSnapshot from dagster._core.storage.partition_status_cache import get_and_update_asset_status_cache_value from dagster._core.storage.sql import AlembicVersion @@ -157,6 +161,7 @@ class AssetCheckSummaryRecord( ("asset_check_key", AssetCheckKey), ("last_check_execution_record", Optional[AssetCheckExecutionRecord]), ("last_run_id", Optional[str]), + ("last_completed_check_execution_record", Optional[AssetCheckExecutionRecord]), ], ), LoadableBy[AssetCheckKey], @@ -170,6 +175,14 @@ def _blocking_batch_load( ) return [records_by_key[key] for key in keys] + @property + def last_completed_run_id(self) -> Optional[str]: + return ( + self.last_completed_check_execution_record.run_id + if self.last_completed_check_execution_record + else None + ) + class PlannedMaterializationInfo(NamedTuple): """Internal representation of an planned materialization event, containing storage_id / run_id. @@ -600,6 +613,7 @@ def get_asset_check_execution_history( check_key: AssetCheckKey, limit: int, cursor: Optional[int] = None, + status: Optional[AbstractSet[AssetCheckExecutionRecordStatus]] = None, ) -> Sequence[AssetCheckExecutionRecord]: """Get executions for one asset check, sorted by recency.""" pass diff --git a/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py b/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py index 62a0463e45933..c23039a43b932 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py @@ -7,6 +7,7 @@ from functools import cached_property from typing import ( TYPE_CHECKING, + AbstractSet, Any, ContextManager, Dict, @@ -58,6 +59,7 @@ from dagster._core.events.log import EventLogEntry from dagster._core.execution.stats import RunStepKeyStatsSnapshot, build_run_step_stats_from_events from dagster._core.storage.asset_check_execution_record import ( + COMPLETED_ASSET_CHECK_EXECUTION_RECORD_STATUSES, AssetCheckExecutionRecord, AssetCheckExecutionRecordStatus, ) @@ -1327,11 +1329,29 @@ def get_asset_check_summary_records( ) -> Mapping[AssetCheckKey, AssetCheckSummaryRecord]: states = {} for asset_check_key in asset_check_keys: - execution_record = self.get_asset_check_execution_history(asset_check_key, limit=1) + last_execution_record = self.get_asset_check_execution_history(asset_check_key, limit=1) + last_completed_execution_record = ( + last_execution_record + # If the check has never been executed or the latest record is a completed record, + # Avoid refetching the last completed record + if ( + not last_execution_record + or last_execution_record[0].status + in COMPLETED_ASSET_CHECK_EXECUTION_RECORD_STATUSES + ) + else self.get_asset_check_execution_history( + asset_check_key, limit=1, status=COMPLETED_ASSET_CHECK_EXECUTION_RECORD_STATUSES + ) + ) states[asset_check_key] = AssetCheckSummaryRecord( asset_check_key=asset_check_key, - last_check_execution_record=execution_record[0] if execution_record else None, - last_run_id=execution_record[0].run_id if execution_record else None, + last_check_execution_record=last_execution_record[0] + if last_execution_record + else None, + last_run_id=last_execution_record[0].run_id if last_execution_record else None, + last_completed_check_execution_record=last_completed_execution_record[0] + if last_completed_execution_record + else None, ) return states @@ -2888,6 +2908,7 @@ def get_asset_check_execution_history( check_key: AssetCheckKey, limit: int, cursor: Optional[int] = None, + status: Optional[AbstractSet[AssetCheckExecutionRecordStatus]] = None, ) -> Sequence[AssetCheckExecutionRecord]: check.inst_param(check_key, "key", AssetCheckKey) check.int_param(limit, "limit") @@ -2915,6 +2936,11 @@ def get_asset_check_execution_history( if cursor: query = query.where(AssetCheckExecutionsTable.c.id < cursor) + if status: + query = query.where( + AssetCheckExecutionsTable.c.execution_status.in_([s.value for s in status]) + ) + with self.index_connection() as conn: rows = db_fetch_mappings(conn, query) diff --git a/python_modules/dagster/dagster/_core/storage/legacy_storage.py b/python_modules/dagster/dagster/_core/storage/legacy_storage.py index 8873d4546b8a1..28668cb5fb2e6 100644 --- a/python_modules/dagster/dagster/_core/storage/legacy_storage.py +++ b/python_modules/dagster/dagster/_core/storage/legacy_storage.py @@ -1,4 +1,14 @@ -from typing import TYPE_CHECKING, Iterable, Mapping, Optional, Sequence, Set, Tuple, Union +from typing import ( + TYPE_CHECKING, + AbstractSet, + Iterable, + Mapping, + Optional, + Sequence, + Set, + Tuple, + Union, +) from dagster import _check as check from dagster._config.config_schema import UserConfigSchema @@ -9,7 +19,10 @@ ) from dagster._core.definitions.events import AssetKey from dagster._core.event_api import EventHandlerFn -from dagster._core.storage.asset_check_execution_record import AssetCheckExecutionRecord +from dagster._core.storage.asset_check_execution_record import ( + AssetCheckExecutionRecord, + AssetCheckExecutionRecordStatus, +) from dagster._core.storage.base_storage import DagsterStorage from dagster._core.storage.event_log.base import ( AssetCheckSummaryRecord, @@ -687,11 +700,13 @@ def get_asset_check_execution_history( check_key: "AssetCheckKey", limit: int, cursor: Optional[int] = None, + status: Optional[AbstractSet[AssetCheckExecutionRecordStatus]] = None, ) -> Sequence[AssetCheckExecutionRecord]: return self._storage.event_log_storage.get_asset_check_execution_history( check_key=check_key, limit=limit, cursor=cursor, + status=status, ) def get_latest_asset_check_execution_by_key( diff --git a/python_modules/dagster/dagster_tests/core_tests/instance_tests/test_instance.py b/python_modules/dagster/dagster_tests/core_tests/instance_tests/test_instance.py index 11d6c94ddafea..fa4e970511638 100644 --- a/python_modules/dagster/dagster_tests/core_tests/instance_tests/test_instance.py +++ b/python_modules/dagster/dagster_tests/core_tests/instance_tests/test_instance.py @@ -37,6 +37,7 @@ from dagster._core.launcher import LaunchRunContext, RunLauncher from dagster._core.run_coordinator.queued_run_coordinator import QueuedRunCoordinator from dagster._core.snap import create_execution_plan_snapshot_id, snapshot_from_execution_plan +from dagster._core.storage.asset_check_execution_record import AssetCheckExecutionRecordStatus from dagster._core.storage.partition_status_cache import AssetPartitionStatus, AssetStatusCacheValue from dagster._core.storage.sqlite_storage import ( _event_logs_directory, @@ -742,7 +743,7 @@ def test_get_status_by_partition(mock_get_and_update): assert partition_status == {"2023-07-01": AssetPartitionStatus.IN_PROGRESS} -def test_report_runless_asset_event(): +def test_report_runless_asset_event() -> None: with instance_for_test() as instance: my_asset_key = AssetKey("my_asset") @@ -768,6 +769,22 @@ def test_report_runless_asset_event(): limit=1, ) assert len(records) == 1 + assert records[0].status == AssetCheckExecutionRecordStatus.SUCCEEDED + + instance.report_runless_asset_event( + AssetCheckEvaluation( + asset_key=my_asset_key, + check_name=my_check, + passed=False, + metadata={}, + ) + ) + records = instance.event_log_storage.get_asset_check_execution_history( + check_key=AssetCheckKey(asset_key=my_asset_key, name=my_check), + limit=1, + ) + assert len(records) == 1 + assert records[0].status == AssetCheckExecutionRecordStatus.FAILED def test_invalid_run_id(): diff --git a/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py b/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py index 55b130a2c0bef..f46909236e75c 100644 --- a/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py +++ b/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py @@ -5220,6 +5220,19 @@ def test_asset_checks( assert checks[0].run_id == run_id_1 assert checks[0].event assert checks[0].event.dagster_event_type == DagsterEventType.ASSET_CHECK_EVALUATION_PLANNED + checks_filtered = storage.get_asset_check_execution_history( + check_key_1, limit=10, status={AssetCheckExecutionRecordStatus.PLANNED} + ) + assert len(checks_filtered) == 1 + checks_filtered_2 = storage.get_asset_check_execution_history( + check_key_1, + limit=10, + status={ + AssetCheckExecutionRecordStatus.SUCCEEDED, + AssetCheckExecutionRecordStatus.FAILED, + }, + ) + assert len(checks_filtered_2) == 0 latest_checks = storage.get_latest_asset_check_execution_by_key([check_key_1, check_key_2]) assert len(latest_checks) == 1 @@ -5259,6 +5272,19 @@ def test_asset_checks( check_data = checks[0].event.dagster_event.asset_check_evaluation_data assert check_data.target_materialization_data assert check_data.target_materialization_data.storage_id == 42 + filtered_checks = storage.get_asset_check_execution_history( + check_key_1, limit=10, status={AssetCheckExecutionRecordStatus.SUCCEEDED} + ) + assert len(filtered_checks) == 1 + filtered_checks_2 = storage.get_asset_check_execution_history( + check_key_1, + limit=10, + status={ + AssetCheckExecutionRecordStatus.FAILED, + AssetCheckExecutionRecordStatus.PLANNED, + }, + ) + assert len(filtered_checks_2) == 0 latest_checks = storage.get_latest_asset_check_execution_by_key([check_key_1, check_key_2]) assert len(latest_checks) == 1 @@ -5556,6 +5582,11 @@ def test_asset_check_summary_record( == AssetCheckExecutionRecordStatus.SUCCEEDED ) assert check_1_summary_record.last_check_execution_record.run_id == run_id_0 + assert ( + check_1_summary_record.last_completed_check_execution_record + == check_1_summary_record.last_check_execution_record + ) + assert check_1_summary_record.last_completed_run_id == run_id_0 check_2_summary_record = summary_records[check_key_2] assert check_2_summary_record.last_check_execution_record @@ -5623,6 +5654,7 @@ def test_asset_check_summary_record( ) # Check that the summary record for check_key_1 has been updated + old_check_1_summary_record = check_1_summary_record records = storage.get_asset_check_summary_records(asset_check_keys=[check_key_1]) assert len(records) == 1 check_1_summary_record = records[check_key_1] @@ -5632,6 +5664,12 @@ def test_asset_check_summary_record( == AssetCheckExecutionRecordStatus.PLANNED ) assert check_1_summary_record.last_check_execution_record.run_id == run_id_1 + # The latest completed data should not be updated. + assert ( + check_1_summary_record.last_completed_check_execution_record + == old_check_1_summary_record.last_check_execution_record + ) + assert check_1_summary_record.last_completed_run_id == run_id_0 def test_large_asset_metadata( self, From fe8cb16993b4b026afa86e79c6a92161712c3791 Mon Sep 17 00:00:00 2001 From: Christopher DeCarolis Date: Thu, 12 Dec 2024 10:49:51 -0800 Subject: [PATCH 19/94] [freshness-checks][rfc] fix tickets (#26335) ## Summary & Motivation Attempts to fix tickets for freshness checks: https://linear.app/dagster-labs/issue/BUILD-527/%5Bfreshness-sensor%5D-check-for-newer-materialization-when-last-check and https://linear.app/dagster-labs/issue/BUILD-528/%5Bfreshness-sensor%5D-catch-long-runtime-issues-even-when-checks-are#comment-8cfd22cb. The exact cases in question: - When the asset becomes overdue because the evaluation is taking too long, and there is a planned freshness check evaluation as part of the run, we should still kick off a run of the check so that users can get alerted. - When there's a materialization more recent than the latest check result, kick off another evaluation of the check. ## How I Tested These Changes I added new tests for the previously failing cases. ## Changelog [bugfixes] - Previously, the freshness check sensor would not re-evaluate freshness checks if an in-flight run was planning on evaluating that check. Now, the freshness check sensor will kick off an independent run of the check, even if there's already an in flight run, as long as the freshness check can potentially fail. - Previously, if the freshness check was in a failing state, the sensor would wait for a run of some sort to update the freshness check before re-evaluating. Now, if there's a materialization later than the last evaluation of the freshness check and no planned evaluation, we will re-evaluate the freshness check automatically. --- .../freshness_checks/sensor.py | 124 ++++++--- .../freshness_checks_tests/test_sensor.py | 239 +++++++++++++++++- 2 files changed, 331 insertions(+), 32 deletions(-) diff --git a/python_modules/dagster/dagster/_core/definitions/asset_check_factories/freshness_checks/sensor.py b/python_modules/dagster/dagster/_core/definitions/asset_check_factories/freshness_checks/sensor.py index 943e9b8094f01..34bb66266296f 100644 --- a/python_modules/dagster/dagster/_core/definitions/asset_check_factories/freshness_checks/sensor.py +++ b/python_modules/dagster/dagster/_core/definitions/asset_check_factories/freshness_checks/sensor.py @@ -19,6 +19,7 @@ SensorEvaluationContext, ) from dagster._core.storage.asset_check_execution_record import AssetCheckExecutionRecordStatus +from dagster._core.storage.tags import SENSOR_NAME_TAG from dagster._time import get_current_datetime, get_current_timestamp DEFAULT_FRESHNESS_SENSOR_NAME = "freshness_checks_sensor" @@ -162,42 +163,105 @@ def freshness_checks_get_evaluations_iter( yield check_key, True continue - # Case 2: The check is currently evaluating. We shouldn't kick off another evaluation until it's done. - if ( - summary_record.last_check_execution_record.status - == AssetCheckExecutionRecordStatus.PLANNED - ): - context.log.info( - f"Freshness check on asset {check_key.asset_key.to_user_string()} is in the planned state, indicating it is currently evaluating. Skipping..." + # Case 2: The check is currently evaluating and has never previously evaluated. We shouldn't kick off another evaluation until it's done. + if summary_record.last_completed_check_execution_record is None: + check.invariant( + summary_record.last_check_execution_record.status + == AssetCheckExecutionRecordStatus.PLANNED, + f"Unexpected status for check {check_key.to_user_string()}. The summary record indicates that the check has never completed, but the last check execution record is in terminal state {summary_record.last_check_execution_record.status}. This is likely a framework error, please report this to the Dagster maintainers.", ) - yield check_key, False - continue - evaluation = check.not_none( - summary_record.last_check_execution_record.event - ).asset_check_evaluation - # Case 3: The check previously failed. We shouldn't kick off another evaluation until the asset has been updated. - if not evaluation or not evaluation.passed: context.log.info( - f"Freshness check {check_key.to_user_string()} failed its last evaluation. Waiting " - "to re-evaluate until the asset has received an update." + f"Freshness check on asset {check_key.asset_key.to_user_string()} is currently evaluating for the first time. Skipping..." ) yield check_key, False continue - # Case 4: The check previously passed. We should re-evaluate if it's possible for the check to be overdue again. - next_deadline = cast(float, evaluation.metadata[FRESH_UNTIL_METADATA_KEY].value) - if next_deadline < start_time.timestamp(): - context.log.info( - f"Freshness check {check_key.to_user_string()} previously passed, but " - "enough time has passed that it can be overdue again. Adding to run request." + + latest_completed_record = check.not_none( + summary_record.last_completed_check_execution_record + ) + latest_record_any_status = check.not_none(summary_record.last_check_execution_record) + latest_completed_evaluation = check.not_none( + check.not_none(latest_completed_record.event).asset_check_evaluation + ) + # Case 3: The check is currently evaluating and the previous evaluation passed. + # - If the check is overdue and the current evaluation was not kicked off by the sensor, we should kick off another evaluation. + # - If the check previously failed, we'll wait for the current evaluation to complete to avoid over-evaluation. + if ( + latest_record_any_status.status == AssetCheckExecutionRecordStatus.PLANNED + and latest_completed_evaluation.passed + ): + run_record = context.instance.get_run_record_by_id(latest_record_any_status.run_id) + # Previous run was kicked off by the sensor, wait for it to complete before kicking off another run. + if ( + run_record + and run_record.dagster_run.tags.get(SENSOR_NAME_TAG) == context.sensor_name + ): + context.log.info( + f"Freshness check {check_key.to_user_string()} is currently evaluating, and was kicked off by this sensor. Skipping..." + ) + yield check_key, False + continue + # Previous run was not kicked off by the sensor, check if it's overdue. + next_deadline = cast( + float, latest_completed_evaluation.metadata[FRESH_UNTIL_METADATA_KEY].value ) - yield check_key, True - continue + if next_deadline < start_time.timestamp(): + context.log.info( + f"Freshness check {check_key.to_user_string()} is currently evaluating, but " + "enough time has passed that it can be overdue again. Adding to run request." + ) + yield check_key, True + continue + else: + how_long_until_next_deadline = next_deadline - start_time.timestamp() + context.log.info( + f"Freshness check {check_key.to_user_string()} is currently evaluating, but " + f"cannot be overdue again until {seconds_in_words(how_long_until_next_deadline)} from now. Skipping..." + ) + yield check_key, False + continue + # Case 4: The previous completed evaluation failed. We should kick off another only if the asset has been updated since it's last evaluation. + elif not latest_completed_evaluation.passed: + latest_materialization = context.instance.get_latest_materialization_event( + check_key.asset_key + ) + # If the asset has been updated since the last evaluation, we should re-evaluate the check. + if ( + latest_materialization + and latest_materialization.timestamp + > check.not_none(latest_completed_record.event).timestamp + ): + context.log.info( + f"Freshness check {check_key.to_user_string()} previously failed, but " + "the asset has been updated since the last evaluation. Adding to run request." + ) + yield check_key, True + continue + else: + context.log.info( + f"Freshness check {check_key.to_user_string()} previously failed, but " + "the asset has not been updated since the last evaluation. Skipping..." + ) + yield check_key, False + continue + # Case 5: The previous evaluation passed and there is no in progress evaluation. We should kick off another evaluation only if the check is overdue. else: - how_long_until_next_deadline = next_deadline - start_time.timestamp() - context.log.info( - f"Freshness check {check_key.to_user_string()} previously passed, but " - f"cannot be overdue again until {seconds_in_words(how_long_until_next_deadline)} from now. Skipping..." + next_deadline = cast( + float, latest_completed_evaluation.metadata[FRESH_UNTIL_METADATA_KEY].value ) - yield check_key, False - continue + if next_deadline < start_time.timestamp(): + context.log.info( + f"Freshness check {check_key.to_user_string()} previously passed, but " + "enough time has passed that it can be overdue again. Adding to run request." + ) + yield check_key, True + continue + else: + how_long_until_next_deadline = next_deadline - start_time.timestamp() + context.log.info( + f"Freshness check {check_key.to_user_string()} previously passed, but " + f"cannot be overdue again until {seconds_in_words(how_long_until_next_deadline)} from now. Skipping..." + ) + yield check_key, False + continue diff --git a/python_modules/dagster/dagster_tests/definitions_tests/freshness_checks_tests/test_sensor.py b/python_modules/dagster/dagster_tests/definitions_tests/freshness_checks_tests/test_sensor.py index ca549b1c40df7..b7881d5a79ba9 100644 --- a/python_modules/dagster/dagster_tests/definitions_tests/freshness_checks_tests/test_sensor.py +++ b/python_modules/dagster/dagster_tests/definitions_tests/freshness_checks_tests/test_sensor.py @@ -21,12 +21,14 @@ from dagster._core.definitions.asset_out import AssetOut from dagster._core.definitions.decorators.asset_decorator import multi_asset from dagster._core.definitions.definitions_class import Definitions +from dagster._core.definitions.events import AssetMaterialization from dagster._core.definitions.metadata import FloatMetadataValue from dagster._core.definitions.run_request import RunRequest, SkipReason from dagster._core.definitions.sensor_definition import build_sensor_context from dagster._core.events import DagsterEvent, DagsterEventType from dagster._core.events.log import EventLogEntry -from dagster._core.test_utils import freeze_time +from dagster._core.storage.tags import SENSOR_NAME_TAG +from dagster._core.test_utils import create_run_for_test, freeze_time from dagster._core.utils import make_new_run_id from dagster._time import get_current_datetime @@ -132,7 +134,7 @@ def my_asset(): def test_sensor_evaluation_planned(instance: DagsterInstance) -> None: - """Test the case where the asset check is currently planned to evaluate. We shouldn't attempt to re-evalaute the check in this case.""" + """Test the case where the asset check is currently planned to evaluate, and has never previously evaluated. We shouldn't be kicking off a new run of the check.""" @asset def my_asset(): @@ -142,6 +144,7 @@ def my_asset(): assets=[my_asset], lower_bound_delta=datetime.timedelta(minutes=10) ) + # Check has never completed evaluation but is in flight. We should skip the check. frozen_time = get_current_datetime() with freeze_time(frozen_time): instance.event_log_storage.store_event( @@ -170,6 +173,238 @@ def my_asset(): assert context.cursor is None +def test_sensor_eval_planned_prev_success(instance: DagsterInstance) -> None: + """Test the case where the asset check is currently planned to evaluate, and has previously evaluated successfully. We should be kicking off a run of the check once the freshness interval has passed.""" + + @asset + def my_asset(): + pass + + freshness_checks = build_last_update_freshness_checks( + assets=[my_asset], lower_bound_delta=datetime.timedelta(minutes=10) + ) + + # Check has never completed evaluation but is in flight. We should skip the check. + frozen_time = get_current_datetime() + with freeze_time(frozen_time - datetime.timedelta(minutes=5)): + instance.report_runless_asset_event( + AssetCheckEvaluation( + asset_key=my_asset.key, + check_name="freshness_check", + passed=True, + metadata={ + FRESH_UNTIL_METADATA_KEY: FloatMetadataValue(frozen_time.timestamp() + 5) + }, + ) + ) + with freeze_time(frozen_time): + instance.event_log_storage.store_event( + EventLogEntry( + error_info=None, + user_message="", + level="debug", + run_id=make_new_run_id(), + timestamp=time.time(), + dagster_event=DagsterEvent( + DagsterEventType.ASSET_CHECK_EVALUATION_PLANNED.value, + "nonce", + event_specific_data=AssetCheckEvaluationPlanned( + asset_key=my_asset.key, check_name="freshness_check" + ), + ), + ) + ) + sensor = build_sensor_for_freshness_checks(freshness_checks=freshness_checks) + defs = Definitions(asset_checks=freshness_checks, assets=[my_asset], sensors=[sensor]) + context = build_sensor_context(instance=instance, definitions=defs) + + # Upon evaluation, we do not yet expect a run request, since the freshness interval has not yet passed. + result = sensor(context) + assert isinstance(result, SkipReason) + # Cursor should be None, since we made it through all assets. + assert context.cursor is None + + # Move time forward to when the check should be evaluated. + with freeze_time(frozen_time + datetime.timedelta(minutes=6)): + # Upon evaluation, we should get a run request for the asset check. + run_request = sensor(context) + assert isinstance(run_request, RunRequest) + assert run_request.asset_check_keys == [AssetCheckKey(my_asset.key, "freshness_check")] + # Cursor should be None, since we made it through all assets. + assert context.cursor is None + + +def test_sensor_eval_planned_prev_failed(instance: DagsterInstance) -> None: + """Test the case where the asset check is currently planned to evaluate, and has previously evaluated unsuccessfully. We should not be kicking off a run of the check.""" + + @asset + def my_asset(): + pass + + freshness_checks = build_last_update_freshness_checks( + assets=[my_asset], lower_bound_delta=datetime.timedelta(minutes=10) + ) + + # Check has never completed evaluation but is in flight. We should skip the check. + frozen_time = get_current_datetime() + with freeze_time(frozen_time - datetime.timedelta(minutes=5)): + instance.report_runless_asset_event( + AssetCheckEvaluation( + asset_key=my_asset.key, + check_name="freshness_check", + passed=False, + metadata={}, + ) + ) + with freeze_time(frozen_time): + instance.event_log_storage.store_event( + EventLogEntry( + error_info=None, + user_message="", + level="debug", + run_id=make_new_run_id(), + timestamp=time.time(), + dagster_event=DagsterEvent( + DagsterEventType.ASSET_CHECK_EVALUATION_PLANNED.value, + "nonce", + event_specific_data=AssetCheckEvaluationPlanned( + asset_key=my_asset.key, check_name="freshness_check" + ), + ), + ) + ) + sensor = build_sensor_for_freshness_checks(freshness_checks=freshness_checks) + defs = Definitions(asset_checks=freshness_checks, assets=[my_asset], sensors=[sensor]) + context = build_sensor_context(instance=instance, definitions=defs) + + # Upon evaluation, we should not get a run request for the asset check. + result = sensor(context) + assert isinstance(result, SkipReason) + # Cursor should be None, since we made it through all assets. + assert context.cursor is None + + +def test_sensor_eval_failed_and_outdated(instance: DagsterInstance) -> None: + """Test the case where the asset check has previously failed, but the result is now out of date. We should kick off a new check evaluation.""" + + @asset + def my_asset(): + pass + + freshness_checks = build_last_update_freshness_checks( + assets=[my_asset], lower_bound_delta=datetime.timedelta(minutes=10) + ) + + frozen_time = get_current_datetime() + with freeze_time(frozen_time - datetime.timedelta(minutes=5)): + instance.report_runless_asset_event( + AssetCheckEvaluation( + asset_key=my_asset.key, + check_name="freshness_check", + passed=False, + metadata={}, + ) + ) + # Freshness check has previously failed, but we've since received a materialization for the asset making it out of date. + with freeze_time(frozen_time): + instance.report_runless_asset_event(AssetMaterialization(asset_key=my_asset.key)) + sensor = build_sensor_for_freshness_checks(freshness_checks=freshness_checks) + defs = Definitions(asset_checks=freshness_checks, assets=[my_asset], sensors=[sensor]) + context = build_sensor_context(instance=instance, definitions=defs) + + # Upon evaluation, we should get a run request for the asset check. + run_request = sensor(context) + assert isinstance(run_request, RunRequest) + assert run_request.asset_check_keys == [AssetCheckKey(my_asset.key, "freshness_check")] + # Cursor should be None, since we made it through all assets. + assert context.cursor is None + + +def test_sensor_eval_planned_and_launched_by_sensor(instance: DagsterInstance) -> None: + """Test the case where the asset check is currently planned to evaluate, but the sensor is what launched the in-flight evaluation. We should not kick off a new evaluation.""" + + @asset + def my_asset(): + pass + + freshness_checks = build_last_update_freshness_checks( + assets=[my_asset], lower_bound_delta=datetime.timedelta(minutes=10) + ) + sensor = build_sensor_for_freshness_checks(freshness_checks=freshness_checks, name="my_sensor") + defs = Definitions(asset_checks=freshness_checks, assets=[my_asset], sensors=[sensor]) + + frozen_time = get_current_datetime() + with freeze_time(frozen_time - datetime.timedelta(minutes=5)): + run_id = make_new_run_id() + # Create a run, simulate started by this sensor + create_run_for_test( + instance=instance, + run_id=run_id, + job_name="my_sensor", + tags={SENSOR_NAME_TAG: "my_sensor"}, + ) + instance.event_log_storage.store_event( + EventLogEntry( + error_info=None, + user_message="", + level="debug", + run_id=run_id, + timestamp=time.time(), + dagster_event=DagsterEvent( + DagsterEventType.ASSET_CHECK_EVALUATION_PLANNED.value, + "nonce", + event_specific_data=AssetCheckEvaluationPlanned( + asset_key=my_asset.key, check_name="freshness_check" + ), + ), + ) + ) + + with freeze_time(frozen_time): + context = build_sensor_context(instance=instance, definitions=defs) + skip_reason = sensor(context) + assert isinstance(skip_reason, SkipReason) + + +def test_sensor_eval_success_and_outdated(instance: DagsterInstance) -> None: + """Test the case where the asset check has previously succeeded, but the result is now out of date. We should not kick off an evaluation unless FRESH_UNTIL_TIMESTAMP has passed.""" + + @asset + def my_asset(): + pass + + freshness_checks = build_last_update_freshness_checks( + assets=[my_asset], lower_bound_delta=datetime.timedelta(minutes=10) + ) + + frozen_time = get_current_datetime() + with freeze_time(frozen_time - datetime.timedelta(minutes=5)): + instance.report_runless_asset_event( + AssetCheckEvaluation( + asset_key=my_asset.key, + check_name="freshness_check", + passed=True, + metadata={ + FRESH_UNTIL_METADATA_KEY: FloatMetadataValue( + (frozen_time + datetime.timedelta(minutes=5)).timestamp() + ) + }, + ) + ) + # Freshness check has previously succeeded, but we've since received a materialization for the asset making it out of date. + with freeze_time(frozen_time): + instance.report_runless_asset_event(AssetMaterialization(asset_key=my_asset.key)) + sensor = build_sensor_for_freshness_checks(freshness_checks=freshness_checks) + defs = Definitions(asset_checks=freshness_checks, assets=[my_asset], sensors=[sensor]) + context = build_sensor_context(instance=instance, definitions=defs) + + # Upon evaluation, we should not get a run request for the asset check. + skip_reason = sensor(context) + assert isinstance(skip_reason, SkipReason) + # Cursor should be None, since we made it through all assets. + assert context.cursor is None + + def test_sensor_cursor_recovery(instance: DagsterInstance) -> None: """Test the case where we have a cursor to evaluate from.""" From 16a87b68887aa293163895744ebee0f95d6e0cc6 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Thu, 12 Dec 2024 13:57:39 -0500 Subject: [PATCH 20/94] [changelog] 1.9.5 (#26450) Changelog for 1.9.5 --- CHANGES.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index ff54736810ef7..911f8fe2c6e34 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,33 @@ # Changelog +## 1.9.5 (core) / 0.25.5 (libraries) + +### New + +- The automatic run retry daemon has been updated so that there is a single source of truth for if a run will be retried and if the retry has been launched. Tags are now added to run at failure time indicating if the run will be retried by the automatic retry system. Once the automatic retry has been launched, the run ID of the retry is added to the original run. +- When canceling a backfill of a job, the backfill daemon will now cancel all runs launched by that backfill before marking the backfill as canceled. +- Dagster execution info (tags such as `dagster/run-id`, `dagster/code-location`, `dagster/user` and Dagster Cloud environment variables) typically attached to external resources are now available under `DagsterRun.dagster_execution_info`. +- `SensorReturnTypesUnion` is now exported for typing the output of sensor functions. +- [dagster-dbt] dbt seeds now get a valid code version (Thanks [@marijncv](https://github.com/marijncv)!). +- Manual and automatic retries of runs launched by backfills that occur while the backfill is still in progress are now incorporated into the backfill's status. +- Manual retries of runs launched by backfills are no longer considered part of the backfill if the backfill is complete when the retry is launched. +- [dagster-fivetran] Fivetran assets can now be materialized using the FivetranWorkspace.sync_and_poll(…) method in the definition of a `@fivetran_assets` decorator. +- [dagster-fivetran] `load_fivetran_asset_specs` has been updated to accept an instance of `DagsterFivetranTranslator` or custom subclass. +- [dagster-fivetran] The `fivetran_assets` decorator was added. It can be used with the `FivetranWorkspace` resource and `DagsterFivetranTranslator` translator to load Fivetran tables for a given connector as assets in Dagster. The `build_fivetran_assets_definitions` factory can be used to create assets for all the connectors in your Fivetran workspace. +- [dagster-aws] `ECSPipesClient.run` now waits up to 70 days for tasks completion (waiter parameters are configurable) (Thanks [@jenkoian](https://github.com/jenkoian)!) +- [dagster-dbt] Update dagster-dbt scaffold template to be compatible with uv (Thanks [@wingyplus](https://github.com/wingyplus)!). +- [dagster-airbyte] A `load_airbyte_cloud_asset_specs` function has + been added. It can be used with the `AirbyteCloudWorkspace` resource and `DagsterAirbyteTranslator` translator to load your Airbyte Cloud connection streams as external assets in Dagster. +- [ui] Add an icon for the `icechunk` kind. +- [ui] Improved ui for manual sensor/schedule evaluation. + +### Bugfixes + +- Fixed database locking bug for the `ConsolidatedSqliteEventLogStorage`, which is mostly used for tests. +- [dagster-aws] Fixed a bug in the ECSRunLauncher that prevented it from accepting a user-provided task definition when DAGSTER_CURRENT_IMAGE was not set in the code location. +- [ui] Fixed an issue that would sometimes cause the asset graph to fail to render on initial load. +- [ui] Fix global auto-materialize tick timeline when paginating. + ## 1.9.4 (core) / 0.25.4 (libraries) ### New From 3a406e24713dd7c0ce25b5f3e001edd1e16ddac2 Mon Sep 17 00:00:00 2001 From: Mathieu Larose Date: Thu, 12 Dec 2024 14:13:41 -0500 Subject: [PATCH 21/94] [azure-docs] refine deployment with ACR docs (#26397) ## Summary & Motivation Updates the Azure Container Registry (ACR) user code documentation with missing instructions for configuring GitHub Actions and Dagster Cloud. Adds detailed steps for setting up environment variables, updating other step of the CI/CD workflow, and configuring the `dagster_cloud.yaml` file to work with ACR. ## How I Tested These Changes - All changes are resulting from reproducing and fixing omissions in the previous version. ## Changelog - NOCHANGELOG --- .../deployment/azure/acr-user-code.mdx | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx b/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx index b9922423bce14..f6c3b9e6b26f1 100644 --- a/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx +++ b/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx @@ -89,18 +89,26 @@ First, we'll need to generate a service principal for GitHub Actions to use to a az ad sp create-for-rbac --name "github-actions-acr" --role contributor --scopes /subscriptions//resourceGroups//providers/Microsoft.ContainerRegistry/registries/ ``` -This command will output a JSON object with the service principal details. Make sure to save the `appId`, `password`, and `tenant` values - we'll use them in the next step. +This command will output a JSON object with the service principal details. Make sure to save the `appId` and `password` values - we'll use them in the next step. ### Add secrets to your repository We'll add the service principal details as secrets in our repository. Go to your repository in GitHub, and navigate to `Settings` -> `Secrets`. Add the following secrets: +- `DAGSTER_CLOUD_API_TOKEN`: An agent token. For more details see [Managing agent tokens](/dagster-plus/account/managing-user-agent-tokens#managing-agent-tokens). - `AZURE_CLIENT_ID`: The `appId` from the service principal JSON object. - `AZURE_CLIENT_SECRET`: The `password` from the service principal JSON object. -### Update the workflow +### Update the GitHub Actions workflow -Finally, we'll update the workflow to use the service principal details. Open `.github/workflows/dagster-cloud-deploy.yml` in your repository, and uncomment the section on Azure Container Registry. It should look like this: +For this step, open `.github/workflows/dagster-cloud-deploy.yml` in your repository with your preferred text editor to perform the changes below. + +In the `env` section of the workflow, update the following variables: + +- `DAGSTER_CLOUD_ORGANIZATION`: The name of your Dagster Cloud organization. +- `IMAGE_REGISTRY`: The URL of your Azure Container Registry: `.azurecr.io`. + +We'll update the workflow to use the Azure Container Registry by uncommenting its section and providing the principal details. It should look like this: ```yaml # Azure Container Registry (ACR) @@ -114,6 +122,34 @@ Finally, we'll update the workflow to use the service principal details. Open `. password: ${{ secrets.AZURE_CLIENT_SECRET }} ``` +Finally, update the tags in the "Build and upload Docker image" step to match the full URL of your image in ACR: + +```yaml +- name: Build and upload Docker image for "quickstart_etl" + if: steps.prerun.outputs.result != 'skip' + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ env.IMAGE_REGISTRY }}/:${{ env.IMAGE_TAG }} + cache-from: type=gha + cache-to: type=gha,mode=max +``` + +### Update the `dagster_cloud.yaml` build configuration to use the Azure Container Registry + +Edit the `dagster_cloud.yaml` file in the root of your repository. Update the `build` section to use the Azure Container Registry, and provide an image name specific to the code location. This must match the registry and image name used in the previous step. + +```yaml +locations: + - location_name: quickstart_etl + code_source: + package_name: quickstart_etl.definitions + build: + directory: ./ + registry: .azurecr.io/ +``` + ### Push and run the workflow Now, commit and push the changes to your repository. The GitHub Actions workflow should run automatically. You can check the status of the workflow in the `Actions` tab of your repository. From 9e60148fc92c2addb643d594aa9b193c738ef35d Mon Sep 17 00:00:00 2001 From: Mathieu Larose Date: Thu, 12 Dec 2024 14:17:43 -0500 Subject: [PATCH 22/94] [azure-docs] refine AzureBlobComputeLogManager guide (#26407) ## Summary & Motivation Updates the Azure Blob Storage compute logs documentation to clarify the setup process and fix issues with workload identity configuration. Adds specific instructions for using the Dagster+ Helm chart and includes a new "Next steps" section in the ACR user code guide. ## How I Tested These Changes - Verified all commands and configurations work in an Azure Kubernetes Service (AKS) environment ## Changelog - NOCHANGELOG --- .../deployment/azure/acr-user-code.mdx | 4 + .../deployment/azure/blob-compute-logs.mdx | 83 ++++++++++++------- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx b/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx index f6c3b9e6b26f1..93d7390bb3890 100644 --- a/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx +++ b/docs/content/dagster-plus/deployment/azure/acr-user-code.mdx @@ -169,3 +169,7 @@ alt="Dagster+ code locations page showing the new code location" width={1152} height={320} /> + +## Next steps + +Now that you have your code location deployed, you can follow the guide [here](/dagster-plus/deployment/azure/blob-compute-logs) to set up logging in your AKS cluster. diff --git a/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx b/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx index 698d8def57482..52bfb2d355606 100644 --- a/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx +++ b/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx @@ -25,14 +25,19 @@ First, we'll enable the cluster to use workload identity. This will allow the AK az aks update --resource-group --name --enable-workload-identity ``` -Then, we'll create a new managed identity for the AKS agent, and a new service account in our AKS cluster. +Then, we'll create a new managed identity for the AKS agent. ```bash az identity create --resource-group --name agent-identity -kubectl create serviceaccount dagster-agent-service-account --namespace dagster-agent ``` -Now we need to federate the managed identity with the service account. +We will need to find the name of the service account used by the Dagster+ Agent. If you used the [Dagster+ Helm chart](/dagster-plus/deployment/agents/kubernetes/configuring-running-kubernetes-agent), it should be `user-cloud-dagster-cloud-agent`. You can confirm by using this command: + +```bash +kubectl get serviceaccount -n +``` + +Now we need to federate the managed identity with the service account used by the Dagster+ Agent. ```bash az identity federated-credential create \ @@ -40,51 +45,63 @@ az identity federated-credential create \ --identity-name agent-identity \ --resource-group \ --issuer $(az aks show -g -n --query "oidcIssuerProfile.issuerUrl" -otsv) \ - --subject system:serviceaccount:dagster-agent:dagster-agent-service-account + --subject system:serviceaccount:: ``` -Finally, we'll edit our AKS agent deployment to use the new service account. +You will need to obtain the client id of this identity for the next few operations. Make sure to save this value: ```bash -kubectl edit deployment -n dagster-agent +az identity show -g -n agent-identity --query 'clientId' -otsv ``` -In the deployment manifest, add the following lines: +We need to grant access to the storage account. + +```bash +az role assignment create \ + --assignee \ + --role "Storage Blob Data Contributor" \ + --scope $(az storage account show -g -n --query 'id' -otsv) +``` + +You will need to add new annotations and labels in Kubernetes to enable the use of workload identities. If you're using the Dagster+ Helm Chart, modify your values.yaml to add the following lines: ```yaml -metadata: - ... +serviceAccount: + annotations: + azure.workload.identity/client-id: "" + +dagsterCloudAgent: + labels: + azure.workload.identity/use: "true" + +workspace: labels: - ... azure.workload.identity/use: "true" -spec: - ... - template: - ... - spec: - ... - serviceAccountName: dagster-agent-sa ``` -If everything is set up correctly, you should be able to run the following command and see an access token returned: + + If you need to retrieve the values used by your Helm deployment, you + can run: `helm get values user-cloud > values.yaml`. + + +Finally, update your Helm release with the new values: ```bash -kubectl exec -n dagster-agent -it -- bash -# in the pod -curl -H "Metadata:true" "http://169.254.169.254/metadata/identity/oauth2/token?resource=https://storage.azure.com/" +helm upgrade user-cloud dagster-cloud/dagster-cloud-agent -n -f values.yaml ``` -## Step 2: Configure Dagster to use Azure Blob Storage - -Now, you need to update the helm values to use Azure Blob Storage for logs. You can do this by editing the `values.yaml` file for your user-cloud deployment. - -Pull down the current values for your deployment: +If everything is set up correctly, you should be able to run the following command and see an access token returned: ```bash -helm get values user-cloud > current-values.yaml +kubectl exec -n -it -- bash +# in the pod +apt update && apt install -y curl # install curl if missing, may vary depending on the base image +curl -H "Metadata:true" "http://169.254.169.254/metadata/identity/oauth2/token?resource=https://storage.azure.com/&api-version=2018-02-01" ``` -Then, edit the `current-values.yaml` file to include the following lines: +## Step 2: Configure Dagster to use Azure Blob Storage + +Once again, you need to update the Helm values to use Azure Blob Storage for logs. You can do this by editing the `values.yaml` file for your user-cloud deployment to include the following lines: ```yaml computeLogs: @@ -97,7 +114,7 @@ computeLogs: container: mycontainer default_azure_credential: exclude_environment_credential: false - prefix: dagster-logs- + prefix: dagster-logs local_dir: "/tmp/cool" upload_interval: 30 ``` @@ -105,10 +122,14 @@ computeLogs: Finally, update your deployment with the new values: ```bash -helm upgrade user-cloud dagster-cloud/dagster-cloud-agent -n dagster-agent -f current-values.yaml +helm upgrade user-cloud dagster-cloud/dagster-cloud-agent -n -f values.yaml ``` -## Step 3: Verify logs are being written to Azure Blob Storage +## Step 3: Update your code location to enable the use of the AzureBlobComputeLogManager + +- Add `dagster-azure` to your `setup.py` file. This will allow you to import the `AzureBlobComputeLogManager` class. + +## Step 4: Verify logs are being written to Azure Blob Storage It's time to kick off a run in Dagster to test your new configuration. If following along with the quickstart repo, you should be able to kick off a run of the `all_assets_job`, which will generate logs for you to test against. Otherwise, use any job that emits logs. When you go to the stdout/stderr window of the run page, you should see a log file that directs you to the Azure Blob Storage container. From 5c7ca2c7d6be92519edb8721aa0aa85bb8e492f7 Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:36:49 -0500 Subject: [PATCH 23/94] [dagster-fivetran] Implement FivetranEventIterator (#26396) ## Summary & Motivation This PR adds at basic `FivetranEventIterator` that wraps materializations yielded by `FivetranWorkspace.sync_and_poll`. This `FivetranEventIterator` will be used to implement fetch_column_metadata in the next stacked PR. ## How I Tested These Changes Existing tests with BK --- .../fivetran_event_iterator.py | 31 +++++++++++++++++++ .../dagster_fivetran/resources.py | 7 ++++- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py new file mode 100644 index 0000000000000..aa24c23cd061f --- /dev/null +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py @@ -0,0 +1,31 @@ +from typing import TYPE_CHECKING, Iterator, Union + +from dagster import AssetMaterialization, MaterializeResult +from typing_extensions import TypeVar + +if TYPE_CHECKING: + from dagster_fivetran.resources import FivetranWorkspace + + +FivetranEventType = Union[AssetMaterialization, MaterializeResult] +T = TypeVar("T", bound=FivetranEventType) + + +class FivetranEventIterator(Iterator[T]): + """A wrapper around an iterator of Fivetran events which contains additional methods for + post-processing the events, such as fetching column metadata. + """ + + def __init__( + self, + events: Iterator[T], + fivetran_workspace: "FivetranWorkspace", + ) -> None: + self._inner_iterator = events + self._fivetran_workspace = fivetran_workspace + + def __next__(self) -> T: + return next(self._inner_iterator) + + def __iter__(self) -> "FivetranEventIterator[T]": + return self diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py index 867c9e6a8a30c..cd464f8f54d3e 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py @@ -34,6 +34,7 @@ from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException +from dagster_fivetran.fivetran_event_iterator import FivetranEventIterator from dagster_fivetran.translator import ( DagsterFivetranTranslator, FivetranConnector, @@ -1023,9 +1024,13 @@ def sync_and_poll( Iterator[Union[AssetMaterialization, MaterializeResult]]: An iterator of MaterializeResult or AssetMaterialization. """ + return FivetranEventIterator( + events=self._sync_and_poll(context=context), fivetran_workspace=self + ) + + def _sync_and_poll(self, context: Union[OpExecutionContext, AssetExecutionContext]): assets_def = context.assets_def dagster_fivetran_translator = get_translator_from_fivetran_assets(assets_def) - connector_id = next( check.not_none(FivetranMetadataSet.extract(spec.metadata).connector_id) for spec in assets_def.specs From cc33cea50265f238c4e403941077d2773c12307c Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:43:16 -0500 Subject: [PATCH 24/94] [dagster-embedded-elt][dlt] Use Iterator[T] in DltEventIterator (#26453) ## Summary & Motivation Same as #26455 but for DltEventIterator ## How I Tested These Changes Same tests with BK --- .../dagster_embedded_elt/dlt/dlt_event_iterator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py index 3a640153b47ea..f11d56b177906 100644 --- a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py +++ b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/dlt_event_iterator.py @@ -1,4 +1,4 @@ -from typing import Generic, Iterator, Optional, Union +from typing import Iterator, Optional, Union from dagster import AssetMaterialization, MaterializeResult from dagster._annotations import experimental, public @@ -57,7 +57,7 @@ def fetch_row_count_metadata( return TableMetadataSet(row_count=None) -class DltEventIterator(Generic[T], Iterator): +class DltEventIterator(Iterator[T]): """A wrapper around an iterator of Dlt events which contains additional methods for post-processing the events, such as fetching column metadata. """ From fbde215525f629c1164325936bb82d5f6a5cea09 Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:43:26 -0500 Subject: [PATCH 25/94] [dagster-dbt] Use Iterator[T] in DbtEventIterator (#26455) ## Summary & Motivation Following changes in #26424, we subclass DbtEventIterator with Iterator[T] and remove Generic[T] ## How I Tested These Changes Same tests with BK --- .../dagster-dbt/dagster_dbt/core/dbt_event_iterator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py b/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py index 5ffa200a422fc..c3364a133006f 100644 --- a/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py +++ b/python_modules/libraries/dagster-dbt/dagster_dbt/core/dbt_event_iterator.py @@ -1,5 +1,5 @@ from concurrent.futures import ThreadPoolExecutor -from typing import TYPE_CHECKING, Any, Callable, Dict, Generic, Iterator, Optional, Union, cast +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, Optional, Union, cast from dagster import ( AssetCheckResult, @@ -185,7 +185,7 @@ def _fetch_row_count_metadata( return None -class DbtEventIterator(Generic[T], Iterator): +class DbtEventIterator(Iterator[T]): """A wrapper around an iterator of dbt events which contains additional methods for post-processing the events, such as fetching row counts for materialized tables. """ From 5a90f6e1bafb489f3d12b6dbecb49b288edf3b7f Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:43:33 -0500 Subject: [PATCH 26/94] [dagster-embedded-elt][sling] Use Iterator[T] in SlingEventIterator (#26454) ## Summary & Motivation Same as #26455 but for SlingEventIterator ## How I Tested These Changes Same tests with BK --- .../dagster_embedded_elt/sling/sling_event_iterator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py index f08b200473f21..9e46a47725c94 100644 --- a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py +++ b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/sling/sling_event_iterator.py @@ -1,5 +1,5 @@ import re -from typing import TYPE_CHECKING, Any, Dict, Generic, Iterator, Optional, Sequence, Union, cast +from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Sequence, Union, cast from dagster import ( AssetMaterialization, @@ -167,7 +167,7 @@ def fetch_column_metadata( return {} -class SlingEventIterator(Generic[T], Iterator): +class SlingEventIterator(Iterator[T]): """A wrapper around an iterator of Sling events which contains additional methods for post-processing the events, such as fetching column metadata. """ From d42712ef0bc9c902465a9ebd46cb89d78394ba28 Mon Sep 17 00:00:00 2001 From: Nikki Everett Date: Thu, 12 Dec 2024 14:52:53 -0600 Subject: [PATCH 27/94] [Docs] Add tutorials category to integrations and reorganize integrations categories and sidebar (#26323) ## Summary & Motivation * Add "Tutorials" category to "Integrations" * Reorganize categories for integrations libraries -- we now have "Dagster supported" and "Community supported". ## How I Tested These Changes Tested locally ## Changelog > Insert changelog entry or delete this section. --------- Signed-off-by: nikki everett --- .../deployment/hybrid/agents/kubernetes.md | 2 +- .../guides/build/integrate/ingesting-data.md | 8 +- .../docs/guides/test/asset-checks.md | 2 +- .../guides/multi-asset-integration.md | 5 + docs/docs-beta/docs/integrations/index.md | 8 -- .../integrations/{ => libraries}/airbyte.md | 3 +- .../{ => libraries}/aws/athena.md | 3 +- .../{ => libraries}/aws/cloudwatch.md | 3 +- .../integrations/{ => libraries}/aws/ecr.md | 3 +- .../integrations/{ => libraries}/aws/emr.md | 3 +- .../integrations/{ => libraries}/aws/glue.md | 3 +- .../integrations/{ => libraries}/aws/index.md | 2 +- .../{ => libraries}/aws/lambda.md | 3 +- .../{ => libraries}/aws/redshift.md | 3 +- .../integrations/{ => libraries}/aws/s3.md | 3 +- .../{ => libraries}/aws/secretsmanager.md | 3 +- .../integrations/{ => libraries}/aws/ssm.md | 3 +- .../{ => libraries}/azure-adls2.md | 3 +- .../integrations/{ => libraries}/census.md | 3 +- .../docs/integrations/{ => libraries}/cube.md | 3 +- .../{ => libraries}/databricks.md | 3 +- .../integrations/{ => libraries}/datadog.md | 3 +- .../integrations/{ => libraries}/dbt-cloud.md | 3 +- .../docs/integrations/{ => libraries}/dbt.md | 3 +- .../integrations/{ => libraries}/deltalake.md | 3 +- .../docs/integrations/{ => libraries}/dlt.md | 3 +- .../integrations/{ => libraries}/docker.md | 3 +- .../integrations/{ => libraries}/duckdb.md | 3 +- .../integrations/{ => libraries}/fivetran.md | 3 +- .../{ => libraries}/gcp/bigquery.md | 3 +- .../{ => libraries}/gcp/dataproc.md | 3 +- .../integrations/{ => libraries}/gcp/gcs.md | 3 +- .../integrations/{ => libraries}/gcp/index.md | 0 .../integrations/{ => libraries}/github.md | 3 +- .../integrations/{ => libraries}/hashicorp.md | 3 +- .../integrations/{ => libraries}/hightouch.md | 3 +- .../docs/integrations/libraries/index.md | 10 ++ .../integrations/{ => libraries}/jupyter.md | 1 + .../{ => libraries}/kubernetes.md | 3 +- .../integrations/{ => libraries}/lakefs.md | 3 +- .../integrations/{ => libraries}/looker.md | 3 +- .../integrations/{ => libraries}/meltano.md | 3 +- .../{ => libraries}/microsoft-teams.md | 3 +- .../{ => libraries}/open-metadata.md | 3 +- .../integrations/{ => libraries}/openai.md | 3 +- .../integrations/{ => libraries}/pagerduty.md | 3 +- .../integrations/{ => libraries}/pandas.md | 3 +- .../integrations/{ => libraries}/pandera.md | 3 +- .../{ => libraries}/prometheus.md | 3 +- .../docs/integrations/{ => libraries}/sdf.md | 3 +- .../integrations/{ => libraries}/secoda.md | 3 +- .../integrations/{ => libraries}/shell.md | 3 +- .../integrations/{ => libraries}/slack.md | 3 +- .../integrations/{ => libraries}/sling.md | 3 +- .../integrations/{ => libraries}/snowflake.md | 3 +- .../integrations/{ => libraries}/spark.md | 3 +- .../integrations/{ => libraries}/ssh-sftp.md | 3 +- .../integrations/{ => libraries}/twilio.md | 3 +- .../integrations/{ => libraries}/wandb.md | 3 +- docs/docs-beta/docs/tags.yml | 36 +++++ docs/docs-beta/docusaurus.config.ts | 3 +- docs/docs-beta/sidebars.ts | 131 ++---------------- 62 files changed, 171 insertions(+), 187 deletions(-) create mode 100644 docs/docs-beta/docs/integrations/guides/multi-asset-integration.md delete mode 100644 docs/docs-beta/docs/integrations/index.md rename docs/docs-beta/docs/integrations/{ => libraries}/airbyte.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/athena.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/cloudwatch.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/ecr.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/emr.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/glue.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/index.md (80%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/lambda.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/redshift.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/s3.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/secretsmanager.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/aws/ssm.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/azure-adls2.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/census.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/cube.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/databricks.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/datadog.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/dbt-cloud.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/dbt.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/deltalake.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/dlt.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/docker.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/duckdb.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/fivetran.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/gcp/bigquery.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/gcp/dataproc.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/gcp/gcs.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/gcp/index.md (100%) rename docs/docs-beta/docs/integrations/{ => libraries}/github.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/hashicorp.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/hightouch.md (97%) create mode 100644 docs/docs-beta/docs/integrations/libraries/index.md rename docs/docs-beta/docs/integrations/{ => libraries}/jupyter.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/kubernetes.md (98%) rename docs/docs-beta/docs/integrations/{ => libraries}/lakefs.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/looker.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/meltano.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/microsoft-teams.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/open-metadata.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/openai.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/pagerduty.md (95%) rename docs/docs-beta/docs/integrations/{ => libraries}/pandas.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/pandera.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/prometheus.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/sdf.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/secoda.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/shell.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/slack.md (95%) rename docs/docs-beta/docs/integrations/{ => libraries}/sling.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/snowflake.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/spark.md (96%) rename docs/docs-beta/docs/integrations/{ => libraries}/ssh-sftp.md (97%) rename docs/docs-beta/docs/integrations/{ => libraries}/twilio.md (95%) rename docs/docs-beta/docs/integrations/{ => libraries}/wandb.md (98%) create mode 100644 docs/docs-beta/docs/tags.yml diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md index 9169ef9783c29..3c8612add3d87 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md @@ -446,7 +446,7 @@ Another option is to launch a pod for each asset by telling Dagster to use the K -Dagster can launch and manage existing Docker images as Kubernetes jobs using the [Dagster kubernetes pipes integration](/integrations/kubernetes). To request resources for these jobs by supplying the appropriate Kubernetes pod spec. +Dagster can launch and manage existing Docker images as Kubernetes jobs using the [Dagster kubernetes pipes integration](/integrations/libraries/kubernetes). To request resources for these jobs by supplying the appropriate Kubernetes pod spec. diff --git a/docs/docs-beta/docs/guides/build/integrate/ingesting-data.md b/docs/docs-beta/docs/guides/build/integrate/ingesting-data.md index a6290c8c37c1d..7d4d0467ff063 100644 --- a/docs/docs-beta/docs/guides/build/integrate/ingesting-data.md +++ b/docs/docs-beta/docs/guides/build/integrate/ingesting-data.md @@ -33,10 +33,10 @@ As a data orchestrator, Dagster helps with data ingestion as it can: Dagster currently integrates with the following data ingestion tools, enabling you to sync diverse data sources into data warehouse tables using pre-built connectors: -- [Airbyte](/integrations/airbyte) -- [dlt](/integrations/dlt) -- [Fivetran](/integrations/fivetran) -- [Sling](/integrations/sling) +- [Airbyte](/integrations/libraries/airbyte) +- [dlt](/integrations/libraries/dlt) +- [Fivetran](/integrations/libraries/fivetran) +- [Sling](/integrations/libraries/sling) ## Writing custom data ingestion pipelines diff --git a/docs/docs-beta/docs/guides/test/asset-checks.md b/docs/docs-beta/docs/guides/test/asset-checks.md index 3fddf035591b1..b28bee6e46e3e 100644 --- a/docs/docs-beta/docs/guides/test/asset-checks.md +++ b/docs/docs-beta/docs/guides/test/asset-checks.md @@ -33,7 +33,7 @@ To get started with asset checks, follow these general steps: ## Defining a single asset check \{#single-check} :::tip -Dagster's dbt integration can model existing dbt tests as asset checks. Refer to the [dagster-dbt documentation](/integrations/dbt) for more information. +Dagster's dbt integration can model existing dbt tests as asset checks. Refer to the [dagster-dbt documentation](/integrations/libraries/dbt) for more information. ::: A asset check is defined using the `@asset_check` decorator. diff --git a/docs/docs-beta/docs/integrations/guides/multi-asset-integration.md b/docs/docs-beta/docs/integrations/guides/multi-asset-integration.md new file mode 100644 index 0000000000000..df0615e217fab --- /dev/null +++ b/docs/docs-beta/docs/integrations/guides/multi-asset-integration.md @@ -0,0 +1,5 @@ +--- +title: Creating a multi-asset integration +--- + +{/* TODO write this */} \ No newline at end of file diff --git a/docs/docs-beta/docs/integrations/index.md b/docs/docs-beta/docs/integrations/index.md deleted file mode 100644 index 233bd07d0fdc0..0000000000000 --- a/docs/docs-beta/docs/integrations/index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -sidebar_class_name: hidden -title: Integrations ---- - -import DocCardList from '@theme/DocCardList'; - - diff --git a/docs/docs-beta/docs/integrations/airbyte.md b/docs/docs-beta/docs/integrations/libraries/airbyte.md similarity index 97% rename from docs/docs-beta/docs/integrations/airbyte.md rename to docs/docs-beta/docs/integrations/libraries/airbyte.md index eec45c87481fb..36e160f2986d9 100644 --- a/docs/docs-beta/docs/integrations/airbyte.md +++ b/docs/docs-beta/docs/integrations/libraries/airbyte.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [dagster-supported, etl] --- -### About this integration + Using this integration, you can trigger Airbyte syncs and orchestrate your Airbyte connections from within Dagster, making it easy to chain an Airbyte sync with upstream or downstream steps in your workflow. diff --git a/docs/docs-beta/docs/integrations/aws/athena.md b/docs/docs-beta/docs/integrations/libraries/aws/athena.md similarity index 97% rename from docs/docs-beta/docs/integrations/aws/athena.md rename to docs/docs-beta/docs/integrations/libraries/aws/athena.md index e17f95e077147..f28c6a5a8fae3 100644 --- a/docs/docs-beta/docs/integrations/aws/athena.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/athena.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + This integration allows you to connect to AWS Athena, a serverless interactive query service that makes it easy to analyze data in Amazon S3 using standard SQL. Using this integration, you can issue queries to Athena, fetch results, and handle query execution states within your Dagster pipelines. diff --git a/docs/docs-beta/docs/integrations/aws/cloudwatch.md b/docs/docs-beta/docs/integrations/libraries/aws/cloudwatch.md similarity index 98% rename from docs/docs-beta/docs/integrations/aws/cloudwatch.md rename to docs/docs-beta/docs/integrations/libraries/aws/cloudwatch.md index 6f31e5b7fbf02..8f27e767cd512 100644 --- a/docs/docs-beta/docs/integrations/aws/cloudwatch.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/cloudwatch.md @@ -14,9 +14,10 @@ categories: - Monitoring enabledBy: enables: +tags: [dagster-supported, monitoring] --- -### About this integration + This integration allows you to send Dagster logs to AWS CloudWatch, enabling centralized logging and monitoring of your Dagster jobs. By using AWS CloudWatch, you can take advantage of its powerful log management features, such as real-time log monitoring, log retention policies, and alerting capabilities. diff --git a/docs/docs-beta/docs/integrations/aws/ecr.md b/docs/docs-beta/docs/integrations/libraries/aws/ecr.md similarity index 98% rename from docs/docs-beta/docs/integrations/aws/ecr.md rename to docs/docs-beta/docs/integrations/libraries/aws/ecr.md index dfaec5dea91f8..a3b2487794a0b 100644 --- a/docs/docs-beta/docs/integrations/aws/ecr.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/ecr.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [dagster-supported] --- -### About this integration + This integration allows you to connect to AWS Elastic Container Registry (ECR). It provides resources to interact with AWS ECR, enabling you to manage your container images. diff --git a/docs/docs-beta/docs/integrations/aws/emr.md b/docs/docs-beta/docs/integrations/libraries/aws/emr.md similarity index 98% rename from docs/docs-beta/docs/integrations/aws/emr.md rename to docs/docs-beta/docs/integrations/libraries/aws/emr.md index 4a055872d2a1f..db5ba4e4bc91d 100644 --- a/docs/docs-beta/docs/integrations/aws/emr.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/emr.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + The `dagster-aws` integration provides ways orchestrating data pipelines that leverage AWS services, including AWS EMR (Elastic MapReduce). This integration allows you to run and scale big data workloads using open source tools such as Apache Spark, Hive, Presto, and more. diff --git a/docs/docs-beta/docs/integrations/aws/glue.md b/docs/docs-beta/docs/integrations/libraries/aws/glue.md similarity index 97% rename from docs/docs-beta/docs/integrations/aws/glue.md rename to docs/docs-beta/docs/integrations/libraries/aws/glue.md index e06ce1494ba57..629df3adc218d 100644 --- a/docs/docs-beta/docs/integrations/aws/glue.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/glue.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + The `dagster-aws` integration library provides the `PipesGlueClient` resource, enabling you to launch AWS Glue jobs directly from Dagster assets and ops. This integration allows you to pass parameters to Glue code while Dagster receives real-time events, such as logs, asset checks, and asset materializations, from the initiated jobs. With minimal code changes required on the job side, this integration is both efficient and easy to implement. diff --git a/docs/docs-beta/docs/integrations/aws/index.md b/docs/docs-beta/docs/integrations/libraries/aws/index.md similarity index 80% rename from docs/docs-beta/docs/integrations/aws/index.md rename to docs/docs-beta/docs/integrations/libraries/aws/index.md index 481931c7b81e2..a95102a5e87c8 100644 --- a/docs/docs-beta/docs/integrations/aws/index.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/index.md @@ -4,4 +4,4 @@ title: AWS import DocCardList from '@theme/DocCardList'; - + \ No newline at end of file diff --git a/docs/docs-beta/docs/integrations/aws/lambda.md b/docs/docs-beta/docs/integrations/libraries/aws/lambda.md similarity index 97% rename from docs/docs-beta/docs/integrations/aws/lambda.md rename to docs/docs-beta/docs/integrations/libraries/aws/lambda.md index 4dd4ba58e903d..5ec9c7c9c64ad 100644 --- a/docs/docs-beta/docs/integrations/aws/lambda.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/lambda.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + Using this integration, you can leverage AWS Lambda to execute external code as part of your Dagster pipelines. This is particularly useful for running serverless functions that can scale automatically and handle various workloads without the need for managing infrastructure. The `PipesLambdaClient` class allows you to invoke AWS Lambda functions and stream logs and structured metadata back to Dagster's UI and tools. diff --git a/docs/docs-beta/docs/integrations/aws/redshift.md b/docs/docs-beta/docs/integrations/libraries/aws/redshift.md similarity index 97% rename from docs/docs-beta/docs/integrations/aws/redshift.md rename to docs/docs-beta/docs/integrations/libraries/aws/redshift.md index 053bd366b417f..593516db98136 100644 --- a/docs/docs-beta/docs/integrations/aws/redshift.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/redshift.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + Using this integration, you can connect to an AWS Redshift cluster and issue queries against it directly from your Dagster assets. This allows you to seamlessly integrate Redshift into your data pipelines, leveraging the power of Redshift's data warehousing capabilities within your Dagster workflows. diff --git a/docs/docs-beta/docs/integrations/aws/s3.md b/docs/docs-beta/docs/integrations/libraries/aws/s3.md similarity index 97% rename from docs/docs-beta/docs/integrations/aws/s3.md rename to docs/docs-beta/docs/integrations/libraries/aws/s3.md index e617605730442..71e35378e38b1 100644 --- a/docs/docs-beta/docs/integrations/aws/s3.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/s3.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + The AWS S3 integration allows data engineers to easily read, and write objects to the durable AWS S3 storage -- enabling engineers to a resilient storage layer when constructing their pipelines. diff --git a/docs/docs-beta/docs/integrations/aws/secretsmanager.md b/docs/docs-beta/docs/integrations/libraries/aws/secretsmanager.md similarity index 98% rename from docs/docs-beta/docs/integrations/aws/secretsmanager.md rename to docs/docs-beta/docs/integrations/libraries/aws/secretsmanager.md index 736b84fc56fb4..48b3b007bf1cd 100644 --- a/docs/docs-beta/docs/integrations/aws/secretsmanager.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/secretsmanager.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [dagster-supported] --- -### About this integration + This integration allows you to manage, retrieve, and rotate credentials, API keys, and other secrets using [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/). diff --git a/docs/docs-beta/docs/integrations/aws/ssm.md b/docs/docs-beta/docs/integrations/libraries/aws/ssm.md similarity index 98% rename from docs/docs-beta/docs/integrations/aws/ssm.md rename to docs/docs-beta/docs/integrations/libraries/aws/ssm.md index 36f480a509482..d0da33d8d7e2f 100644 --- a/docs/docs-beta/docs/integrations/aws/ssm.md +++ b/docs/docs-beta/docs/integrations/libraries/aws/ssm.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [dagster-supported] --- -### About this integration + The Dagster AWS Systems Manager (SSM) Parameter Store integration allows you to manage and retrieve parameters stored in AWS SSM Parameter Store directly within your Dagster pipelines. This integration provides resources to fetch parameters by name, tags, or paths, and optionally set them as environment variables for your operations. diff --git a/docs/docs-beta/docs/integrations/azure-adls2.md b/docs/docs-beta/docs/integrations/libraries/azure-adls2.md similarity index 97% rename from docs/docs-beta/docs/integrations/azure-adls2.md rename to docs/docs-beta/docs/integrations/libraries/azure-adls2.md index 9f766bac09d09..780b800aa62dc 100644 --- a/docs/docs-beta/docs/integrations/azure-adls2.md +++ b/docs/docs-beta/docs/integrations/libraries/azure-adls2.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + Dagster helps you use Azure Storage Accounts as part of your data pipeline. Azure Data Lake Storage Gen 2 (ADLS2) is our primary focus but we also provide utilities for Azure Blob Storage. diff --git a/docs/docs-beta/docs/integrations/census.md b/docs/docs-beta/docs/integrations/libraries/census.md similarity index 96% rename from docs/docs-beta/docs/integrations/census.md rename to docs/docs-beta/docs/integrations/libraries/census.md index ae13177111531..1c3e4f8e2c903 100644 --- a/docs/docs-beta/docs/integrations/census.md +++ b/docs/docs-beta/docs/integrations/libraries/census.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [community-supported, etl] --- -### About this integration + With the `dagster-census` integration you can execute a Census sync and poll until that sync completes, raising an error if it's unsuccessful. diff --git a/docs/docs-beta/docs/integrations/cube.md b/docs/docs-beta/docs/integrations/libraries/cube.md similarity index 97% rename from docs/docs-beta/docs/integrations/cube.md rename to docs/docs-beta/docs/integrations/libraries/cube.md index 9bac9cd168c7b..e1e976090adf0 100644 --- a/docs/docs-beta/docs/integrations/cube.md +++ b/docs/docs-beta/docs/integrations/libraries/cube.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [community-supported] --- -### About this integration + With the `dagster_cube` integration you can setup Cube and Dagster to work together so that Dagster can push changes from upstream data sources to Cube using its integration API. diff --git a/docs/docs-beta/docs/integrations/databricks.md b/docs/docs-beta/docs/integrations/libraries/databricks.md similarity index 98% rename from docs/docs-beta/docs/integrations/databricks.md rename to docs/docs-beta/docs/integrations/libraries/databricks.md index 92ee6a0fc6a78..ff4736c3c0c4e 100644 --- a/docs/docs-beta/docs/integrations/databricks.md +++ b/docs/docs-beta/docs/integrations/libraries/databricks.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + The `dagster-databricks` integration library provides the `PipesDatabricksClient` resource, enabling you to launch Databricks jobs directly from Dagster assets and ops. This integration allows you to pass parameters to Databricks code while Dagster receives real-time events, such as logs, asset checks, and asset materializations, from the initiated jobs. With minimal code changes required on the job side, this integration is both efficient and easy to implement. diff --git a/docs/docs-beta/docs/integrations/datadog.md b/docs/docs-beta/docs/integrations/libraries/datadog.md similarity index 96% rename from docs/docs-beta/docs/integrations/datadog.md rename to docs/docs-beta/docs/integrations/libraries/datadog.md index 9bac8f21649b5..4f2e867eb2fd7 100644 --- a/docs/docs-beta/docs/integrations/datadog.md +++ b/docs/docs-beta/docs/integrations/libraries/datadog.md @@ -14,9 +14,10 @@ categories: - Monitoring enabledBy: enables: +tags: [dagster-supported, monitoring] --- -### About this integration + While Dagster provides comprehensive monitoring and observability of the pipelines it orchestrates, many teams look to centralize all their monitoring across apps, processes and infrastructure using Datadog's 'Cloud Monitoring as a Service'. The `dagster-datadog` integration allows you to publish metrics to Datadog from within Dagster ops. diff --git a/docs/docs-beta/docs/integrations/dbt-cloud.md b/docs/docs-beta/docs/integrations/libraries/dbt-cloud.md similarity index 97% rename from docs/docs-beta/docs/integrations/dbt-cloud.md rename to docs/docs-beta/docs/integrations/libraries/dbt-cloud.md index ae375f429e15e..80c07e9990d41 100644 --- a/docs/docs-beta/docs/integrations/dbt-cloud.md +++ b/docs/docs-beta/docs/integrations/libraries/dbt-cloud.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [dagster-supported, etl] --- -### About this integration + Dagster allows you to run dbt Cloud jobs alongside other technologies. You can schedule them to run as a step in a larger pipeline and manage them as a data asset. diff --git a/docs/docs-beta/docs/integrations/dbt.md b/docs/docs-beta/docs/integrations/libraries/dbt.md similarity index 98% rename from docs/docs-beta/docs/integrations/dbt.md rename to docs/docs-beta/docs/integrations/libraries/dbt.md index cd2b7f873e3f2..177dc9f4e45f3 100644 --- a/docs/docs-beta/docs/integrations/dbt.md +++ b/docs/docs-beta/docs/integrations/libraries/dbt.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [dagster-supported, etl] --- -### About this integration + Dagster orchestrates dbt alongside other technologies, so you can schedule dbt with Spark, Python, etc. in a single data pipeline. diff --git a/docs/docs-beta/docs/integrations/deltalake.md b/docs/docs-beta/docs/integrations/libraries/deltalake.md similarity index 97% rename from docs/docs-beta/docs/integrations/deltalake.md rename to docs/docs-beta/docs/integrations/libraries/deltalake.md index 175fc173c5534..3a3fc20373fef 100644 --- a/docs/docs-beta/docs/integrations/deltalake.md +++ b/docs/docs-beta/docs/integrations/libraries/deltalake.md @@ -15,9 +15,10 @@ categories: - Storage enabledBy: enables: +tags: [community-supported, storage] --- -### About this integration + Delta Lake is a great storage format for Dagster workflows. With this integration, you can use the Delta Lake I/O Manager to read and write your Dagster assets. diff --git a/docs/docs-beta/docs/integrations/dlt.md b/docs/docs-beta/docs/integrations/libraries/dlt.md similarity index 97% rename from docs/docs-beta/docs/integrations/dlt.md rename to docs/docs-beta/docs/integrations/libraries/dlt.md index 9381022348790..19c54360eea56 100644 --- a/docs/docs-beta/docs/integrations/dlt.md +++ b/docs/docs-beta/docs/integrations/libraries/dlt.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [dagster-supported, etl] --- -### About this integration + This integration allows you to use [dlt](https://dlthub.com/) to easily ingest and replicate data between systems through Dagster. diff --git a/docs/docs-beta/docs/integrations/docker.md b/docs/docs-beta/docs/integrations/libraries/docker.md similarity index 97% rename from docs/docs-beta/docs/integrations/docker.md rename to docs/docs-beta/docs/integrations/libraries/docker.md index 16bdd0ab960c0..6a65e2818cee9 100644 --- a/docs/docs-beta/docs/integrations/docker.md +++ b/docs/docs-beta/docs/integrations/libraries/docker.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + The `dagster-docker` integration library provides the `PipesDockerClient` resource, enabling you to launch Docker containers and execute external code directly from Dagster assets and ops. This integration allows you to pass parameters to Docker containers while Dagster receives real-time events, such as logs, asset checks, and asset materializations, from the initiated jobs. With minimal code changes required on the job side, this integration is both efficient and easy to implement. diff --git a/docs/docs-beta/docs/integrations/duckdb.md b/docs/docs-beta/docs/integrations/libraries/duckdb.md similarity index 96% rename from docs/docs-beta/docs/integrations/duckdb.md rename to docs/docs-beta/docs/integrations/libraries/duckdb.md index 5335df37db094..e8097b5040ed8 100644 --- a/docs/docs-beta/docs/integrations/duckdb.md +++ b/docs/docs-beta/docs/integrations/libraries/duckdb.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + This library provides an integration with the DuckDB database, and allows for an out-of-the-box [I/O Manager](https://docs.dagster.io/concepts/io-management/io-managers) so that you can make DuckDB your storage of choice. diff --git a/docs/docs-beta/docs/integrations/fivetran.md b/docs/docs-beta/docs/integrations/libraries/fivetran.md similarity index 96% rename from docs/docs-beta/docs/integrations/fivetran.md rename to docs/docs-beta/docs/integrations/libraries/fivetran.md index 9235e4e3788e5..9edbfbbee1dc3 100644 --- a/docs/docs-beta/docs/integrations/fivetran.md +++ b/docs/docs-beta/docs/integrations/libraries/fivetran.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [dagster-supported, etl] --- -### About this integration + The Dagster-Fivetran integration enables you to orchestrate data ingestion as part of a larger pipeline. Programmatically interact with the Fivetran REST API to initiate syncs and monitor their progress. diff --git a/docs/docs-beta/docs/integrations/gcp/bigquery.md b/docs/docs-beta/docs/integrations/libraries/gcp/bigquery.md similarity index 96% rename from docs/docs-beta/docs/integrations/gcp/bigquery.md rename to docs/docs-beta/docs/integrations/libraries/gcp/bigquery.md index 3decbd33ad606..986a7f4070de2 100644 --- a/docs/docs-beta/docs/integrations/gcp/bigquery.md +++ b/docs/docs-beta/docs/integrations/libraries/gcp/bigquery.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + The Google Cloud Platform BigQuery integration allows data engineers to easily query and store data in the BigQuery data warehouse through the use of the `BigQueryResource`. diff --git a/docs/docs-beta/docs/integrations/gcp/dataproc.md b/docs/docs-beta/docs/integrations/libraries/gcp/dataproc.md similarity index 97% rename from docs/docs-beta/docs/integrations/gcp/dataproc.md rename to docs/docs-beta/docs/integrations/libraries/gcp/dataproc.md index fbb9527fb6065..dc168778f798b 100644 --- a/docs/docs-beta/docs/integrations/gcp/dataproc.md +++ b/docs/docs-beta/docs/integrations/libraries/gcp/dataproc.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + Using this integration, you can manage and interact with Google Cloud Platform's Dataproc service directly from Dagster. This integration allows you to create, manage, and delete Dataproc clusters, and submit and monitor jobs on these clusters. diff --git a/docs/docs-beta/docs/integrations/gcp/gcs.md b/docs/docs-beta/docs/integrations/libraries/gcp/gcs.md similarity index 96% rename from docs/docs-beta/docs/integrations/gcp/gcs.md rename to docs/docs-beta/docs/integrations/libraries/gcp/gcs.md index 4969db7e33882..5969fe8f89368 100644 --- a/docs/docs-beta/docs/integrations/gcp/gcs.md +++ b/docs/docs-beta/docs/integrations/libraries/gcp/gcs.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + This integration allows you to interact with Google Cloud Storage (GCS) using Dagster. It provides resources, I/O Managers, and utilities to manage and store data in GCS, making it easier to integrate GCS into your data pipelines. diff --git a/docs/docs-beta/docs/integrations/gcp/index.md b/docs/docs-beta/docs/integrations/libraries/gcp/index.md similarity index 100% rename from docs/docs-beta/docs/integrations/gcp/index.md rename to docs/docs-beta/docs/integrations/libraries/gcp/index.md diff --git a/docs/docs-beta/docs/integrations/github.md b/docs/docs-beta/docs/integrations/libraries/github.md similarity index 97% rename from docs/docs-beta/docs/integrations/github.md rename to docs/docs-beta/docs/integrations/libraries/github.md index 19c278d44ea0a..8d4176eb8e940 100644 --- a/docs/docs-beta/docs/integrations/github.md +++ b/docs/docs-beta/docs/integrations/libraries/github.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [dagster-supported] --- -### About this integration + This library provides an integration with _[GitHub Apps](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps)_ by providing a thin wrapper on the GitHub v4 GraphQL API. This allows for automating operations within your GitHub repositories and with the tighter permissions scopes that GitHub Apps allow for vs using a personal token. diff --git a/docs/docs-beta/docs/integrations/hashicorp.md b/docs/docs-beta/docs/integrations/libraries/hashicorp.md similarity index 97% rename from docs/docs-beta/docs/integrations/hashicorp.md rename to docs/docs-beta/docs/integrations/libraries/hashicorp.md index 5664934092637..5d65ae6106959 100644 --- a/docs/docs-beta/docs/integrations/hashicorp.md +++ b/docs/docs-beta/docs/integrations/libraries/hashicorp.md @@ -15,9 +15,10 @@ categories: - Other enabledBy: enables: +tags: [community-supported] --- -### About this integration + Package for integrating HashiCorp Vault into Dagster so that you can securely manage tokens and passwords. diff --git a/docs/docs-beta/docs/integrations/hightouch.md b/docs/docs-beta/docs/integrations/libraries/hightouch.md similarity index 97% rename from docs/docs-beta/docs/integrations/hightouch.md rename to docs/docs-beta/docs/integrations/libraries/hightouch.md index 11f81649565c9..eea47836e2390 100644 --- a/docs/docs-beta/docs/integrations/hightouch.md +++ b/docs/docs-beta/docs/integrations/libraries/hightouch.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [community-supported, etl] --- -### About this integration + With this integration you can trigger Hightouch syncs and monitor them from within Dagster. Fine-tune when Hightouch syncs kick-off, visualize their dependencies, and monitor the steps in your data activation workflow. diff --git a/docs/docs-beta/docs/integrations/libraries/index.md b/docs/docs-beta/docs/integrations/libraries/index.md new file mode 100644 index 0000000000000..99a53949d12af --- /dev/null +++ b/docs/docs-beta/docs/integrations/libraries/index.md @@ -0,0 +1,10 @@ +--- +title: Libraries +sidebar_class_name: hidden +--- + +You can integrate Dagster with external services using our libraries and libraries supported by the community. + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/integrations/jupyter.md b/docs/docs-beta/docs/integrations/libraries/jupyter.md similarity index 96% rename from docs/docs-beta/docs/integrations/jupyter.md rename to docs/docs-beta/docs/integrations/libraries/jupyter.md index f0ab1db8998cf..c24ab32e1f1d5 100644 --- a/docs/docs-beta/docs/integrations/jupyter.md +++ b/docs/docs-beta/docs/integrations/libraries/jupyter.md @@ -15,6 +15,7 @@ enabledBy: categories: - Compute enables: +tags: [dagster-supported, compute] --- ### About Jupyter diff --git a/docs/docs-beta/docs/integrations/kubernetes.md b/docs/docs-beta/docs/integrations/libraries/kubernetes.md similarity index 98% rename from docs/docs-beta/docs/integrations/kubernetes.md rename to docs/docs-beta/docs/integrations/libraries/kubernetes.md index dbe389b9b2536..bdff728e10bbf 100644 --- a/docs/docs-beta/docs/integrations/kubernetes.md +++ b/docs/docs-beta/docs/integrations/libraries/kubernetes.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + The `dagster-k8s` integration library provides the `PipesK8sClient` resource, enabling you to launch Kubernetes pods and execute external code directly from Dagster assets and ops. This integration allows you to pass parameters to Kubernetes pods while Dagster receives real-time events, such as logs, asset checks, and asset materializations, from the initiated jobs. With minimal code changes required on the job side, this integration is both efficient and easy to implement. diff --git a/docs/docs-beta/docs/integrations/lakefs.md b/docs/docs-beta/docs/integrations/libraries/lakefs.md similarity index 97% rename from docs/docs-beta/docs/integrations/lakefs.md rename to docs/docs-beta/docs/integrations/libraries/lakefs.md index c4901e7bc28f6..64f3510405c21 100644 --- a/docs/docs-beta/docs/integrations/lakefs.md +++ b/docs/docs-beta/docs/integrations/libraries/lakefs.md @@ -15,9 +15,10 @@ categories: - Storage enabledBy: enables: +tags: [community-supported, storage] --- -### About this integration + By integrating with lakeFS, a big data scale version control system, you can leverage the versioning capabilities of lakeFS to track changes to your data. This integration allows you to have a complete lineage of your data, from the initial raw data to the transformed and processed data, making it easier to understand and reproduce data transformations. diff --git a/docs/docs-beta/docs/integrations/looker.md b/docs/docs-beta/docs/integrations/libraries/looker.md similarity index 97% rename from docs/docs-beta/docs/integrations/looker.md rename to docs/docs-beta/docs/integrations/libraries/looker.md index 33b936b606125..4cff5bf5fddcd 100644 --- a/docs/docs-beta/docs/integrations/looker.md +++ b/docs/docs-beta/docs/integrations/libraries/looker.md @@ -15,9 +15,10 @@ categories: - BI enabledBy: enables: +tags: [dagster-supported, bi] --- -### About this integration + Dagster allows you to represent your Looker project as assets, alongside other your other technologies like dbt and Sling. This allows you to see how your Looker assets are connected to your other data assets, and how changes to other data assets might impact your Looker project. diff --git a/docs/docs-beta/docs/integrations/meltano.md b/docs/docs-beta/docs/integrations/libraries/meltano.md similarity index 97% rename from docs/docs-beta/docs/integrations/meltano.md rename to docs/docs-beta/docs/integrations/libraries/meltano.md index 3a36625b75b4c..c78e518e8ca24 100644 --- a/docs/docs-beta/docs/integrations/meltano.md +++ b/docs/docs-beta/docs/integrations/libraries/meltano.md @@ -15,9 +15,10 @@ categories: communityIntegration: true enabledBy: enables: +tags: [community-supported, etl] --- -### About this integration + The `dagster-meltano` library allows you to run Meltano using Dagster. Design and configure ingestion jobs using the popular [Singer.io](https://singer.io) specification. diff --git a/docs/docs-beta/docs/integrations/microsoft-teams.md b/docs/docs-beta/docs/integrations/libraries/microsoft-teams.md similarity index 96% rename from docs/docs-beta/docs/integrations/microsoft-teams.md rename to docs/docs-beta/docs/integrations/libraries/microsoft-teams.md index bed3741fdcda1..183b9f3d54cab 100644 --- a/docs/docs-beta/docs/integrations/microsoft-teams.md +++ b/docs/docs-beta/docs/integrations/libraries/microsoft-teams.md @@ -14,10 +14,9 @@ categories: - Alerting enabledBy: enables: +tags: [dagster-supported, alerting] --- -### About this integration - By configuring this resource, you can post messages to MS Teams from any Dagster op or asset. ### Installation diff --git a/docs/docs-beta/docs/integrations/open-metadata.md b/docs/docs-beta/docs/integrations/libraries/open-metadata.md similarity index 97% rename from docs/docs-beta/docs/integrations/open-metadata.md rename to docs/docs-beta/docs/integrations/libraries/open-metadata.md index 476eaaa032b48..65c6c5077fd86 100644 --- a/docs/docs-beta/docs/integrations/open-metadata.md +++ b/docs/docs-beta/docs/integrations/libraries/open-metadata.md @@ -15,9 +15,10 @@ categories: - Metadata enabledBy: enables: +tags: [community-supported, metadata] --- -### About this integration + With this integration you can create a Open Metadata service to ingest metadata produced by the Dagster application. View the Ingestion Pipeline running from the Open Metadata Service Page. diff --git a/docs/docs-beta/docs/integrations/openai.md b/docs/docs-beta/docs/integrations/libraries/openai.md similarity index 97% rename from docs/docs-beta/docs/integrations/openai.md rename to docs/docs-beta/docs/integrations/libraries/openai.md index 16d3f84270a96..532e21a9018eb 100644 --- a/docs/docs-beta/docs/integrations/openai.md +++ b/docs/docs-beta/docs/integrations/libraries/openai.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [dagster-supported] --- -### About this integration + The `dagster-openai` library allows you to easily interact with the OpenAI REST API using the OpenAI Python API to build AI steps into your Dagster pipelines. You can also log OpenAI API usage metadata in Dagster Insights, giving you detailed observability on API call credit consumption. diff --git a/docs/docs-beta/docs/integrations/pagerduty.md b/docs/docs-beta/docs/integrations/libraries/pagerduty.md similarity index 95% rename from docs/docs-beta/docs/integrations/pagerduty.md rename to docs/docs-beta/docs/integrations/libraries/pagerduty.md index b2ac9dbcb111c..4c3b577b03fcc 100644 --- a/docs/docs-beta/docs/integrations/pagerduty.md +++ b/docs/docs-beta/docs/integrations/libraries/pagerduty.md @@ -14,9 +14,10 @@ categories: - Alerting enabledBy: enables: +tags: [dagster-supported, alerting] --- -### About this integration + This library provides an integration between Dagster and PagerDuty to support creating alerts from your Dagster code. diff --git a/docs/docs-beta/docs/integrations/pandas.md b/docs/docs-beta/docs/integrations/libraries/pandas.md similarity index 96% rename from docs/docs-beta/docs/integrations/pandas.md rename to docs/docs-beta/docs/integrations/libraries/pandas.md index b051eb7a98023..6f7ea38111aac 100644 --- a/docs/docs-beta/docs/integrations/pandas.md +++ b/docs/docs-beta/docs/integrations/libraries/pandas.md @@ -14,9 +14,10 @@ categories: - Metadata enabledBy: enables: +tags: [dagster-supported, metadata] --- -### About this integration + Perform data validation, emit summary statistics, and enable reliable DataFrame serialization/deserialization. The dagster_pandas library provides you with the utilities for implementing validation on Pandas DataFrames. The Dagster type system generates documentation of your DataFrame constraints and makes it accessible in the Dagster UI. diff --git a/docs/docs-beta/docs/integrations/pandera.md b/docs/docs-beta/docs/integrations/libraries/pandera.md similarity index 96% rename from docs/docs-beta/docs/integrations/pandera.md rename to docs/docs-beta/docs/integrations/libraries/pandera.md index 6957b91cbe3f7..1549013311feb 100644 --- a/docs/docs-beta/docs/integrations/pandera.md +++ b/docs/docs-beta/docs/integrations/libraries/pandera.md @@ -14,9 +14,10 @@ categories: - Metadata enabledBy: enables: +tags: [dagster-supported, metadata] --- -### About this integration + The `dagster-pandera` integration library provides an API for generating Dagster Types from [Pandera DataFrame schemas](https://pandera.readthedocs.io/en/stable/dataframe_schemas.html). diff --git a/docs/docs-beta/docs/integrations/prometheus.md b/docs/docs-beta/docs/integrations/libraries/prometheus.md similarity index 96% rename from docs/docs-beta/docs/integrations/prometheus.md rename to docs/docs-beta/docs/integrations/libraries/prometheus.md index a25da65aaaeaa..e90e0fe7fb10b 100644 --- a/docs/docs-beta/docs/integrations/prometheus.md +++ b/docs/docs-beta/docs/integrations/libraries/prometheus.md @@ -14,9 +14,10 @@ categories: - Monitoring enabledBy: enables: +tags: [dagster-supported, monitoring] --- -### About this integration + This integration allows you to push metrics to the Prometheus gateway from within a Dagster pipeline. diff --git a/docs/docs-beta/docs/integrations/sdf.md b/docs/docs-beta/docs/integrations/libraries/sdf.md similarity index 97% rename from docs/docs-beta/docs/integrations/sdf.md rename to docs/docs-beta/docs/integrations/libraries/sdf.md index ce80dd510ce77..a155f37bfa613 100644 --- a/docs/docs-beta/docs/integrations/sdf.md +++ b/docs/docs-beta/docs/integrations/libraries/sdf.md @@ -15,9 +15,10 @@ categories: - ETL enabledBy: enables: +tags: [community-supported, etl] --- -### About this integration + SDF can integrate seamlessly with your existing Dagster projects, providing the best-in-class transformation layer while enabling you to schedule, orchestrate, and monitor your dags in Dagster. diff --git a/docs/docs-beta/docs/integrations/secoda.md b/docs/docs-beta/docs/integrations/libraries/secoda.md similarity index 96% rename from docs/docs-beta/docs/integrations/secoda.md rename to docs/docs-beta/docs/integrations/libraries/secoda.md index 58c4c738eff32..3ec41ce364776 100644 --- a/docs/docs-beta/docs/integrations/secoda.md +++ b/docs/docs-beta/docs/integrations/libraries/secoda.md @@ -15,9 +15,10 @@ categories: - Metadata enabledBy: enables: +tags: [community-supported, metadata] --- -### About this integration + Connect Dagster to Secoda and see metadata related to your Dagster assets, asset groups and jobs right in Secoda. Simplify your team's access, and remove the need to switch between tools. diff --git a/docs/docs-beta/docs/integrations/shell.md b/docs/docs-beta/docs/integrations/libraries/shell.md similarity index 97% rename from docs/docs-beta/docs/integrations/shell.md rename to docs/docs-beta/docs/integrations/libraries/shell.md index 0c5653a4f47c6..6b69731c6aeea 100644 --- a/docs/docs-beta/docs/integrations/shell.md +++ b/docs/docs-beta/docs/integrations/libraries/shell.md @@ -14,9 +14,10 @@ categories: - Compute enabledBy: enables: +tags: [dagster-supported, compute] --- -### About this integration + Dagster comes with a native `PipesSubprocessClient` resource that enables you to launch shell commands directly from Dagster assets and ops. This integration allows you to pass parameters to external shell scripts while Dagster receives real-time events, such as logs, asset checks, and asset materializations, from the initiated external execution. With minimal code changes required on the job side, this integration is both efficient and easy to implement. diff --git a/docs/docs-beta/docs/integrations/slack.md b/docs/docs-beta/docs/integrations/libraries/slack.md similarity index 95% rename from docs/docs-beta/docs/integrations/slack.md rename to docs/docs-beta/docs/integrations/libraries/slack.md index ead87dc85b4b2..3c5d3b0253ec9 100644 --- a/docs/docs-beta/docs/integrations/slack.md +++ b/docs/docs-beta/docs/integrations/libraries/slack.md @@ -14,9 +14,10 @@ categories: - Alerting enabledBy: enables: +tags: [dagster-supported, alerting] --- -### About this integration + This library provides an integration with Slack to support posting messages in your company's Slack workspace. diff --git a/docs/docs-beta/docs/integrations/sling.md b/docs/docs-beta/docs/integrations/libraries/sling.md similarity index 96% rename from docs/docs-beta/docs/integrations/sling.md rename to docs/docs-beta/docs/integrations/libraries/sling.md index 0c00aea6bb7e7..58cceb2bac261 100644 --- a/docs/docs-beta/docs/integrations/sling.md +++ b/docs/docs-beta/docs/integrations/libraries/sling.md @@ -14,9 +14,10 @@ categories: - ETL enabledBy: enables: +tags: [dagster-supported, etl] --- -### About this integration + This integration allows you to use [Sling](https://slingdata.io/) to extract and load data from popular data sources to destinations with high performance and ease. diff --git a/docs/docs-beta/docs/integrations/snowflake.md b/docs/docs-beta/docs/integrations/libraries/snowflake.md similarity index 96% rename from docs/docs-beta/docs/integrations/snowflake.md rename to docs/docs-beta/docs/integrations/libraries/snowflake.md index 1f8adf390a4be..3e3f45986ff76 100644 --- a/docs/docs-beta/docs/integrations/snowflake.md +++ b/docs/docs-beta/docs/integrations/libraries/snowflake.md @@ -14,9 +14,10 @@ categories: - Storage enabledBy: enables: +tags: [dagster-supported, storage] --- -### About this integration + This library provides an integration with the Snowflake data warehouse. Connect to Snowflake as a resource, then use the integration-provided functions to construct an op to establish connections and execute Snowflake queries. Read and write natively to Snowflake from Dagster assets. diff --git a/docs/docs-beta/docs/integrations/spark.md b/docs/docs-beta/docs/integrations/libraries/spark.md similarity index 96% rename from docs/docs-beta/docs/integrations/spark.md rename to docs/docs-beta/docs/integrations/libraries/spark.md index a8e1b693e82b3..e14f63f73a10a 100644 --- a/docs/docs-beta/docs/integrations/spark.md +++ b/docs/docs-beta/docs/integrations/libraries/spark.md @@ -15,9 +15,10 @@ categories: enabledBy: - dagster-pyspark enables: +tags: [dagster-supported, compute] --- -### About this integration + Spark jobs typically execute on infrastructure that's specialized for Spark. Spark applications are typically not containerized or executed on Kubernetes. diff --git a/docs/docs-beta/docs/integrations/ssh-sftp.md b/docs/docs-beta/docs/integrations/libraries/ssh-sftp.md similarity index 97% rename from docs/docs-beta/docs/integrations/ssh-sftp.md rename to docs/docs-beta/docs/integrations/libraries/ssh-sftp.md index bd8d15ed34626..be2314fa07cbb 100644 --- a/docs/docs-beta/docs/integrations/ssh-sftp.md +++ b/docs/docs-beta/docs/integrations/libraries/ssh-sftp.md @@ -14,9 +14,10 @@ categories: - Other enabledBy: enables: +tags: [dagster-supported] --- -### About this integration + This integration provides a resource for SSH remote execution using [Paramiko](https://github.com/paramiko/paramiko). It allows you to establish secure connections to networked resources and execute commands remotely. The integration also provides an SFTP client for secure file transfers between the local and remote systems. diff --git a/docs/docs-beta/docs/integrations/twilio.md b/docs/docs-beta/docs/integrations/libraries/twilio.md similarity index 95% rename from docs/docs-beta/docs/integrations/twilio.md rename to docs/docs-beta/docs/integrations/libraries/twilio.md index 2b2cb4d56f3af..4584fdb550781 100644 --- a/docs/docs-beta/docs/integrations/twilio.md +++ b/docs/docs-beta/docs/integrations/libraries/twilio.md @@ -14,9 +14,10 @@ categories: - Alerting enabledBy: enables: +tags: [dagster-supported, alerting] --- -### About this integration + Use your Twilio `Account SID` and `Auth Token` to build Twilio tasks right into your Dagster pipeline. diff --git a/docs/docs-beta/docs/integrations/wandb.md b/docs/docs-beta/docs/integrations/libraries/wandb.md similarity index 98% rename from docs/docs-beta/docs/integrations/wandb.md rename to docs/docs-beta/docs/integrations/libraries/wandb.md index 44a7ad762600c..363950d2fa10e 100644 --- a/docs/docs-beta/docs/integrations/wandb.md +++ b/docs/docs-beta/docs/integrations/libraries/wandb.md @@ -15,9 +15,10 @@ categories: - Other enabledBy: enables: +tags: [community-supported] --- -### About this integration + Use Dagster and Weights & Biases (W&B) to orchestrate your MLOps pipelines and maintain ML assets. The integration with W&B makes it easy within Dagster to: diff --git a/docs/docs-beta/docs/tags.yml b/docs/docs-beta/docs/tags.yml new file mode 100644 index 0000000000000..c4ec13c2a2145 --- /dev/null +++ b/docs/docs-beta/docs/tags.yml @@ -0,0 +1,36 @@ +community-supported: + label: 'community-supported' + permalink: '/integrations/community-supported' + description: 'Community-supported integrations.' +dagster-supported: + label: 'dagster-supported' + permalink: '/integrations/dagster-supported' + description: 'Dagster-supported integrations.' +etl: + label: 'ETL' + permalink: '/integrations/etl' + description: 'ETL integrations.' +storage: + label: 'storage' + permalink: '/integrations/storage' + description: 'Storage integrations.' +compute: + label: 'compute' + permalink: '/integrations/compute' + description: 'Compute integrations.' +bi: + label: 'BI' + permalink: '/integrations/bi' + description: 'BI integrations.' +monitoring: + label: 'monitoring' + permalink: '/integrations/monitoring' + description: 'Monitoring integrations.' +alerting: + label: 'alerting' + permalink: '/integrations/alerting' + description: 'Alerting integrations.' +metadata: + label: 'metadata' + permalink: '/integrations/metadata' + description: 'Metadata integrations.' diff --git a/docs/docs-beta/docusaurus.config.ts b/docs/docs-beta/docusaurus.config.ts index 491dc86f6ba46..7a3f8dd9f75af 100644 --- a/docs/docs-beta/docusaurus.config.ts +++ b/docs/docs-beta/docusaurus.config.ts @@ -1,6 +1,7 @@ import {themes as prismThemes} from 'prism-react-renderer'; import type {Config} from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; +import { groupCollapsed } from 'console'; const config: Config = { title: 'Dagster Docs - Beta', @@ -84,7 +85,7 @@ const config: Config = { { label: 'Integrations', type: 'doc', - docId: 'integrations/index', + docId: 'integrations/libraries/index', position: 'left', }, { diff --git a/docs/docs-beta/sidebars.ts b/docs/docs-beta/sidebars.ts index 99bf0f852575c..03ca26fa27bcb 100644 --- a/docs/docs-beta/sidebars.ts +++ b/docs/docs-beta/sidebars.ts @@ -88,133 +88,24 @@ const sidebars: SidebarsConfig = { integrations: [ { type: 'category', - label: 'Categories', - collapsible: false, - items: [ - { - type: 'category', - label: 'ETL', - items: [ - 'integrations/airbyte', - 'integrations/sdf', - 'integrations/fivetran', - 'integrations/dlt', - 'integrations/census', - 'integrations/dbt', - 'integrations/dbt-cloud', - 'integrations/sling', - 'integrations/hightouch', - 'integrations/meltano', - ], - }, - { - type: 'category', - label: 'Storage', - items: [ - 'integrations/snowflake', - 'integrations/gcp/bigquery', - 'integrations/aws/athena', - 'integrations/aws/s3', - 'integrations/duckdb', - 'integrations/deltalake', - 'integrations/aws/redshift', - 'integrations/gcp/gcs', - 'integrations/azure-adls2', - 'integrations/lakefs', - ], - }, - { - type: 'category', - label: 'Compute', - items: [ - 'integrations/kubernetes', - 'integrations/spark', - 'integrations/aws/glue', - 'integrations/jupyter', - 'integrations/aws/emr', - 'integrations/databricks', - 'integrations/aws/lambda', - 'integrations/docker', - 'integrations/shell', - 'integrations/gcp/dataproc', - ], - }, - { - type: 'category', - label: 'BI', - items: ['integrations/looker'], - }, - { - type: 'category', - label: 'Monitoring', - items: ['integrations/prometheus', 'integrations/datadog', 'integrations/aws/cloudwatch'], - }, - { - type: 'category', - label: 'Alerting', - items: [ - 'integrations/slack', - 'integrations/twilio', - 'integrations/pagerduty', - 'integrations/microsoft-teams', - ], - }, - { - type: 'category', - label: 'Metadata', - items: [ - 'integrations/secoda', - 'integrations/pandera', - 'integrations/open-metadata', - 'integrations/pandas', - ], - }, - { - type: 'category', - label: 'Other', - items: [ - 'integrations/cube', - 'integrations/aws/secretsmanager', - 'integrations/openai', - 'integrations/ssh-sftp', - 'integrations/github', - 'integrations/aws/ssm', - 'integrations/aws/ecr', - 'integrations/wandb', - 'integrations/hashicorp', - ], - }, - ], - }, - { - type: 'category', - label: 'Community Supported', + label: 'Guides', + collapsed: false, items: [ - 'integrations/secoda', - 'integrations/cube', - 'integrations/sdf', - 'integrations/open-metadata', - 'integrations/census', - 'integrations/deltalake', - 'integrations/hightouch', - 'integrations/wandb', - 'integrations/meltano', - 'integrations/hashicorp', - 'integrations/lakefs', - ], + 'integrations/guides/multi-asset-integration' + ] }, { type: 'category', - label: 'All Integrations', - collapsed: true, - // link: {type: 'doc', id: 'integrations'}, + label: 'Libraries', + collapsible: false, + link: {type: 'doc', id: 'integrations/libraries/index'}, items: [ { type: 'autogenerated', - dirName: 'integrations', - }, - ], - }, + dirName: 'integrations/libraries' + } + ] + } ], dagsterPlus: [ 'dagster-plus/index', From e289de1a56123a7a81e8f996d11f25ffff5675a3 Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Thu, 12 Dec 2024 14:55:07 -0600 Subject: [PATCH 28/94] make mdx-format (#26456) ## How I Tested These Changes make mdx-format --- .../dagster-plus/deployment/azure/blob-compute-logs.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx b/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx index 52bfb2d355606..98d80e90aac2f 100644 --- a/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx +++ b/docs/content/dagster-plus/deployment/azure/blob-compute-logs.mdx @@ -80,8 +80,8 @@ workspace: ``` - If you need to retrieve the values used by your Helm deployment, you - can run: `helm get values user-cloud > values.yaml`. + If you need to retrieve the values used by your Helm deployment, you can run: + `helm get values user-cloud > values.yaml`. Finally, update your Helm release with the new values: From 5843e2ca17c24bc52e690f4f3c150833cf5b26db Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Thu, 12 Dec 2024 15:19:48 -0600 Subject: [PATCH 29/94] add extract_serialized_job_snap_from_serialized_job_data_snap (#26270) We are working towards a change in how the dagster cloud agent uploads definition snapshots to the server. An issue we currently face in that work is that the grpc server returns `JobDataSnap` but we want to upload and persist only its inner `JobSnap`. To facilitate this as efficiently and safely as possible this PR adds a method to do the extraction quickly falling back to safely and a series of tests to defend it. ## How I Tested These Changes added tests --- .../remote_representation/external_data.py | 53 ++++++++++++++++++- .../dagster/dagster/_serdes/serdes.py | 24 +++++++++ .../dagster_tests/api_tests/api_tests_repo.py | 10 +++- .../api_tests/test_api_snapshot_repository.py | 50 +++++++++++++---- .../cli_tests/test_api_commands.py | 2 +- .../general_tests/test_serdes.py | 4 ++ 6 files changed, 128 insertions(+), 15 deletions(-) diff --git a/python_modules/dagster/dagster/_core/remote_representation/external_data.py b/python_modules/dagster/dagster/_core/remote_representation/external_data.py index 3afe97064d9af..637ac03ca6e9d 100644 --- a/python_modules/dagster/dagster/_core/remote_representation/external_data.py +++ b/python_modules/dagster/dagster/_core/remote_representation/external_data.py @@ -6,6 +6,7 @@ import inspect import json +import os from abc import ABC, abstractmethod from collections import defaultdict from enum import Enum @@ -102,7 +103,11 @@ from dagster._core.utils import is_valid_email from dagster._record import IHaveNew, record, record_custom from dagster._serdes import whitelist_for_serdes -from dagster._serdes.serdes import FieldSerializer, is_whitelisted_for_serdes_object +from dagster._serdes.serdes import ( + FieldSerializer, + get_prefix_for_a_serialized, + is_whitelisted_for_serdes_object, +) from dagster._time import datetime_from_timestamp from dagster._utils.error import SerializableErrorInfo from dagster._utils.warnings import suppress_dagster_warnings @@ -388,10 +393,13 @@ def __new__( ) +_JOB_SNAP_STORAGE_FIELD = "pipeline_snapshot" + + @whitelist_for_serdes( storage_name="ExternalPipelineData", storage_field_names={ - "job": "pipeline_snapshot", + "job": _JOB_SNAP_STORAGE_FIELD, "parent_job": "parent_pipeline_snapshot", }, # There was a period during which `JobDefinition` was a newer subclass of the legacy @@ -1859,3 +1867,44 @@ def resolve_automation_condition_args( else: # for non-serializable conditions, only include the snapshot return None, automation_condition.get_snapshot() + + +def _extract_fast(serialized_job_data: str): + target_key = f'"{_JOB_SNAP_STORAGE_FIELD}": ' + target_substr = target_key + get_prefix_for_a_serialized(JobSnap) + # look for key: type + idx = serialized_job_data.find(target_substr) + check.invariant(idx > 0) + # slice starting after key: + start_idx = idx + len(target_key) + + # trim outer object } + # assumption that pipeline_snapshot is last field under test in test_job_data_snap_layout + serialized_job_snap = serialized_job_data[start_idx:-1] + check.invariant(serialized_job_snap[0] == "{" and serialized_job_snap[-1] == "}") + + return serialized_job_snap + + +def _extract_safe(serialized_job_data: str): + # Intentionally use json directly instead of serdes to avoid losing information if the current process + # is older than the source process. + return json.dumps(json.loads(serialized_job_data)[_JOB_SNAP_STORAGE_FIELD]) + + +DISABLE_FAST_EXTRACT_ENV_VAR = "DAGSTER_DISABLE_JOB_SNAP_FAST_EXTRACT" + + +def extract_serialized_job_snap_from_serialized_job_data_snap(serialized_job_data_snap: str): + # utility used by DagsterCloudAgent to extract JobSnap out of JobDataSnap + # efficiently and safely + if not serialized_job_data_snap.startswith(get_prefix_for_a_serialized(JobDataSnap)): + raise Exception("Passed in string does not meet expectations for a serialized JobDataSnap") + + if not os.getenv(DISABLE_FAST_EXTRACT_ENV_VAR): + try: + return _extract_fast(serialized_job_data_snap) + except Exception: + pass + + return _extract_safe(serialized_job_data_snap) diff --git a/python_modules/dagster/dagster/_serdes/serdes.py b/python_modules/dagster/dagster/_serdes/serdes.py index 741ff44487cf2..7cc5efe798e2f 100644 --- a/python_modules/dagster/dagster/_serdes/serdes.py +++ b/python_modules/dagster/dagster/_serdes/serdes.py @@ -1423,3 +1423,27 @@ def get_storage_name(klass: Type, *, whitelist_map: WhitelistMap = _WHITELIST_MA check.failed(f"{klass.__name__} is not a known serializable object type.") ser = whitelist_map.object_serializers[klass.__name__] return ser.get_storage_name() + + +def get_storage_fields(klass: Type, whitelist_map: WhitelistMap = _WHITELIST_MAP): + if klass.__name__ not in whitelist_map.object_serializers: + check.failed(f"{klass.__name__} is not a known serializable object type.") + ser = whitelist_map.object_serializers[klass.__name__] + # get the current fields + current_fields = ser.constructor_param_names + # remap defined storage field names + stored_fields = [ser.storage_field_names.get(f, f) for f in current_fields] + # insert old fields + stored_fields.extend(ser.old_fields.keys()) + # we sort_keys=True in json dump + return sorted(stored_fields) + + +_OBJECT_START = '{"__class__":' + + +def get_prefix_for_a_serialized(klass: Type, *, whitelist_map=_WHITELIST_MAP): + """Returns the expected start of the string for a serdes serialized object + of the passed type. + """ + return f'{_OBJECT_START} "{get_storage_name(klass, whitelist_map=whitelist_map)}"' diff --git a/python_modules/dagster/dagster_tests/api_tests/api_tests_repo.py b/python_modules/dagster/dagster_tests/api_tests/api_tests_repo.py index 8ad4e79a19c2d..0e45a4097d1a1 100644 --- a/python_modules/dagster/dagster_tests/api_tests/api_tests_repo.py +++ b/python_modules/dagster/dagster_tests/api_tests/api_tests_repo.py @@ -17,6 +17,7 @@ ) from dagster._core.definitions.asset_graph import AssetGraph from dagster._core.definitions.decorators.sensor_decorator import sensor +from dagster._core.definitions.metadata.metadata_value import MetadataValue from dagster._core.definitions.partition import PartitionedConfig, StaticPartitionsDefinition from dagster._core.definitions.sensor_definition import RunRequest from dagster._core.errors import DagsterError @@ -192,6 +193,12 @@ def sensor_raises_dagster_error(_): raise DagsterError("Dagster error") +@job(metadata={"pipeline_snapshot": MetadataValue.json({"pipeline_snapshot": "pipeline_snapshot"})}) +def pipeline_snapshot(): + do_something() + do_fail() + + @repository(metadata={"string": "foo", "integer": 123}) def bar_repo(): return { @@ -201,9 +208,10 @@ def bar_repo(): "dynamic_job": define_asset_job( "dynamic_job", [dynamic_asset], partitions_def=dynamic_partitions_def ).resolve(asset_graph=AssetGraph.from_assets([dynamic_asset])), - "fail": fail_job, + "fail_job": fail_job, "foo": foo_job, "forever": forever_job, + "pipeline_snapshot": pipeline_snapshot.get_subset(op_selection=["do_something"]), }, "schedules": define_bar_schedules(), "sensors": { diff --git a/python_modules/dagster/dagster_tests/api_tests/test_api_snapshot_repository.py b/python_modules/dagster/dagster_tests/api_tests/test_api_snapshot_repository.py index dc854e851f0f1..5f75fb0a7a0ca 100644 --- a/python_modules/dagster/dagster_tests/api_tests/test_api_snapshot_repository.py +++ b/python_modules/dagster/dagster_tests/api_tests/test_api_snapshot_repository.py @@ -15,12 +15,19 @@ RepositorySnap, ) from dagster._core.remote_representation.external import RemoteRepository -from dagster._core.remote_representation.external_data import JobDataSnap +from dagster._core.remote_representation.external_data import ( + DISABLE_FAST_EXTRACT_ENV_VAR, + JobDataSnap, + JobRefSnap, + extract_serialized_job_snap_from_serialized_job_data_snap, +) from dagster._core.remote_representation.handle import RepositoryHandle from dagster._core.remote_representation.origin import RemoteRepositoryOrigin from dagster._core.test_utils import instance_for_test from dagster._core.types.loadable_target_origin import LoadableTargetOrigin -from dagster._serdes.serdes import deserialize_value +from dagster._serdes.serdes import deserialize_value, get_storage_fields +from dagster._serdes.utils import hash_str +from dagster._utils.env import environ from dagster_tests.api_tests.utils import get_bar_repo_code_location @@ -121,8 +128,9 @@ def test_giant_external_repository_streaming_grpc(): assert repository_snap.name == "giant_repo" -def test_defer_snapshots(instance: DagsterInstance): - with get_bar_repo_code_location(instance) as code_location: +@pytest.mark.parametrize("env", [{}, {DISABLE_FAST_EXTRACT_ENV_VAR: "true"}]) +def test_defer_snapshots(instance: DagsterInstance, env): + with get_bar_repo_code_location(instance) as code_location, environ(env): repo_origin = RemoteRepositoryOrigin( code_location.origin, "bar_repo", @@ -135,16 +143,27 @@ def test_defer_snapshots(instance: DagsterInstance): _state = {} - def _ref_to_data(ref): + def _ref_to_data(ref: JobRefSnap): _state["cnt"] = _state.get("cnt", 0) + 1 reply = code_location.client.external_job( repo_origin, ref.name, ) - return deserialize_value(reply.serialized_job_data, JobDataSnap) + assert reply.serialized_job_data, reply.serialized_error + assert ( + hash_str( + extract_serialized_job_snap_from_serialized_job_data_snap( + reply.serialized_job_data + ) + ) + == ref.snapshot_id + ), ref.name + + job_data_snap = deserialize_value(reply.serialized_job_data, JobDataSnap) + return job_data_snap repository_snap = deserialize_value(ser_repo_data, RepositorySnap) - assert repository_snap.job_refs and len(repository_snap.job_refs) == 6 + assert repository_snap.job_refs and len(repository_snap.job_refs) == 7 assert repository_snap.job_datas is None repo = RemoteRepository( @@ -154,7 +173,7 @@ def _ref_to_data(ref): ref_to_data_fn=_ref_to_data, ) jobs = repo.get_all_jobs() - assert len(jobs) == 6 + assert len(jobs) == 7 assert _state.get("cnt", 0) == 0 job = jobs[0] @@ -177,6 +196,15 @@ def _ref_to_data(ref): assert _state.get("cnt", 0) == 1 # refetching job should share fetched data - job = repo.get_all_jobs()[0] - _ = job.job_snapshot - assert _state.get("cnt", 0) == 1 + expected = 1 # from job[0] access + for job in repo.get_all_jobs(): + _ = job.job_snapshot + assert _state.get("cnt", 0) == expected + expected += 1 + + +def test_job_data_snap_layout(): + # defend against assumptions made in + + # must remain last position + assert get_storage_fields(JobDataSnap)[-1] == "pipeline_snapshot" diff --git a/python_modules/dagster/dagster_tests/cli_tests/test_api_commands.py b/python_modules/dagster/dagster_tests/cli_tests/test_api_commands.py index 1c483394bd1c2..6fc1739fa8211 100644 --- a/python_modules/dagster/dagster_tests/cli_tests/test_api_commands.py +++ b/python_modules/dagster/dagster_tests/cli_tests/test_api_commands.py @@ -179,7 +179,7 @@ def test_execute_run_fail_job(): } ) as instance: with get_bar_repo_handle(instance) as repo_handle: - job_handle = JobHandle("fail", repo_handle) + job_handle = JobHandle("fail_job", repo_handle) runner = CliRunner() run = create_run_for_test( diff --git a/python_modules/dagster/dagster_tests/general_tests/test_serdes.py b/python_modules/dagster/dagster_tests/general_tests/test_serdes.py index e39e158e89961..57bc1ac5a378a 100644 --- a/python_modules/dagster/dagster_tests/general_tests/test_serdes.py +++ b/python_modules/dagster/dagster_tests/general_tests/test_serdes.py @@ -22,6 +22,7 @@ WhitelistMap, _whitelist_for_serdes, deserialize_value, + get_prefix_for_a_serialized, get_storage_name, pack_value, serialize_value, @@ -445,6 +446,7 @@ class Foo(NamedTuple): val = Foo("red") serialized = serialize_value(val, whitelist_map=test_map) + assert serialized.startswith(get_prefix_for_a_serialized(Foo, whitelist_map=test_map)) deserialized = deserialize_value(serialized, whitelist_map=test_map) assert deserialized == val @@ -465,12 +467,14 @@ class Bar(NamedTuple): val = Foo("red") serialized = serialize_value(val, whitelist_map=test_env) assert serialized == '{"__class__": "Bar", "color": "red"}' + assert serialized.startswith(get_prefix_for_a_serialized(Foo, whitelist_map=test_env)) deserialized = deserialize_value(serialized, whitelist_map=test_env) assert deserialized == val val = Bar("square") serialized = serialize_value(val, whitelist_map=test_env) assert serialized == '{"__class__": "Foo", "shape": "square"}' + assert serialized.startswith(get_prefix_for_a_serialized(Bar, whitelist_map=test_env)) deserialized = deserialize_value(serialized, whitelist_map=test_env) assert deserialized == val From 007fe7dd7883c14d58818977b65195cc99c459d2 Mon Sep 17 00:00:00 2001 From: elementl Date: Thu, 12 Dec 2024 21:41:28 +0000 Subject: [PATCH 30/94] Automation: versioned docs for 1.9.5 --- docs/next/.versioned_content/_versions_with_static_links.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/next/.versioned_content/_versions_with_static_links.json b/docs/next/.versioned_content/_versions_with_static_links.json index 03a000fd36b18..5b12b5f2ea18d 100644 --- a/docs/next/.versioned_content/_versions_with_static_links.json +++ b/docs/next/.versioned_content/_versions_with_static_links.json @@ -606,5 +606,9 @@ { "url": "https://release-1-9-4.dagster.dagster-docs.io/", "version": "1.9.4" + }, + { + "url": "https://release-1-9-5.dagster.dagster-docs.io/", + "version": "1.9.5" } ] \ No newline at end of file From 3d792fda8ac4e23b498161d263afd23536c632b3 Mon Sep 17 00:00:00 2001 From: Nikki Everett Date: Thu, 12 Dec 2024 16:12:33 -0600 Subject: [PATCH 31/94] [Docs] Add structure for remaining missing content (Dagster+) (#26299) ## Summary & Motivation * Adds (mostly empty) directories and files for remaining Dagster+ content and adds TODOs and links to old content to be copied over * Makes metadata consistent across files so future docs contributors don't needlessly copy metadata that doesn't matter into new docs * Reorganizes deployment docs into "Deployment types", "Management", and "Migration" categories * Moves "Code locations" section to "Features" * Creates "CI/CD" section in "Features" and moves "Branch deployments" into it ## How I Tested These Changes Local and staging deployment ## Changelog --------- Signed-off-by: nikki everett --- .../code-locations/code-location-history.md | 6 +- .../code-locations/dagster-cloud-yaml.md | 7 + .../deployment/code-locations/index.md | 7 +- .../deployment/code-requirements.md | 5 +- .../deployment/deployment-settings.md | 9 - .../deployment/deployment-types.md | 7 - .../amazon-ecs/configuration-reference.md | 7 + .../hybrid/amazon-ecs/existing-vpc.md | 7 + .../hybrid/amazon-ecs/index.md | 8 + .../hybrid/amazon-ecs/manual-provision.md | 7 + .../hybrid/amazon-ecs/new-vpc.md | 7 + .../amazon-ecs/upgrading-cloudformation.md | 8 + .../hybrid/architecture.md | 7 +- .../hybrid/docker/configuration.md | 7 + .../hybrid/docker/index.md} | 5 +- .../deployment-types/hybrid/docker/setup.md | 7 + .../{ => deployment-types}/hybrid/index.md | 12 +- .../hybrid/kubernetes/configuration.md | 7 + .../hybrid/kubernetes/index.md | 8 + .../hybrid/kubernetes/setup.md} | 16 +- .../hybrid}/local.md | 9 +- .../deployment-types/hybrid/multiple.md | 8 + .../deployment/deployment-types/index.md | 8 + .../deployment-types/multi-tenancy.md | 5 + .../serverless/ci-cd-in-serverless.md | 17 +- .../serverless/dagster-ips.md | 6 +- .../serverless/index.md | 4 +- .../serverless/run-isolation.md | 7 +- .../serverless/runtime-environment.md | 21 +- .../serverless/security.md | 10 +- .../environment-variables/index.mdx | 12 - .../hybrid/agents/amazon-ecs-existing-vpc.md | 7 - .../hybrid/agents/amazon-ecs-new-vpc.md | 7 - .../deployment/hybrid/agents/docker.md | 9 - .../deployment/hybrid/agents/index.mdx | 11 - .../deployment/hybrid/agents/multiple.md | 8 - .../deployment/hybrid/agents/settings.md | 9 - .../dagster-plus/deployment/hybrid/tokens.md | 8 - .../dagster-cloud-cli-reference.md | 7 + .../management/dagster-cloud-cli/index.md | 10 + .../installing-and-configuring.md | 8 + .../environment-variables/agent-config.md | 3 +- .../environment-variables/built-in.md | 2 - .../environment-variables/dagster-ui.md | 3 +- .../management/environment-variables/index.md | 9 + .../management/index.md} | 5 +- ...anaging-compute-logs-and-error-messages.md | 6 + .../managing-multiple-projects-and-teams.md | 6 + .../deployment/management/rate-limits.md | 6 + .../settings/customizing-agent-settings.md | 7 + .../settings}/dagster-plus-settings.md | 3 +- .../settings/deployment-settings.md | 7 + .../settings/hybrid-agent-settings.md | 8 + .../deployment/management/settings/index.md | 8 + .../management/tokens/agent-tokens.md | 7 + .../deployment/management/tokens/index.md | 8 + .../management/tokens/user-tokens.md | 7 + .../deployment/migration/index.md | 8 + .../migration/self-hosted-to-dagster-plus.md | 5 +- .../serverless-to-hybrid.md} | 14 +- .../dagster-plus/deployment/multi-tenancy.md | 7 - .../deployment/user-agent-tokens.md | 8 - .../docs/dagster-plus/features/alerts/cli.md | 7 - ...nfiguring-an-alert-notification-service.md | 52 +++ .../features/alerts/creating-alerts.md | 277 +++++++++++++++ .../dagster-plus/features/alerts/email.md | 7 - .../dagster-plus/features/alerts/index.md | 322 +----------------- .../features/alerts/microsoft-teams.md | 8 - .../dagster-plus/features/alerts/pagerduty.md | 8 - .../dagster-plus/features/alerts/slack.md | 8 - .../docs/dagster-plus/features/alerts/ui.md | 8 - .../{index.mdx => index.md} | 5 +- .../rbac/audit-logs.md | 11 +- .../rbac/{index.mdx => index.md} | 3 - .../rbac/teams.md | 6 +- .../rbac/user-roles-permissions.md | 20 +- .../rbac/users.md | 1 - .../scim/azure-active-directory.md | 8 +- .../scim/enabling-scim-provisioning.md | 7 + .../scim/index.md | 11 + .../scim/okta-scim.md | 5 +- .../sso/authentication.md | 4 +- .../sso/azure-ad-sso.md | 6 +- .../sso/google-workspace-sso.md | 6 +- .../sso/{index.mdx => index.md} | 3 - .../sso/okta-sso.md | 6 +- .../sso/onelogin-sso.md | 3 - .../sso/pingone-sso.md | 6 +- .../branch-deployments/change-tracking.md | 9 - .../branch-deployments/dagster-cloud-cli.md | 9 - .../features/branch-deployments/index.mdx | 11 - .../features/branch-deployments/testing.md | 7 - .../{saved-views.md => catalog-views.md} | 13 +- .../branch-deployments/change-tracking.md | 7 + .../branch-deployments/dagster-cloud-cli.md | 7 + .../ci-cd/branch-deployments/index.md | 8 + .../setting-up-branch-deployments.md | 14 +- .../ci-cd/branch-deployments/testing.md | 7 + .../features/ci-cd/ci-cd-file-reference.md | 6 + .../docs/dagster-plus/features/ci-cd/index.md | 8 + .../dagster-plus/features/data-catalog.md | 3 +- .../features/insights/export-metrics.md | 1 - .../dagster-plus/features/insights/index.md | 7 +- .../docs/dagster-plus/getting-started.md | 11 +- docs/docs-beta/docs/dagster-plus/index.md | 7 +- .../build/configure/managing-concurrency.md | 4 +- 106 files changed, 723 insertions(+), 706 deletions(-) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/code-locations/dagster-cloud-yaml.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-settings.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/configuration-reference.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/existing-vpc.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/index.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/manual-provision.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/new-vpc.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/upgrading-cloudformation.md rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/hybrid/architecture.md (96%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/configuration.md rename docs/docs-beta/docs/dagster-plus/deployment/{migration/index.mdx => deployment-types/hybrid/docker/index.md} (59%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/setup.md rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/hybrid/index.md (90%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/configuration.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/index.md rename docs/docs-beta/docs/dagster-plus/deployment/{hybrid/agents/kubernetes.md => deployment-types/hybrid/kubernetes/setup.md} (95%) rename docs/docs-beta/docs/dagster-plus/deployment/{hybrid/agents => deployment-types/hybrid}/local.md (94%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/multiple.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/index.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/deployment-types/multi-tenancy.md rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/serverless/ci-cd-in-serverless.md (81%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/serverless/dagster-ips.md (84%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/serverless/index.md (95%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/serverless/run-isolation.md (94%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/serverless/runtime-environment.md (85%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => deployment-types}/serverless/security.md (85%) delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/environment-variables/index.mdx delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-existing-vpc.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-new-vpc.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/docker.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/index.mdx delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/multiple.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/settings.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/hybrid/tokens.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/dagster-cloud-cli-reference.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/index.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/installing-and-configuring.md rename docs/docs-beta/docs/dagster-plus/deployment/{ => management}/environment-variables/agent-config.md (54%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => management}/environment-variables/built-in.md (98%) rename docs/docs-beta/docs/dagster-plus/deployment/{ => management}/environment-variables/dagster-ui.md (95%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/index.md rename docs/docs-beta/docs/dagster-plus/{features/authentication-and-access-control/scim/index.mdx => deployment/management/index.md} (53%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/managing-compute-logs-and-error-messages.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/managing-multiple-projects-and-teams.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/rate-limits.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/settings/customizing-agent-settings.md rename docs/docs-beta/docs/dagster-plus/deployment/{ => management/settings}/dagster-plus-settings.md (54%) create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/settings/deployment-settings.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/settings/hybrid-agent-settings.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/settings/index.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/tokens/agent-tokens.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/tokens/index.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/management/tokens/user-tokens.md create mode 100644 docs/docs-beta/docs/dagster-plus/deployment/migration/index.md rename docs/docs-beta/docs/dagster-plus/deployment/{serverless/transition-hybrid.md => migration/serverless-to-hybrid.md} (63%) delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/multi-tenancy.md delete mode 100644 docs/docs-beta/docs/dagster-plus/deployment/user-agent-tokens.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/cli.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/configuring-an-alert-notification-service.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/creating-alerts.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/email.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/microsoft-teams.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/pagerduty.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/slack.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/alerts/ui.md rename docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/{index.mdx => index.md} (55%) rename docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/{index.mdx => index.md} (67%) create mode 100644 docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/enabling-scim-provisioning.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.md rename docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/{index.mdx => index.md} (69%) delete mode 100644 docs/docs-beta/docs/dagster-plus/features/branch-deployments/change-tracking.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/branch-deployments/dagster-cloud-cli.md delete mode 100644 docs/docs-beta/docs/dagster-plus/features/branch-deployments/index.mdx delete mode 100644 docs/docs-beta/docs/dagster-plus/features/branch-deployments/testing.md rename docs/docs-beta/docs/dagster-plus/features/{saved-views.md => catalog-views.md} (91%) create mode 100644 docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/change-tracking.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/index.md rename docs/docs-beta/docs/dagster-plus/features/{ => ci-cd}/branch-deployments/setting-up-branch-deployments.md (95%) create mode 100644 docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/testing.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/ci-cd/ci-cd-file-reference.md create mode 100644 docs/docs-beta/docs/dagster-plus/features/ci-cd/index.md diff --git a/docs/docs-beta/docs/dagster-plus/deployment/code-locations/code-location-history.md b/docs/docs-beta/docs/dagster-plus/deployment/code-locations/code-location-history.md index f7e080d785acb..33c575030c05a 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/code-locations/code-location-history.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/code-locations/code-location-history.md @@ -1,12 +1,8 @@ --- title: "Code location history and rollbacks" -displayed_sidebar: "dagsterPlus" sidebar_position: 100 -sidebar_label: "Code location history and rollbacks" --- -# Code location history and rollbacks - Dagster+ automatically tracks metadata every time a code location is loaded. This can be used to understand when changes have been made, and what those changes were. In addition, this metadata can be used to quickly redeploy an older version.
@@ -54,4 +50,4 @@ If you notice an issue with newly deployed code, or your code fails to deploy su ## Next steps - Learn more about [Code Locations](/dagster-plus/deployment/code-locations) -- Learn how to [Alert when a code location fails to load](/dagster-plus/features/alerts#alerting-when-a-code-location-fails-to-load) +- Learn how to [Alert when a code location fails to load](/dagster-plus/features/alerts/creating-alerts#alerting-when-a-code-location-fails-to-load) diff --git a/docs/docs-beta/docs/dagster-plus/deployment/code-locations/dagster-cloud-yaml.md b/docs/docs-beta/docs/dagster-plus/deployment/code-locations/dagster-cloud-yaml.md new file mode 100644 index 0000000000000..7790f2cf5230a --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/code-locations/dagster-cloud-yaml.md @@ -0,0 +1,7 @@ +--- +title: dagster_cloud.yaml reference +sidebar_position: 200 +unlisted: true +--- + +{/* TODO move content from https://docs.dagster.io/dagster-plus/managing-deployments/dagster-cloud-yaml */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/code-locations/index.md b/docs/docs-beta/docs/dagster-plus/deployment/code-locations/index.md index ad60593d0bfb4..facde90edf2aa 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/code-locations/index.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/code-locations/index.md @@ -1,11 +1,8 @@ --- title: "Code locations" -displayed_sidebar: "dagsterPlus" -sidebar_position: 50 +sidebar_position: 40 --- -# Code locations - Separate code locations allow you to deploy different projects that still roll up into a single Dagster+ deployment with one global lineage graph. This guide will cover three options for adding a new code location: @@ -237,4 +234,4 @@ The monorepo should have CI/CD configured to deploy your changes and add or upda ## Next steps - After adding a code location, you may want to setup access controls -- You may want to add additional configuration to your code location. This configuration will vary by agent type, but see examples for [setting default resource limits for Kubernetes](/dagster-plus/deployment/hybrid/agents/kubernetes) or [changing the IAM role for ECS](/todo). +- You may want to add additional configuration to your code location. This configuration will vary by agent type, but see examples for [setting default resource limits for Kubernetes](/dagster-plus/deployment/deployment-types/hybrid/kubernetes) or [changing the IAM role for ECS](/todo). diff --git a/docs/docs-beta/docs/dagster-plus/deployment/code-requirements.md b/docs/docs-beta/docs/dagster-plus/deployment/code-requirements.md index 1fba813927a18..ad75ee2411dd0 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/code-requirements.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/code-requirements.md @@ -1,8 +1,7 @@ --- title: 'Dagster+ code requirements' -displayed_sidebar: 'dagsterPlus' sidebar_label: "Code requirements" -sidebar_position: 100 +sidebar_position: 10 --- Your Dagster project must meet a few requirements to run in Dagster+. @@ -34,7 +33,7 @@ To work with Dagster+, your Dagster code: ## Hybrid deployment requirements -If you're using [Hybrid Deployment](/dagster-plus/deployment/hybrid), there are a few additional requirements. +If you're using [Hybrid Deployment](/dagster-plus/deployment/deployment-types/hybrid), there are a few additional requirements. - **If using an Amazon Elastic Container Service (ECS), Kubernetes, or Docker agent**, your code must be packaged into a Docker image and pushed to a registry your agent can access. Dagster+ doesn't need access to your image - the agent only needs to be able to pull it. diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-settings.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-settings.md deleted file mode 100644 index bbfa62beba985..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-settings.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Deployment settings" -displayed_sidebar: "dagsterPlus" -sidebar_label: "Deployment settings" -unlisted: true -sidebar_position: 300 ---- - -# Deployment settings diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types.md deleted file mode 100644 index 383e5b696c920..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Deployment types -unlisted: true -sidebar_position: 400 ---- - -# Deployment types diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/configuration-reference.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/configuration-reference.md new file mode 100644 index 0000000000000..62d9f00dcf50d --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/configuration-reference.md @@ -0,0 +1,7 @@ +--- +title: Configuration reference +sidebar_position: 400 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/amazon-ecs/configuration-reference */} diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/existing-vpc.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/existing-vpc.md new file mode 100644 index 0000000000000..edddddfbded2f --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/existing-vpc.md @@ -0,0 +1,7 @@ +--- +title: Existing VPC setup +sidebar_position: 200 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/amazon-ecs/creating-ecs-agent-existing-vpc */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/index.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/index.md new file mode 100644 index 0000000000000..ade5c5b935ffa --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/index.md @@ -0,0 +1,8 @@ +--- +title: Amazon ECS agent +sidebar_position: 50 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/manual-provision.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/manual-provision.md new file mode 100644 index 0000000000000..8604054fa0824 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/manual-provision.md @@ -0,0 +1,7 @@ +--- +title: Manual provision setup +sidebar_position: 300 +unlisted: true +--- + +{/* TODO move content from https://docs.dagster.io/dagster-plus/deployment/agents/amazon-ecs/manually-provisioning-ecs-agent */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/new-vpc.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/new-vpc.md new file mode 100644 index 0000000000000..d68622e6d7eb0 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/new-vpc.md @@ -0,0 +1,7 @@ +--- +title: New VPC setup +sidebar_position: 100 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/amazon-ecs/creating-ecs-agent-new-vpc */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/upgrading-cloudformation.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/upgrading-cloudformation.md new file mode 100644 index 0000000000000..ee612a4ba34d4 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/upgrading-cloudformation.md @@ -0,0 +1,8 @@ +--- +title: Upgrading CloudFormation for an Amazon ECS agent +sidebar_label: Upgrading CloudFormation +sidebar_position: 500 +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/dagster-plus/deployment/agents/amazon-ecs/upgrading-cloudformation-template */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/architecture.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/architecture.md similarity index 96% rename from docs/docs-beta/docs/dagster-plus/deployment/hybrid/architecture.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/architecture.md index 3209f88f7a55d..7c21d41a38430 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/architecture.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/architecture.md @@ -1,11 +1,8 @@ --- title: 'Dagster+ Hybrid architecture' -displayed_sidebar: 'dagsterPlus' -sidebar_position: 100 +sidebar_position: 10 --- -# Dagster+ Hybrid architecture - The Hybrid architecture is the most flexible and secure way to deploy Dagster+. It allows you to run your user code in your environment while leveraging Dagster+'s infrastructure for orchestration and metadata management
@@ -83,7 +80,7 @@ Runs are launched by calling the `dagster api` CLI command in a separate process When runs are launched, the user code process/container streams structured metadata (containing everything that's viewable in the integrated logs viewer in the Dagster+ UI) back to Dagster+ over a well-defined GraphQL interface. Structured metadata is stored in Amazon RDS, encrypted at rest. -By default, the run worker also uploads the compute logs (raw `stdout` and `stderr` from runs) to Dagster+. If you don't want to upload logs, you can disable this feature in the [agent settings](/dagster-plus/deployment/hybrid/agents/settings). +By default, the run worker also uploads the compute logs (raw `stdout` and `stderr` from runs) to Dagster+. If you don't want to upload logs, you can disable this feature in the [agent settings](/dagster-plus/deployment/management/settings/hybrid-agent-settings). ### Ingress diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/configuration.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/configuration.md new file mode 100644 index 0000000000000..1294b30313cfb --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/configuration.md @@ -0,0 +1,7 @@ +--- +title: Docker agent configuration +sidebar_position: 200 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/docker/configuration-reference */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/migration/index.mdx b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/index.md similarity index 59% rename from docs/docs-beta/docs/dagster-plus/deployment/migration/index.mdx rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/index.md index 83ccdabe3b421..cb00c69f21296 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/migration/index.mdx +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/index.md @@ -1,11 +1,8 @@ --- -title: Migration -displayed_sidebar: "dagsterPlus" +title: Docker agent sidebar_position: 30 --- -# Migration - import DocCardList from '@theme/DocCardList'; \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/setup.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/setup.md new file mode 100644 index 0000000000000..f16e0dc8e25a9 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/docker/setup.md @@ -0,0 +1,7 @@ +--- +title: Docker agent setup +sidebar_position: 100 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/docker/configuring-running-docker-agent */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/index.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/index.md similarity index 90% rename from docs/docs-beta/docs/dagster-plus/deployment/hybrid/index.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/index.md index 5a7836ad79bcd..3d96293d0c923 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/index.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/index.md @@ -1,11 +1,9 @@ --- title: "Hybrid deployment" -displayed_sidebar: "dagsterPlus" +sidebar_label: Hybrid sidebar_position: 20 --- -# Hybrid deployment - In a Dagster+ Hybrid deployment, the orchestration control plane is run by Dagster+ while your Dagster code is executed within your environment. [comment]: <> (TODO: Architecture diagram) @@ -23,10 +21,10 @@ To get started with a Hybrid deployment you'll need to: The Dagster+ agent is a long-lived process that polls Dagster+'s API servers for new work. See the following guides for setting up an agent: - - [Kubernetes](/dagster-plus/deployment/hybrid/agents/kubernetes) - - [AWS ECS](/dagster-plus/deployment/hybrid/agents/amazon-ecs-new-vpc) - - [Docker](/dagster-plus/deployment/hybrid/agents/docker) - - [Locally](/dagster-plus/deployment/hybrid/agents/local) + - [Kubernetes](/dagster-plus/deployment/deployment-types/hybrid/kubernetes) + - [AWS ECS](/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/new-vpc) + - [Docker](/dagster-plus/deployment/deployment-types/hybrid/docker) + - [Locally](/dagster-plus/deployment/deployment-types/hybrid/local) ## What you'll see in your environment diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/configuration.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/configuration.md new file mode 100644 index 0000000000000..f3053801d3c1c --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/configuration.md @@ -0,0 +1,7 @@ +--- +title: Kubernetes agent configuration +sidebar_position: 200 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/kubernetes/configuration-reference */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/index.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/index.md new file mode 100644 index 0000000000000..d744a447c3b87 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/index.md @@ -0,0 +1,8 @@ +--- +title: Kubernetes agent +sidebar_position: 40 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/setup.md similarity index 95% rename from docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/setup.md index 3c8612add3d87..619f5ffa72326 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/kubernetes.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/kubernetes/setup.md @@ -1,12 +1,8 @@ --- -title: "Running Dagster+ agents on Kubernetes" -displayed_sidebar: "dagsterPlus" -sidebar_position: 300 -sidebar_label: "Kubernetes" +title: Kubernetes agent setup +sidebar_position: 100 --- -# Running Dagster+ agents on Kubernetes - This page provides instructions for running the [Dagster+ agent](/todo) on a [Kubernetes](https://kubernetes.io) cluster. ## Installation @@ -28,7 +24,7 @@ kubectl create namespace dagster-cloud ### Step 2: Create an agent token secret -[Generate an agent token](/dagster-plus/deployment/hybrid/tokens) and set it as a Kubernetes secret: +[Generate an agent token](/dagster-plus/deployment/management/tokens) and set it as a Kubernetes secret: ```shell kubectl --namespace dagster-cloud create secret generic dagster-cloud-agent-token --from-literal=DAGSTER_CLOUD_AGENT_TOKEN= @@ -90,12 +86,12 @@ There are three places to customize how Dagster interacts with Kubernetes: Changes apply in a hierarchy, for example, a customization for an asset will override a default set globally in the agent configuration. Attributes that are not customized will use the global defaults. -An exhaustive list of settings is available [here](/dagster-plus/deployment/hybrid/agents/settings), but common options are presented below. +An exhaustive list of settings is available [here](/dagster-plus/deployment/management/settings/hybrid-agent-settings), but common options are presented below. ### Configure your agents to serve branch deployments -[Branch deployments](/dagster-plus/features/branch-deployments/index.mdx) are lightweight staging environments created for each code change. To configure your Dagster+ agent to manage them: +[Branch deployments](/dagster-plus/features/ci-cd/branch-deployments/index.md) are lightweight staging environments created for each code change. To configure your Dagster+ agent to manage them: ```yaml # values.yaml @@ -223,7 +219,7 @@ helm --namespace dagster-cloud upgrade agent \ ### Make secrets available to your code -You can make secrets available [through the Dagster+ web interface](/dagster-plus/deployment/environment-variables) or through Kubernetes. Configuring secrets through Kubernetes has the benefit that Dagster+ never stores or accesses the secrets, and they can be managed as code. First, create the Kubernetes secret: +You can make secrets available [through the Dagster+ web interface](/dagster-plus/deployment/management/environment-variables) or through Kubernetes. Configuring secrets through Kubernetes has the benefit that Dagster+ never stores or accesses the secrets, and they can be managed as code. First, create the Kubernetes secret: ```bash kubectl create secret generic database-password-kubernetes-secret \ diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/local.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/local.md similarity index 94% rename from docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/local.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/local.md index 2c3c48aa94460..53c43ba09d468 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/local.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/local.md @@ -1,11 +1,10 @@ --- -title: "Running a Dagster+ agent locally" -displayed_sidebar: "dagsterPlus" -sidebar_position: 600 -sidebar_label: "Local" +title: Running a local agent +sidebar_position: 20 +sidebar_label: Local agent --- -Local agents are a good way to experiment with Dagster+ before deploying a more scalable Hybrid agent like [Kubernetes](/dagster-plus/deployment/hybrid/agents/kubernetes) or [Amazon ECS](/todo). +Local agents are a good way to experiment with Dagster+ before deploying a more scalable Hybrid agent like [Kubernetes](/dagster-plus/deployment/deployment-types/hybrid/kubernetes) or [Amazon ECS](/todo). :::note Local agents aren't well suited for most production use cases. If you're running the local agent in production, make sure that: diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/multiple.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/multiple.md new file mode 100644 index 0000000000000..0df411c9e2b52 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/hybrid/multiple.md @@ -0,0 +1,8 @@ +--- +title: Running multiple agents +sidebar_position: 60 +sidebar_label: Multiple agents +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/deployment/agents/running-multiple-agents */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/index.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/index.md new file mode 100644 index 0000000000000..bd70a65d90ffd --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/index.md @@ -0,0 +1,8 @@ +--- +title: Deployment types +sidebar_position: 20 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/multi-tenancy.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/multi-tenancy.md new file mode 100644 index 0000000000000..afac5b4cce012 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/multi-tenancy.md @@ -0,0 +1,5 @@ +--- +title: Multi-tenant +sidebar_position: 30 +unlisted: true +--- diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/ci-cd-in-serverless.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md similarity index 81% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/ci-cd-in-serverless.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md index e27b93194a034..265a378ea82b0 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/ci-cd-in-serverless.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md @@ -1,17 +1,14 @@ --- -title: 'CI/CD in Serverless ' -displayed_sidebar: 'dagsterPlus' +title: 'CI/CD in Serverless' sidebar_position: 300 --- -# CI/CD in Serverless - -If you're a GitHub or GitLab user, you can use our predefined workflows to seamlessly deploy and synchronize your code to Dagster+. You can also use other Git providers or a local Git repository with our [dagster-cloud CLI](/dagster-plus/features/branch-deployments/dagster-cloud-cli) to run your own CI/CD process. +If you're a GitHub or GitLab user, you can use our predefined workflows to seamlessly deploy and synchronize your code to Dagster+. You can also use other Git providers or a local Git repository with our [dagster-cloud CLI](/dagster-plus/deployment/management/dagster-cloud-cli) to run your own CI/CD process. -If you're a GitHub user, with a single click our GitHub app with GitHub Actions can set up a repo containing skeleton code and configuration for you consistent with Dagster+'s best practices. Pushing your code changes to the `main` branch will automatically deploy them to your `prod` Serverless deployment. Pull requests will spin up ephemeral [branch deployments](/dagster-plus/features/branch-deployments/index.mdx) that you can view in the Dagster+ UI for previewing and testing. +If you're a GitHub user, with a single click our GitHub app with GitHub Actions can set up a repo containing skeleton code and configuration for you consistent with Dagster+'s best practices. Pushing your code changes to the `main` branch will automatically deploy them to your `prod` Serverless deployment. Pull requests will spin up ephemeral [branch deployments](/dagster-plus/features/ci-cd/branch-deployments/index.md) that you can view in the Dagster+ UI for previewing and testing. :::note **If you are importing a Dagster project that's in an existing GitHub repo:** @@ -28,13 +25,13 @@ If you're a GitHub user, with a single click our GitHub app with GitHub Actions -If you're a GitLab user, with a single click our GitLab app can set up a repo containing skeleton code and CI/CD configuration for you consistent with Dagster+'s best practices. Pushing your code changes to the `main` branch will automatically deploy them to your `prod` Serverless deployment. Pull requests will spin up ephemeral [branch deployments](/dagster-plus/features/branch-deployments/index.mdx) that you can view in the Dagster+ UI for previewing and testing. +If you're a GitLab user, with a single click our GitLab app can set up a repo containing skeleton code and CI/CD configuration for you consistent with Dagster+'s best practices. Pushing your code changes to the `main` branch will automatically deploy them to your `prod` Serverless deployment. Pull requests will spin up ephemeral [branch deployments](/dagster-plus/features/ci-cd/branch-deployments/index.md) that you can view in the Dagster+ UI for previewing and testing. -If you don't want to use our automated GitHub/GitLab process, we offer [the powerful `dagster-cloud` command-line interface (CLI)](/dagster-plus/features/branch-deployments/dagster-cloud-cli) that you can use in another CI environment or locally. +If you don't want to use our automated GitHub/GitLab process, we offer [the powerful `dagster-cloud` command-line interface (CLI)](/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli) that you can use in another CI environment or locally. First, [create a new project](/getting-started/quickstart) with the Dagster open source CLI. @@ -62,7 +59,7 @@ install_requires=[ ::: -Next, install the [`dagster-cloud` CLI](/dagster-plus/features/branch-deployments/dagster-cloud-cli) and use its `configure` command to authenticate it to your Dagster+ organization. +Next, install the [`dagster-cloud` CLI](/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli) and use its `configure` command to authenticate it to your Dagster+ organization. **Note:** The CLI requires a recent version of Python 3 and Docker. @@ -71,7 +68,7 @@ pip install dagster-cloud dagster-cloud configure ``` -You can also configure the `dagster-cloud` tool non-interactively; see [the CLI docs](/dagster-plus/features/branch-deployments/dagster-cloud-cli) for more information. +You can also configure the `dagster-cloud` tool non-interactively; see [the CLI docs](/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli) for more information. Finally, deploy your project to Dagster+ using the `serverless` command: diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/dagster-ips.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/dagster-ips.md similarity index 84% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/dagster-ips.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/dagster-ips.md index 9b15bb595293e..2ea95704944f5 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/dagster-ips.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/dagster-ips.md @@ -1,11 +1,9 @@ --- -title: 'IP addresses' -displayed_sidebar: 'dagsterPlus' +title: Dagster+ Serverless IP addresses +sidebar_label: IP addresses sidebar_position: 400 --- -# Dagster+ Serverless IP addresses - Serverless code will make requests from one of the following IP addresses. You may need to whitelist / allowlist them for services your code interacts with. ```plain diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/index.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md similarity index 95% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/index.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md index 0684a378be624..02b9ce40ada82 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/index.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md @@ -1,6 +1,6 @@ --- title: 'Serverless deployment' -displayed_sidebar: 'dagsterPlus' +sidebar_label: Serverless sidebar_position: 10 --- @@ -14,7 +14,7 @@ Dagster+ Serverless is a fully managed version of Dagster+ and is the easiest wa Serverless works best with workloads that primarily orchestrate other services or perform light computation. Most workloads fit into this category, especially those that orchestrate third-party SaaS products like cloud data warehouses and ETL tools. -If any of the following are applicable, you should select [Hybrid deployment](/dagster-plus/deployment/hybrid): +If any of the following are applicable, you should select [Hybrid deployment](/dagster-plus/deployment/deployment-types/hybrid): - You require substantial computational resources. For example, training a large machine learning (ML) model in-process - Your dataset is too large to fit in memory. For example, training a large ML model in-process on a terabyte of data diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/run-isolation.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md similarity index 94% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/run-isolation.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md index 68b58ee1231b5..c9c5d04ab6756 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/run-isolation.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md @@ -1,12 +1,9 @@ --- title: 'Serverless run isolation' -displayed_sidebar: 'dagsterPlus' sidebar_label: 'Run isolation' sidebar_position: 200 --- -# Serverless run isolation - Dagster+ Serverless offers two settings for run isolation: isolated and non-isolated. Isolated runs are the default and are intended for production, while non-isolated runs are intended for faster iteration during development.
@@ -15,7 +12,7 @@ Dagster+ Serverless offers two settings for run isolation: isolated and non-isol To follow the steps in this guide, you'll need: - An active Dagster+ Serverless deployment -- An understanding of [Dagster+ deployment settings](/dagster-plus/deployment/deployment-settings) +- An understanding of [Dagster+ deployment settings](/dagster-plus/deployment/management/settings/deployment-settings)
--- @@ -57,7 +54,7 @@ While launching runs from the Launchpad, un-check `Isolate run environment`. Whe To avoid crashes and memory exhaustion, only one non-isolated run will execute at once by default. While a non-isolated run is in progress, the Launchpad will only allow isolated runs to be launched. -This limit can be configured in [deployment settings](/dagster-plus/deployment/deployment-settings). +This limit can be configured in [deployment settings](/dagster-plus/deployment/management/settings/deployment-settings). ```yaml non_isolated_runs: diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/runtime-environment.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md similarity index 85% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/runtime-environment.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md index 76cf15cb741db..750eefa59919a 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/runtime-environment.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md @@ -1,6 +1,5 @@ --- title: 'Serverless runtime environment' -displayed_sidebar: 'dagsterPlus' sidebar_label: 'Runtime environment' sidebar_position: 100 --- @@ -18,7 +17,7 @@ By default, Dagster+ Serverless will package your code as PEX files and deploys You can add dependencies by including the corresponding Python libraries in your Dagster project's `setup.py` file. These should follow [PEP 508](https://peps.python.org/pep-0508/). - + You can also use a tarball to install a dependency, such as if `pip` is unable to resolve a package using `dependency_links`. For example, `soda` and `soda-snowflake` provide tarballs that you can include in the `install_requires` section: @@ -49,18 +48,18 @@ The default Python version for Dagster+ Serverless is Python 3.9. Python version In your `.github/workflows/deploy.yml` file, update the `PYTHON_VERSION` environment variable with your desired Python version: - + 1. Open your `.gitlab-ci.yml` file. If your `.gitlab-ci.yml` contains an `include` with a link to a Dagster provided CI/CD template: - + Follow the link and replace the contents of your `.gitlab-ci.yml` with the YAML document at the link address. Otherwise, continue to the next step. 3. Update the `PYTHON_VERSION` environment variable with your desired Python version - + @@ -102,7 +101,7 @@ Setting a custom base image isn't supported for GitLab CI/CD workflows out of th In your `.github/workflows/deploy.yml` file, add the `SERVERLESS_BASE_IMAGE_TAG` environment variable and set it to the tag printed out in the previous step: - + @@ -133,7 +132,7 @@ To add data files to your deployment, use the [Data Files Support](https://setup ``` If you want to include the data folder, modify your `setup.py` to add the `package_data` line: - + ## Disable PEX deploys \{#disable-pex} @@ -142,18 +141,18 @@ You have the option to disable PEX-based deploys and deploy using a Docker image In your `.github/workflows/deploy.yml` file, update the `ENABLE_FAST_DEPLOYS` environment variable to `false`: - + 1. Open your `.gitlab-ci.yml` file. If your `.gitlab-ci.yml` contains an `include` with a link to a Dagster provided CI/CD template: - + Follow the link and replace the contents of your `.gitlab-ci.yml` with the YAML document at the link address. Otherwise, continue to the next step. 3. Update the `DISABLE_FAST_DEPLOYS` variable to `true` - + @@ -187,7 +186,7 @@ Setting a custom base image isn't supported for GitLab CI/CD workflows out of th In your `.github/workflows/deploy.yml` file, add the `SERVERLESS_BASE_IMAGE_TAG` environment variable and set it to the tag printed out in the previous step: - + diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/security.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md similarity index 85% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/security.md rename to docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md index d6a29601a7f44..bd1b23f2e1c6e 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/security.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md @@ -1,12 +1,10 @@ --- -title: 'Security & data protection' -displayed_sidebar: 'dagsterPlus' +title: Serverless security & data protection +sidebar_label: 'Security & data protection' sidebar_position: 500 --- -# Serverless security & data protection - -Unlike [Hybrid deployments](/dagster-plus/deployment/hybrid), Serverless deployments on Dagster+ require direct access to your data, secrets and source code. +Unlike [Hybrid deployments](/dagster-plus/deployment/deployment-types/hybrid), Serverless deployments on Dagster+ require direct access to your data, secrets and source code. Secrets and source code are built into the image directly. Images are stored in a per-customer container registry with restricted access. User code is securely sandboxed using modern container sandboxing techniques. @@ -36,6 +34,6 @@ You must have [boto3](https://pypi.org/project/boto3/) or `dagster-cloud[serverl ## Adding environment variables and secrets \{#adding-secrets} -Often you'll need to securely access secrets from your jobs. Dagster+ supports several methods for adding secrets—refer to the [Dagster+ environment variables documentation](/dagster-plus/deployment/environment-variables) for more information. +Often you'll need to securely access secrets from your jobs. Dagster+ supports several methods for adding secrets—refer to the [Dagster+ environment variables documentation](/dagster-plus/deployment/management/environment-variables) for more information. --- diff --git a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/index.mdx b/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/index.mdx deleted file mode 100644 index 6184b57ef8d88..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/index.mdx +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "Environment variables" -displayed_sidebar: "dagsterPlus" -unlisted: true -sidebar_position: 40 ---- - -# Environment variables - -import DocCardList from '@theme/DocCardList'; - - diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-existing-vpc.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-existing-vpc.md deleted file mode 100644 index 24ce5ad107359..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-existing-vpc.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Amazon ECS agents (Existing VPC)" -displayed_sidebar: "dagsterPlus" -sidebar_position: 110 -sidebar_label: "Amazon ECS (Existing VPC)" -unlisted: true ---- diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-new-vpc.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-new-vpc.md deleted file mode 100644 index 8cfbd7c7b48b0..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/amazon-ecs-new-vpc.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Amazon ECS agents (New VPC)" -displayed_sidebar: "dagsterPlus" -sidebar_position: 100 -sidebar_label: "Amazon ECS (New VPC)" -unlisted: true ---- diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/docker.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/docker.md deleted file mode 100644 index ddd98a2f185a3..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/docker.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Docker agents" -displayed_sidebar: "dagsterPlus" -sidebar_position: 200 -sidebar_label: "Docker" -unlisted: true ---- - -# Docker agents diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/index.mdx b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/index.mdx deleted file mode 100644 index 2bd0168cc8167..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/index.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "Agents" -displayed_sidebar: "dagsterPlus" -sidebar_class_name: hidden ---- - -# Agents - -import DocCardList from '@theme/DocCardList'; - - \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/multiple.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/multiple.md deleted file mode 100644 index 0ec8c793882cb..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/multiple.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Using multiple agents" -displayed_sidebar: "dagsterPlus" -sidebar_position: 400 -unlisted: true ---- - -# Use multiple agents with Dagster+ diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/settings.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/settings.md deleted file mode 100644 index 5fa76858ea8f7..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/agents/settings.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Hybrid agent settings" -displayed_sidebar: "dagsterPlus" -sidebar_position: 700 -sidebar_label: "Settings" -unlisted: true ---- - -# Hybrid agent settings diff --git a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/tokens.md b/docs/docs-beta/docs/dagster-plus/deployment/hybrid/tokens.md deleted file mode 100644 index 133556526e526..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/hybrid/tokens.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: 'Hybrid agent tokens' -displayed_sidebar: 'dagsterPlus' -sidebar_position: 200 -unlisted: true ---- - -# Hybrid agent tokens diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/dagster-cloud-cli-reference.md b/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/dagster-cloud-cli-reference.md new file mode 100644 index 0000000000000..90d74f2c112e5 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/dagster-cloud-cli-reference.md @@ -0,0 +1,7 @@ +--- +title: dagster-cloud CLI reference +sidebar_position: 200 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/managing-deployments/dagster-plus-cli#reference */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/index.md b/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/index.md new file mode 100644 index 0000000000000..96f6f0d097bd7 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/index.md @@ -0,0 +1,10 @@ +--- +title: dagster-cloud CLI +sidebar_position: 90 +--- + +The dagster-cloud CLI is a command-line toolkit designed to work with Dagster+. + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/installing-and-configuring.md b/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/installing-and-configuring.md new file mode 100644 index 0000000000000..ff5280c31f89c --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/dagster-cloud-cli/installing-and-configuring.md @@ -0,0 +1,8 @@ +--- +title: Installing and configuring the dagster-cloud CLI +sidebar_position: 100 +unlisted: true +--- + +{/* TODO copy from "Installing the CLI" and "Configuring the CLI" sections of https://docs.dagster.io/dagster-plus/managing-deployments/dagster-plus-cli */} + diff --git a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/agent-config.md b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/agent-config.md similarity index 54% rename from docs/docs-beta/docs/dagster-plus/deployment/environment-variables/agent-config.md rename to docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/agent-config.md index a22abdf31e07b..a800e113a83ba 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/agent-config.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/agent-config.md @@ -1,9 +1,8 @@ --- title: "Set environment variables using agent config" -displayed_sidebar: "dagsterPlus" sidebar_position: 300 sidebar_label: "Set with agent config" unlisted: true --- -# Set environment variables using agent config +{/* TODO move from https://docs.dagster.io/dagster-plus/managing-deployments/setting-environment-variables-agents */} diff --git a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/built-in.md b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/built-in.md similarity index 98% rename from docs/docs-beta/docs/dagster-plus/deployment/environment-variables/built-in.md rename to docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/built-in.md index 89eea22a2bef0..6bf5398f0088e 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/built-in.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/built-in.md @@ -1,11 +1,9 @@ --- title: "Built-in environment variables" -displayed_sidebar: "dagsterPlus" sidebar_position: 100 sidebar_label: "Built-in variables" --- - [Dagster+](/todo) provides a set of built-in, automatically populated environment variables, such as the name of a deployment or details about a branch deployment commit, that can be used to modify behavior based on environment. ### All deployment variables diff --git a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/dagster-ui.md b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/dagster-ui.md similarity index 95% rename from docs/docs-beta/docs/dagster-plus/deployment/environment-variables/dagster-ui.md rename to docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/dagster-ui.md index a4c76d4dba0b6..705aae2cba831 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/environment-variables/dagster-ui.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/dagster-ui.md @@ -1,6 +1,5 @@ --- title: "Setting environment variables with the Dagster+ UI" -displayed_sidebar: "dagsterPlus" sidebar_position: 200 sidebar_label: "Set with Dagster+ UI" --- @@ -90,4 +89,4 @@ For example, if you wanted to provide different Snowflake passwords for your pro ## Next steps - Learn how to [access environment variables in Dagster code](/todo) -- Learn about the [built-in environment variables](https://docs.dagster.io/dagster-plus/managing-deployments/environment-variables-and-secrets#built-in-environment-variables) provided by Dagster+ +- Learn about the [built-in environment variables](built-in) provided by Dagster+ diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/index.md b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/index.md new file mode 100644 index 0000000000000..59dace1b3724b --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/environment-variables/index.md @@ -0,0 +1,9 @@ +--- +title: Environment variables +sidebar_position: 60 +unlisted: true +--- + +import DocCardList from '@theme/DocCardList'; + + diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.mdx b/docs/docs-beta/docs/dagster-plus/deployment/management/index.md similarity index 53% rename from docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.mdx rename to docs/docs-beta/docs/dagster-plus/deployment/management/index.md index 19ee9983dc77d..144dd10871fe2 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.mdx +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/index.md @@ -1,11 +1,8 @@ --- -title: "SCIM provisioning" -displayed_sidebar: "dagsterPlus" +title: Deployment management sidebar_position: 30 --- -# SCIM provisioning - import DocCardList from '@theme/DocCardList'; \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/managing-compute-logs-and-error-messages.md b/docs/docs-beta/docs/dagster-plus/deployment/management/managing-compute-logs-and-error-messages.md new file mode 100644 index 0000000000000..01279273021f2 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/managing-compute-logs-and-error-messages.md @@ -0,0 +1,6 @@ +--- +title: Managing compute logs and error messages +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/dagster-plus/managing-deployments/controlling-logs */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/managing-multiple-projects-and-teams.md b/docs/docs-beta/docs/dagster-plus/deployment/management/managing-multiple-projects-and-teams.md new file mode 100644 index 0000000000000..cc59bd13364a9 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/managing-multiple-projects-and-teams.md @@ -0,0 +1,6 @@ +--- +title: Managing multiple projects and teams +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/dagster-plus/best-practices/managing-multiple-projects-and-teams */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/rate-limits.md b/docs/docs-beta/docs/dagster-plus/deployment/management/rate-limits.md new file mode 100644 index 0000000000000..b4364e74ff276 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/rate-limits.md @@ -0,0 +1,6 @@ +--- +title: Dagster+ rate limits +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/dagster-plus/references/limits */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/settings/customizing-agent-settings.md b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/customizing-agent-settings.md new file mode 100644 index 0000000000000..df595ee48e153 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/customizing-agent-settings.md @@ -0,0 +1,7 @@ +--- +title: Customizing agent settings in dagster.yaml +sidebar_position: 80 +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/dagster-plus/deployment/agents/customizing-configuration */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/dagster-plus-settings.md b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/dagster-plus-settings.md similarity index 54% rename from docs/docs-beta/docs/dagster-plus/deployment/dagster-plus-settings.md rename to docs/docs-beta/docs/dagster-plus/deployment/management/settings/dagster-plus-settings.md index 0d7330cf5a6a9..ac4d6cfc1af70 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/dagster-plus-settings.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/dagster-plus-settings.md @@ -1,7 +1,6 @@ --- title: "Dagster+ settings" +sidebar_position: 100 unlisted: true -sidebar_position: 200 --- -# Dagster+ settings diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/settings/deployment-settings.md b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/deployment-settings.md new file mode 100644 index 0000000000000..c0cc4dbecca60 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/deployment-settings.md @@ -0,0 +1,7 @@ +--- +title: "Deployment settings" +sidebar_position: 200 +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/dagster-plus/managing-deployments/deployment-settings-reference */} diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/settings/hybrid-agent-settings.md b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/hybrid-agent-settings.md new file mode 100644 index 0000000000000..8b076b2f2e919 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/hybrid-agent-settings.md @@ -0,0 +1,8 @@ +--- +title: "Hybrid agent settings" +sidebar_position: 70 +unlisted: true +--- + +{/* TODO not sure why this page exists, is this covered by "Customizing agent settings"? */} + diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/settings/index.md b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/index.md new file mode 100644 index 0000000000000..0bc19ee72c5b6 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/settings/index.md @@ -0,0 +1,8 @@ +--- +title: Settings +sidebar_position: 70 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/agent-tokens.md b/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/agent-tokens.md new file mode 100644 index 0000000000000..e777a568a9f9f --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/agent-tokens.md @@ -0,0 +1,7 @@ +--- +title: 'Agent tokens' +sidebar_position: 200 +unlisted: true +--- + +{/* TODO move agent token content from https://docs.dagster.io/dagster-plus/account/managing-user-agent-tokens */} diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/index.md b/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/index.md new file mode 100644 index 0000000000000..f42a1600d7018 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/index.md @@ -0,0 +1,8 @@ +--- +title: Tokens +sidebar_position: 80 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/user-tokens.md b/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/user-tokens.md new file mode 100644 index 0000000000000..130e274d49ab7 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/management/tokens/user-tokens.md @@ -0,0 +1,7 @@ +--- +title: User tokens +sidebar_position: 100 +unlisted: true +--- + +{/* TODO move user token content from https://docs.dagster.io/dagster-plus/account/managing-user-agent-tokens */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/migration/index.md b/docs/docs-beta/docs/dagster-plus/deployment/migration/index.md new file mode 100644 index 0000000000000..ea7c4a344ade3 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/deployment/migration/index.md @@ -0,0 +1,8 @@ +--- +title: Migration +sidebar_position: 50 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/deployment/migration/self-hosted-to-dagster-plus.md b/docs/docs-beta/docs/dagster-plus/deployment/migration/self-hosted-to-dagster-plus.md index daee67878b339..e9ea6226a40ff 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/migration/self-hosted-to-dagster-plus.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/migration/self-hosted-to-dagster-plus.md @@ -1,5 +1,6 @@ --- -title: "Migrate from self-hosted to Dagster+" -sidebar_position: 100 +title: Migrating from self-hosted to Dagster+ +sidebar_label: Self-hosted to Dagster+ +sidebar_position: 200 unlisted: true --- diff --git a/docs/docs-beta/docs/dagster-plus/deployment/serverless/transition-hybrid.md b/docs/docs-beta/docs/dagster-plus/deployment/migration/serverless-to-hybrid.md similarity index 63% rename from docs/docs-beta/docs/dagster-plus/deployment/serverless/transition-hybrid.md rename to docs/docs-beta/docs/dagster-plus/deployment/migration/serverless-to-hybrid.md index 1ce8719fbde5e..f7b5d3e556fdd 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/serverless/transition-hybrid.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/migration/serverless-to-hybrid.md @@ -1,10 +1,10 @@ --- -title: "Transitioning to Hybrid" -displayed_sidebar: "dagsterPlus" -sidebar_position: 600 +title: Migrating from Serverless to Hybrid +sidebar_label: Serverless to Hybrid +sidebar_position: 100 --- -After utilizing a Dagster+ [Serverless](/dagster-plus/deployment/serverless) deployment, you may decide to leverage your own infrastructure to execute your code. Transitioning to a Hybrid deployment requires only a few steps and can be done without any loss of execution history or metadata, allowing you to maintain continuity and control over your operations. +After utilizing a Dagster+ [Serverless](/dagster-plus/deployment/deployment-types/serverless) deployment, you may decide to leverage your own infrastructure to execute your code. Transitioning to a Hybrid deployment requires only a few steps and can be done without any loss of execution history or metadata, allowing you to maintain continuity and control over your operations. :::warning Transitioning from Serverless to Hybrid requires some downtime, as your Dagster+ deployment won't have an agent to execute user code. @@ -33,9 +33,9 @@ It may take a few minutes for the agent to deactivate and be removed from the li Next, you'll need to create a Hybrid agent to execute your code. Follow the setup instructions for the agent of your choice: - **[Amazon Web Services (AWS)](/todo)**, which launches user code as Amazon Elastic Container Service (ECS) tasks. -- **[Docker](/dagster-plus/deployment/hybrid/agents/docker)**, which launches user code in Docker containers on your machine -- **[Kubernetes](/dagster-plus/deployment/hybrid/agents/kubernetes)**, which launches user code on a Kubernetes cluster -- **[Local](/dagster-plus/deployment/hybrid/agents/local)**, which launches user code in operating system subprocesses on your machine +- **[Docker](/dagster-plus/deployment/deployment-types/hybrid/docker)**, which launches user code in Docker containers on your machine +- **[Kubernetes](/dagster-plus/deployment/deployment-types/hybrid/kubernetes)**, which launches user code on a Kubernetes cluster +- **[Local](/dagster-plus/deployment/deployment-types/hybrid/local)**, which launches user code in operating system subprocesses on your machine ## Step 3: Confirm successful setup diff --git a/docs/docs-beta/docs/dagster-plus/deployment/multi-tenancy.md b/docs/docs-beta/docs/dagster-plus/deployment/multi-tenancy.md deleted file mode 100644 index 28b41d6d7f9d3..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/multi-tenancy.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Multi-tenancy" -unlisted: true -sidebar_position: 500 ---- - -# Dagster+ multi-tenancy diff --git a/docs/docs-beta/docs/dagster-plus/deployment/user-agent-tokens.md b/docs/docs-beta/docs/dagster-plus/deployment/user-agent-tokens.md deleted file mode 100644 index 8a1b94d891046..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/deployment/user-agent-tokens.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Tokens" -displayed_sidebar: "dagsterPlus" -unlisted: true -sidebar_position: 600 ---- - -# Managing user and agent tokens in Dagster+ diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/cli.md b/docs/docs-beta/docs/dagster-plus/features/alerts/cli.md deleted file mode 100644 index 71e28ce328c5e..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/cli.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Dagster+ alerts with the CLI" -unlisted: true -sidebar_position: 200 ---- - -# Alerts with the CLI diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/configuring-an-alert-notification-service.md b/docs/docs-beta/docs/dagster-plus/features/alerts/configuring-an-alert-notification-service.md new file mode 100644 index 0000000000000..5cd722b49385b --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/alerts/configuring-an-alert-notification-service.md @@ -0,0 +1,52 @@ +--- +title: Configuring an alert notification service +sidebar_position: 100 +--- + +Dagster+ allows you to configure alerts to fire in response to a range of events. These alerts can be sent to a variety of different services, depending on your organization's needs. + +{/* TODO this needs content on the value prop of alerts -- save money, etc */} + +:::note +You must have **Organization**, **Admin**, or **Editor** permissions on Dagster+ to configure an alert notification service. +::: + +Before [creating alerts](creating-alerts), you'll need to configure a service to send alerts. Dagster+ currently supports sending alerts through email, Microsoft Teams, PagerDuty, and Slack. + + + + No additional configuration is required to send emails from Dagster+. + +All alert emails will be sent by `"no-reply@dagster.cloud"` or `"no-reply@.dagster.cloud"`. Alerts can be configured to be sent to any number of emails. + + + Create an incoming webhook by following the [Microsoft Teams documentation](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cdotnet). + +This will provide you with a **webhook URL** which will be required when configuring alerts in the UI (after selecting "Microsoft Teams" as your Notification Service) or using the CLI (in the `notification_service` configuration). + + + + :::note +You will need sufficient permissions in PagerDuty to add or edit services. +::: + +In PagerDuty, you can either: + +- [Create a new service](https://support.pagerduty.com/main/docs/services-and-integrations#create-a-service), and add Dagster+ as an integration, or +- [Edit an existing service](https://support.pagerduty.com/main/docs/services-and-integrations#edit-service-settings) to include Dagster+ as an integration + +When configuring the integration, choose **Dagster+** as the integration type, and choose an integration name in the format `dagster-plus-{your_service_name}`. + +After adding your new integration, you will be taken to a screen containing an **Integration Key**. This value will be required when configuring alerts in the UI (after selecting "PagerDuty" as your Notification Service) or using the CLI (in the `notification_service` configuration). + + + + :::note +You will need sufficient permissions in Slack to add apps to your workspace. +::: +Navigate to **Deployment > Alerts** in the Dagster+ UI and click **Connect to Slack**. From there, you can complete the installation process. + +When setting up an alert, you can choose a Slack channel to send those alerts to. Make sure to invite the `@Dagster+` bot to any channel that you'd like to receive an alert in. + + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/creating-alerts.md b/docs/docs-beta/docs/dagster-plus/features/alerts/creating-alerts.md new file mode 100644 index 0000000000000..8239359b605fd --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/alerts/creating-alerts.md @@ -0,0 +1,277 @@ +--- +title: Creating alerts in Dagster+ +sidebar_position: 200 +--- + +You can create alerts in the Dagster+ UI or using the [`dagster-cloud` CLI](/dagster-plus/deployment/management/dagster-cloud-cli). + +{/* TODO link to dagster-cloud CLI tool doc */} + +:::note +Before you create alerts, you must [configure an alert notification service](configuring-an-alert-notification-service). +::: + +## Alerting when a run fails +You can set up alerts to notify you when a run fails. + +By default, these alerts will target all runs in the deployment, but they can be scoped to runs with a specific tag. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Run alert** from the dropdown. + +5. Select **Job failure**. + +If desired, add **tags** in the format `{key}:{value}` to filter the runs that will be considered. + + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + + +## Alerting when a run is taking too long to complete +You can set up alerts to notify you whenever a run takes more than some threshold amount of time. + + By default, these alerts will target all runs in the deployment, but they can be scoped to runs with a specific tag. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Run alert** from the dropdown. + +5. Select **Job running over** and how many hours to alert after. + +If desired, add **tags** in the format `{key}:{value}` to filter the runs that will be considered. + + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + + +## Alerting when an asset fails to materialize +You can set up alerts to notify you when an asset materialization attempt fails. + +By default, these alerts will target all assets in the deployment, but they can be scoped to a specific asset or group of assets. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Asset alert** from the dropdown. + +5. Select **Failure** under the **Materializations** heading. + +If desired, select a **target** from the dropdown menu to scope this alert to a specific asset or group. + + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + + +## Alerting when an asset check fails +You can set up alerts to notify you when an asset check on an asset fails. + +By default, these alerts will target all assets in the deployment, but they can be scoped to checks on a specific asset or group of assets. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Asset alert** from the dropdown. + +5. Select **Failed (ERROR)** under the **Asset Checks** heading. + +If desired, select a **target** from the dropdown menu to scope this alert to a specific asset or group. + + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + + +## Alerting when a schedule or sensor tick fails +You can set up alerts to fire when any schedule or sensor tick across your entire deployment fails. + +Alerts are sent only when a schedule/sensor transitions from **success** to **failure**, so only the initial failure will trigger the alert. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Schedule/Sensor alert** from the dropdown. + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + + +## Alerting when a code location fails to load +You can set up alerts to fire when any code location fails to load due to an error. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Code location error alert** from the dropdown. + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + + +## Alerting when a Hybrid agent becomes unavailable +:::note +This is only available for [Hybrid](/todo) deployments. +::: + +You can set up alerts to fire if your Hybrid agent hasn't sent a heartbeat in the last 5 minutes. + + + 1. In the Dagster UI, click **Deployment**. +2. Click the **Alerts** tab. +3. Click **Add alert policy**. +4. Select **Code location error alert** from the dropdown. + + + Execute the following command to sync the configured alert policy to your Dagster+ deployment. + + ```bash + dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml + ``` + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/email.md b/docs/docs-beta/docs/dagster-plus/features/alerts/email.md deleted file mode 100644 index 2b516c6b73bac..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/email.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Dagster+ email alerts" -unlisted: true -sidebar_position: 300 ---- - -# Dagster+ email alerts diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/index.md b/docs/docs-beta/docs/dagster-plus/features/alerts/index.md index b869009c354d0..fcdb9c9068ac1 100644 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/index.md +++ b/docs/docs-beta/docs/dagster-plus/features/alerts/index.md @@ -1,322 +1,8 @@ --- -title: Setting up alerts on Dagster+ -sidebar_label: "Dagster+ Alerts" -sidebar_position: 30 +title: Alerts +sidebar_position: 40 --- -[comment]: <> (This file is automatically generated by `dagster-plus/deployment/alerts/generate_alerts_doc.py`) -Dagster+ allows you to configure alerts to automatically fire in response to a range of events. These alerts can be sent to a variety of different services, depending on your organization's needs. +import DocCardList from '@theme/DocCardList'; -These alerts can be configured in the Dagster+ UI, or using the `dagster-cloud` CLI tool. - -
-Prerequisites -- **Organization**, **Admin**, or **Editor** permissions on Dagster+ -
- -## Configuring a notification service - -To start, you'll need to configure a service to send alerts. Dagster+ current supports sending alerts through email, Microsoft Teams, PagerDuty, and Slack. - - - - No additional configuration is required to send emails from Dagster+. - -All alert emails will be sent by `"no-reply@dagster.cloud"` or `"no-reply@.dagster.cloud"`. Alerts can be configured to be sent to any number of emails. - - - Create an incoming webhook by following the [Microsoft Teams documentation](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cdotnet). - -This will provide you with a **webhook URL** which will be required when configuring alerts in the UI (after selecting "Microsoft Teams" as your Notification Service) or using the CLI (in the `notification_service` configuration). - - - - :::note -You will need sufficient permissions in PagerDuty to add or edit services. -::: - -In PagerDuty, you can either: - -- [Create a new service](https://support.pagerduty.com/main/docs/services-and-integrations#create-a-service), and add Dagster+ as an integration, or -- [Edit an existing service](https://support.pagerduty.com/main/docs/services-and-integrations#edit-service-settings) to include Dagster+ as an integration - -When configuring the integration, choose **Dagster+** as the integration type, and choose an integration name in the format `dagster-plus-{your_service_name}`. - -After adding your new integration, you will be taken to a screen containing an **Integration Key**. This value will be required when configuring alerts in the UI (after selecting "PagerDuty" as your Notification Service) or using the CLI (in the `notification_service` configuration). - - - - :::note -You will need sufficient permissions in Slack to add apps to your workspace. -::: -Navigate to **Deployment > Alerts** in the Dagster+ UI and click **Connect to Slack**. From there, you can complete the installation process. - -When setting up an alert, you can choose a Slack channel to send those alerts to. Make sure to invite the `@Dagster+` bot to any channel that you'd like to receive an alert in. - - - - -## Alerting when a run fails -You can set up alerts to notify you when a run fails. - -By default, these alerts will target all runs in the deployment, but they can be scoped to runs with a specific tag. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Run alert** from the dropdown. - -5. Select **Job failure**. - -If desired, add **tags** in the format `{key}:{value}` to filter the runs that will be considered. - - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - - -## Alerting when a run is taking too long to complete -You can set up alerts to notify you whenever a run takes more than some threshold amount of time. - - By default, these alerts will target all runs in the deployment, but they can be scoped to runs with a specific tag. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Run alert** from the dropdown. - -5. Select **Job running over** and how many hours to alert after. - -If desired, add **tags** in the format `{key}:{value}` to filter the runs that will be considered. - - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - - -## Alerting when an asset fails to materialize -You can set up alerts to notify you when an asset materialization attempt fails. - -By default, these alerts will target all assets in the deployment, but they can be scoped to a specific asset or group of assets. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Asset alert** from the dropdown. - -5. Select **Failure** under the **Materializations** heading. - -If desired, select a **target** from the dropdown menu to scope this alert to a specific asset or group. - - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - - -## Alerting when an asset check fails -You can set up alerts to notify you when an asset check on an asset fails. - -By default, these alerts will target all assets in the deployment, but they can be scoped to checks on a specific asset or group of assets. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Asset alert** from the dropdown. - -5. Select **Failed (ERROR)** under the **Asset Checks** heading. - -If desired, select a **target** from the dropdown menu to scope this alert to a specific asset or group. - - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - - -## Alerting when a schedule or sensor tick fails -You can set up alerts to fire when any schedule or sensor tick across your entire deployment fails. - -Alerts are sent only when a schedule/sensor transitions from **success** to **failure**, so only the initial failure will trigger the alert. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Schedule/Sensor alert** from the dropdown. - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - - -## Alerting when a code location fails to load -You can set up alerts to fire when any code location fails to load due to an error. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Code location error alert** from the dropdown. - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - - -## Alerting when a Hybrid agent becomes unavailable -:::note -This is only available for [Hybrid](/todo) deployments. -::: - -You can set up alerts to fire if your Hybrid agent hasn't sent a heartbeat in the last 5 minutes. - - - 1. In the Dagster UI, click **Deployment**. -2. Click the **Alerts** tab. -3. Click **Add alert policy**. -4. Select **Code location error alert** from the dropdown. - - - Execute the following command to sync the configured alert policy to your Dagster+ deployment. - - ```bash - dagster-cloud deployment alert-policies sync -a /path/to/alert_policies.yaml - ``` - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/microsoft-teams.md b/docs/docs-beta/docs/dagster-plus/features/alerts/microsoft-teams.md deleted file mode 100644 index 7c66b3e2dae8b..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/microsoft-teams.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Dagster+ Microsoft Teams alerts" -unlisted: true -sidebar_label: "Microsoft Teams" -sidebar_position: 400 ---- - -# Dagster+ Microsoft Teams alerts diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/pagerduty.md b/docs/docs-beta/docs/dagster-plus/features/alerts/pagerduty.md deleted file mode 100644 index c8a32645e592f..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/pagerduty.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Dagster+ PagerDuty alerts" -unlisted: true -sidebar_label: "PagerDuty" -sidebar_position: 500 ---- - -# Dagster+ PagerDuty alerts diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/slack.md b/docs/docs-beta/docs/dagster-plus/features/alerts/slack.md deleted file mode 100644 index 3d9f5423dd890..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/slack.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Dagster+ Slack alerts" -unlisted: true -sidebar_label: "Slack" -sidebar_position: 600 ---- - -# Dagster+ Slack alerts diff --git a/docs/docs-beta/docs/dagster-plus/features/alerts/ui.md b/docs/docs-beta/docs/dagster-plus/features/alerts/ui.md deleted file mode 100644 index b613282af846e..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/alerts/ui.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Dagster+ alerts in the UI" -unlisted: true -sidebar_label: "UI" -sidebar_position: 100 ---- - -# Alerts in the UI diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/index.mdx b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/index.md similarity index 55% rename from docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/index.mdx rename to docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/index.md index a17a4992483d4..4b3a0e15bfa4f 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/index.mdx +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/index.md @@ -1,11 +1,8 @@ --- title: "Authentication and access control" -displayed_sidebar: "dagsterPlus" -sidebar_position: 40 +sidebar_position: 10 --- -# Authentication and access control - import DocCardList from '@theme/DocCardList'; \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/audit-logs.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/audit-logs.md index cfc6c1cd81337..fd298db800102 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/audit-logs.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/audit-logs.md @@ -1,11 +1,8 @@ --- title: "Audit logs" -displayed_sidebar: "dagsterPlus" sidebar_position: 300 --- -# Audit logs - The Dagster+ audit log enables Dagster+ Pro organizations to track and attribute changes to their Dagster deployment. For large organizations, tracking down when and by whom changes were made can be crucial for maintaining security and compliance. The audit log is also valuable @@ -46,7 +43,7 @@ The **Filter** button near the top left of the page can be used to filter the li | Log in | A user logs in to the Dagster+ organization | | | Update sensor | A user toggles a sensor on or off | The sensor name, code location, and cursor | | Update schedule | A user toggles a schedule on or off | The schedule name, code location, and cursor | -| Update alert policy | A user modifies an [alert policy](/dagster-plus/features/alerts/ui) | The new configuration for the alert policy | +| Update alert policy | A user modifies an [alert policy](/dagster-plus/features/alerts/creating-alerts) | The new configuration for the alert policy | | Create deployment | A user creates a new deployment | Whether the deployment is a branch deployment | | Delete deployment | A user removes an existing deployment | Whether the deployment is a branch deployment | | Create user token | A user creates a new user token | | @@ -55,9 +52,9 @@ The **Filter** button near the top left of the page can be used to filter the li | Create agent token | A user creates a new agent token | | | Revoke agent token | A user revokes an existing agent token | | | Update agent token permissions | A user alters [permissions](/dagster-plus/features/authentication-and-access-control/rbac/user-roles-permissions) for an agent token | The permission grant and targeted deployment | -| Create secret | A user creates a new [environment variable](/dagster-plus/deployment/environment-variables/dagster-ui) | The created variable name | -| Update secret | A user modifies an existing [environment variable](/dagster-plus/deployment/environment-variables/dagster-ui) | The previous and current variable names and whether the value was changed | -| Delete secret | A user removes an [environment variable](/dagster-plus/deployment/environment-variables/dagster-ui) | The deleted variable name | +| Create secret | A user creates a new [environment variable](/dagster-plus/deployment/management/environment-variables/dagster-ui) | The created variable name | +| Update secret | A user modifies an existing [environment variable](/dagster-plus/deployment/management/environment-variables/dagster-ui) | The previous and current variable names and whether the value was changed | +| Delete secret | A user removes an [environment variable](/dagster-plus/deployment/management/environment-variables/dagster-ui) | The deleted variable name | | Update subscription | A user modifies the selected Dagster+ subscription for the organization | The previous and current plan types | ## Programmatic access to audit logs diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/index.mdx b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/index.md similarity index 67% rename from docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/index.mdx rename to docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/index.md index 1443bd749b3b4..5f6a44b46616a 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/index.mdx +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/index.md @@ -1,11 +1,8 @@ --- title: "Role-based access control" -displayed_sidebar: "dagsterPlus" sidebar_position: 10 --- -# Role-based access control - import DocCardList from '@theme/DocCardList'; \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/teams.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/teams.md index dff5866950069..894a4a29f0db9 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/teams.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/teams.md @@ -1,11 +1,9 @@ --- -title: "Team management" -displayed_sidebar: "dagsterPlus" +title: Team management in Dagster+ +sidebar_label: "Team management" sidebar_position: 100 --- -# Team management in Dagster+ - As part of [role-based access control (RBAC)](/dagster-plus/features/authentication-and-access-control/rbac/user-roles-permissions), Dagster+ supports the ability to assign users to teams. A team is a group of users with a set of default deployment, code location, and Branch Deployment user roles.
diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/user-roles-permissions.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/user-roles-permissions.md index 6281ae236cd9e..d6ce4c96de5e3 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/user-roles-permissions.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/user-roles-permissions.md @@ -1,11 +1,9 @@ --- -title: 'User roles & permissions' -displayed_sidebar: 'dagsterPlus' +title: User roles & permissions in Dagster+ +sidebar_label: 'User roles & permissions' sidebar_position: 200 --- -# Understanding user roles & permissions in Dagster+ - Role-based access control (RBAC) enables you to grant specific permissions to users in your organization, ensuring that Dagster users have access to what they require in Dagster+, and no more. In this guide, we'll cover how RBAC works in Dagster+, how to assign roles to users, and the granular permissions for each user role. @@ -44,7 +42,7 @@ Dagster+ Pro users can create teams of users and assign default permission sets. With the exception of the **Organization Admin** role, user and team roles are set on a per-deployment basis. -Organization Admins have access to the entire organization, including all [deployments](/todo), [code locations](/dagster-plus/deployment/code-locations), and [Branch Deployments](dagster-plus/features/branch-deployments/index.mdx). +Organization Admins have access to the entire organization, including all [deployments](/todo), [code locations](/dagster-plus/deployment/code-locations), and [Branch Deployments](dagster-plus/features/ci-cd/branch-deployments/index.md). | Level | Plan | Description | | ------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -128,11 +126,11 @@ Deployment settings are accessed in the UI by navigating to **user menu (your ic |----------------------------------------------------------------------------------------------|-------|-----------|--------|-------|-------------------------------| | View [deployments](/todo) | ✅ | ✅ | ✅ | ✅ | ✅ | | Modify [deployment](/todo) settings | ❌ | ❌ | ✅ | ✅ | ✅ | -| Create, edit, delete [environment variables](/dagster-plus/deployment/environment-variables) | ❌ | ❌ | ✅ | ✅ | ✅ | -| View [environment variable](/dagster-plus/deployment/environment-variables) values | ❌ | ❌ | ✅ | ✅ | ✅ | -| Export [environment variables](/dagster-plus/deployment/environment-variables) | ❌ | ❌ | ✅ | ✅ | ✅ | +| Create, edit, delete [environment variables](/dagster-plus/deployment/management/environment-variables) | ❌ | ❌ | ✅ | ✅ | ✅ | +| View [environment variable](/dagster-plus/deployment/management/environment-variables) values | ❌ | ❌ | ✅ | ✅ | ✅ | +| Export [environment variables](/dagster-plus/deployment/management/environment-variables) | ❌ | ❌ | ✅ | ✅ | ✅ | | Create and delete [deployments](/todo) | ❌ | ❌ | ❌ | ❌ | ✅ | -| Create [Branch Deployments](dagster-plus/features/branch-deployments/index.mdx) | ❌ | ❌ | ✅ | ✅ | ✅ | +| Create [Branch Deployments](dagster-plus/features/ci-cd/branch-deployments/index.md) | ❌ | ❌ | ✅ | ✅ | ✅ | ### Code locations @@ -150,7 +148,7 @@ Agent tokens are accessed in the UI by navigating to **user menu (your icon) > O | | Viewer | Launcher | Editor | Admin | Organization
admin | | ----------------------------------------------------------- | ------ | -------- | ------ | ----- | ------------------------ | -| View [agent tokens](/dagster-plus/deployment/hybrid/tokens) | ❌ | ❌ | ❌ | ❌ | ✅ | +| View [agent tokens](/dagster-plus/deployment/management/tokens/agent-tokens) | ❌ | ❌ | ❌ | ❌ | ✅ | | Create agent tokens | ❌ | ❌ | ❌ | ❌ | ✅ | | Edit agent tokens | ❌ | ❌ | ❌ | ❌ | ✅ | | Revoke agent tokens | ❌ | ❌ | ❌ | ❌ | ✅ | @@ -207,5 +205,5 @@ Team management is accessed in the UI by navigating to **user menu (your icon) > - Learn more about how to manage users in Dagster+ in [Understanding User Management in Dagster+](/dagster-plus/features/authentication-and-access-control/rbac/users) - Learn more about how to manage teams in Dagster+ in [Understanding Team Management in Dagster+](/dagster-plus/features/authentication-and-access-control/rbac/teams) -- Learn more about SCIM provisioning in [Understanding SCIM Provisioning](/dagster-plus/features/authentication-and-access-control/scim/index.mdx) +- Learn more about SCIM provisioning in [Understanding SCIM Provisioning](/dagster-plus/features/authentication-and-access-control/scim/index.md) - Learn more about authentication in [Understanding Authentication](/dagster-plus/features/authentication-and-access-control/sso/authentication) diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/users.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/users.md index 61c3a2f55401f..2f1294cb4fb17 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/users.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/rbac/users.md @@ -1,6 +1,5 @@ --- title: "Managing users in Dagster+" -displayed_sidebar: "dagsterPlus" sidebar_label: "User management" sidebar_position: 400 --- diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/azure-active-directory.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/azure-active-directory.md index 28fd1473a5e56..a27c033a49b64 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/azure-active-directory.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/azure-active-directory.md @@ -1,10 +1,6 @@ --- title: 'Azure Active Directory' -displayed_sidebar: 'dagsterPlus' -unlisted: true -sidebar_position: 200 +sidebar_position: 300 --- -# Azure Active Directory - -See the [Dagster Cloud provisioning tutorial](https://learn.microsoft.com/en-us/azure/active-directory/saas-apps/dagster-cloud-provisioning-tutorial). +See the [Microsoft Dagster Cloud provisioning tutorial](https://learn.microsoft.com/en-us/azure/active-directory/saas-apps/dagster-cloud-provisioning-tutorial). diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/enabling-scim-provisioning.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/enabling-scim-provisioning.md new file mode 100644 index 0000000000000..2effe2befed3a --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/enabling-scim-provisioning.md @@ -0,0 +1,7 @@ +--- +title: Enabling SCIM provisioning +sidebar_position: 100 +unlisted: true +--- + +{/* TODO content from https://docs.dagster.io/dagster-plus/account/authentication/utilizing-scim-provisioning#enabling-scim-provisioning should be copied here */} diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.md new file mode 100644 index 0000000000000..392c7b0be278a --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/index.md @@ -0,0 +1,11 @@ +--- +title: "SCIM provisioning" +sidebar_position: 30 +unlisted: true +--- + +{/* TODO content from top of "Utilizing SCIM provisioning" https://docs.dagster.io/dagster-plus/account/authentication/utilizing-scim-provisioning page and "Understanding SCIM provisioning" section https://docs.dagster.io/dagster-plus/account/authentication/utilizing-scim-provisioning#understanding-scim-provisioning should be copied here. */} + +## User management with SCIM + +## Team management with SCIM \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/okta-scim.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/okta-scim.md index a1dd29b1bf275..c007683bc3df8 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/okta-scim.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/scim/okta-scim.md @@ -1,8 +1,7 @@ --- title: 'Okta SCIM provisioning' -displayed_sidebar: 'dagsterPlus' +sidebar_position: 200 unlisted: true -sidebar_position: 100 --- -# Okta SCIM provisioning +{/* TODO copy from https://docs.dagster.io/dagster-plus/account/authentication/okta/scim-provisioning */} diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/authentication.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/authentication.md index 2c626adac16d8..4a3489acf0fbe 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/authentication.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/authentication.md @@ -1,8 +1,6 @@ --- title: "Authentication" -displayed_sidebar: "dagsterPlus" -unlisted: true sidebar_position: 100 +unlisted: true --- -# Authentication diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/azure-ad-sso.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/azure-ad-sso.md index 5921d30d4d995..969014b7520cd 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/azure-ad-sso.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/azure-ad-sso.md @@ -1,11 +1,9 @@ --- -title: 'Azure Active Directory SSO' -displayed_sidebar: 'dagsterPlus' +title: Setting up Azure Active Directory SSO for Dagster+ +sidebar_label: 'Azure Active Directory SSO' sidebar_position: 200 --- -# Setting up Azure Active Directory SSO for Dagster+ - In this guide, you'll configure Azure Active Directory (AD) to use single sign-on (SSO) with your Dagster+ organization.
diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/google-workspace-sso.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/google-workspace-sso.md index 49727f24ad5c2..6c980a33717f7 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/google-workspace-sso.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/google-workspace-sso.md @@ -1,11 +1,9 @@ --- -title: 'Google Workspace SSO' -displayed_sidebar: 'dagsterPlus' +title: Setting up Google Workspace SSO for Dagster+ +sidebar_label: 'Google Workspace SSO' sidebar_position: 300 --- -# Setting up Google Workspace SSO for Dagster+ - In this guide, you'll configure Google Workspace to use single sign-on (SSO) with your Dagster+ organization.
diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/index.mdx b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/index.md similarity index 69% rename from docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/index.mdx rename to docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/index.md index fe5219e36a95f..e5711aad31dd8 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/index.mdx +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/index.md @@ -1,11 +1,8 @@ --- title: "Single sign-on" -displayed_sidebar: "dagsterPlus" sidebar_position: 20 --- -# Single sign-on - import DocCardList from '@theme/DocCardList'; \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/okta-sso.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/okta-sso.md index 2b9d01f0aeda1..7161afbccd1cb 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/okta-sso.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/okta-sso.md @@ -1,11 +1,9 @@ --- -title: 'Okta SSO' -displayed_sidebar: 'dagsterPlus' +title: Setting up Okta SSO for Dagster+ +sidebar_label: 'Okta SSO' sidebar_position: 400 --- -# Setting up Okta SSO for Dagster+ - In this guide, you'll configure Okta to use single sign-on (SSO) with your Dagster+ organization.
diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/onelogin-sso.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/onelogin-sso.md index 4b9c10a57c1a7..5c4ec8a246dda 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/onelogin-sso.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/onelogin-sso.md @@ -1,11 +1,8 @@ --- title: 'OneLogin SSO' -displayed_sidebar: 'dagsterPlus' sidebar_position: 500 --- -# OneLogin SSO - In this guide, you'll configure OneLogin to use single sign-on (SSO) with your Dagster+ organization. diff --git a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/pingone-sso.md b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/pingone-sso.md index 2c766cb1cfc70..3b824c9c5c24d 100644 --- a/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/pingone-sso.md +++ b/docs/docs-beta/docs/dagster-plus/features/authentication-and-access-control/sso/pingone-sso.md @@ -1,11 +1,9 @@ --- -title: 'PingOne SSO' -displayed_sidebar: 'dagsterPlus' +title: Setting up PingOne SSO for Dagster+ +sidebar_label: 'PingOne SSO' sidebar_position: 600 --- -# Setting up PingOne SSO for Dagster+ - In this guide, you'll configure PingOne to use single sign-on (SSO) with your Dagster+ organization.
diff --git a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/change-tracking.md b/docs/docs-beta/docs/dagster-plus/features/branch-deployments/change-tracking.md deleted file mode 100644 index 40b5a837ae8d6..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/change-tracking.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Change tracking in branch deployments" -displayed_sidebar: "dagsterPlus" -sidebar_position: 200 -sidebar_label: "Change tracking" -unlisted: true ---- - -# Change tracking in branch deployments diff --git a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/dagster-cloud-cli.md b/docs/docs-beta/docs/dagster-plus/features/branch-deployments/dagster-cloud-cli.md deleted file mode 100644 index 76615d4e4ad5d..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/dagster-cloud-cli.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Branch deployments & the dagster-cloud CLI" -displayed_sidebar: "dagsterPlus" -sidebar_position: 300 -sidebar_label: "dagster-cloud CLI" -unlisted: true ---- - -# Use branch deployments with the dagster-cloud CLI diff --git a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/index.mdx b/docs/docs-beta/docs/dagster-plus/features/branch-deployments/index.mdx deleted file mode 100644 index bdb1ae1d19be9..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/index.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "Branch deployments (CI)" -displayed_sidebar: "dagsterPlus" -sidebar_position: 20 ---- - -# Branch deployments (CI) - -import DocCardList from '@theme/DocCardList'; - - \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/testing.md b/docs/docs-beta/docs/dagster-plus/features/branch-deployments/testing.md deleted file mode 100644 index aaf141806d021..0000000000000 --- a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/testing.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Testing against production with branch deployments" -unlisted: true -sidebar_position: 400 ---- - -# Testing against production with branch deployments \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/saved-views.md b/docs/docs-beta/docs/dagster-plus/features/catalog-views.md similarity index 91% rename from docs/docs-beta/docs/dagster-plus/features/saved-views.md rename to docs/docs-beta/docs/dagster-plus/features/catalog-views.md index fc06f04032485..201467bd939ad 100644 --- a/docs/docs-beta/docs/dagster-plus/features/saved-views.md +++ b/docs/docs-beta/docs/dagster-plus/features/catalog-views.md @@ -1,11 +1,8 @@ --- -title: "Saving asset filters as catalog views" -displayed_sidebar: "dagsterPlus" +title: "Catalog views" sidebar_position: 100 --- -# Saving asset filters as catalog views - Catalog views enable you to filter down your view of the Dagster Asset catalog in Dagster+, allowing you to toggle between sets of assets that you care about most. You can save catalog views for your own use or share them with your team. For example, you could create views that: @@ -27,7 +24,7 @@ In this guide, you'll learn how to create, access, and share catalog views with -## Create catalog views +## Creating catalog views To view the Dagster+ Asset catalog, use the **Catalog** button on the top navigation. @@ -39,7 +36,7 @@ To create a new catalog view, you have two options: 1. Create a new catalog view from scratch, from the catalog view menu. 2. Create a new catalog view from your current set of filters. -### Create a new catalog view from scratch +### Creating a new catalog view from scratch 1. Click the catalog view button to open the catalog view menu. From here, click the **New** button. 2. Give the view a name and optionally, a description and icon. @@ -51,7 +48,7 @@ To create a new catalog view, you have two options: Give your view a name and optionally a description and icon. Next, you can select one or more filters to apply to your view by clicking the "Add filters" button. Filters can select a subset of assets based on their metadata, tags, kinds, owners, asset groups, or other properties. -### Create a new catalog view from your current set of filters +### Creating a new catalog view from your current set of filters When viewing the global asset lineage or asset list, you can create a new catalog view from your current set of filters. @@ -61,7 +58,7 @@ When viewing the global asset lineage or asset list, you can create a new catalo 4. To make the view shareable, toggle the **Public view** switch. 5. Click **Create view** to create the view. -## Edit, duplicate, or delete catalog views +## Editing, duplicating, or deleting catalog views 1. Click the catalog view button to open the catalog view menu. 2. Search for the view you want to edit, duplicate, or delete. diff --git a/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/change-tracking.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/change-tracking.md new file mode 100644 index 0000000000000..f798ce75e47bd --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/change-tracking.md @@ -0,0 +1,7 @@ +--- +title: "Change tracking in branch deployments" +sidebar_position: 200 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/managing-deployments/branch-deployments/change-tracking */} diff --git a/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli.md new file mode 100644 index 0000000000000..f5af56c5b9abe --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/dagster-cloud-cli.md @@ -0,0 +1,7 @@ +--- +title: Using branch deployments with the dagster-cloud CLI +sidebar_position: 300 +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/managing-deployments/dagster-plus-cli#using-the-dagster-cloud-cli */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/index.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/index.md new file mode 100644 index 0000000000000..39e2db6935879 --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/index.md @@ -0,0 +1,8 @@ +--- +title: Branch deployments +sidebar_position: 20 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/setting-up-branch-deployments.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/setting-up-branch-deployments.md similarity index 95% rename from docs/docs-beta/docs/dagster-plus/features/branch-deployments/setting-up-branch-deployments.md rename to docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/setting-up-branch-deployments.md index 39ef33b1362cb..79c27ab7f9383 100644 --- a/docs/docs-beta/docs/dagster-plus/features/branch-deployments/setting-up-branch-deployments.md +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/setting-up-branch-deployments.md @@ -1,8 +1,6 @@ --- title: "Setting up branch deployments" -displayed_sidebar: "dagsterPlus" sidebar_position: 100 -sidebar_label: "Setting up branch deployments" --- In this guide, we'll walk you through setting up Branch Deployments for a code location. Once you're finished, any time a PR is created or updated in your repository, it will automatically create or update an associated branch deployment in Dagster+. @@ -76,7 +74,7 @@ Keep the token somewhere handy - you'll need it to complete the setup. ## Step 3: Create and configure an agent :::note -If using [Serverless deployment](/dagster-plus/deployment/serverless), this step can be skipped. +If using [Serverless deployment](/dagster-plus/deployment/deployment-types/serverless), this step can be skipped. ::: While you can use your existing production agent, we recommend creating a dedicated branch deployment agent. This ensures that your production instance isn't negatively impacted by the workload associated with branch deployments. @@ -84,7 +82,7 @@ While you can use your existing production agent, we recommend creating a dedica - 1. **Deploy an ECS agent to serve your branch deployments**. Follow the [ECS agent](/dagster-plus/deployment/hybrid/agents/amazon-ecs-new-vpc) setup guide, making sure to set the **Enable Branch Deployments** parameter if using the CloudFormation template. If you are running an existing agent, follow the [upgrade guide](/dagster-plus/deployment/hybrid/agents/amazon-ecs-existing-vpc) to ensure your template is up-to-date. Then, turn on the **Enable Branch Deployments** parameter. + 1. **Deploy an ECS agent to serve your branch deployments**. Follow the [ECS agent](/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/new-vpc) setup guide, making sure to set the **Enable Branch Deployments** parameter if using the CloudFormation template. If you are running an existing agent, follow the [upgrade guide](/dagster-plus/deployment/deployment-types/hybrid/amazon-ecs/existing-vpc) to ensure your template is up-to-date. Then, turn on the **Enable Branch Deployments** parameter. 2. **Create a private [Amazon Elastic Registry (ECR) repository](https://console.aws.amazon.com/ecr/repositories).** Refer to the [AWS ECR documentation](https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-create.html) for instructions. @@ -108,7 +106,7 @@ While you can use your existing production agent, we recommend creating a dedica - 1. Set up a new Docker agent. Refer to the [Docker agent setup guide](/dagster-plus/deployment/hybrid/agents/docker) for instructions. + 1. Set up a new Docker agent. Refer to the [Docker agent setup guide](/dagster-plus/deployment/deployment-types/hybrid/docker) for instructions. 2. After the agent is set up, modify the `dagster.yaml` file as follows: - Set the `dagster_cloud_api.branch_deployments` field to `true` @@ -121,7 +119,7 @@ While you can use your existing production agent, we recommend creating a dedica - 1. Set up a new Kubernetes agent. Refer to the [Kubernetes agent setup guide](/dagster-plus/deployment/hybrid/agents/kubernetes) for instructions. + 1. Set up a new Kubernetes agent. Refer to the [Kubernetes agent setup guide](/dagster-plus/deployment/deployment-types/hybrid/kubernetes) for instructions. 2. After the agent is set up, modify your Helm values file to include the following: @@ -444,5 +442,5 @@ dagster-cloud deployment add-location \ ## Next steps -- Learn more about [Branch Deployments](/dagster-plus/features/branch-deployments/index.mdx) -- Learn how to [Track changes on a Branch Deployment](/dagster-plus/features/branch-deployments/change-tracking) +- Learn more about [Branch Deployments](/dagster-plus/features/ci-cd/branch-deployments/index.md) +- Learn how to [Track changes on a Branch Deployment](/dagster-plus/features/ci-cd/branch-deployments/change-tracking) diff --git a/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/testing.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/testing.md new file mode 100644 index 0000000000000..8106ced129daa --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/branch-deployments/testing.md @@ -0,0 +1,7 @@ +--- +title: Testing against production with branch deployments +sidebar_position: 400 +unlisted: true +--- + +{/* TODO move from https://docs.dagster.io/guides/dagster/branch_deployments#testing-against-production-with-dagster-branch-deployments */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/ci-cd/ci-cd-file-reference.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/ci-cd-file-reference.md new file mode 100644 index 0000000000000..21c585c75361c --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/ci-cd-file-reference.md @@ -0,0 +1,6 @@ +--- +title: CI/CD file reference +unlisted: true +--- + +{/* TODO copy from https://docs.dagster.io/dagster-plus/references/ci-cd-file-reference */} \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/ci-cd/index.md b/docs/docs-beta/docs/dagster-plus/features/ci-cd/index.md new file mode 100644 index 0000000000000..27f8c4ab52dba --- /dev/null +++ b/docs/docs-beta/docs/dagster-plus/features/ci-cd/index.md @@ -0,0 +1,8 @@ +--- +title: "CI/CD" +sidebar_position: 30 +--- + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs-beta/docs/dagster-plus/features/data-catalog.md b/docs/docs-beta/docs/dagster-plus/features/data-catalog.md index 41afe2b6a7bed..bed4e9bfef93e 100644 --- a/docs/docs-beta/docs/dagster-plus/features/data-catalog.md +++ b/docs/docs-beta/docs/dagster-plus/features/data-catalog.md @@ -1,7 +1,6 @@ --- title: "Data catalog" -unlisted: true sidebar_position: 200 +unlisted: true --- -# Dagster+ data catalog diff --git a/docs/docs-beta/docs/dagster-plus/features/insights/export-metrics.md b/docs/docs-beta/docs/dagster-plus/features/insights/export-metrics.md index 3651b20fdbf4e..219eee2060f41 100644 --- a/docs/docs-beta/docs/dagster-plus/features/insights/export-metrics.md +++ b/docs/docs-beta/docs/dagster-plus/features/insights/export-metrics.md @@ -5,4 +5,3 @@ sidebar_position: 200 unlisted: true --- -# Export metrics from Dagster+ Insights diff --git a/docs/docs-beta/docs/dagster-plus/features/insights/index.md b/docs/docs-beta/docs/dagster-plus/features/insights/index.md index a36a2e9513a76..994cc938df500 100644 --- a/docs/docs-beta/docs/dagster-plus/features/insights/index.md +++ b/docs/docs-beta/docs/dagster-plus/features/insights/index.md @@ -1,11 +1,10 @@ --- -title: 'Insights' +title: Dagster+ Insights +sidebar_label: 'Insights' description: 'Visiblity into historical usage, cost, and metadata.' -sidebar_position: 10 +sidebar_position: 50 --- -# Dagster+ Insights - Using Dagster+ Insights, you can gain visibility into historical usage and cost metrics such as Dagster+ run duration, credit usage, and failures. You can also define your own custom metrics, such as the number of rows processed by an asset. Visualizations are built into the Dagster+ UI, allowing you to explore metrics from Dagster and external systems, such as Google BigQuery, in one place. diff --git a/docs/docs-beta/docs/dagster-plus/getting-started.md b/docs/docs-beta/docs/dagster-plus/getting-started.md index 52b79f7b13418..fb4214b62e4ce 100644 --- a/docs/docs-beta/docs/dagster-plus/getting-started.md +++ b/docs/docs-beta/docs/dagster-plus/getting-started.md @@ -1,10 +1,7 @@ --- title: "Getting started with Dagster+" -displayed_sidebar: "dagsterPlus" --- -# Getting started with Dagster+ - First [create a Dagster+ organization](https://dagster.plus/signup). Note: you can sign up with: - a Google email address - a GitHub account @@ -12,9 +9,9 @@ First [create a Dagster+ organization](https://dagster.plus/signup). Note: you c Next, pick your deployment type. Not sure? -- [Dagster+ Serverless](/dagster-plus/deployment/serverless) is the easiest way to get started and is great for teams with limited DevOps support. In Dagster+ Serverless, your Dagster code is executed in Dagster+. You will need to be okay [giving Dagster+ the credentials](/dagster-plus/deployment/environment-variables) to connect to the tools you want to orchestrate. +- [Dagster+ Serverless](/dagster-plus/deployment/deployment-types/serverless) is the easiest way to get started and is great for teams with limited DevOps support. In Dagster+ Serverless, your Dagster code is executed in Dagster+. You will need to be okay [giving Dagster+ the credentials](/dagster-plus/deployment/management/environment-variables) to connect to the tools you want to orchestrate. -- [Dagster+ Hybrid](/dagster-plus/deployment/hybrid) is great for teams who want to orchestrate tools without giving Dagster+ direct access to your systems. Dagster+ Hybrid requires more DevOps support. +- [Dagster+ Hybrid](/dagster-plus/deployment/deployment-types/hybrid) is great for teams who want to orchestrate tools without giving Dagster+ direct access to your systems. Dagster+ Hybrid requires more DevOps support. The remaining steps depend on your deployment type. @@ -40,7 +37,7 @@ See the guide on [adding code locations](/dagster-plus/deployment/code-locations ## Install a Dagster+ Hybrid agent -Follow [these guides](/dagster-plus/deployment/hybrid) for installing a Dagster+ Hybrid agent. Not sure which agent to pick? We recommend using the Dagster+ Kubernetes agent in most cases. +Follow [these guides](/dagster-plus/deployment/deployment-types/hybrid) for installing a Dagster+ Hybrid agent. Not sure which agent to pick? We recommend using the Dagster+ Kubernetes agent in most cases. ## Setup CI/CD @@ -58,4 +55,4 @@ Refer to the guide for [adding a code location](/dagster-plus/deployment/code-lo ## Next steps -Your Dagster+ account is automatically enrolled in a trial. You can [pick your plan type and enter your billing information](/dagster-plus/deployment/dagster-plus-settings), or [contact the Dagster team](https://dagster.io/contact) if you need support or want to evaluate the Dagster+ Pro plan. +Your Dagster+ account is automatically enrolled in a trial. You can [pick your plan type and enter your billing information](/dagster-plus/deployment/management/settings/dagster-plus-settings), or [contact the Dagster team](https://dagster.io/contact) if you need support or want to evaluate the Dagster+ Pro plan. diff --git a/docs/docs-beta/docs/dagster-plus/index.md b/docs/docs-beta/docs/dagster-plus/index.md index 295a68941b406..fa8e16a0df269 100644 --- a/docs/docs-beta/docs/dagster-plus/index.md +++ b/docs/docs-beta/docs/dagster-plus/index.md @@ -1,16 +1,13 @@ --- title: "About Dagster+" -displayed_sidebar: 'dagsterPlus' sidebar_position: 1 --- -# About Dagster+ - Dagster+ is a managed orchestration platform built on top of Dagster's open source engine. Dagster+ is built to be the most performant, reliable, and cost effective way for data engineering teams to run Dagster in production. Dagster+ is also great for students, researchers, or individuals who want to explore Dagster with minimal overhead. -Dagster+ comes in two flavors: a fully [Serverless](/dagster-plus/deployment/serverless) offering and a [Hybrid](/dagster-plus/deployment/hybrid) offering. In both cases, Dagster+ does the hard work of managing your data orchestration control plane. Compared to a [Dagster open source deployment](/guides/), Dagster+ manages: +Dagster+ comes in two flavors: a fully [Serverless](/dagster-plus/deployment/deployment-types/serverless) offering and a [Hybrid](/dagster-plus/deployment/deployment-types/hybrid) offering. In both cases, Dagster+ does the hard work of managing your data orchestration control plane. Compared to a [Dagster open source deployment](/guides/), Dagster+ manages: - Dagster's web UI at https://dagster.plus - Metadata stores for data cataloging and cost insights @@ -24,7 +21,7 @@ In addition to managed infrastructure, Dagster+ also adds core capabilities on t - [Alerts](/dagster-plus/features/alerts) to a variety of services like Slack, PagerDuty, and email to notify your team of failed runs, data quality issues, and violated SLAs. - Authentication, [Role Based Access Control](/dagster-plus/features/authentication-and-access-control/rbac), and [Audit Logs](/dagster-plus/features/authentication-and-access-control/rbac/audit-logs) which help teams implement data mesh strategies while remaining compliant. - [Data Catalog](/dagster-plus/features/data-catalog), a powerful search-first experience that builds off of Dagster's best-in-class lineage graph to include searching for assets, metadata, column lineage, and more. -- [Branch Deployments](/dagster-plus/features/branch-deployments/index.mdx) +- [Branch Deployments](/dagster-plus/features/ci-cd/branch-deployments/index.md) Ready to [get started](/dagster-plus/getting-started)? diff --git a/docs/docs-beta/docs/guides/build/configure/managing-concurrency.md b/docs/docs-beta/docs/guides/build/configure/managing-concurrency.md index 59efe3ac2fe5d..133c36e7cf9a6 100644 --- a/docs/docs-beta/docs/guides/build/configure/managing-concurrency.md +++ b/docs/docs-beta/docs/guides/build/configure/managing-concurrency.md @@ -21,7 +21,7 @@ You often want to control the number of concurrent runs for a Dagster job, a spe * Dagster Core, add the following to your [dagster.yaml](/todo) -* In Dagster+, add the following to your [deployment settings](/dagster-plus/deployment/deployment-settings) +* In Dagster+, add the following to your [deployment settings](/dagster-plus/deployment/management/settings/deployment-settings) ```yaml run_queue: @@ -144,7 +144,7 @@ The possible causes for runs remaining in `QUEUED` status depend on whether you' If runs aren't being dequeued in Dagster+, the root causes could be: - * **If using a [hybrid deployment](/dagster-plus/deployment/hybrid)**, the agent serving the deployment may be down. In this situation, runs will be paused. + * **If using a [hybrid deployment](/dagster-plus/deployment/deployment-types/hybrid)**, the agent serving the deployment may be down. In this situation, runs will be paused. * **Dagster+ is experiencing downtime**. Check the [status page](https://dagstercloud.statuspage.io/) for the latest on potential outages. From 28757165c79ba61c86c5a297d0a077ee172e657a Mon Sep 17 00:00:00 2001 From: gibsondan Date: Thu, 12 Dec 2024 17:04:29 -0600 Subject: [PATCH 32/94] Cleanup instance changes in test_asset_backfill_logs after test (#26462) Summary: This test currently leaves backfill storage on, potentially causing issues for other tests. Make it a fixture instead. Test plan BK,: Should unblock test failures on https://github.com/dagster-io/dagster/pull/26189 NOCHANGELOG > Insert changelog entry or delete this section. ## Summary & Motivation ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --- .../daemon_tests/test_backfill.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py b/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py index 9f6bad53bb2ed..a8514ce5becd8 100644 --- a/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py +++ b/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py @@ -2642,19 +2642,28 @@ def test_old_dynamic_partitions_job_backfill( assert instance.get_runs_count() == 4 +@pytest.fixture +def instance_with_backfill_log_storage_enabled(instance): + def override_backfill_storage_setting(self): + return True + + orig_backfill_storage_setting = instance.backfill_log_storage_enabled + + try: + instance.backfill_log_storage_enabled = override_backfill_storage_setting.__get__( + instance, DagsterInstance + ) + yield instance + finally: + instance.backfill_log_storage_enabled = orig_backfill_storage_setting + + def test_asset_backfill_logs( - instance: DagsterInstance, + instance_with_backfill_log_storage_enabled: DagsterInstance, workspace_context: WorkspaceProcessContext, remote_repo: RemoteRepository, ): - # need to override this method on the instance since it defaults ot False in OSS. When we enable this - # feature in OSS we can remove this override - def override_backfill_storage_setting(self): - return True - - instance.backfill_log_storage_enabled = override_backfill_storage_setting.__get__( - instance, DagsterInstance - ) + instance = instance_with_backfill_log_storage_enabled partition_keys = static_partitions.get_partition_keys() asset_selection = [AssetKey("foo"), AssetKey("a1"), AssetKey("bar")] From a50a81315788d34e104ecb362a43c56b929d3c46 Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:09:48 -0500 Subject: [PATCH 33/94] [dagster-fivetran] Support fetch_column_metadata in FivetranWorkspace.sync_and_poll (#26110) ## Summary & Motivation This PR implements `FivetranEventIterator.fetch_column_metadata`, which can be called when using the asset decorator like: ```python from dagster_fivetran import FivetranWorkspace, fivetran_assets import dagster as dg fivetran_workspace = FivetranWorkspace( account_id=dg.EnvVar("FIVETRAN_ACCOUNT_ID"), api_key=dg.EnvVar("FIVETRAN_API_KEY"), api_secret=dg.EnvVar("FIVETRAN_API_SECRET"), ) @fivetran_assets( connector_id="fivetran_connector_id", workspace=fivetran_workspace, ) def fivetran_connector_assets(context: dg.AssetExecutionContext, fivetran: FivetranWorkspace): yield from fivetran.sync_and_poll(context=context).fetch_column_metadata() ``` ## How I Tested These Changes Additional test with BK ## Changelog [dagster-fivetran] Column metadata can be fetched for Fivetran assets using `FivetranWorkspace.sync_and_poll(...).fetch_column_metadata()` --- .../fivetran_event_iterator.py | 130 +++++++++++++++- .../dagster_fivetran/resources.py | 17 ++- .../dagster_fivetran/translator.py | 11 +- .../dagster_fivetran/utils.py | 22 +-- .../experimental/conftest.py | 4 +- .../experimental/test_columns_metadata.py | 144 ++++++++++++++++++ 6 files changed, 307 insertions(+), 21 deletions(-) create mode 100644 python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/test_columns_metadata.py diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py index aa24c23cd061f..f1ea98a332760 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/fivetran_event_iterator.py @@ -1,15 +1,69 @@ -from typing import TYPE_CHECKING, Iterator, Union +import os +from concurrent.futures import ThreadPoolExecutor +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, Union -from dagster import AssetMaterialization, MaterializeResult +from dagster import ( + AssetExecutionContext, + AssetMaterialization, + MaterializeResult, + OpExecutionContext, + _check as check, +) +from dagster._annotations import experimental, public +from dagster._core.definitions.metadata.metadata_set import TableMetadataSet +from dagster._core.utils import imap from typing_extensions import TypeVar +from dagster_fivetran.translator import FivetranMetadataSet +from dagster_fivetran.utils import get_column_schema_for_columns, get_fivetran_connector_table_name + if TYPE_CHECKING: from dagster_fivetran.resources import FivetranWorkspace - FivetranEventType = Union[AssetMaterialization, MaterializeResult] T = TypeVar("T", bound=FivetranEventType) +DEFAULT_MAX_THREADPOOL_WORKERS = 10 + + +def _fetch_column_metadata( + materialization: FivetranEventType, + fivetran_workspace: "FivetranWorkspace", +) -> Dict[str, Any]: + """Subroutine to fetch column metadata for a given table from the Fivetran API.""" + materialization_metadata = check.not_none(materialization.metadata) + connector_id = check.not_none( + FivetranMetadataSet.extract(materialization_metadata).connector_id + ) + schema_name = check.not_none( + FivetranMetadataSet.extract(materialization_metadata).destination_schema_name + ) + table_name = check.not_none( + FivetranMetadataSet.extract(materialization_metadata).destination_table_name + ) + + client = fivetran_workspace.get_client() + + metadata = {} + try: + table_conn_data = client.get_columns_config_for_table( + connector_id=connector_id, + schema_name=schema_name, + table_name=table_name, + ) + + columns = check.dict_elem(table_conn_data, "columns") + metadata = {**TableMetadataSet(column_schema=get_column_schema_for_columns(columns))} + except Exception as e: + client._log.warning( # noqa + f"An error occurred while fetching column metadata for table " + f"{get_fivetran_connector_table_name(schema_name=schema_name, table_name=table_name)}." + "Column metadata will not be included in the event.\n\n" + f"Exception: {e}", + exc_info=True, + ) + return metadata + class FivetranEventIterator(Iterator[T]): """A wrapper around an iterator of Fivetran events which contains additional methods for @@ -20,12 +74,82 @@ def __init__( self, events: Iterator[T], fivetran_workspace: "FivetranWorkspace", + context: Union[OpExecutionContext, AssetExecutionContext], ) -> None: self._inner_iterator = events self._fivetran_workspace = fivetran_workspace + self._context = context def __next__(self) -> T: return next(self._inner_iterator) def __iter__(self) -> "FivetranEventIterator[T]": return self + + @experimental + @public + def fetch_column_metadata(self) -> "FivetranEventIterator": + """Fetches column metadata for each table synced with the Fivetran API. + + Retrieves the column schema for each destination table. + + Returns: + FivetranEventIterator: An iterator of Dagster events with column metadata attached. + """ + fetch_metadata_fn: Callable[ + [FivetranEventType], + Dict[str, Any], + ] = lambda materialization: _fetch_column_metadata( + materialization=materialization, + fivetran_workspace=self._fivetran_workspace, + ) + + return self._attach_metadata(fetch_metadata_fn) + + def _attach_metadata( + self, + fn: Callable[[FivetranEventType], Dict[str, Any]], + ) -> "FivetranEventIterator": + """Runs a threaded task to attach metadata to each event in the iterator. + + Args: + fn (Callable[[Union[AssetMaterialization, MaterializeResult]], Dict[str, Any]]): + A function which takes a FivetranEventType and returns + a dictionary of metadata to attach to the event. + + Returns: + Iterator[Union[AssetMaterialization, MaterializeResult]]: + A set of corresponding Dagster events for Fivetran tables, with any metadata output + by the function attached, yielded in the order they are emitted by the Fivetran API. + """ + + def _map_fn(event: FivetranEventType) -> FivetranEventType: + return event._replace(metadata={**check.is_dict(event.metadata), **fn(event)}) + + def _threadpool_wrap_map_fn() -> Iterator[FivetranEventType]: + assets_def = self._context.assets_def + connector_id = next( + check.not_none(FivetranMetadataSet.extract(spec.metadata).connector_id) + for spec in assets_def.specs + ) + + with ThreadPoolExecutor( + max_workers=int( + os.getenv( + "FIVETRAN_POSTPROCESSING_THREADPOOL_WORKERS", + default=DEFAULT_MAX_THREADPOOL_WORKERS, + ) + ), + thread_name_prefix=f"fivetran_{connector_id}", + ) as executor: + yield from imap( + executor=executor, + iterable=self._inner_iterator, + func=_map_fn, + ) + + return FivetranEventIterator( + events=_threadpool_wrap_map_fn(), + fivetran_workspace=self._fivetran_workspace, + context=self._context, + ) diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py index cd464f8f54d3e..82b36a45ad1bd 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/resources.py @@ -4,7 +4,7 @@ import time from datetime import datetime, timedelta from functools import partial -from typing import Any, Callable, Iterator, Mapping, Optional, Sequence, Tuple, Union +from typing import Any, Callable, Mapping, Optional, Sequence, Tuple, Union from urllib.parse import urljoin import requests @@ -968,11 +968,11 @@ def _generate_materialization( schema_config_details=fivetran_output.schema_config ) - for schema_source_name, schema in schema_config.schemas.items(): + for schema in schema_config.schemas.values(): if not schema.enabled: continue - for table_source_name, table in schema.tables.items(): + for table in schema.tables.values(): if not table.enabled: continue @@ -1005,14 +1005,17 @@ def _generate_materialization( schema=schema.name_in_destination, table=table.name_in_destination, ), - "schema_source_name": schema_source_name, - "table_source_name": table_source_name, + **FivetranMetadataSet( + connector_id=connector.id, + destination_schema_name=schema.name_in_destination, + destination_table_name=table.name_in_destination, + ), }, ) def sync_and_poll( self, context: Union[OpExecutionContext, AssetExecutionContext] - ) -> Iterator[Union[AssetMaterialization, MaterializeResult]]: + ) -> FivetranEventIterator[Union[AssetMaterialization, MaterializeResult]]: """Executes a sync and poll process to materialize Fivetran assets. Args: @@ -1025,7 +1028,7 @@ def sync_and_poll( or AssetMaterialization. """ return FivetranEventIterator( - events=self._sync_and_poll(context=context), fivetran_workspace=self + events=self._sync_and_poll(context=context), fivetran_workspace=self, context=context ) def _sync_and_poll(self, context: Union[OpExecutionContext, AssetExecutionContext]): diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/translator.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/translator.py index 3a35d335703b5..054b6cee51301 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/translator.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/translator.py @@ -251,6 +251,8 @@ def to_fivetran_connector_table_props_data(self) -> Sequence[FivetranConnectorTa class FivetranMetadataSet(NamespacedMetadataSet): connector_id: Optional[str] = None + destination_schema_name: Optional[str] = None + destination_table_name: Optional[str] = None @classmethod def namespace(cls) -> str: @@ -284,7 +286,14 @@ def get_asset_spec(self, props: FivetranConnectorTableProps) -> AssetSpec: table=table_name, ) - augmented_metadata = {**metadata, **FivetranMetadataSet(connector_id=props.connector_id)} + augmented_metadata = { + **metadata, + **FivetranMetadataSet( + connector_id=props.connector_id, + destination_schema_name=schema_name, + destination_table_name=table_name, + ), + } return AssetSpec( key=AssetKey(props.table.split(".")), diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran/utils.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran/utils.py index 13c67b76135b0..0ec34676aadd8 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran/utils.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran/utils.py @@ -61,15 +61,7 @@ def metadata_for_table( table_name = None if table_data.get("columns"): columns = check.dict_elem(table_data, "columns") - table_columns = sorted( - [ - TableColumn(name=col["name_in_destination"], type="") - for col in columns.values() - if "name_in_destination" in col and col.get("enabled") - ], - key=lambda col: col.name, - ) - column_schema = TableSchema(columns=table_columns) + column_schema = get_column_schema_for_columns(columns=columns) if include_column_info: metadata["column_info"] = MetadataValue.json(columns) @@ -84,6 +76,18 @@ def metadata_for_table( return metadata +def get_column_schema_for_columns(columns: Mapping[str, Any]): + table_columns = sorted( + [ + TableColumn(name=col["name_in_destination"], type="") + for col in columns.values() + if "name_in_destination" in col and col.get("enabled") + ], + key=lambda col: col.name, + ) + return TableSchema(columns=table_columns) + + def _table_data_to_materialization( fivetran_output: FivetranOutput, asset_key_prefix: Sequence[str], diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/conftest.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/conftest.py index 76df67e6416e3..a28903099a709 100644 --- a/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/conftest.py +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/conftest.py @@ -20,6 +20,8 @@ TEST_SCHEMA_NAME = "schema_name_in_destination_1" TEST_TABLE_NAME = "table_name_in_destination_1" +TEST_SECOND_SCHEMA_NAME = "schema_name_in_destination_2" +TEST_SECOND_TABLE_NAME = "table_name_in_destination_2" TEST_ANOTHER_TABLE_NAME = "another_table_name_in_destination_1" # Taken from Fivetran API documentation @@ -343,7 +345,7 @@ def get_sample_schema_config_for_connector(table_name: str) -> Mapping[str, Any] "is_primary_key": True, }, "property2": { - "name_in_destination": "column_name_in_destination_1", + "name_in_destination": "column_name_in_destination_2", "enabled": True, "hashed": False, "enabled_patch_settings": { diff --git a/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/test_columns_metadata.py b/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/test_columns_metadata.py new file mode 100644 index 0000000000000..5550a82c9bce3 --- /dev/null +++ b/python_modules/libraries/dagster-fivetran/dagster_fivetran_tests/experimental/test_columns_metadata.py @@ -0,0 +1,144 @@ +import re +from unittest.mock import MagicMock + +import pytest +import responses +from dagster import AssetExecutionContext, AssetKey, TableColumn, TableSchema +from dagster._config.field_utils import EnvVar +from dagster._core.definitions.materialize import materialize +from dagster._core.definitions.metadata import TableMetadataSet +from dagster._core.definitions.metadata.table import TableColumnConstraints, TableConstraints +from dagster._core.test_utils import environ +from dagster_fivetran import FivetranWorkspace, fivetran_assets + +from dagster_fivetran_tests.experimental.conftest import ( + SAMPLE_SOURCE_TABLE_COLUMNS_CONFIG, + TEST_ACCOUNT_ID, + TEST_API_KEY, + TEST_API_SECRET, + TEST_SCHEMA_NAME, + TEST_SECOND_SCHEMA_NAME, + TEST_SECOND_TABLE_NAME, + TEST_TABLE_NAME, + get_fivetran_connector_api_url, +) + + +def test_column_schema( + connector_id: str, + fetch_workspace_data_api_mocks: responses.RequestsMock, + sync_and_poll: MagicMock, + capsys: pytest.CaptureFixture, +) -> None: + with environ({"FIVETRAN_API_KEY": TEST_API_KEY, "FIVETRAN_API_SECRET": TEST_API_SECRET}): + test_connector_api_url = get_fivetran_connector_api_url(connector_id) + for schema_name, table_name in [ + (TEST_SCHEMA_NAME, TEST_TABLE_NAME), + (TEST_SCHEMA_NAME, TEST_SECOND_TABLE_NAME), + (TEST_SECOND_SCHEMA_NAME, TEST_TABLE_NAME), + (TEST_SECOND_SCHEMA_NAME, TEST_SECOND_TABLE_NAME), + ]: + fetch_workspace_data_api_mocks.add( + method=responses.GET, + url=f"{test_connector_api_url}/schemas/{schema_name}/tables/{table_name}/columns", + json=SAMPLE_SOURCE_TABLE_COLUMNS_CONFIG, + status=200, + ) + + workspace = FivetranWorkspace( + account_id=TEST_ACCOUNT_ID, + api_key=EnvVar("FIVETRAN_API_KEY"), + api_secret=EnvVar("FIVETRAN_API_SECRET"), + ) + + @fivetran_assets(connector_id=connector_id, workspace=workspace, name=connector_id) + def my_fivetran_assets(context: AssetExecutionContext, fivetran: FivetranWorkspace): + yield from fivetran.sync_and_poll(context=context).fetch_column_metadata() + + for schema_name, table_name in [ + (TEST_SCHEMA_NAME, TEST_TABLE_NAME), + (TEST_SCHEMA_NAME, TEST_SECOND_TABLE_NAME), + (TEST_SECOND_SCHEMA_NAME, TEST_TABLE_NAME), + (TEST_SECOND_SCHEMA_NAME, TEST_SECOND_TABLE_NAME), + ]: + table_spec = my_fivetran_assets.get_asset_spec( + AssetKey( + [ + schema_name, + table_name, + ] + ) + ) + spec_table_schema = TableMetadataSet.extract(table_spec.metadata).column_schema + + expected_spec_table_schema = TableSchema( + columns=[ + TableColumn( + name="column_name_in_destination_1", + type="", + description=None, + constraints=TableColumnConstraints(nullable=True, unique=False, other=[]), + tags={}, + ), + TableColumn( + name="column_name_in_destination_2", + type="", + description=None, + constraints=TableColumnConstraints(nullable=True, unique=False, other=[]), + tags={}, + ), + ], + constraints=TableConstraints(other=[]), + ) + + assert spec_table_schema == expected_spec_table_schema + + result = materialize( + [my_fivetran_assets], + resources={"fivetran": workspace}, + ) + assert result.success + + for schema_name, table_name in [ + (TEST_SCHEMA_NAME, TEST_TABLE_NAME), + (TEST_SCHEMA_NAME, TEST_SECOND_TABLE_NAME), + (TEST_SECOND_SCHEMA_NAME, TEST_TABLE_NAME), + (TEST_SECOND_SCHEMA_NAME, TEST_SECOND_TABLE_NAME), + ]: + table_schema_by_asset_key = { + event.materialization.asset_key: TableMetadataSet.extract( + event.materialization.metadata + ).column_schema + for event in result.get_asset_materialization_events() + if event.materialization.asset_key + == AssetKey( + [ + schema_name, + table_name, + ] + ) + } + expected_table_schema_by_asset_key = { + AssetKey( + [ + schema_name, + table_name, + ] + ): TableSchema( + columns=[ + TableColumn("column_name_in_destination_1", type=""), + TableColumn("column_name_in_destination_2", type=""), + ] + ), + } + + assert table_schema_by_asset_key == expected_table_schema_by_asset_key + + captured = capsys.readouterr() + # If an exception occurs in fetch_column_metadata, + # a message is logged as a warning and the exception is not raised. + # We test that this message is not in the logs. + assert not re.search( + r"dagster - WARNING - (?s:.)+ - An error occurred while fetching column metadata for table", + captured.err, + ) From acb823229cbb206c2c4b626a96d158f60520c16a Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Thu, 12 Dec 2024 17:33:27 -0600 Subject: [PATCH 34/94] [asset backfill] fix self dependency with backfill policy issues (#26419) Currently the evaluation for determining what can be run together in an asset backfill looks at the previous results that have been resolved so far during breadth first search over the topo-sorted graph. For self dependencies, the `len(asset_partitions_to_request_map[parent.asset_key]) == parent_target_subset.size` would fail since `parent` is the `candidate` and we in the middle of filling `asset_partitions_to_request_map` with `parent_target_subset`. This failure would cause the backfill to issue the partitions of the self dependency iteratively. This additionally created a mismatch in expectations between the backfill and how the runs would end up getting split up, causing dependencies to not be respected. Both of these issues are fixed by disregarding that check if we are evaluating a self dependency. ## How I Tested These Changes added test ## Changelog Assets with self dependencies and `BackfillPolicy` are now evaluated correctly during backfills. Self dependent assets no longer result in serial partition submissions or disregarded upstream dependencies. --- .../dagster/_core/execution/asset_backfill.py | 9 +- .../daemon_tests/test_backfill.py | 101 +++++++++++++++++- 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/python_modules/dagster/dagster/_core/execution/asset_backfill.py b/python_modules/dagster/dagster/_core/execution/asset_backfill.py index 590ad6f7ecb82..5d33dc5246b6c 100644 --- a/python_modules/dagster/dagster/_core/execution/asset_backfill.py +++ b/python_modules/dagster/dagster/_core/execution/asset_backfill.py @@ -1605,6 +1605,8 @@ def can_run_with_parent( candidate.asset_key, parent_asset_key=parent.asset_key ) + is_self_dependency = parent.asset_key == candidate.asset_key + parent_node = asset_graph.get(parent.asset_key) candidate_node = asset_graph.get(candidate.asset_key) # checks if there is a simple partition mapping between the parent and the child @@ -1666,8 +1668,11 @@ def can_run_with_parent( or parent_node.backfill_policy.max_partitions_per_run > len(asset_partitions_to_request_map[parent.asset_key]) ) - # all targeted parents are being requested this tick - and len(asset_partitions_to_request_map[parent.asset_key]) == parent_target_subset.size + # all targeted parents are being requested this tick, or its a self dependency + and ( + len(asset_partitions_to_request_map[parent.asset_key]) == parent_target_subset.size + or is_self_dependency + ) ) ): return True, "" diff --git a/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py b/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py index a8514ce5becd8..740e8bb9ae0a3 100644 --- a/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py +++ b/python_modules/dagster/dagster_tests/daemon_tests/test_backfill.py @@ -11,6 +11,7 @@ from dagster import ( AllPartitionMapping, Any, + AssetDep, AssetExecutionContext, AssetIn, AssetKey, @@ -24,6 +25,7 @@ Out, Output, StaticPartitionMapping, + TimeWindowPartitionMapping, _seven, asset, daily_partitioned_config, @@ -68,6 +70,7 @@ DagsterRunStatus, RunsFilter, ) +from dagster._core.storage.partition_status_cache import AssetPartitionStatus from dagster._core.storage.tags import ( ASSET_PARTITION_RANGE_END_TAG, ASSET_PARTITION_RANGE_START_TAG, @@ -402,18 +405,40 @@ def daily_2(daily_1): partitions_def=daily_partitions_def, backfill_policy=BackfillPolicy.single_run(), ) -def asset_with_single_run_backfill_policy(): - return 1 +def asset_with_single_run_backfill_policy() -> None: + pass @asset( partitions_def=daily_partitions_def, backfill_policy=BackfillPolicy.multi_run(), ) -def asset_with_multi_run_backfill_policy(): +def asset_with_multi_run_backfill_policy() -> None: pass +@asset( + partitions_def=daily_partitions_def, + backfill_policy=BackfillPolicy.single_run(), + deps=[ + asset_with_single_run_backfill_policy, + AssetDep( + "complex_asset_with_backfill_policy", + partition_mapping=TimeWindowPartitionMapping(start_offset=-1, end_offset=-1), + ), + ], +) +def complex_asset_with_backfill_policy(context: AssetExecutionContext) -> None: + statuses = context.instance.get_status_by_partition( + asset_key=asset_with_single_run_backfill_policy.key, + partition_keys=context.partition_keys, + partitions_def=daily_partitions_def, + ) + assert statuses + context.log.info(f"got {statuses}") + assert all(status == AssetPartitionStatus.MATERIALIZED for status in statuses.values()) + + asset_job_partitions = StaticPartitionsDefinition(["a", "b", "c", "d"]) @@ -490,6 +515,7 @@ def the_repo(): downstream_of_fails_once_asset_c, asset_with_single_run_backfill_policy, asset_with_multi_run_backfill_policy, + complex_asset_with_backfill_policy, bp_single_run, bp_single_run_config, bp_multi_run, @@ -2276,6 +2302,75 @@ def test_asset_backfill_with_multi_run_backfill_policy( ] +def test_complex_asset_with_backfill_policy( + instance: DagsterInstance, workspace_context: WorkspaceProcessContext +): + # repro of bug + partitions = ["2023-01-01", "2023-01-02", "2023-01-03"] + asset_graph = workspace_context.create_request_context().asset_graph + + backfill_id = "complex_asset_with_backfills" + backfill = PartitionBackfill.from_partitions_by_assets( + backfill_id=backfill_id, + asset_graph=asset_graph, + backfill_timestamp=get_current_timestamp(), + tags={}, + dynamic_partitions_store=instance, + partitions_by_assets=[ + PartitionsByAssetSelector( + asset_key=asset_with_single_run_backfill_policy.key, + partitions=PartitionsSelector( + [PartitionRangeSelector(partitions[0], partitions[-1])] + ), + ), + PartitionsByAssetSelector( + asset_key=complex_asset_with_backfill_policy.key, + partitions=PartitionsSelector( + [PartitionRangeSelector(partitions[0], partitions[-1])] + ), + ), + ], + title=None, + description=None, + ) + instance.add_backfill(backfill) + + assert instance.get_runs_count() == 0 + backfill = instance.get_backfill(backfill_id) + assert backfill + assert backfill.status == BulkActionStatus.REQUESTED + assert backfill.asset_selection == [ + asset_with_single_run_backfill_policy.key, + complex_asset_with_backfill_policy.key, + ] + + assert all( + not error + for error in list( + execute_backfill_iteration( + workspace_context, get_default_daemon_logger("BackfillDaemon") + ) + ) + ) + + # 1 run for the full range + assert instance.get_runs_count() == 1 + wait_for_all_runs_to_start(instance, timeout=30) + wait_for_all_runs_to_finish(instance, timeout=30) + + assert all( + not error + for error in list( + execute_backfill_iteration( + workspace_context, get_default_daemon_logger("BackfillDaemon") + ) + ) + ) + backfill = instance.get_backfill(backfill_id) + assert backfill + assert backfill.status == BulkActionStatus.COMPLETED_SUCCESS + + def test_error_code_location( caplog, instance, workspace_context, unloadable_location_workspace_context ): From 72e891a9c1f4813196770e22c9c898f62e3b587d Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Thu, 12 Dec 2024 17:55:30 -0600 Subject: [PATCH 35/94] fix assets_modern_data_stack (#26464) remove bad old pin --- examples/assets_modern_data_stack/setup.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/assets_modern_data_stack/setup.py b/examples/assets_modern_data_stack/setup.py index 419a06850ae31..2b0aabbd2d2f1 100644 --- a/examples/assets_modern_data_stack/setup.py +++ b/examples/assets_modern_data_stack/setup.py @@ -23,11 +23,6 @@ "dagster-webserver", "pytest", ], - "test": [ - # cant build psycopg2 in buildkite - # something about the 1.8.0 dependency setup to avoid psycopg2-binary on linux - # seems to prevent that dependency from being used even if explicitly added - "dbt-postgres<1.8.0" - ], + "test": [], }, ) From dc092d47ec9bda47e10f04a8b991e3f05ebd5176 Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Thu, 12 Dec 2024 17:55:33 -0600 Subject: [PATCH 36/94] fix docs build (#26463) new dep ## How I Tested These Changes bk --- examples/docs_beta_snippets/tox.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/docs_beta_snippets/tox.ini b/examples/docs_beta_snippets/tox.ini index 44645d7b1f94e..f294484e22ad2 100644 --- a/examples/docs_beta_snippets/tox.ini +++ b/examples/docs_beta_snippets/tox.ini @@ -12,6 +12,11 @@ install_command = uv pip install {opts} {packages} deps = duckdb plotly + #### + # need deps of dagster-cloud that we need to add since we --no-deps below to avoid reinstalling dagster packages + opentelemetry-api + opentelemetry-sdk + #### -e ../../python_modules/dagster[test] -e ../../python_modules/dagster-pipes -e ../../python_modules/dagster-graphql From a4fdec7053300604c82fec1480bec2d1f22af785 Mon Sep 17 00:00:00 2001 From: Dennis Hume Date: Fri, 13 Dec 2024 07:44:22 -0600 Subject: [PATCH 37/94] [du] consistency issues (#26416) ## Summary & Motivation Minor consistency issues from working through Dagster University ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --- docs/dagster-university/next-env.d.ts | 2 +- .../lesson-2/requirements-and-installation.md | 5 +++-- .../dagster-essentials/lesson-3/whats-an-asset.md | 4 ++-- .../lesson-4/coding-practice-taxi-zones-asset.md | 4 ++-- .../lesson-4/loading-data-into-a-database.md | 14 +++++++------- .../lesson-6/using-resources-in-assets.md | 8 ++++---- .../lesson-7/what-are-schedules.md | 2 +- .../lesson-8/adding-partitions-to-assets.md | 6 +++--- .../coding-practice-partition-taxi-trips.md | 2 +- ...ating-a-schedule-with-a-date-based-partition.md | 6 ++++-- 10 files changed, 28 insertions(+), 25 deletions(-) diff --git a/docs/dagster-university/next-env.d.ts b/docs/dagster-university/next-env.d.ts index 4f11a03dc6cc3..a4a7b3f5cfa2f 100644 --- a/docs/dagster-university/next-env.d.ts +++ b/docs/dagster-university/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-2/requirements-and-installation.md b/docs/dagster-university/pages/dagster-essentials/lesson-2/requirements-and-installation.md index 363718ca770fe..b074d2757ae49 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-2/requirements-and-installation.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-2/requirements-and-installation.md @@ -9,11 +9,12 @@ lesson: '2' To install Dagster, you’ll need: - **To install Python**. Dagster supports Python 3.9 through 3.12. -- **A package manager like pip or poetry**. If you need to install a package manager, refer to the following installation guides: +- **A package manager like pip, Poetry, or uv**. If you need to install a package manager, refer to the following installation guides: - [pip](https://pip.pypa.io/en/stable/installation/) - [Poetry](https://python-poetry.org/docs/) + - [uv](https://docs.astral.sh/uv/getting-started/installation/) -To check that Python and the pip or Poetry package manager are already installed in your environment, run: +To check that Python and the package manager are already installed in your environment, run: ```shell python --version diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-3/whats-an-asset.md b/docs/dagster-university/pages/dagster-essentials/lesson-3/whats-an-asset.md index 7e3d27ebd2cee..99499c844f619 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-3/whats-an-asset.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-3/whats-an-asset.md @@ -10,8 +10,8 @@ An asset is an object in persistent storage that captures some understanding of - **A database table or view**, such as those in a Google BigQuery data warehouse - **A file**, such as a file in your local machine or blob storage like Amazon S3 -- **A machine learning model** -- **An asset from an integration,** like a dbt model or a Fivetran connector +- **A machine learning model**, such as TensorFlow or PyTorch +- **An asset from an integration,** such as a dbt model or a Fivetran connector Assets aren’t limited to just the objects listed above - these are just some common examples. diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md b/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md index 92eab5b00a8b5..5cb1bc9b33abc 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md @@ -30,7 +30,7 @@ The asset you built should look similar to the following code. Click **View answ deps=["taxi_zones_file"] ) def taxi_zones() -> None: - sql_query = f""" + query = f""" create or replace table zones as ( select LocationID as zone_id, @@ -42,5 +42,5 @@ def taxi_zones() -> None: """ conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) - conn.execute(sql_query) + conn.execute(query) ``` diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md b/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md index 0bf9ced624484..560c46b30273c 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md @@ -25,7 +25,7 @@ Now that you have a query that produces an asset, let’s use Dagster to manage """ The raw taxi trips dataset, loaded into a DuckDB database """ - sql_query = """ + query = """ create or replace table trips as ( select VendorID as vendor_id, @@ -43,7 +43,7 @@ Now that you have a query that produces an asset, let’s use Dagster to manage """ conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) - conn.execute(sql_query) + conn.execute(query) ``` Let’s walk through what this code does: @@ -52,13 +52,13 @@ Now that you have a query that produces an asset, let’s use Dagster to manage 2. The `taxi_trips_file` asset is defined as a dependency of `taxi_trips` through the `deps` argument. - 3. Next, a variable named `sql_query` is created. This variable contains a SQL query that creates a table named `trips`, which sources its data from the `data/raw/taxi_trips_2023-03.parquet` file. This is the file created by the `taxi_trips_file` asset. + 3. Next, a variable named `query` is created. This variable contains a SQL query that creates a table named `trips`, which sources its data from the `data/raw/taxi_trips_2023-03.parquet` file. This is the file created by the `taxi_trips_file` asset. 4. A variable named `conn` is created, which defines the connection to the DuckDB database in the project. To do this, it uses the `.connect` method from the `duckdb` library, passing in the `DUCKDB_DATABASE` environment variable to tell DuckDB where the database is located. The `DUCKDB_DATABASE` environment variable, sourced from your project’s `.env` file, resolves to `data/staging/data.duckdb`. **Note**: We set up this file in Lesson 2 - refer to this lesson if you need a refresher. If this file isn’t set up correctly, the materialization will result in an error. - 5. Finally, `conn` is paired with the DuckDB `execute` method, where our SQL query (`sql_query`) is passed in as an argument. This tells the asset that, when materializing, to connect to the DuckDB database and execute the query in `sql_query`. + 5. Finally, `conn` is paired with the DuckDB `execute` method, where our SQL query (`query`) is passed in as an argument. This tells the asset that, when materializing, to connect to the DuckDB database and execute the query in `query`. 3. Save the changes to the file. @@ -98,9 +98,9 @@ This is because you’ve told Dagster that taxi_trips depends on the taxi_trips_ To confirm that the `taxi_trips` asset materialized properly, you can access the newly made `trips` table in DuckDB. In a new terminal session, open a Python REPL and run the following snippet: ```python -> import duckdb -> conn = duckdb.connect(database="data/staging/data.duckdb") # assumes you're writing to the same destination as specified in .env.example -> conn.execute("select count(*) from trips").fetchall() +import duckdb +conn = duckdb.connect(database="data/staging/data.duckdb") # assumes you're writing to the same destination as specified in .env.example +conn.execute("select count(*) from trips").fetchall() ``` The command should succeed and return a row count of the taxi trips that were ingested. When finished, make sure to stop the terminal process before continuing or you may encounter an error. Use `Control+C` or `Command+C` to stop the process. diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md b/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md index 7e27a7e555ab1..3af063b4515b0 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md @@ -31,7 +31,7 @@ from dagster import asset deps=["taxi_trips_file"], ) def taxi_trips() -> None: - sql_query = """ + query = """ create or replace table taxi_trips as ( select VendorID as vendor_id, @@ -49,7 +49,7 @@ def taxi_trips() -> None: """ conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) - conn.execute(sql_query) + conn.execute(query) ``` --- @@ -72,7 +72,7 @@ from dagster import asset deps=["taxi_trips_file"], ) def taxi_trips(database: DuckDBResource) -> None: - sql_query = """ + query = """ create or replace table taxi_trips as ( select VendorID as vendor_id, @@ -90,7 +90,7 @@ def taxi_trips(database: DuckDBResource) -> None: """ with database.get_connection() as conn: - conn.execute(sql_query) + conn.execute(query) ``` To refactor `taxi_trips` to use the `database` resource, we had to: diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-7/what-are-schedules.md b/docs/dagster-university/pages/dagster-essentials/lesson-7/what-are-schedules.md index 7abd4f66c4963..f91b4cd4900f0 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-7/what-are-schedules.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-7/what-are-schedules.md @@ -92,7 +92,7 @@ Despite many schedulers and orchestrators replacing the cron program since then, Consider the following example: -```python +``` 15 5 * * 1-5 ``` diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-8/adding-partitions-to-assets.md b/docs/dagster-university/pages/dagster-essentials/lesson-8/adding-partitions-to-assets.md index cdfdd00cf041e..c44c2b93eafc9 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-8/adding-partitions-to-assets.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-8/adding-partitions-to-assets.md @@ -63,7 +63,7 @@ To add the partition to the asset: @asset( partitions_def=monthly_partition ) - def taxi_trips_file(context) -> None: + def taxi_trips_file(context: AssetExecutionContext) -> None: partition_date_str = context.partition_key ``` @@ -73,7 +73,7 @@ To add the partition to the asset: @asset( partitions_def=monthly_partition ) - def taxi_trips_file(context) -> None: + def taxi_trips_file(context: AssetExecutionContext) -> None: partition_date_str = context.partition_key month_to_fetch = partition_date_str[:-3] ``` @@ -86,7 +86,7 @@ from ..partitions import monthly_partition @asset( partitions_def=monthly_partition ) -def taxi_trips_file(context) -> None: +def taxi_trips_file(context: AssetExecutionContext) -> None: """ The raw parquet files for the taxi trips dataset. Sourced from the NYC Open Data portal. """ diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-8/coding-practice-partition-taxi-trips.md b/docs/dagster-university/pages/dagster-essentials/lesson-8/coding-practice-partition-taxi-trips.md index f2aa0b5ffc093..606ee4b3847c0 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-8/coding-practice-partition-taxi-trips.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-8/coding-practice-partition-taxi-trips.md @@ -17,7 +17,7 @@ To practice what you’ve learned, partition the `taxi_trips` asset by month usi {% callout %} You’ll need to drop the existing `taxi_trips` because of the new `partition_date` column. In a Python REPL or scratch script, run the following: - ```yaml + ``` import duckdb conn = duckdb.connect(database="data/staging/data.duckdb") conn.execute("drop table trips;") diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-8/creating-a-schedule-with-a-date-based-partition.md b/docs/dagster-university/pages/dagster-essentials/lesson-8/creating-a-schedule-with-a-date-based-partition.md index a6327cb6ad954..cd8793b6755fe 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-8/creating-a-schedule-with-a-date-based-partition.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-8/creating-a-schedule-with-a-date-based-partition.md @@ -36,12 +36,14 @@ To add partition to the job, make the following changes: The job should now look like this: ```python -from dagster import define_asset_job, AssetSelection, AssetKey +from dagster import define_asset_job, AssetSelection from ..partitions import monthly_partition +trips_by_week = AssetSelection.assets("trips_by_week") + trip_update_job = define_asset_job( name="trip_update_job", partitions_def=monthly_partition, # partitions added here - selection=AssetSelection.all() - AssetSelection.assets(["trips_by_week"]) + selection=AssetSelection.all() - trips_by_week ) ``` From 9eb5c0a3bac57d7e369af523a96e6d5e72340747 Mon Sep 17 00:00:00 2001 From: Dennis Hume Date: Fri, 13 Dec 2024 08:56:31 -0600 Subject: [PATCH 38/94] [du] add backoff for duckdb connections (#26408) ## Summary & Motivation Update code snippets for sections 4 and 6 to wrap DuckDB connection in backoff to prevent race conditions when materializing all assets (Not an issue after these assets switch to using resources). ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --- .../coding-practice-taxi-zones-asset.md | 9 ++++++++- .../coding-practice-trips-by-week-asset.md | 10 +++++++++- .../lesson-4/loading-data-into-a-database.md | 12 +++++++++-- .../setting-up-a-database-resource.md | 9 ++++++++- .../lesson-6/using-resources-in-assets.md | 20 +++++++++++++++++-- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md b/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md index 5cb1bc9b33abc..69f9139b16c2b 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-taxi-zones-asset.md @@ -41,6 +41,13 @@ def taxi_zones() -> None: ); """ - conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) + conn = backoff( + fn=duckdb.connect, + retry_on=(RuntimeError, duckdb.IOException), + kwargs={ + "database": os.getenv("DUCKDB_DATABASE"), + }, + max_retries=10, + ) conn.execute(query) ``` diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-trips-by-week-asset.md b/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-trips-by-week-asset.md index 8067d27dd281a..b5c5e90b1bfad 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-trips-by-week-asset.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-4/coding-practice-trips-by-week-asset.md @@ -62,12 +62,20 @@ from datetime import datetime, timedelta from . import constants import pandas as pd +from dagster._utils.backoff import backoff @asset( deps=["taxi_trips"] ) def trips_by_week() -> None: - conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) + conn = backoff( + fn=duckdb.connect, + retry_on=(RuntimeError, duckdb.IOException), + kwargs={ + "database": os.getenv("DUCKDB_DATABASE"), + }, + max_retries=10, + ) current_date = datetime.strptime("2023-03-01", constants.DATE_FORMAT) end_date = datetime.strptime("2023-04-01", constants.DATE_FORMAT) diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md b/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md index 560c46b30273c..f5bc537d9837b 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-4/loading-data-into-a-database.md @@ -13,6 +13,7 @@ Now that you have a query that produces an asset, let’s use Dagster to manage ```python import duckdb import os + from dagster._utils.backoff import backoff ``` 2. Copy and paste the code below into the bottom of the `trips.py` file. Note how this code looks similar to the asset definition code for the `taxi_trips_file` and the `taxi_zones` assets: @@ -42,7 +43,14 @@ Now that you have a query that produces an asset, let’s use Dagster to manage ); """ - conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) + conn = backoff( + fn=duckdb.connect, + retry_on=(RuntimeError, duckdb.IOException), + kwargs={ + "database": os.getenv("DUCKDB_DATABASE"), + }, + max_retries=10, + ) conn.execute(query) ``` @@ -54,7 +62,7 @@ Now that you have a query that produces an asset, let’s use Dagster to manage 3. Next, a variable named `query` is created. This variable contains a SQL query that creates a table named `trips`, which sources its data from the `data/raw/taxi_trips_2023-03.parquet` file. This is the file created by the `taxi_trips_file` asset. - 4. A variable named `conn` is created, which defines the connection to the DuckDB database in the project. To do this, it uses the `.connect` method from the `duckdb` library, passing in the `DUCKDB_DATABASE` environment variable to tell DuckDB where the database is located. + 4. A variable named `conn` is created, which defines the connection to the DuckDB database in the project. To do this, we first wrap everything with the Dagster utility function `backoff`. Using the backoff function ensures that multiple assets can use DuckDB safely without locking resources. The backoff function takes in the function we want to call (in this case the `.connect` method from the `duckdb` library), any errors to retry on (`RuntimeError` and `duckdb.IOException`), the max number of retries, and finally, the arguments to supply to the `.connect` DuckDB method. Here we are passing in the `DUCKDB_DATABASE` environment variable to tell DuckDB where the database is located. The `DUCKDB_DATABASE` environment variable, sourced from your project’s `.env` file, resolves to `data/staging/data.duckdb`. **Note**: We set up this file in Lesson 2 - refer to this lesson if you need a refresher. If this file isn’t set up correctly, the materialization will result in an error. diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-6/setting-up-a-database-resource.md b/docs/dagster-university/pages/dagster-essentials/lesson-6/setting-up-a-database-resource.md index 311748941755c..9dadbf149bfa1 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-6/setting-up-a-database-resource.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-6/setting-up-a-database-resource.md @@ -14,7 +14,14 @@ Throughout this module, you’ve used DuckDB to store and transform your data. E ) def taxi_trips() -> None: ... - conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) + conn = backoff( + fn=duckdb.connect, + retry_on=(RuntimeError, duckdb.IOException), + kwargs={ + "database": os.getenv("DUCKDB_DATABASE"), + }, + max_retries=10, + ) ... ``` diff --git a/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md b/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md index 3af063b4515b0..6f059f62f2bdc 100644 --- a/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md +++ b/docs/dagster-university/pages/dagster-essentials/lesson-6/using-resources-in-assets.md @@ -48,7 +48,14 @@ def taxi_trips() -> None: ); """ - conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) + conn = backoff( + fn=duckdb.connect, + retry_on=(RuntimeError, duckdb.IOException), + kwargs={ + "database": os.getenv("DUCKDB_DATABASE"), + }, + max_retries=10, + ) conn.execute(query) ``` @@ -100,7 +107,14 @@ To refactor `taxi_trips` to use the `database` resource, we had to: 3. Replace the lines that connect to DuckDB and execute a query: ```python - conn = duckdb.connect(os.getenv("DUCKDB_DATABASE")) + conn = backoff( + fn=duckdb.connect, + retry_on=(RuntimeError, duckdb.IOException), + kwargs={ + "database": os.getenv("DUCKDB_DATABASE"), + }, + max_retries=10, + ) conn.execute(query) ``` @@ -111,6 +125,8 @@ To refactor `taxi_trips` to use the `database` resource, we had to: conn.execute(query) ``` + Notice that we no longer need to use the `backoff` function. The Dagster `DuckDBResource` handles this functionality for us. + --- ## Before you continue From 4fad91397f2372d0801907c3b821238bd864d2e8 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Fri, 13 Dec 2024 10:40:10 -0500 Subject: [PATCH 39/94] [components] Stop forcing editable dagster for `dg generate code-location` (#26447) ## Summary & Motivation Removes the forced use of an editable installation for `dagster-dg`-generated code locations. Allows for dependencies to be added incrementally. `dg generate code-location` takes a `--use-editable-dagster` option. This can either be used as a flag, in which case env var `DAGSTER_GIT_REPO_DIR` will be read, or takes a value pointing to the directory containing the dagster repo. ## How I Tested These Changes Unit tests and ran through demo using published code on this branch. --- .../automation/automation_tests/test_repo.py | 7 +- .../dagster_components/__init__.py | 4 - .../libraries/dagster-components/setup.py | 2 +- .../dagster-dg/dagster_dg/cli/generate.py | 21 +++- .../dagster-dg/dagster_dg/generate.py | 99 ++++++++++++++----- .../pyproject.toml.jinja | 19 +--- .../cli_tests/test_generate_commands.py | 53 +++++++--- .../cli_tests/test_list_commands.py | 2 - 8 files changed, 145 insertions(+), 62 deletions(-) diff --git a/python_modules/automation/automation_tests/test_repo.py b/python_modules/automation/automation_tests/test_repo.py index e7e2aaabe7df7..1e3cc83667b36 100644 --- a/python_modules/automation/automation_tests/test_repo.py +++ b/python_modules/automation/automation_tests/test_repo.py @@ -2,9 +2,10 @@ import subprocess from pathlib import Path -# Some libraries are excluded because they lack a Dagster dependency, which is a prerequisite for -# registering in the DagsterLibraryRegistry. -EXCLUDE_LIBRARIES = ["dagster-dg"] +# Some libraries are excluded because they either: +# - lack a Dagster dependency, which is a prerequisite for registering in the DagsterLibraryRegistry. +# - are temporary or on a separate release schedule from the rest of the libraries. +EXCLUDE_LIBRARIES = ["dagster-components", "dagster-dg"] def test_all_libraries_register() -> None: diff --git a/python_modules/libraries/dagster-components/dagster_components/__init__.py b/python_modules/libraries/dagster-components/dagster_components/__init__.py index f5463bf0d60f8..ecb7d3be238a4 100644 --- a/python_modules/libraries/dagster-components/dagster_components/__init__.py +++ b/python_modules/libraries/dagster-components/dagster_components/__init__.py @@ -1,5 +1,3 @@ -from dagster._core.libraries import DagsterLibraryRegistry - from dagster_components.core.component import ( Component as Component, ComponentLoadContext as ComponentLoadContext, @@ -10,5 +8,3 @@ build_defs_from_toplevel_components_folder as build_defs_from_toplevel_components_folder, ) from dagster_components.version import __version__ as __version__ - -DagsterLibraryRegistry.register("dagster-components", __version__) diff --git a/python_modules/libraries/dagster-components/setup.py b/python_modules/libraries/dagster-components/setup.py index 903e3fa1c9f7b..0c009b3e36907 100644 --- a/python_modules/libraries/dagster-components/setup.py +++ b/python_modules/libraries/dagster-components/setup.py @@ -36,7 +36,7 @@ def get_version() -> str: ], packages=find_packages(exclude=["dagster_components_tests*", "examples*"]), install_requires=[ - f"dagster{pin}", + "dagster>=1.9.5", "tomli", ], zip_safe=False, diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index 6f035d57db520..83d0ffd61f61d 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -44,8 +44,19 @@ def generate_deployment_command(path: Path) -> None: @generate_cli.command(name="code-location") @click.argument("name", type=str) -@click.option("--use-editable-dagster", is_flag=True, default=False) -def generate_code_location_command(name: str, use_editable_dagster: bool) -> None: +@click.option( + "--use-editable-dagster", + type=str, + flag_value="TRUE", + is_flag=False, + default=None, + help=( + "Install Dagster package dependencies from a local Dagster clone. Accepts a path to local Dagster clone root or" + " may be set as a flag (no value is passed). If set as a flag," + " the location of the local Dagster clone will be read from the `DAGSTER_GIT_REPO_DIR` environment variable." + ), +) +def generate_code_location_command(name: str, use_editable_dagster: Optional[str]) -> None: """Generate a Dagster code location file structure and a uv-managed virtual environment scoped to the code location. @@ -78,8 +89,8 @@ def generate_code_location_command(name: str, use_editable_dagster: bool) -> Non else: code_location_path = Path.cwd() / name - if use_editable_dagster: - if "DAGSTER_GIT_REPO_DIR" not in os.environ: + if use_editable_dagster == "TRUE": + if not os.environ.get("DAGSTER_GIT_REPO_DIR"): click.echo( click.style( "The `--use-editable-dagster` flag requires the `DAGSTER_GIT_REPO_DIR` environment variable to be set.", @@ -88,6 +99,8 @@ def generate_code_location_command(name: str, use_editable_dagster: bool) -> Non ) sys.exit(1) editable_dagster_root = os.environ["DAGSTER_GIT_REPO_DIR"] + elif use_editable_dagster: # a string value was passed + editable_dagster_root = use_editable_dagster else: editable_dagster_root = None diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index a0f93908a5e6f..e712f1c2b7984 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -9,13 +9,16 @@ from dagster_dg.context import CodeLocationDirectoryContext from dagster_dg.utils import ( camelcase, - discover_git_root, execute_code_location_command, generate_subtree, get_uv_command_env, pushd, ) +# ######################## +# ##### DEPLOYMENT +# ######################## + def generate_deployment(path: Path) -> None: click.echo(f"Creating a Dagster deployment at {path}.") @@ -29,32 +32,72 @@ def generate_deployment(path: Path) -> None: ) -def generate_code_location(path: Path, editable_dagster_root: Optional[str] = None) -> None: - click.echo(f"Creating a Dagster code location at {path}.") +# ######################## +# ##### CODE LOCATION +# ######################## + +# Despite the fact that editable dependencies are resolved through tool.uv.sources, we need to set +# the dependencies themselves differently depending on whether we are using editable dagster or +# not. This is because `tool.uv.sources` only seems to apply to direct dependencies of the package, +# so any 2+-order Dagster dependency of our package needs to be listed as a direct dependency in the +# editable case. +EDITABLE_DAGSTER_DEPENDENCIES = ( + "dagster", + "dagster-pipes", + "dagster-components", +) +EDITABLE_DAGSTER_DEV_DEPENDENCIES = ("dagster-webserver", "dagster-graphql") +PYPI_DAGSTER_DEPENDENCIES = ("dagster-components",) +PYPI_DAGSTER_DEV_DEPENDENCIES = ("dagster-webserver",) + + +def get_pyproject_toml_dependencies(use_editable_dagster: bool) -> str: + deps = EDITABLE_DAGSTER_DEPENDENCIES if use_editable_dagster else PYPI_DAGSTER_DEPENDENCIES + return "\n".join( + [ + "dependencies = [", + *[f' "{dep}",' for dep in deps], + "]", + ] + ) + - # Temporarily we always set an editable dagster root. This is needed while the packages are not - # published. - editable_dagster_root = ( - editable_dagster_root - or os.environ.get("DAGSTER_GIT_REPO_DIR") - or str(discover_git_root(Path(__file__))) +def get_pyproject_toml_dev_dependencies(use_editable_dagster: bool) -> str: + deps = ( + EDITABLE_DAGSTER_DEV_DEPENDENCIES if use_editable_dagster else PYPI_DAGSTER_DEV_DEPENDENCIES + ) + return "\n".join( + [ + "dev = [", + *[f' "{dep}",' for dep in deps], + "]", + ] ) - editable_dagster_uv_sources = textwrap.dedent(f""" - [tool.uv.sources] - dagster = {{ path = "{editable_dagster_root}/python_modules/dagster", editable = true }} - dagster-graphql = {{ path = "{editable_dagster_root}/python_modules/dagster-graphql", editable = true }} - dagster-pipes = {{ path = "{editable_dagster_root}/python_modules/dagster-pipes", editable = true }} - dagster-webserver = {{ path = "{editable_dagster_root}/python_modules/dagster-webserver", editable = true }} - dagster-components = {{ path = "{editable_dagster_root}/python_modules/libraries/dagster-components", editable = true }} - dagster-embedded-elt = {{ path = "{editable_dagster_root}/python_modules/libraries/dagster-embedded-elt", editable = true }} - dagster-dbt = {{ path = "{editable_dagster_root}/python_modules/libraries/dagster-dbt", editable = true }} + +def get_pyproject_toml_uv_sources(editable_dagster_root: str) -> str: + return textwrap.dedent(f""" + [tool.uv.sources] + dagster = {{ path = "{editable_dagster_root}/python_modules/dagster", editable = true }} + dagster-graphql = {{ path = "{editable_dagster_root}/python_modules/dagster-graphql", editable = true }} + dagster-pipes = {{ path = "{editable_dagster_root}/python_modules/dagster-pipes", editable = true }} + dagster-webserver = {{ path = "{editable_dagster_root}/python_modules/dagster-webserver", editable = true }} + dagster-components = {{ path = "{editable_dagster_root}/python_modules/libraries/dagster-components", editable = true }} + dagster-embedded-elt = {{ path = "{editable_dagster_root}/python_modules/libraries/dagster-embedded-elt", editable = true }} + dagster-dbt = {{ path = "{editable_dagster_root}/python_modules/libraries/dagster-dbt", editable = true }} """) - if editable_dagster_root: - uv_sources = editable_dagster_uv_sources - else: - uv_sources = editable_dagster_uv_sources + +def generate_code_location(path: Path, editable_dagster_root: Optional[str] = None) -> None: + click.echo(f"Creating a Dagster code location at {path}.") + + dependencies = get_pyproject_toml_dependencies(use_editable_dagster=bool(editable_dagster_root)) + dev_dependencies = get_pyproject_toml_dev_dependencies( + use_editable_dagster=bool(editable_dagster_root) + ) + uv_sources = ( + get_pyproject_toml_uv_sources(editable_dagster_root) if editable_dagster_root else "" + ) generate_subtree( path=path, @@ -62,6 +105,8 @@ def generate_code_location(path: Path, editable_dagster_root: Optional[str] = No templates_path=os.path.join( os.path.dirname(__file__), "templates", "CODE_LOCATION_NAME_PLACEHOLDER" ), + dependencies=dependencies, + dev_dependencies=dev_dependencies, uv_sources=uv_sources, ) @@ -70,6 +115,11 @@ def generate_code_location(path: Path, editable_dagster_root: Optional[str] = No subprocess.run(["uv", "sync"], check=True, env=get_uv_command_env()) +# ######################## +# ##### COMPONENT TYPE +# ######################## + + def generate_component_type(context: CodeLocationDirectoryContext, name: str) -> None: root_path = Path(context.local_component_types_root_path) click.echo(f"Creating a Dagster component type at {root_path}/{name}.py.") @@ -89,6 +139,11 @@ def generate_component_type(context: CodeLocationDirectoryContext, name: str) -> ) +# ######################## +# ##### COMPONENT INSTANCE +# ######################## + + def generate_component_instance( root_path: Path, name: str, diff --git a/python_modules/libraries/dagster-dg/dagster_dg/templates/CODE_LOCATION_NAME_PLACEHOLDER/pyproject.toml.jinja b/python_modules/libraries/dagster-dg/dagster_dg/templates/CODE_LOCATION_NAME_PLACEHOLDER/pyproject.toml.jinja index 688e8e80ab91d..7ff9af903784a 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/templates/CODE_LOCATION_NAME_PLACEHOLDER/pyproject.toml.jinja +++ b/python_modules/libraries/dagster-dg/dagster_dg/templates/CODE_LOCATION_NAME_PLACEHOLDER/pyproject.toml.jinja @@ -2,25 +2,14 @@ name = "{{ project_name }}" requires-python = ">=3.9,<3.13" version = "0.1.0" -dependencies = [ - "dagster", - "dagster-graphql", - "dagster-pipes", - "dagster-webserver", - "dagster-components[sling,dbt]", - "dagster-embedded-elt", - "dagster-dbt", - "sling-mac-arm64", -] - -[project.optional-dependencies] -dev = [ - "dagster-webserver", -] +{{ dependencies }} [project.entry-points] "dagster.components" = { {{ project_name }} = "{{ project_name }}.lib"} +[dependency-groups] +{{ dev_dependencies }} + [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 36fd9e154fdf7..6fa572e49eca5 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -1,6 +1,7 @@ import inspect import json import os +import subprocess import sys import textwrap from contextlib import contextmanager @@ -72,14 +73,21 @@ def isolated_example_deployment_foo(runner: CliRunner) -> Iterator[None]: def isolated_example_code_location_bar( runner: CliRunner, in_deployment: bool = True ) -> Iterator[None]: + dagster_git_repo_dir = str(discover_git_root(Path(__file__))) if in_deployment: with isolated_example_deployment_foo(runner), clean_module_cache("bar"): - runner.invoke(generate_code_location_command, ["bar"]) + runner.invoke( + generate_code_location_command, + ["--use-editable-dagster", dagster_git_repo_dir, "bar"], + ) with pushd("code_locations/bar"): yield else: with runner.isolated_filesystem(), clean_module_cache("bar"): - runner.invoke(generate_code_location_command, ["bar"]) + runner.invoke( + generate_code_location_command, + ["--use-editable-dagster", dagster_git_repo_dir, "bar"], + ) with pushd("bar"): yield @@ -148,12 +156,11 @@ def test_generate_code_location_inside_deployment_success() -> None: assert Path("code_locations/bar/.venv").exists() assert Path("code_locations/bar/uv.lock").exists() - # Commented out because we are always adding sources right now - # with open("code_locations/bar/pyproject.toml") as f: - # toml = tomli.loads(f.read()) - # - # # No tool.uv.sources added without --use-editable-dagster - # assert "uv" not in toml["tool"] + with open("code_locations/bar/pyproject.toml") as f: + toml = tomli.loads(f.read()) + + # No tool.uv.sources added without --use-editable-dagster + assert "uv" not in toml["tool"] def test_generate_code_location_outside_deployment_success() -> None: @@ -173,12 +180,17 @@ def test_generate_code_location_outside_deployment_success() -> None: assert Path("bar/uv.lock").exists() -def test_generate_code_location_editable_dagster_success(monkeypatch) -> None: +@pytest.mark.parametrize("mode", ["env_var", "arg"]) +def test_generate_code_location_editable_dagster_success(mode: str, monkeypatch) -> None: runner = CliRunner() dagster_git_repo_dir = discover_git_root(Path(__file__)) - monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", str(dagster_git_repo_dir)) + if mode == "env_var": + monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", str(dagster_git_repo_dir)) + editable_args = ["--use-editable-dagster", "--"] + else: + editable_args = ["--use-editable-dagster", str(dagster_git_repo_dir)] with isolated_example_deployment_foo(runner): - result = runner.invoke(generate_code_location_command, ["--use-editable-dagster", "bar"]) + result = runner.invoke(generate_code_location_command, [*editable_args, "bar"]) assert result.exit_code == 0 assert Path("code_locations/bar").exists() assert Path("code_locations/bar/pyproject.toml").exists() @@ -202,6 +214,17 @@ def test_generate_code_location_editable_dagster_success(monkeypatch) -> None: } +def test_generate_code_location_editable_dagster_no_env_var_no_value_fails(monkeypatch) -> None: + runner = CliRunner() + monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", "") + with isolated_example_deployment_foo(runner): + result = runner.invoke( + generate_code_location_command, ["--use-editable-dagster", "--", "bar"] + ) + assert result.exit_code != 0 + assert "requires the `DAGSTER_GIT_REPO_DIR`" in result.output + + def test_generate_code_location_already_exists_fails() -> None: runner = CliRunner() with isolated_example_deployment_foo(runner): @@ -326,6 +349,11 @@ def test_generate_component_already_exists_fails(in_deployment: bool) -> None: def test_generate_sling_replication_instance() -> None: runner = CliRunner() with isolated_example_code_location_bar(runner): + # We need to add dagster-embedded-elt also because we are using editable installs. Only + # direct dependencies will be resolved by uv.tool.sources. + subprocess.run( + ["uv", "add", "dagster-components[sling]", "dagster-embedded-elt"], check=True + ) result = runner.invoke( generate_component_command, ["dagster_components.sling_replication", "file_ingest"] ) @@ -354,6 +382,9 @@ def test_generate_sling_replication_instance() -> None: def test_generate_dbt_project_instance(params) -> None: runner = CliRunner() with isolated_example_code_location_bar(runner): + # We need to add dagster-dbt also because we are using editable installs. Only + # direct dependencies will be resolved by uv.tool.sources. + subprocess.run(["uv", "add", "dagster-components[dbt]", "dagster-dbt"], check=True) result = runner.invoke( generate_component_command, ["dagster_components.dbt_project", "my_project", *params] ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py index f48f2e7d4ce6d..a53a51058a8e4 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py @@ -55,9 +55,7 @@ def test_list_component_types_success(): result.output == "\n".join( [ - "dagster_components.dbt_project", "dagster_components.pipes_subprocess_script_collection", - "dagster_components.sling_replication", ] ) + "\n" From 758341768ac6b1f33766fb2226fd3f46d6d8066b Mon Sep 17 00:00:00 2001 From: Nick Schrock Date: Fri, 13 Dec 2024 10:47:54 -0500 Subject: [PATCH 40/94] Add linguist-generated=true for uv.lock (#26472) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary & Motivation Mark uv.lock as generated. * Github doesn't render by default * Graphite claims that it doesn't as well but that is not working right now. Asking in GraphiteSlack. * Graphite Reviewer does not analyze ## How I Tested These Changes ![Screenshot 2024-12-13 at 9.51.50 AM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/wS38mdcdU6aAeJobBdry/95a55b19-9a72-4f16-bcc5-c8f2eae88e34.png) --- .gitattributes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 84ef90f32fb6b..dbdb53bb0d1b3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -*.py diff=python \ No newline at end of file +*.py diff=python +**/uv.lock linguist-generated From fbd0fe5b89f8fd293372a3f188747e8b4260b27f Mon Sep 17 00:00:00 2001 From: David Liu <48995019+dliu27@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:52:40 -0500 Subject: [PATCH 41/94] [ui] add tracking to launch all button (#26411) ## Summary & Motivation Linear: https://linear.app/dagster-labs/issue/FE-719/add-tracking-to-the-launch-all-button Adds tracking to the launch all button in the preview tick result modal ## How I Tested These Changes Tested locally --- .../packages/ui-core/src/ticks/EvaluateScheduleDialog.tsx | 7 ++++++- .../packages/ui-core/src/ticks/SensorDryRunDialog.tsx | 6 ++++++ .../src/ticks/__tests__/EvaluateScheduleDialog.test.tsx | 8 ++++++++ .../src/ticks/__tests__/SensorDryRunDialog.test.tsx | 8 ++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/ticks/EvaluateScheduleDialog.tsx b/js_modules/dagster-ui/packages/ui-core/src/ticks/EvaluateScheduleDialog.tsx index 06add60352b2c..7262979f9473a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/ticks/EvaluateScheduleDialog.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/ticks/EvaluateScheduleDialog.tsx @@ -34,6 +34,7 @@ import {showCustomAlert} from '../app/CustomAlertProvider'; import {PYTHON_ERROR_FRAGMENT} from '../app/PythonErrorFragment'; import {PythonErrorInfo} from '../app/PythonErrorInfo'; import {assertUnreachable} from '../app/Util'; +import {useTrackEvent} from '../app/analytics'; import {TimeContext} from '../app/time/TimeContext'; import {timestampToString} from '../app/time/timestampToString'; import {PythonErrorFragment} from '../app/types/PythonErrorFragment.types'; @@ -77,6 +78,8 @@ export const EvaluateScheduleDialog = (props: Props) => { }; const EvaluateSchedule = ({repoAddress, name, onClose, jobName}: Props) => { + const trackEvent = useTrackEvent(); + const [selectedTimestamp, setSelectedTimestamp] = useState<{ts: number; label: string}>(); const scheduleSelector: ScheduleSelector = useMemo( () => ({ @@ -181,6 +184,8 @@ const EvaluateSchedule = ({repoAddress, name, onClose, jobName}: Props) => { if (!canLaunchAll) { return; } + + trackEvent('launch-all-schedule'); setLaunching(true); try { @@ -193,7 +198,7 @@ const EvaluateSchedule = ({repoAddress, name, onClose, jobName}: Props) => { setLaunching(false); onClose(); - }, [canLaunchAll, executionParamsList, launchMultipleRunsWithTelemetry, onClose]); + }, [canLaunchAll, executionParamsList, launchMultipleRunsWithTelemetry, onClose, trackEvent]); const content = useMemo(() => { // launching all runs state diff --git a/js_modules/dagster-ui/packages/ui-core/src/ticks/SensorDryRunDialog.tsx b/js_modules/dagster-ui/packages/ui-core/src/ticks/SensorDryRunDialog.tsx index 1cd0bda5aad43..1047d13d9a391 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/ticks/SensorDryRunDialog.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/ticks/SensorDryRunDialog.tsx @@ -32,6 +32,7 @@ import {showSharedToaster} from '../app/DomUtils'; import {PYTHON_ERROR_FRAGMENT} from '../app/PythonErrorFragment'; import {PythonErrorInfo} from '../app/PythonErrorInfo'; import {assertUnreachable} from '../app/Util'; +import {useTrackEvent} from '../app/analytics'; import {PythonErrorFragment} from '../app/types/PythonErrorFragment.types'; import {SensorSelector} from '../graphql/types'; import {useLaunchMultipleRunsWithTelemetry} from '../launchpad/useLaunchMultipleRunsWithTelemetry'; @@ -74,6 +75,8 @@ export const SensorDryRunDialog = (props: Props) => { }; const SensorDryRun = ({repoAddress, name, currentCursor, onClose, jobName}: Props) => { + const trackEvent = useTrackEvent(); + const [sensorDryRun] = useMutation( EVALUATE_SENSOR_MUTATION, ); @@ -187,6 +190,8 @@ const SensorDryRun = ({repoAddress, name, currentCursor, onClose, jobName}: Prop if (!canLaunchAll) { return; } + + trackEvent('launch-all-sensor'); setLaunching(true); try { @@ -206,6 +211,7 @@ const SensorDryRun = ({repoAddress, name, currentCursor, onClose, jobName}: Prop launchMultipleRunsWithTelemetry, onClose, onCommitTickResult, + trackEvent, ]); const leftButtons = useMemo(() => { diff --git a/js_modules/dagster-ui/packages/ui-core/src/ticks/__tests__/EvaluateScheduleDialog.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/ticks/__tests__/EvaluateScheduleDialog.test.tsx index 6c17208d0628d..a8a2b55c06eb5 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/ticks/__tests__/EvaluateScheduleDialog.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/ticks/__tests__/EvaluateScheduleDialog.test.tsx @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event'; import {MemoryRouter, useHistory} from 'react-router-dom'; import {Resolvers} from '../../apollo-client'; +import {useTrackEvent} from '../../app/analytics'; import {EvaluateScheduleDialog} from '../EvaluateScheduleDialog'; import { GetScheduleQueryMock, @@ -26,6 +27,11 @@ jest.mock('react-router-dom', () => ({ useHistory: jest.fn(), })); +// Mocking useTrackEvent +jest.mock('../../app/analytics', () => ({ + useTrackEvent: jest.fn(() => jest.fn()), +})); + const onCloseMock = jest.fn(); function Test({mocks, resolvers}: {mocks?: MockedResponse[]; resolvers?: Resolvers}) { @@ -119,6 +125,8 @@ describe('EvaluateScheduleTest', () => { createHref: createHrefSpy, }); + (useTrackEvent as jest.Mock).mockReturnValue(jest.fn()); + render( ({ useHistory: jest.fn(), })); +// Mocking useTrackEvent +jest.mock('../../app/analytics', () => ({ + useTrackEvent: jest.fn(() => jest.fn()), +})); + const onCloseMock = jest.fn(); function Test({mocks, resolvers}: {mocks?: MockedResponse[]; resolvers?: Resolvers}) { @@ -98,6 +104,8 @@ describe('SensorDryRunTest', () => { createHref: createHrefSpy, }); + (useTrackEvent as jest.Mock).mockReturnValue(jest.fn()); + render( Date: Fri, 13 Dec 2024 11:02:39 -0500 Subject: [PATCH 42/94] [components] Access more detailed component information from `dg` CLI (#26473) ## Summary & Motivation Adds summary output to `dg list component-types` and a new `dg info component-type` command. `dg info component-type` takes any of `--description`, `--generate-params-schema`, or `--component-params-schema` to print a single field. If none of these are passed than all fields are printed. ## How I Tested These Changes Unit tests, manually. Example output from manual test in env with all `dagster-components` extras installed: ``` $ dg list component-types dagster_components.dbt_project dagster_components.pipes_subprocess_script_collection Assets that wrap Python scripts executed with Dagster's PipesSubprocessClient. dagster_components.sling_replication ``` ``` $ dg info component-type dagster_components.dbt_project dagster_components.dbt_project Generate params schema: { "properties": { "init": { "default": false, "title": "Init", "type": "boolean" }, "project_path": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Project Path" } }, "title": "DbtGenerateParams", "type": "object" } ``` --- .../dagster_components/cli/list.py | 14 +-- .../dagster_components/core/component.py | 44 ++++++++- .../dagster_components/core/deployment.py | 7 +- .../lib/pipes_subprocess_script_collection.py | 2 + .../dagster-dg/dagster_dg/cli/__init__.py | 2 + .../dagster-dg/dagster_dg/cli/info.py | 85 +++++++++++++++++ .../dagster-dg/dagster_dg/cli/list.py | 6 +- .../dagster-dg/dagster_dg/component.py | 7 +- .../dagster-dg/dagster_dg/context.py | 7 +- .../libraries/dagster-dg/dagster_dg/utils.py | 11 +++ .../cli_tests/test_info_commands.py | 92 +++++++++++++++++++ .../cli_tests/test_list_commands.py | 27 ++---- 12 files changed, 267 insertions(+), 37 deletions(-) create mode 100644 python_modules/libraries/dagster-dg/dagster_dg/cli/info.py create mode 100644 python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py diff --git a/python_modules/libraries/dagster-components/dagster_components/cli/list.py b/python_modules/libraries/dagster-components/dagster_components/cli/list.py index 9368a9fa1206a..eb34c62ce9063 100644 --- a/python_modules/libraries/dagster-components/dagster_components/cli/list.py +++ b/python_modules/libraries/dagster-components/dagster_components/cli/list.py @@ -5,7 +5,7 @@ import click -from dagster_components.core.component import ComponentRegistry +from dagster_components.core.component import ComponentMetadata, ComponentRegistry from dagster_components.core.deployment import ( CodeLocationProjectContext, is_inside_code_location_project, @@ -32,9 +32,11 @@ def list_component_types_command() -> None: Path.cwd(), ComponentRegistry.from_entry_point_discovery() ) output: Dict[str, Any] = {} - for component_type in context.list_component_types(): - # package, name = component_type.rsplit(".", 1) - output[component_type] = { - "name": component_type, - } + for key, component_type in context.list_component_types(): + package, name = key.rsplit(".", 1) + output[key] = ComponentMetadata( + name=name, + package=package, + **component_type.get_metadata(), + ) click.echo(json.dumps(output)) diff --git a/python_modules/libraries/dagster-components/dagster_components/core/component.py b/python_modules/libraries/dagster-components/dagster_components/core/component.py index 524bcd5f58766..4e9a75ffc856d 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/component.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/component.py @@ -1,10 +1,22 @@ import copy import importlib import importlib.metadata +import inspect import sys from abc import ABC, abstractmethod from types import ModuleType -from typing import TYPE_CHECKING, Any, ClassVar, Dict, Iterable, Mapping, Optional, Sequence, Type +from typing import ( + TYPE_CHECKING, + Any, + ClassVar, + Dict, + Iterable, + Mapping, + Optional, + Sequence, + Type, + TypedDict, +) from dagster import _check as check from dagster._core.errors import DagsterError @@ -35,6 +47,36 @@ def from_decl_node( cls, context: "ComponentLoadContext", decl_node: "ComponentDeclNode" ) -> Self: ... + @classmethod + def get_metadata(cls) -> "ComponentInternalMetadata": + docstring = cls.__doc__ + return { + "summary": docstring.split("\n\n")[0] if docstring else None, + "description": docstring, + "generate_params_schema": cls.generate_params_schema.schema() + if cls.generate_params_schema + else None, + "component_params_schema": cls.component_params_schema.schema() + if cls.component_params_schema + else None, + } + + @classmethod + def get_description(cls) -> Optional[str]: + return inspect.getdoc(cls) + + +class ComponentInternalMetadata(TypedDict): + summary: Optional[str] + description: Optional[str] + generate_params_schema: Optional[Any] # json schema + component_params_schema: Optional[Any] # json schema + + +class ComponentMetadata(ComponentInternalMetadata): + name: str + package: str + def get_entry_points_from_python_environment(group: str) -> Sequence[importlib.metadata.EntryPoint]: if sys.version_info >= (3, 10): diff --git a/python_modules/libraries/dagster-components/dagster_components/core/deployment.py b/python_modules/libraries/dagster-components/dagster_components/core/deployment.py index ca52531dc4e77..de95b5875a0ad 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/deployment.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/deployment.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import Final, Iterable, Type +from typing import Final, Iterable, Tuple, Type import tomli from dagster._core.errors import DagsterError @@ -78,8 +78,9 @@ def get_component_type(self, name: str) -> Type[Component]: raise DagsterError(f"No component type named {name}") return self._component_registry.get(name) - def list_component_types(self) -> Iterable[str]: - return sorted(self._component_registry.keys()) + def list_component_types(self) -> Iterable[Tuple[str, Type[Component]]]: + for key in sorted(self._component_registry.keys()): + yield key, self._component_registry.get(key) def get_component_instance_path(self, name: str) -> str: if name not in self.component_instances: diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py index cc461b6b2b234..4fe157f1243f0 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py @@ -55,6 +55,8 @@ class PipesSubprocessScriptCollectionParams(BaseModel): @component(name="pipes_subprocess_script_collection") class PipesSubprocessScriptCollection(Component): + """Assets that wrap Python scripts executed with Dagster's PipesSubprocessClient.""" + params_schema = PipesSubprocessScriptCollectionParams def __init__(self, dirpath: Path, path_specs: Mapping[Path, Sequence[AssetSpec]]): diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py index ff14bee381e63..38ac45544ae77 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py @@ -1,6 +1,7 @@ import click from dagster_dg.cli.generate import generate_cli +from dagster_dg.cli.info import info_cli from dagster_dg.cli.list import list_cli from dagster_dg.version import __version__ @@ -8,6 +9,7 @@ def create_dg_cli(): commands = { "generate": generate_cli, + "info": info_cli, "list": list_cli, } diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py new file mode 100644 index 0000000000000..8cc094a0a34c3 --- /dev/null +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py @@ -0,0 +1,85 @@ +import json +import sys +from pathlib import Path +from typing import Any, Mapping + +import click + +from dagster_dg.context import CodeLocationDirectoryContext, is_inside_code_location_directory + + +@click.group(name="info") +def info_cli(): + """Commands for listing Dagster components and related entities.""" + + +def _serialize_json_schema(schema: Mapping[str, Any]) -> str: + return json.dumps(schema, indent=4) + + +@info_cli.command(name="component-type") +@click.argument("component_type", type=str) +@click.option("--description", is_flag=True, default=False) +@click.option("--generate-params-schema", is_flag=True, default=False) +@click.option("--component-params-schema", is_flag=True, default=False) +def info_component_type_command( + component_type: str, + description: bool, + generate_params_schema: bool, + component_params_schema: bool, +) -> None: + """Get detailed information on a registered Dagster component type.""" + if not is_inside_code_location_directory(Path.cwd()): + click.echo( + click.style( + "This command must be run inside a Dagster code location directory.", fg="red" + ) + ) + sys.exit(1) + + context = CodeLocationDirectoryContext.from_path(Path.cwd()) + if not context.has_component_type(component_type): + click.echo( + click.style(f"No component type `{component_type}` could be resolved.", fg="red") + ) + sys.exit(1) + + if sum([description, generate_params_schema, component_params_schema]) > 1: + click.echo( + click.style( + "Only one of --description, --generate-params-schema, and --component-params-schema can be specified.", + fg="red", + ) + ) + sys.exit(1) + + context = CodeLocationDirectoryContext.from_path(Path.cwd()) + component_type_metadata = context.get_component_type(component_type) + + if description: + if component_type_metadata.description: + click.echo(component_type_metadata.description) + else: + click.echo("No description available.") + elif generate_params_schema: + if component_type_metadata.generate_params_schema: + click.echo(component_type_metadata.generate_params_schema) + else: + click.echo("No generate params schema defined.") + elif component_params_schema: + if component_type_metadata.component_params_schema: + click.echo(component_type_metadata.component_params_schema) + else: + click.echo("No component params schema defined.") + # print all available metadata + else: + click.echo(component_type) + if component_type_metadata.description: + click.echo("\nDescription:\n") + click.echo(component_type_metadata.description) + if component_type_metadata.generate_params_schema: + click.echo("\nGenerate params schema:\n") + click.echo(_serialize_json_schema(component_type_metadata.generate_params_schema)) + if component_type_metadata.component_params_schema: + click.echo("\nComponent params schema:\n") + click.echo(_serialize_json_schema(component_type_metadata.component_params_schema)) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py index 35c2b68f6073a..e8ad870233509 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py @@ -42,8 +42,10 @@ def list_component_types_command() -> None: sys.exit(1) context = CodeLocationDirectoryContext.from_path(Path.cwd()) - for component_type in context.get_component_type_names(): - click.echo(component_type) + for key, component_type in context.iter_component_types(): + click.echo(key) + if component_type.summary: + click.echo(f" {component_type.summary}") @list_cli.command(name="components") diff --git a/python_modules/libraries/dagster-dg/dagster_dg/component.py b/python_modules/libraries/dagster-dg/dagster_dg/component.py index fc3567da3470a..304cb45dd497d 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/component.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/component.py @@ -1,11 +1,16 @@ import copy from dataclasses import dataclass -from typing import Any, Dict, Iterable, Mapping +from typing import Any, Dict, Iterable, Mapping, Optional @dataclass class RemoteComponentType: name: str + package: str + summary: Optional[str] + description: Optional[str] + generate_params_schema: Optional[Mapping[str, Any]] # json schema + component_params_schema: Optional[Mapping[str, Any]] # json schema @property def key(self) -> str: diff --git a/python_modules/libraries/dagster-dg/dagster_dg/context.py b/python_modules/libraries/dagster-dg/dagster_dg/context.py index bce491322d325..2c105ae0a0efc 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/context.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/context.py @@ -1,7 +1,7 @@ import json import os from pathlib import Path -from typing import Final, Iterable, Mapping, Optional +from typing import Final, Iterable, Mapping, Optional, Tuple import tomli from typing_extensions import Self @@ -140,8 +140,9 @@ def local_component_types_root_path(self) -> str: def local_component_types_root_module_name(self) -> str: return f"{self._name}.{_CODE_LOCATION_CUSTOM_COMPONENTS_DIR}" - def get_component_type_names(self) -> Iterable[str]: - return sorted(self._component_registry.keys()) + def iter_component_types(self) -> Iterable[Tuple[str, RemoteComponentType]]: + for key in sorted(self._component_registry.keys()): + yield key, self._component_registry.get(key) def has_component_type(self, name: str) -> bool: return self._component_registry.has(name) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index c021337245409..a3999f10447a9 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -3,6 +3,7 @@ import posixpath import re import subprocess +import sys from pathlib import Path from typing import Any, Final, Iterator, List, Mapping, Optional, Sequence, Union @@ -163,3 +164,13 @@ def _should_skip_file(path: str, excludes: List[str] = _DEFAULT_EXCLUDES): return True return False + + +def ensure_dagster_dg_tests_import() -> None: + from dagster_dg import __file__ as dagster_dg_init_py + + dagster_dg_package_root = (Path(dagster_dg_init_py) / ".." / "..").resolve() + assert ( + dagster_dg_package_root / "dagster_dg_tests" + ).exists(), "Could not find dagster_dg_tests where expected" + sys.path.append(dagster_dg_package_root.as_posix()) diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py new file mode 100644 index 0000000000000..82a68cf6105d4 --- /dev/null +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py @@ -0,0 +1,92 @@ +import textwrap + +from click.testing import CliRunner +from dagster_dg.cli.info import info_component_type_command +from dagster_dg.utils import ensure_dagster_dg_tests_import + +ensure_dagster_dg_tests_import() + +from dagster_dg_tests.cli_tests.test_generate_commands import isolated_example_code_location_bar + + +def test_info_component_type_all_metadata_success(): + runner = CliRunner() + with isolated_example_code_location_bar(runner): + result = runner.invoke( + info_component_type_command, ["dagster_components.pipes_subprocess_script_collection"] + ) + assert result.exit_code == 0 + assert result.output.startswith( + textwrap.dedent(""" + dagster_components.pipes_subprocess_script_collection + + Description: + + Assets that wrap Python scripts + """).strip() + ) + + +def test_info_component_type_flag_fields_success(): + runner = CliRunner() + with isolated_example_code_location_bar(runner): + result = runner.invoke( + info_component_type_command, + ["dagster_components.pipes_subprocess_script_collection", "--description"], + ) + assert result.exit_code == 0 + assert result.output.startswith( + textwrap.dedent(""" + Assets that wrap Python scripts + """).strip() + ) + + result = runner.invoke( + info_component_type_command, + ["dagster_components.pipes_subprocess_script_collection", "--generate-params-schema"], + ) + assert result.exit_code == 0 + assert result.output.startswith( + textwrap.dedent(""" + No generate params schema defined. + """).strip() + ) + + result = runner.invoke( + info_component_type_command, + ["dagster_components.pipes_subprocess_script_collection", "--component-params-schema"], + ) + assert result.exit_code == 0 + assert result.output.startswith( + textwrap.dedent(""" + No component params schema defined. + """).strip() + ) + + +def test_info_component_type_outside_code_location_fails() -> None: + runner = CliRunner() + with runner.isolated_filesystem(): + result = runner.invoke( + info_component_type_command, ["dagster_components.pipes_subprocess_script_collection"] + ) + assert result.exit_code != 0 + assert "must be run inside a Dagster code location directory" in result.output + + +def test_info_component_type_multiple_flags_fails() -> None: + runner = CliRunner() + with isolated_example_code_location_bar(runner): + result = runner.invoke( + info_component_type_command, + [ + "dagster_components.pipes_subprocess_script_collection", + "--description", + "--generate-params-schema", + ], + ) + assert result.exit_code != 0 + assert ( + "Only one of --description, --generate-params-schema, and --component-params-schema can be specified." + in result.output + ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py index a53a51058a8e4..d50dc8c905764 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py @@ -1,23 +1,13 @@ -import sys -from pathlib import Path +import re from click.testing import CliRunner -from dagster_dg import __file__ as dagster_dg_init_py from dagster_dg.cli.generate import generate_code_location_command, generate_component_command from dagster_dg.cli.list import ( list_code_locations_command, list_component_types_command, list_components_command, ) - - -def ensure_dagster_dg_tests_import() -> None: - dagster_dg_package_root = (Path(dagster_dg_init_py) / ".." / "..").resolve() - assert ( - dagster_dg_package_root / "dagster_dg_tests" - ).exists(), "Could not find dagster_dg_tests where expected" - sys.path.append(dagster_dg_package_root.as_posix()) - +from dagster_dg.utils import ensure_dagster_dg_tests_import ensure_dagster_dg_tests_import() @@ -51,15 +41,10 @@ def test_list_component_types_success(): with isolated_example_code_location_bar(runner): result = runner.invoke(list_component_types_command) assert result.exit_code == 0 - assert ( - result.output - == "\n".join( - [ - "dagster_components.pipes_subprocess_script_collection", - ] - ) - + "\n" - ) + lines = result.output.strip().split("\n") + assert len(lines) == 2 + assert lines[0] == "dagster_components.pipes_subprocess_script_collection" + assert re.match(r" Assets that wrap.*", lines[1]) def test_list_component_types_outside_code_location_fails() -> None: From a64aa2cb3f11e27ccae0c17beacdcfcf3eb60319 Mon Sep 17 00:00:00 2001 From: OwenKephart Date: Fri, 13 Dec 2024 09:30:36 -0800 Subject: [PATCH 43/94] [components] allow automation_condition to be set with AssetSpecModel (#26451) ## Summary & Motivation As title. ## How I Tested These Changes ## Changelog NOCHANGELOG --- .../dagster_components/core/dsl_schema.py | 53 ++++++++++++++++++- .../dagster_components/lib/dbt_project.py | 13 +++-- .../lib/pipes_subprocess_script_collection.py | 5 ++ .../lib/sling_replication.py | 20 +++++-- .../components/scripts/component.yaml | 6 +++ .../integration_tests/test_dbt_project.py | 4 ++ .../components/jaffle_shop_dbt/component.yaml | 10 ++++ ...test_pipes_subprocess_script_collection.py | 12 ++++- 8 files changed, 114 insertions(+), 9 deletions(-) diff --git a/python_modules/libraries/dagster-components/dagster_components/core/dsl_schema.py b/python_modules/libraries/dagster-components/dagster_components/core/dsl_schema.py index bf63f7aba6e76..ffba4fca0531e 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/dsl_schema.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/dsl_schema.py @@ -1,8 +1,59 @@ -from typing import Dict, Optional +from typing import Any, Dict, Literal, Mapping, Optional, Union +from dagster._core.definitions.asset_spec import AssetSpec, map_asset_specs +from dagster._core.definitions.assets import AssetsDefinition +from dagster._core.definitions.declarative_automation.automation_condition import ( + AutomationCondition, +) +from dagster._core.definitions.definitions_class import Definitions +from dagster._record import replace +from dagster._utils.warnings import suppress_dagster_warnings from pydantic import BaseModel class OpSpecBaseModel(BaseModel): name: Optional[str] = None tags: Optional[Dict[str, str]] = None + + +class AutomationConditionModel(BaseModel): + type: str + params: Mapping[str, Any] = {} + + def to_automation_condition(self) -> AutomationCondition: + return getattr(AutomationCondition, self.type)(**self.params) + + +class AssetSpecProcessorModel(BaseModel): + target: str = "*" + strategy: Union[Literal["replace"], Literal["merge"]] = "replace" + description: Optional[str] = None + metadata: Optional[Mapping[str, Any]] = None + group_name: Optional[str] = None + tags: Optional[Mapping[str, str]] = None + automation_condition: Optional[AutomationConditionModel] = None + + def _props(self) -> Mapping[str, Any]: + return { + **self.model_dump(exclude={"target", "strategy"}), + "automation_condition": self.automation_condition.to_automation_condition() + if self.automation_condition + else None, + } + + @suppress_dagster_warnings + def _apply_to_spec(self, spec: AssetSpec) -> AssetSpec: + if self.strategy == "replace": + return spec.replace_attributes(**self._props()) + else: + return spec.merge_attributes(**self._props()) + + def transform(self, defs: Definitions) -> Definitions: + """Applies the specified transformation to the asset specs in the given definitions.""" + mappable = [d for d in defs.assets or [] if isinstance(d, (AssetsDefinition, AssetSpec))] + mapped_assets = map_asset_specs(self._apply_to_spec, mappable) + assets = [ + *mapped_assets, + *[d for d in defs.assets or [] if not isinstance(d, (AssetsDefinition, AssetSpec))], + ] + return replace(defs, assets=assets) diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py index 9ce448ad9f569..be79d0568856a 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import Any, Iterator, Mapping, Optional +from typing import Any, Iterator, Mapping, Optional, Sequence import click import dagster._check as check @@ -17,7 +17,7 @@ from dagster_components import Component, ComponentLoadContext from dagster_components.core.component import component from dagster_components.core.component_decl_builder import ComponentDeclNode, YamlComponentDecl -from dagster_components.core.dsl_schema import OpSpecBaseModel +from dagster_components.core.dsl_schema import AssetSpecProcessorModel, OpSpecBaseModel class DbtNodeTranslatorParams(BaseModel): @@ -29,6 +29,7 @@ class DbtProjectParams(BaseModel): dbt: DbtCliResource op: Optional[OpSpecBaseModel] = None translator: Optional[DbtNodeTranslatorParams] = None + asset_attributes: Optional[Sequence[AssetSpecProcessorModel]] = None class DbtGenerateParams(BaseModel): @@ -76,10 +77,12 @@ def __init__( dbt_resource: DbtCliResource, op_spec: Optional[OpSpecBaseModel], dbt_translator: Optional[DagsterDbtTranslator], + asset_transforms: Sequence[AssetSpecProcessorModel], ): self.dbt_resource = dbt_resource self.op_spec = op_spec self.dbt_translator = dbt_translator + self.asset_transforms = asset_transforms @classmethod def from_decl_node(cls, context: ComponentLoadContext, decl_node: ComponentDeclNode) -> Self: @@ -96,6 +99,7 @@ def from_decl_node(cls, context: ComponentLoadContext, decl_node: ComponentDeclN dbt_translator=DbtProjectComponentTranslator( translator_params=loaded_params.translator ), + asset_transforms=loaded_params.asset_attributes or [], ) def build_defs(self, context: ComponentLoadContext) -> Definitions: @@ -112,7 +116,10 @@ def build_defs(self, context: ComponentLoadContext) -> Definitions: def _fn(context: AssetExecutionContext): yield from self.execute(context=context, dbt=self.dbt_resource) - return Definitions(assets=[_fn]) + defs = Definitions(assets=[_fn]) + for transform in self.asset_transforms: + defs = transform.transform(defs) + return defs @classmethod def generate_files(cls, params: DbtGenerateParams) -> Mapping[str, Any]: diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py index 4fe157f1243f0..bacc8edb36dba 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py @@ -18,6 +18,7 @@ component, ) from dagster_components.core.component_decl_builder import YamlComponentDecl +from dagster_components.core.dsl_schema import AutomationConditionModel if TYPE_CHECKING: from dagster._core.definitions.definitions_class import Definitions @@ -33,6 +34,7 @@ class AssetSpecModel(BaseModel): code_version: Optional[str] = None owners: Sequence[str] = [] tags: Mapping[str, str] = {} + automation_condition: Optional[AutomationConditionModel] = None @suppress_dagster_warnings def to_asset_spec(self) -> AssetSpec: @@ -40,6 +42,9 @@ def to_asset_spec(self) -> AssetSpec: **{ **self.__dict__, "key": AssetKey.from_user_string(self.key), + "automation_condition": self.automation_condition.to_automation_condition() + if self.automation_condition + else None, }, ) diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py b/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py index 772cc42d0e1ec..2ad4160f49ad2 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import Any, Iterator, Optional, Union +from typing import Any, Iterator, Optional, Sequence, Union import yaml from dagster._core.definitions.definitions_class import Definitions @@ -14,22 +14,30 @@ from dagster_components import Component, ComponentLoadContext from dagster_components.core.component import component from dagster_components.core.component_decl_builder import ComponentDeclNode, YamlComponentDecl -from dagster_components.core.dsl_schema import OpSpecBaseModel +from dagster_components.core.dsl_schema import AssetSpecProcessorModel, OpSpecBaseModel class SlingReplicationParams(BaseModel): sling: Optional[SlingResource] = None op: Optional[OpSpecBaseModel] = None + asset_attributes: Optional[Sequence[AssetSpecProcessorModel]] = None @component(name="sling_replication") class SlingReplicationComponent(Component): params_schema = SlingReplicationParams - def __init__(self, dirpath: Path, resource: SlingResource, op_spec: Optional[OpSpecBaseModel]): + def __init__( + self, + dirpath: Path, + resource: SlingResource, + op_spec: Optional[OpSpecBaseModel], + asset_transforms: Sequence[AssetSpecProcessorModel], + ): self.dirpath = dirpath self.resource = resource self.op_spec = op_spec + self.asset_transforms = asset_transforms @classmethod def from_decl_node(cls, context: ComponentLoadContext, decl_node: ComponentDeclNode) -> Self: @@ -41,6 +49,7 @@ def from_decl_node(cls, context: ComponentLoadContext, decl_node: ComponentDeclN dirpath=decl_node.path, resource=loaded_params.sling or SlingResource(), op_spec=loaded_params.op, + asset_transforms=loaded_params.asset_attributes or [], ) def build_defs(self, context: ComponentLoadContext) -> Definitions: @@ -52,7 +61,10 @@ def build_defs(self, context: ComponentLoadContext) -> Definitions: def _fn(context: AssetExecutionContext, sling: SlingResource): yield from self.execute(context=context, sling=sling) - return Definitions(assets=[_fn], resources={"sling": self.resource}) + defs = Definitions(assets=[_fn], resources={"sling": self.resource}) + for transform in self.asset_transforms: + defs = transform.transform(defs) + return defs @classmethod def generate_files(cls, params: Any) -> None: diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/code_locations/python_script_location/components/scripts/component.yaml b/python_modules/libraries/dagster-components/dagster_components_tests/code_locations/python_script_location/components/scripts/component.yaml index 34bd590951b8b..e65c0273bb93b 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/code_locations/python_script_location/components/scripts/component.yaml +++ b/python_modules/libraries/dagster-components/dagster_components_tests/code_locations/python_script_location/components/scripts/component.yaml @@ -5,7 +5,13 @@ params: - path: script_one.py assets: - key: a + automation_condition: + type: eager - key: b + automation_condition: + type: on_cron + params: + cron_schedule: "@daily" deps: [up1, up2] - path: script_two.py assets: diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py index d3bc69c881f32..b71fc6a17c469 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py @@ -79,3 +79,7 @@ def test_load_from_path(dbt_path: Path) -> None: ) assert defs.get_asset_graph().get_all_asset_keys() == JAFFLE_SHOP_KEYS + + for asset_node in defs.get_asset_graph().asset_nodes: + assert asset_node.tags["foo"] == "bar" + assert asset_node.metadata["something"] == 1 diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/stub_code_locations/dbt_project_location/components/jaffle_shop_dbt/component.yaml b/python_modules/libraries/dagster-components/dagster_components_tests/stub_code_locations/dbt_project_location/components/jaffle_shop_dbt/component.yaml index 85c04ada2fb8d..4cbf5322769c5 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/stub_code_locations/dbt_project_location/components/jaffle_shop_dbt/component.yaml +++ b/python_modules/libraries/dagster-components/dagster_components_tests/stub_code_locations/dbt_project_location/components/jaffle_shop_dbt/component.yaml @@ -3,3 +3,13 @@ type: dagster_components.dbt_project params: dbt: project_dir: jaffle_shop + + asset_attributes: + - tags: + foo: bar + metadata: + something: 1 + automation_condition: + type: on_cron + params: + cron_schedule: "@daily" diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py index ae4206ef1fe58..65e61a54b312c 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py @@ -35,7 +35,17 @@ def test_python_params() -> None: "scripts": [ { "path": "script_one.py", - "assets": [{"key": "a"}, {"key": "b", "deps": ["up1", "up2"]}], + "assets": [ + {"key": "a", "automation_condition": {"type": "eager"}}, + { + "key": "b", + "automation_condition": { + "type": "on_cron", + "params": {"cron_schedule": "@daily"}, + }, + "deps": ["up1", "up2"], + }, + ], }, {"path": "subdir/script_three.py", "assets": [{"key": "key_override"}]}, ] From 9e640201e59bc42588f9da5a7b5ffc6f960ac94e Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Fri, 13 Dec 2024 12:03:38 -0600 Subject: [PATCH 44/94] [graphql] use get_assets_in_job in Solid.assetNodes (#26475) Allows leveraging overridden implemntation for resolving theses assets ## How I Tested These Changes existing coverage --- .../dagster_graphql/schema/solids.py | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/solids.py b/python_modules/dagster-graphql/dagster_graphql/schema/solids.py index c6ce0836b408e..0a1a58b15133a 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/solids.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/solids.py @@ -373,7 +373,7 @@ class GrapheneISolidDefinition(graphene.Interface): metadata = non_null_list(GrapheneMetadataItemDefinition) input_definitions = non_null_list(GrapheneInputDefinition) output_definitions = non_null_list(GrapheneOutputDefinition) - asset_nodes = non_null_list("dagster_graphql.schema.asset_graph.GrapheneAssetNode") + assetNodes = non_null_list("dagster_graphql.schema.asset_graph.GrapheneAssetNode") class Meta: name = "ISolidDefinition" @@ -424,10 +424,7 @@ def resolve_output_definitions(self, _graphene_info): for output_def_snap in self._solid_def_snap.output_def_snaps ] - def resolve_asset_nodes(self, graphene_info: ResolveInfo) -> Sequence["GrapheneAssetNode"]: - # NOTE: This is a temporary hack. We really should prob be resolving solids against the repo - # rather than pipeline, that way we would not have to refetch the repo here here in order to - # access the asset nodes. + def resolve_assetNodes(self, graphene_info: ResolveInfo) -> Sequence["GrapheneAssetNode"]: from dagster_graphql.schema.asset_graph import GrapheneAssetNode # This is a workaround for the fact that asset info is not persisted in pipeline snapshots. @@ -435,13 +432,12 @@ def resolve_asset_nodes(self, graphene_info: ResolveInfo) -> Sequence["GrapheneA return [] else: assert isinstance(self._represented_pipeline, RemoteJob) - repo_handle = self._represented_pipeline.repository_handle - origin = repo_handle.code_location_origin - location = graphene_info.context.get_code_location(origin.location_name) - ext_repo = location.get_repository(repo_handle.repository_name) + job_asset_nodes = graphene_info.context.get_assets_in_job( + self._represented_pipeline.handle.to_selector() + ) remote_nodes = [ remote_node - for remote_node in ext_repo.asset_graph.asset_nodes + for remote_node in job_asset_nodes if ( (remote_node.asset_node_snap.node_definition_name == self.solid_def_name) or ( @@ -450,21 +446,20 @@ def resolve_asset_nodes(self, graphene_info: ResolveInfo) -> Sequence["GrapheneA ) ) ] - + differ = None base_deployment_context = graphene_info.context.get_base_deployment_context() + if base_deployment_context: + differ = AssetGraphDiffer.from_remote_repositories( + code_location_name=self._represented_pipeline.handle.location_name, + repository_name=self._represented_pipeline.handle.repository_name, + branch_workspace=graphene_info.context, + base_workspace=base_deployment_context, + ) return [ GrapheneAssetNode( remote_node=remote_node, - # base_deployment_context will be None if we are not in a branch deployment - asset_graph_differ=AssetGraphDiffer.from_remote_repositories( - code_location_name=location.name, - repository_name=ext_repo.name, - branch_workspace=graphene_info.context, - base_workspace=base_deployment_context, - ) - if base_deployment_context is not None - else None, + asset_graph_differ=differ, ) for remote_node in remote_nodes ] From 813660f6947f190f3daf2339f1313fb80e936e43 Mon Sep 17 00:00:00 2001 From: Marco polo Date: Fri, 13 Dec 2024 13:12:52 -0500 Subject: [PATCH 45/94] [Selection syntax autocomplete](Refactor) input component to be generalized. (#26410) ## Summary & Motivation Last remaining piece of the generalized autocomplete work is to generalize the input component itself. The generalized SelectionAutoCompleteInput component will be used by the Run gantt chart selection input, the op selection input and the asset selection input. Note this PR is just a refactor. No new logic was added. ## How I Tested These Changes Existing jest tests + manually tested the asset selection filtering input and made sure it still works. --- .../src/app/DefaultFeatureFlags.oss.tsx | 3 + .../input/AssetSelectionInput.oss.tsx | 285 +++++------------- .../input/AssetSelectionLinter.ts | 34 --- .../AssetSelectionSyntaxErrorListener.tsx | 26 -- .../src/selection/SelectionAutoComplete.ts | 16 +- .../selection/SelectionAutoCompleteInput.tsx | 212 +++++++++++++ .../__tests__/SelectionAutoComplete.test.ts | 71 ++++- .../src/selection/createSelectionLinter.ts | 46 +++ 8 files changed, 413 insertions(+), 280 deletions(-) delete mode 100644 js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionLinter.ts delete mode 100644 js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionSyntaxErrorListener.tsx create mode 100644 js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoCompleteInput.tsx create mode 100644 js_modules/dagster-ui/packages/ui-core/src/selection/createSelectionLinter.ts diff --git a/js_modules/dagster-ui/packages/ui-core/src/app/DefaultFeatureFlags.oss.tsx b/js_modules/dagster-ui/packages/ui-core/src/app/DefaultFeatureFlags.oss.tsx index 63a0632523530..4dab268bccfc8 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/app/DefaultFeatureFlags.oss.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/app/DefaultFeatureFlags.oss.tsx @@ -8,6 +8,9 @@ export const DEFAULT_FEATURE_FLAG_VALUES: Partial> [FeatureFlag.flagAssetSelectionSyntax]: new URLSearchParams(global?.location?.search ?? '').has( 'new-asset-selection-syntax', ), + [FeatureFlag.flagRunSelectionSyntax]: new URLSearchParams(global?.location?.search ?? '').has( + 'new-run-selection-syntax', + ), // Flags for tests [FeatureFlag.__TestFlagDefaultTrue]: true, diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionInput.oss.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionInput.oss.tsx index f3060d7f460f8..ef87451179f9b 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionInput.oss.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionInput.oss.tsx @@ -1,19 +1,15 @@ -import {Colors, Icon, Icons} from '@dagster-io/ui-components'; -import CodeMirror, {Editor, HintFunction} from 'codemirror'; -import {useLayoutEffect, useMemo, useRef} from 'react'; -import styled, {createGlobalStyle, css} from 'styled-components'; +import {Icons} from '@dagster-io/ui-components'; +import {useMemo} from 'react'; +import styled from 'styled-components'; -import {lintAssetSelection} from './AssetSelectionLinter'; import {assertUnreachable} from '../../app/Util'; import {AssetGraphQueryItem} from '../../asset-graph/useAssetGraphData'; -import {useUpdatingRef} from '../../hooks/useUpdatingRef'; -import {createSelectionHint} from '../../selection/SelectionAutoComplete'; -import { - SelectionAutoCompleteInputCSS, - applyStaticSyntaxHighlighting, -} from '../../selection/SelectionAutoCompleteHighlighter'; +import {SelectionAutoCompleteInput, iconStyle} from '../../selection/SelectionAutoCompleteInput'; +import {createSelectionLinter} from '../../selection/createSelectionLinter'; import {placeholderTextForItems} from '../../ui/GraphQueryInput'; import {buildRepoPathForHuman} from '../../workspace/buildRepoAddress'; +import {AssetSelectionLexer} from '../generated/AssetSelectionLexer'; +import {AssetSelectionParser} from '../generated/AssetSelectionParser'; import 'codemirror/addon/edit/closebrackets'; import 'codemirror/lib/codemirror.css'; @@ -32,215 +28,86 @@ interface AssetSelectionInputProps { const FUNCTIONS = ['sinks', 'roots']; export const AssetSelectionInput = ({value, onChange, assets}: AssetSelectionInputProps) => { - const editorRef = useRef(null); - const cmInstance = useRef(null); - - const currentValueRef = useRef(value); - - const hintRef = useUpdatingRef( - useMemo(() => { - const assetNamesSet: Set = new Set(); - const tagNamesSet: Set = new Set(); - const ownersSet: Set = new Set(); - const groupsSet: Set = new Set(); - const kindsSet: Set = new Set(); - const codeLocationSet: Set = new Set(); - - assets.forEach((asset) => { - assetNamesSet.add(asset.name); - asset.node.tags.forEach((tag) => { - if (tag.key && tag.value) { - tagNamesSet.add(`${tag.key}=${tag.value}`); - } else { - tagNamesSet.add(tag.key); - } - }); - asset.node.owners.forEach((owner) => { - switch (owner.__typename) { - case 'TeamAssetOwner': - ownersSet.add(owner.team); - break; - case 'UserAssetOwner': - ownersSet.add(owner.email); - break; - default: - assertUnreachable(owner); - } - }); - if (asset.node.groupName) { - groupsSet.add(asset.node.groupName); + const attributesMap = useMemo(() => { + const assetNamesSet: Set = new Set(); + const tagNamesSet: Set = new Set(); + const ownersSet: Set = new Set(); + const groupsSet: Set = new Set(); + const kindsSet: Set = new Set(); + const codeLocationSet: Set = new Set(); + + assets.forEach((asset) => { + assetNamesSet.add(asset.name); + asset.node.tags.forEach((tag) => { + if (tag.key && tag.value) { + tagNamesSet.add(`${tag.key}=${tag.value}`); + } else { + tagNamesSet.add(tag.key); } - asset.node.kinds.forEach((kind) => { - kindsSet.add(kind); - }); - const location = buildRepoPathForHuman( - asset.node.repository.name, - asset.node.repository.location.name, - ); - codeLocationSet.add(location); - }); - - const assetNames = Array.from(assetNamesSet); - const tagNames = Array.from(tagNamesSet); - const owners = Array.from(ownersSet); - const groups = Array.from(groupsSet); - const kinds = Array.from(kindsSet); - const codeLocations = Array.from(codeLocationSet); - - return createSelectionHint( - 'key', - { - key: assetNames, - tag: tagNames, - owner: owners, - group: groups, - kind: kinds, - code_location: codeLocations, - }, - FUNCTIONS, - ); - }, [assets]), - ); - - useLayoutEffect(() => { - if (editorRef.current && !cmInstance.current) { - cmInstance.current = CodeMirror(editorRef.current, { - value, - mode: 'assetSelection', - lineNumbers: false, - lineWrapping: false, - scrollbarStyle: 'native', - autoCloseBrackets: true, - lint: { - getAnnotations: lintAssetSelection, - async: false, - }, - placeholder: placeholderTextForItems('Type an asset subset…', assets), - extraKeys: { - 'Ctrl-Space': 'autocomplete', - Tab: (cm: Editor) => { - cm.replaceSelection(' ', 'end'); - }, - }, }); - - cmInstance.current.setSize('100%', 20); - - // Enforce single line by preventing newlines - cmInstance.current.on('beforeChange', (_instance: Editor, change) => { - if (change.text.some((line) => line.includes('\n'))) { - change.cancel(); - } - }); - - cmInstance.current.on('change', (instance: Editor, change) => { - const newValue = instance.getValue().replace(/\s+/g, ' '); - currentValueRef.current = newValue; - onChange(newValue); - - if (change.origin === 'complete' && change.text[0]?.endsWith('()')) { - // Set cursor inside the right parenthesis - const cursor = instance.getCursor(); - instance.setCursor({...cursor, ch: cursor.ch - 1}); + asset.node.owners.forEach((owner) => { + switch (owner.__typename) { + case 'TeamAssetOwner': + ownersSet.add(owner.team); + break; + case 'UserAssetOwner': + ownersSet.add(owner.email); + break; + default: + assertUnreachable(owner); } }); - - cmInstance.current.on('inputRead', (instance: Editor) => { - showHint(instance, hintRef.current); - }); - - cmInstance.current.on('cursorActivity', (instance: Editor) => { - applyStaticSyntaxHighlighting(instance); - showHint(instance, hintRef.current); - }); - - requestAnimationFrame(() => { - if (!cmInstance.current) { - return; - } - - applyStaticSyntaxHighlighting(cmInstance.current); + if (asset.node.groupName) { + groupsSet.add(asset.node.groupName); + } + asset.node.kinds.forEach((kind) => { + kindsSet.add(kind); }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // Update CodeMirror when value prop changes - useLayoutEffect(() => { - const noNewLineValue = value.replace('\n', ' '); - if (cmInstance.current && cmInstance.current.getValue() !== noNewLineValue) { - const instance = cmInstance.current; - const cursor = instance.getCursor(); - instance.setValue(noNewLineValue); - instance.setCursor(cursor); - showHint(instance, hintRef.current); - } - }, [hintRef, value]); + const location = buildRepoPathForHuman( + asset.node.repository.name, + asset.node.repository.location.name, + ); + codeLocationSet.add(location); + }); + const assetNames = Array.from(assetNamesSet); + const tagNames = Array.from(tagNamesSet); + const owners = Array.from(ownersSet); + const groups = Array.from(groupsSet); + const kinds = Array.from(kindsSet); + const codeLocations = Array.from(codeLocationSet); + + return { + key: assetNames, + tag: tagNames, + owner: owners, + group: groups, + kind: kinds, + code_location: codeLocations, + }; + }, [assets]); + + const linter = useMemo( + () => createSelectionLinter({Lexer: AssetSelectionLexer, Parser: AssetSelectionParser}), + [], + ); return ( - <> - - - -
- - - + + + ); }; -const iconStyle = (img: string) => css` - &:before { - content: ' '; - width: 14px; - mask-size: contain; - mask-repeat: no-repeat; - mask-position: center; - mask-image: url(${img}); - background: ${Colors.accentPrimary()}; - display: inline-block; - } -`; - -const InputDiv = styled.div` - ${SelectionAutoCompleteInputCSS} +const WrapperDiv = styled.div` .attribute-owner { ${iconStyle(Icons.owner.src)} } `; - -const GlobalHintStyles = createGlobalStyle` - .CodeMirror-hints { - background: ${Colors.popoverBackground()}; - border: none; - border-radius: 4px; - padding: 8px 4px; - .CodeMirror-hint { - border-radius: 4px; - font-size: 14px; - padding: 6px 8px 6px 12px; - color: ${Colors.textDefault()}; - &.CodeMirror-hint-active { - background-color: ${Colors.backgroundBlue()}; - color: ${Colors.textDefault()}; - } - } - } -`; - -function showHint(instance: Editor, hint: HintFunction) { - requestAnimationFrame(() => { - instance.showHint({ - hint, - completeSingle: false, - moveOnOverlap: true, - updateOnCursorActivity: true, - }); - }); -} diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionLinter.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionLinter.ts deleted file mode 100644 index f1f1eb059c23e..0000000000000 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionLinter.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {CharStreams, CommonTokenStream} from 'antlr4ts'; -import CodeMirror from 'codemirror'; - -import {AssetSelectionSyntaxErrorListener} from './AssetSelectionSyntaxErrorListener'; -import {AssetSelectionLexer} from '../generated/AssetSelectionLexer'; -import {AssetSelectionParser} from '../generated/AssetSelectionParser'; - -export const lintAssetSelection = (text: string) => { - const errorListener = new AssetSelectionSyntaxErrorListener(); - - const inputStream = CharStreams.fromString(text); - const lexer = new AssetSelectionLexer(inputStream); - - lexer.removeErrorListeners(); - lexer.addErrorListener(errorListener); - - const tokens = new CommonTokenStream(lexer); - const parser = new AssetSelectionParser(tokens); - - parser.removeErrorListeners(); // Remove default console error listener - parser.addErrorListener(errorListener); - - parser.start(); - - // Map syntax errors to CodeMirror's lint format - const lintErrors = errorListener.errors.map((error) => ({ - message: error.message.replace(', ', ''), - severity: 'error', - from: CodeMirror.Pos(error.line, error.column), - to: CodeMirror.Pos(error.line, text.length), - })); - - return lintErrors; -}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionSyntaxErrorListener.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionSyntaxErrorListener.tsx deleted file mode 100644 index 89d87f2dbf09e..0000000000000 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-selection/input/AssetSelectionSyntaxErrorListener.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import {ANTLRErrorListener, RecognitionException, Recognizer} from 'antlr4ts'; - -interface SyntaxError { - message: string; - line: number; - column: number; -} - -export class AssetSelectionSyntaxErrorListener implements ANTLRErrorListener { - public errors: SyntaxError[] = []; - - syntaxError( - _recognizer: Recognizer, - _offendingSymbol: T | undefined, - line: number, - charPositionInLine: number, - msg: string, - _e: RecognitionException | undefined, - ): void { - this.errors.push({ - message: msg, - line: line - 1, // CodeMirror lines are 0-based - column: charPositionInLine, - }); - } -} diff --git a/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoComplete.ts b/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoComplete.ts index 8603de6447fe8..8973cd0835cdd 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoComplete.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoComplete.ts @@ -38,7 +38,7 @@ type TextCallback = (value: string) => string; const DEFAULT_TEXT_CALLBACK = (value: string) => value; // set to true for useful debug output. -const DEBUG = true; +const DEBUG = false; export class SelectionAutoCompleteVisitor extends AbstractParseTreeVisitor @@ -507,11 +507,15 @@ export class SelectionAutoCompleteVisitor } } -export function createSelectionHint, N extends keyof T>( - _nameBase: N, - attributesMap: T, - functions: string[], -): CodeMirror.HintFunction { +export function createSelectionHint, N extends keyof T>({ + nameBase: _nameBase, + attributesMap, + functions, +}: { + nameBase: N; + attributesMap: T; + functions: string[]; +}): CodeMirror.HintFunction { const nameBase = _nameBase as string; return function (cm: CodeMirror.Editor, _options: CodeMirror.ShowHintOptions): any { diff --git a/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoCompleteInput.tsx b/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoCompleteInput.tsx new file mode 100644 index 0000000000000..e84b930cf248d --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/selection/SelectionAutoCompleteInput.tsx @@ -0,0 +1,212 @@ +import {Colors, Icon} from '@dagster-io/ui-components'; +import CodeMirror, {Editor, HintFunction} from 'codemirror'; +import {Linter} from 'codemirror/addon/lint/lint'; +import {useLayoutEffect, useMemo, useRef} from 'react'; +import styled, {createGlobalStyle, css} from 'styled-components'; + +import { + SelectionAutoCompleteInputCSS, + applyStaticSyntaxHighlighting, +} from './SelectionAutoCompleteHighlighter'; +import {useUpdatingRef} from '../hooks/useUpdatingRef'; +import {createSelectionHint} from '../selection/SelectionAutoComplete'; + +import 'codemirror/addon/edit/closebrackets'; +import 'codemirror/lib/codemirror.css'; +import 'codemirror/addon/hint/show-hint'; +import 'codemirror/addon/hint/show-hint.css'; +import 'codemirror/addon/lint/lint.css'; +import 'codemirror/addon/display/placeholder'; + +type SelectionAutoCompleteInputProps, N extends keyof T> = { + nameBase: N; + attributesMap: T; + placeholder: string; + functions: string[]; + linter: Linter; + value: string; + onChange: (value: string) => void; +}; + +export const SelectionAutoCompleteInput = , N extends keyof T>({ + value, + nameBase, + placeholder, + onChange, + functions, + linter, + attributesMap, +}: SelectionAutoCompleteInputProps) => { + const editorRef = useRef(null); + const cmInstance = useRef(null); + + const currentValueRef = useUpdatingRef(value); + const currentPendingValueRef = useRef(value); + const setValueTimeoutRef = useRef>(null); + + const hintRef = useUpdatingRef( + useMemo(() => { + return createSelectionHint({nameBase, attributesMap, functions}); + }, [nameBase, attributesMap, functions]), + ); + + useLayoutEffect(() => { + if (editorRef.current && !cmInstance.current) { + cmInstance.current = CodeMirror(editorRef.current, { + value, + mode: 'assetSelection', + lineNumbers: false, + lineWrapping: false, + scrollbarStyle: 'native', + autoCloseBrackets: true, + lint: { + getAnnotations: linter, + async: false, + }, + placeholder, + extraKeys: { + 'Ctrl-Space': 'autocomplete', + Tab: (cm: Editor) => { + cm.replaceSelection(' ', 'end'); + }, + }, + }); + + cmInstance.current.setSize('100%', 20); + + // Enforce single line by preventing newlines + cmInstance.current.on('beforeChange', (_instance: Editor, change) => { + if (change.text.some((line) => line.includes('\n'))) { + change.cancel(); + } + }); + + cmInstance.current.on('change', (instance: Editor, change) => { + const newValue = instance.getValue().replace(/\s+/g, ' '); + currentPendingValueRef.current = newValue; + if (setValueTimeoutRef.current) { + clearTimeout(setValueTimeoutRef.current); + } + setValueTimeoutRef.current = setTimeout(() => { + onChange(newValue); + }, 2000); + + if (change.origin === 'complete' && change.text[0]?.endsWith('()')) { + // Set cursor inside the right parenthesis + const cursor = instance.getCursor(); + instance.setCursor({...cursor, ch: cursor.ch - 1}); + } + }); + + cmInstance.current.on('inputRead', (instance: Editor) => { + showHint(instance, hintRef.current); + }); + + cmInstance.current.on('cursorActivity', (instance: Editor) => { + applyStaticSyntaxHighlighting(instance); + showHint(instance, hintRef.current); + }); + + cmInstance.current.on('blur', () => { + if (currentPendingValueRef.current !== currentValueRef.current) { + onChange(currentPendingValueRef.current); + } + }); + + requestAnimationFrame(() => { + if (!cmInstance.current) { + return; + } + + applyStaticSyntaxHighlighting(cmInstance.current); + }); + } + + return () => { + const cm = cmInstance.current; + if (cm) { + // Clean up the instance... + cm.closeHint(); + cm.getWrapperElement()?.parentNode?.removeChild(cm.getWrapperElement()); + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // Update CodeMirror when value prop changes + useLayoutEffect(() => { + const noNewLineValue = value.replace('\n', ' '); + if (cmInstance.current && cmInstance.current.getValue() !== noNewLineValue) { + const instance = cmInstance.current; + const cursor = instance.getCursor(); + instance.setValue(noNewLineValue); + instance.setCursor(cursor); + showHint(instance, hintRef.current); + } + }, [hintRef, value]); + + return ( + <> + + + +
+ + + ); +}; + +export const iconStyle = (img: string) => css` + &:before { + content: ' '; + width: 14px; + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; + mask-image: url(${img}); + background: ${Colors.accentPrimary()}; + display: inline-block; + } +`; + +export const InputDiv = styled.div` + ${SelectionAutoCompleteInputCSS} +`; + +const GlobalHintStyles = createGlobalStyle` + .CodeMirror-hints { + background: ${Colors.popoverBackground()}; + border: none; + border-radius: 4px; + padding: 8px 4px; + .CodeMirror-hint { + border-radius: 4px; + font-size: 14px; + padding: 6px 8px 6px 12px; + color: ${Colors.textDefault()}; + &.CodeMirror-hint-active { + background-color: ${Colors.backgroundBlue()}; + color: ${Colors.textDefault()}; + } + } + } +`; + +function showHint(instance: Editor, hint: HintFunction) { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + instance.showHint({ + hint, + completeSingle: false, + moveOnOverlap: true, + updateOnCursorActivity: true, + }); + }); + }); +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/selection/__tests__/SelectionAutoComplete.test.ts b/js_modules/dagster-ui/packages/ui-core/src/selection/__tests__/SelectionAutoComplete.test.ts index 9e63b325f6d1a..88322779bd09a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/selection/__tests__/SelectionAutoComplete.test.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/selection/__tests__/SelectionAutoComplete.test.ts @@ -3,9 +3,9 @@ import {Hint, Hints, Position} from 'codemirror'; import {createSelectionHint} from '../SelectionAutoComplete'; describe('createAssetSelectionHint', () => { - const selectionHint = createSelectionHint( - 'key', - { + const selectionHint = createSelectionHint({ + nameBase: 'key', + attributesMap: { key: ['asset1', 'asset2', 'asset3'], tag: ['tag1', 'tag2', 'tag3'], owner: ['marco@dagsterlabs.com', 'team:frontend'], @@ -13,8 +13,8 @@ describe('createAssetSelectionHint', () => { kind: ['kind1', 'kind2'], code_location: ['repo1@location1', 'repo2@location2'], }, - ['sinks', 'roots'], - ); + functions: ['sinks', 'roots'], + }); type HintsModified = Omit & { list: Array; @@ -818,4 +818,65 @@ describe('createAssetSelectionHint', () => { to: 60, }); }); + + it('handles complex ands/ors', () => { + expect(testAutocomplete('key:"value"* or tag:"value"+ and owner:"owner" and |')).toEqual({ + from: 51, + list: [ + { + displayText: 'key_substring:', + text: 'key_substring:', + }, + { + displayText: 'key:', + text: 'key:', + }, + { + displayText: 'tag:', + text: 'tag:', + }, + { + displayText: 'owner:', + text: 'owner:', + }, + { + displayText: 'group:', + text: 'group:', + }, + { + displayText: 'kind:', + text: 'kind:', + }, + { + displayText: 'code_location:', + text: 'code_location:', + }, + { + displayText: 'sinks()', + text: 'sinks()', + }, + { + displayText: 'roots()', + text: 'roots()', + }, + { + displayText: 'not', + text: 'not ', + }, + { + displayText: '*', + text: '*', + }, + { + displayText: '+', + text: '+', + }, + { + displayText: '(', + text: '()', + }, + ], + to: 51, + }); + }); }); diff --git a/js_modules/dagster-ui/packages/ui-core/src/selection/createSelectionLinter.ts b/js_modules/dagster-ui/packages/ui-core/src/selection/createSelectionLinter.ts new file mode 100644 index 0000000000000..ac10d4c98f504 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/selection/createSelectionLinter.ts @@ -0,0 +1,46 @@ +import {CharStreams, CommonTokenStream, Lexer, Parser, ParserRuleContext} from 'antlr4ts'; +import CodeMirror from 'codemirror'; +import {Linter} from 'codemirror/addon/lint/lint'; + +import {CustomErrorListener} from './CustomErrorListener'; + +type LexerConstructor = new (...args: any[]) => Lexer; +type ParserConstructor = new (...args: any[]) => Parser & { + start: () => ParserRuleContext; +}; + +export function createSelectionLinter({ + Lexer: LexerKlass, + Parser: ParserKlass, +}: { + Lexer: LexerConstructor; + Parser: ParserConstructor; +}): Linter { + return (text: string) => { + const errorListener = new CustomErrorListener(); + + const inputStream = CharStreams.fromString(text); + const lexer = new LexerKlass(inputStream); + + lexer.removeErrorListeners(); + lexer.addErrorListener(errorListener); + + const tokens = new CommonTokenStream(lexer); + const parser = new ParserKlass(tokens); + + parser.removeErrorListeners(); // Remove default console error listener + parser.addErrorListener(errorListener); + + parser.start(); + + // Map syntax errors to CodeMirror's lint format + const lintErrors = errorListener.getErrors().map((error) => ({ + message: error.message.replace(', ', ''), + severity: 'error', + from: CodeMirror.Pos(error.line, error.column), + to: CodeMirror.Pos(error.line, text.length), + })); + + return lintErrors; + }; +} From 72c7f5e6c6bdc0ae4ffe65796427038a081275ee Mon Sep 17 00:00:00 2001 From: Ben Pankow Date: Fri, 13 Dec 2024 11:19:31 -0800 Subject: [PATCH 46/94] [dagster-sigma] Implement materializing workbooks (#25433) ## Summary Introduces asset definitions builder to allow materializing Sigma workbooks. Runs each scheduled materialization for the provided workbook. ## How I Tested These Changes Unit test, tested against Sigma instance. --- .../dagster-sigma/dagster_sigma/__init__.py | 3 + .../dagster-sigma/dagster_sigma/assets.py | 38 ++++++ .../dagster-sigma/dagster_sigma/resource.py | 127 ++++++++++++++++++ .../dagster-sigma/dagster_sigma/translator.py | 44 +++++- .../dagster_sigma_tests/conftest.py | 29 ++++ .../materialize_workbook.py | 38 ++++++ .../dagster_sigma_tests/test_asset_specs.py | 23 ++++ .../dagster_sigma_tests/test_translator.py | 1 + 8 files changed, 296 insertions(+), 7 deletions(-) create mode 100644 python_modules/libraries/dagster-sigma/dagster_sigma/assets.py create mode 100644 python_modules/libraries/dagster-sigma/dagster_sigma_tests/materialize_workbook.py diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma/__init__.py b/python_modules/libraries/dagster-sigma/dagster_sigma/__init__.py index eed90af5624b8..944e51de4e4c2 100644 --- a/python_modules/libraries/dagster-sigma/dagster_sigma/__init__.py +++ b/python_modules/libraries/dagster-sigma/dagster_sigma/__init__.py @@ -1,5 +1,8 @@ from dagster._core.libraries import DagsterLibraryRegistry +from dagster_sigma.assets import ( + build_materialize_workbook_assets_definition as build_materialize_workbook_assets_definition, +) from dagster_sigma.resource import ( SigmaBaseUrl as SigmaBaseUrl, SigmaFilter as SigmaFilter, diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma/assets.py b/python_modules/libraries/dagster-sigma/dagster_sigma/assets.py new file mode 100644 index 0000000000000..8f7ff644e5d6e --- /dev/null +++ b/python_modules/libraries/dagster-sigma/dagster_sigma/assets.py @@ -0,0 +1,38 @@ +from typing import cast + +from dagster import AssetExecutionContext, AssetsDefinition, AssetSpec, multi_asset +from dagster._annotations import experimental + + +@experimental +def build_materialize_workbook_assets_definition( + resource_key: str, + spec: AssetSpec, +) -> AssetsDefinition: + """Returns an AssetsDefinition which will, when materialized, + run all materialization schedules for the targeted Sigma workbook. + Note that this will not update portions of a workbook which are not + assigned to a materialization schedule. + + For more information, see + https://help.sigmacomputing.com/docs/materialization#create-materializations-in-workbooks + + Args: + resource_key (str): The resource key to use for the Sigma resource. + spec (AssetSpec): The asset spec of the Sigma workbook. + + Returns: + AssetsDefinition: The AssetsDefinition which rebuilds a Sigma workbook. + """ + from dagster_sigma import SigmaOrganization + + @multi_asset( + name=f"sigma_materialize_{spec.key.to_python_identifier()}", + specs=[spec], + required_resource_keys={resource_key}, + ) + def asset_fn(context: AssetExecutionContext): + sigma = cast(SigmaOrganization, getattr(context.resources, resource_key)) + yield from sigma.run_materializations_for_workbook(spec) + + return asset_fn diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma/resource.py b/python_modules/libraries/dagster-sigma/dagster_sigma/resource.py index 733be0d2f29fd..55d20e57968e9 100644 --- a/python_modules/libraries/dagster-sigma/dagster_sigma/resource.py +++ b/python_modules/libraries/dagster-sigma/dagster_sigma/resource.py @@ -1,6 +1,8 @@ import asyncio import contextlib +import enum import os +import time import urllib.parse import warnings from collections import defaultdict @@ -30,6 +32,7 @@ from dagster._core.definitions.asset_spec import AssetSpec from dagster._core.definitions.definitions_class import Definitions from dagster._core.definitions.definitions_load_context import StateBackedDefinitionsLoader +from dagster._core.definitions.events import AssetMaterialization from dagster._core.definitions.repository_definition.repository_definition import RepositoryLoadData from dagster._record import IHaveNew, record_custom from dagster._serdes.serdes import deserialize_value @@ -45,6 +48,7 @@ SigmaOrganizationData, SigmaTable, SigmaWorkbook, + SigmaWorkbookMetadataSet, _inode_from_url, ) @@ -53,6 +57,12 @@ logger = get_dagster_logger("dagster_sigma") +class SigmaMaterializationStatus(str, enum.Enum): + PENDING = "pending" + BUILDING = "building" + READY = "ready" + + @record_custom class SigmaFilter(IHaveNew): """Filters the set of Sigma objects to fetch. @@ -162,6 +172,30 @@ async def _fetch_json_async( response.raise_for_status() return await response.json() + def _fetch_json( + self, + endpoint: str, + method: str = "GET", + query_params: Optional[Dict[str, Any]] = None, + json: Optional[Dict[str, Any]] = None, + ) -> Dict[str, Any]: + url = f"{self.base_url}/v2/{endpoint}" + if query_params: + url = f"{url}?{urllib.parse.urlencode(query_params)}" + + response = requests.request( + method=method, + url=url, + headers={ + "Accept": "application/json", + "Authorization": f"Bearer {self.api_token}", + **SIGMA_PARTNER_ID_TAG, + }, + json=json, + ) + response.raise_for_status() + return response.json() + async def _fetch_json_async_paginated_entries( self, endpoint: str, query_params: Optional[Dict[str, Any]] = None, limit: int = 1000 ) -> List[Dict[str, Any]]: @@ -255,6 +289,86 @@ def try_except_http_warn(self, should_catch: bool, msg: str) -> Iterator[None]: else: raise + def _begin_workbook_materialization(self, workbook_id: str, sheet_id: str) -> str: + output = self._fetch_json( + f"workbooks/{workbook_id}/materializations", + method="POST", + json={"sheetId": sheet_id}, + ) + return output["materializationId"] + + def _fetch_materialization_status( + self, workbook_id: str, materialization_id: str + ) -> Dict[str, Any]: + return self._fetch_json(f"workbooks/{workbook_id}/materializations/{materialization_id}") + + def _run_materializations_for_workbook( + self, workbook_id: str, sheet_ids: AbstractSet[str] + ) -> None: + materialization_id_to_sheet = dict( + zip( + [ + self._begin_workbook_materialization(workbook_id, sheet_id) + for sheet_id in sheet_ids + ], + sheet_ids, + ) + ) + remaining_materializations = set(materialization_id_to_sheet.keys()) + + successful_sheets = set() + failed_sheets = set() + + while remaining_materializations: + materialization_statuses = [ + self._fetch_materialization_status(workbook_id, materialization_id) + for materialization_id in remaining_materializations + ] + for status in materialization_statuses: + if status["status"] not in ( + SigmaMaterializationStatus.PENDING, + SigmaMaterializationStatus.BUILDING, + ): + remaining_materializations.remove(status["materializationId"]) + if status["status"] == SigmaMaterializationStatus.READY: + successful_sheets.add( + materialization_id_to_sheet[status["materializationId"]] + ) + else: + failed_sheets.add(materialization_id_to_sheet[status["materializationId"]]) + + time.sleep(5) + + if failed_sheets: + if successful_sheets: + raise Exception( + f"Materializations for sheets {', '.join(failed_sheets)} failed for workbook {workbook_id}" + f", materializations for sheets {', '.join(successful_sheets)} succeeded." + ) + else: + raise Exception( + f"Materializations for sheets {', '.join(failed_sheets)} failed for workbook {workbook_id}" + ) + + def run_materializations_for_workbook( + self, workbook_spec: AssetSpec + ) -> Iterator[AssetMaterialization]: + """Runs all scheduled materializations for a workbook. + + See https://help.sigmacomputing.com/docs/materialization#create-materializations-in-workbooks + for more information. + """ + metadata = SigmaWorkbookMetadataSet.extract(workbook_spec.metadata) + workbook_id = metadata.workbook_id + materialization_schedules = check.is_list( + check.not_none(metadata.materialization_schedules).value + ) + + materialization_sheets = {schedule["sheetId"] for schedule in materialization_schedules} + + self._run_materializations_for_workbook(workbook_id, materialization_sheets) + yield (AssetMaterialization(asset_key=workbook_spec.key)) + @cached_method async def _fetch_dataset_upstreams_by_inode( self, sigma_filter: SigmaFilter @@ -386,6 +500,14 @@ async def build_member_id_to_email_mapping(self) -> Mapping[str, str]: members = (await self._fetch_json_async("members", query_params={"limit": 500}))["entries"] return {member["memberId"]: member["email"] for member in members} + @cached_method + async def _fetch_materialization_schedules_for_workbook( + self, workbook_id: str + ) -> List[Dict[str, Any]]: + return await self._fetch_json_async_paginated_entries( + f"workbooks/{workbook_id}/materialization-schedules" + ) + async def load_workbook_data(self, raw_workbook_data: Dict[str, Any]) -> SigmaWorkbook: dataset_deps = set() direct_table_deps = set() @@ -430,12 +552,17 @@ async def safe_fetch_lineage_for_element( if item.get("type") == "table": direct_table_deps.add(item["nodeId"]) + materialization_schedules = await self._fetch_materialization_schedules_for_workbook( + raw_workbook_data["workbookId"] + ) + return SigmaWorkbook( properties=raw_workbook_data, datasets=dataset_deps, direct_table_deps=direct_table_deps, owner_email=None, lineage=lineages, + materialization_schedules=materialization_schedules, ) @cached_method diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma/translator.py b/python_modules/libraries/dagster-sigma/dagster_sigma/translator.py index a949b73f7b6fb..de54d74219115 100644 --- a/python_modules/libraries/dagster-sigma/dagster_sigma/translator.py +++ b/python_modules/libraries/dagster-sigma/dagster_sigma/translator.py @@ -3,7 +3,12 @@ from dagster import AssetKey, AssetSpec, MetadataValue, TableSchema from dagster._annotations import deprecated -from dagster._core.definitions.metadata.metadata_set import TableMetadataSet +from dagster._core.definitions.metadata.metadata_set import NamespacedMetadataSet, TableMetadataSet +from dagster._core.definitions.metadata.metadata_value import ( + JsonMetadataValue, + TimestampMetadataValue, + UrlMetadataValue, +) from dagster._core.definitions.metadata.table import TableColumn from dagster._record import record from dagster._serdes.serdes import whitelist_for_serdes @@ -26,6 +31,20 @@ def _inode_from_url(url: str) -> str: return f'inode-{url.split("/")[-1]}' +class SigmaWorkbookMetadataSet(NamespacedMetadataSet): + web_url: Optional[UrlMetadataValue] + version: Optional[int] + created_at: Optional[TimestampMetadataValue] + properties: Optional[JsonMetadataValue] + lineage: Optional[JsonMetadataValue] + materialization_schedules: Optional[JsonMetadataValue] = None + workbook_id: str + + @classmethod + def namespace(cls) -> str: + return "dagster_sigma" + + @whitelist_for_serdes @record class SigmaWorkbook: @@ -40,6 +59,7 @@ class SigmaWorkbook: datasets: AbstractSet[str] direct_table_deps: AbstractSet[str] owner_email: Optional[str] + materialization_schedules: Optional[List[Dict[str, Any]]] @whitelist_for_serdes @@ -110,13 +130,23 @@ def get_asset_spec(self, data: Union[SigmaDataset, SigmaWorkbook]) -> AssetSpec: """Get the AssetSpec for a Sigma object, such as a workbook or dataset.""" if isinstance(data, SigmaWorkbook): metadata = { - "dagster_sigma/web_url": MetadataValue.url(data.properties["url"]), - "dagster_sigma/version": data.properties["latestVersion"], - "dagster_sigma/created_at": MetadataValue.timestamp( - isoparse(data.properties["createdAt"]) + **SigmaWorkbookMetadataSet( + web_url=MetadataValue.url(data.properties["url"]), + version=data.properties["latestVersion"], + created_at=MetadataValue.timestamp(isoparse(data.properties["createdAt"])), + properties=MetadataValue.json(data.properties), + lineage=MetadataValue.json(data.lineage), + workbook_id=data.properties["workbookId"], + **( + { + "materialization_schedules": MetadataValue.json( + data.materialization_schedules + ) + } + if data.materialization_schedules + else {} + ), ), - "dagster_sigma/properties": MetadataValue.json(data.properties), - "dagster_sigma/lineage": MetadataValue.json(data.lineage), } datasets = [self._context.get_datasets_by_inode()[inode] for inode in data.datasets] tables = [ diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/conftest.py b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/conftest.py index e2d862fe35527..29fa8aae9f778 100644 --- a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/conftest.py +++ b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/conftest.py @@ -105,6 +105,29 @@ def lineage_warn_fixture(responses: aioresponses) -> None: ) +@pytest.fixture(name="sigma_materialization") +def sigma_materialization_fixture(responses: aioresponses) -> None: + # Trigger materialization, check status, check status again + request_responses.add( + method=request_responses.POST, + url=f"{SigmaBaseUrl.AWS_US.value}/v2/workbooks/4ea60fe9-f487-43b0-aa7a-3ef43ca3a90e/materializations", + status=200, + body=json.dumps({"materializationId": "foobar"}), + ) + request_responses.add( + method=request_responses.GET, + url=f"{SigmaBaseUrl.AWS_US.value}/v2/workbooks/4ea60fe9-f487-43b0-aa7a-3ef43ca3a90e/materializations/foobar", + status=200, + body=json.dumps({"materializationId": "foobar", "status": "pending"}), + ) + request_responses.add( + method=request_responses.GET, + url=f"{SigmaBaseUrl.AWS_US.value}/v2/workbooks/4ea60fe9-f487-43b0-aa7a-3ef43ca3a90e/materializations/foobar", + status=200, + body=json.dumps({"materializationId": "foobar", "status": "ready"}), + ) + + @pytest.fixture(name="sigma_sample_data") def sigma_sample_data_fixture(responses: aioresponses) -> None: # Single workbook, dataset @@ -133,6 +156,12 @@ def sigma_sample_data_fixture(responses: aioresponses) -> None: body=json.dumps(_build_paginated_response([{"pageId": "qwMyyHBCuC", "name": "Page 1"}])), status=200, ) + responses.add( + method=hdrs.METH_GET, + url="https://aws-api.sigmacomputing.com/v2/workbooks/4ea60fe9-f487-43b0-aa7a-3ef43ca3a90e/materialization-schedules?limit=1000", + body=json.dumps(_build_paginated_response([{"sheetId": "qwMyyHBCuC"}])), + status=200, + ) elements = [ { "elementId": "_MuHPbskp0", diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/materialize_workbook.py b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/materialize_workbook.py new file mode 100644 index 0000000000000..c5735a936d0af --- /dev/null +++ b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/materialize_workbook.py @@ -0,0 +1,38 @@ +from dagster import EnvVar, asset, define_asset_job +from dagster._core.definitions.definitions_class import Definitions +from dagster._utils.env import environ +from dagster_sigma import ( + SigmaBaseUrl, + SigmaOrganization, + build_materialize_workbook_assets_definition, + load_sigma_asset_specs, +) + +fake_client_id = "fake_client_id" +fake_client_secret = "fake_client_secret" + +with environ({"SIGMA_CLIENT_ID": fake_client_id, "SIGMA_CLIENT_SECRET": fake_client_secret}): + fake_token = "fake_token" + resource = SigmaOrganization( + base_url=SigmaBaseUrl.AWS_US, + client_id=EnvVar("SIGMA_CLIENT_ID"), + client_secret=EnvVar("SIGMA_CLIENT_SECRET"), + ) + + @asset + def my_materializable_asset(): + pass + + sigma_specs = load_sigma_asset_specs(resource) + sigma_assets = [ + build_materialize_workbook_assets_definition("sigma", spec) + if spec.metadata.get("dagster_sigma/materialization_schedules") + else spec + for spec in sigma_specs + ] + + defs = Definitions( + assets=[my_materializable_asset, *sigma_assets], + jobs=[define_asset_job("all_asset_job")], + resources={"sigma": resource}, + ) diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_asset_specs.py b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_asset_specs.py index 47e76cea6497f..c3cc5a383c885 100644 --- a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_asset_specs.py +++ b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_asset_specs.py @@ -4,6 +4,8 @@ import responses from click.testing import CliRunner from dagster._core.code_pointer import CodePointer +from dagster._core.definitions import materialize +from dagster._core.definitions.asset_key import AssetKey from dagster._core.definitions.reconstruct import ( initialize_repository_def_from_pointer, reconstruct_repository_def_from_pointer, @@ -79,6 +81,27 @@ def test_load_assets_organization_data(sigma_auth_token: str, sigma_sample_data: assert len(responses.calls) == calls +@responses.activate +def test_materialize_workbook( + sigma_auth_token: str, sigma_sample_data: None, sigma_materialization: None +) -> None: + with instance_for_test() as _instance: + # first, we resolve the repository to generate our cached metadata + repository_def = initialize_repository_def_from_pointer( + CodePointer.from_python_file( + str(Path(__file__).parent / "materialize_workbook.py"), "defs", None + ), + ) + + workbook_asset = repository_def.assets_defs_by_key[AssetKey(["Sample_Workbook"])] + assert workbook_asset.is_materializable + + # materialize the workbook + with environ({"SIGMA_CLIENT_ID": "fake", "SIGMA_CLIENT_SECRET": "fake"}): + result = materialize([workbook_asset], raise_on_error=False) + assert result.success + + @responses.activate def test_load_assets_organization_data_translator( sigma_auth_token: str, sigma_sample_data: None diff --git a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_translator.py b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_translator.py index d847ce0074c9b..a32aa3977518e 100644 --- a/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_translator.py +++ b/python_modules/libraries/dagster-sigma/dagster_sigma_tests/test_translator.py @@ -28,6 +28,7 @@ def test_workbook_translation() -> None: owner_email="ben@dagsterlabs.com", direct_table_deps={SAMPLE_TABLE_INODE}, lineage=[], + materialization_schedules=None, ) sample_dataset = SigmaDataset(properties=SAMPLE_DATASET_DATA, columns=set(), inputs=set()) From 5d4edc826e67d1e2f6142c0de82ff810d3840b6f Mon Sep 17 00:00:00 2001 From: Brian Tu Date: Fri, 13 Dec 2024 15:50:40 -0500 Subject: [PATCH 47/94] [OPER-1484] Add ANTLR syntax for op selection on frontend (#26099) ## Summary & Motivation Similar to the new asset selection syntax, we want to add one for ops on the frontend. This PR just adds grammar, which is just a subset of the asset selection grammar, and the generated files from ANTLR. ## How I Tested These Changes N/A --- js_modules/dagster-ui/.gitattributes | 1 + .../dagster-ui/packages/ui-core/package.json | 1 + .../ui-core/src/op-selection/OpSelection.g4 | 63 + .../op-selection/generated/OpSelection.interp | 43 + .../op-selection/generated/OpSelection.tokens | 23 + .../generated/OpSelectionLexer.interp | 56 + .../generated/OpSelectionLexer.tokens | 23 + .../generated/OpSelectionLexer.ts | 170 +++ .../generated/OpSelectionListener.ts | 252 ++++ .../generated/OpSelectionParser.ts | 1115 +++++++++++++++++ .../generated/OpSelectionVisitor.ts | 171 +++ .../src/scripts/generateOpSelection.ts | 16 + 12 files changed, 1934 insertions(+) create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.interp create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.tokens create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.interp create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.tokens create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionListener.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionParser.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionVisitor.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/scripts/generateOpSelection.ts diff --git a/js_modules/dagster-ui/.gitattributes b/js_modules/dagster-ui/.gitattributes index bf95c09ab463e..9428a42a1d54b 100644 --- a/js_modules/dagster-ui/.gitattributes +++ b/js_modules/dagster-ui/.gitattributes @@ -10,3 +10,4 @@ packages/ui-core/client.json linguist-generated=true packages/ui-core/src/asset-selection/generated/* linguist-generated=true packages/ui-core/src/selection/generated/* linguist-generated=true packages/ui-core/src/run-selection/generated/* linguist-generated=true +packages/ui-core/src/op-selection/generated/* linguist-generated=true diff --git a/js_modules/dagster-ui/packages/ui-core/package.json b/js_modules/dagster-ui/packages/ui-core/package.json index af7ba534148f7..ff98bbec75a34 100644 --- a/js_modules/dagster-ui/packages/ui-core/package.json +++ b/js_modules/dagster-ui/packages/ui-core/package.json @@ -17,6 +17,7 @@ "generate-asset-selection": "ts-node -O '{\"module\": \"commonjs\"}' ./src/scripts/generateAssetSelection.ts && eslint src/asset-selection/generated/ --fix -c .eslintrc.js", "generate-selection-autocomplete": "ts-node -O '{\"module\": \"commonjs\"}' ./src/scripts/generateSelection.ts && eslint src/selection/generated/ --fix -c .eslintrc.js", "generate-run-selection": "ts-node -O '{\"module\": \"commonjs\"}' ./src/scripts/generateRunSelection.ts && eslint src/run-selection/generated/ --fix -c .eslintrc.js", + "generate-op-selection": "ts-node -O '{\"module\": \"commonjs\"}' ./src/scripts/generateOpSelection.ts && eslint src/op-selection/generated/ --fix -c .eslintrc.js", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" }, diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 b/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 new file mode 100644 index 0000000000000..1edc8b2e04c85 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 @@ -0,0 +1,63 @@ +grammar OpSelection; + +start: expr EOF; + +// Root rule for parsing expressions +expr + : traversalAllowedExpr # TraversalAllowedExpression + | traversal traversalAllowedExpr traversal # UpAndDownTraversalExpression + | traversal traversalAllowedExpr # UpTraversalExpression + | traversalAllowedExpr traversal # DownTraversalExpression + | NOT expr # NotExpression + | expr AND expr # AndExpression + | expr OR expr # OrExpression + | STAR # AllExpression + ; + +// Allowed expressions for traversals +traversalAllowedExpr + : attributeExpr # AttributeExpression + | LPAREN expr RPAREN # ParenthesizedExpression + ; + +// Traversal operators +traversal + : STAR + | PLUS+ + ; + +// Attribute expressions for specific attributes +attributeExpr + : NAME COLON value # NameExpr + | NAME_SUBSTRING COLON value # NameSubstringExpr + ; + +// Value can be a quoted or unquoted string +value + : QUOTED_STRING + | UNQUOTED_STRING + ; + +// Tokens for operators and keywords +AND : 'and'; +OR : 'or'; +NOT : 'not'; + +STAR : '*'; +PLUS : '+'; + +COLON : ':'; + +LPAREN : '('; +RPAREN : ')'; + +// Tokens for attributes +NAME : 'name'; +NAME_SUBSTRING : 'name_substring'; + +// Tokens for strings +QUOTED_STRING : '"' (~["\\\r\n])* '"' ; +UNQUOTED_STRING : [a-zA-Z_][a-zA-Z0-9_]*; + +// Whitespace +WS : [ \t\r\n]+ -> skip ; \ No newline at end of file diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.interp b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.interp new file mode 100644 index 0000000000000..88357962b7070 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.interp @@ -0,0 +1,43 @@ +token literal names: +null +'and' +'or' +'not' +'*' +'+' +':' +'(' +')' +'name' +'name_substring' +null +null +null + +token symbolic names: +null +AND +OR +NOT +STAR +PLUS +COLON +LPAREN +RPAREN +NAME +NAME_SUBSTRING +QUOTED_STRING +UNQUOTED_STRING +WS + +rule names: +start +expr +traversalAllowedExpr +traversal +attributeExpr +value + + +atn: +[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 3, 15, 71, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 33, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 41, 10, 3, 12, 3, 14, 3, 44, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 51, 10, 4, 3, 5, 3, 5, 6, 5, 55, 10, 5, 13, 5, 14, 5, 56, 5, 5, 59, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 67, 10, 6, 3, 7, 3, 7, 3, 7, 2, 2, 3, 4, 8, 2, 2, 4, 2, 6, 2, 8, 2, 10, 2, 12, 2, 2, 3, 3, 2, 13, 14, 2, 75, 2, 14, 3, 2, 2, 2, 4, 32, 3, 2, 2, 2, 6, 50, 3, 2, 2, 2, 8, 58, 3, 2, 2, 2, 10, 66, 3, 2, 2, 2, 12, 68, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 8, 3, 1, 2, 18, 33, 5, 6, 4, 2, 19, 20, 5, 8, 5, 2, 20, 21, 5, 6, 4, 2, 21, 22, 5, 8, 5, 2, 22, 33, 3, 2, 2, 2, 23, 24, 5, 8, 5, 2, 24, 25, 5, 6, 4, 2, 25, 33, 3, 2, 2, 2, 26, 27, 5, 6, 4, 2, 27, 28, 5, 8, 5, 2, 28, 33, 3, 2, 2, 2, 29, 30, 7, 5, 2, 2, 30, 33, 5, 4, 3, 6, 31, 33, 7, 6, 2, 2, 32, 17, 3, 2, 2, 2, 32, 19, 3, 2, 2, 2, 32, 23, 3, 2, 2, 2, 32, 26, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 32, 31, 3, 2, 2, 2, 33, 42, 3, 2, 2, 2, 34, 35, 12, 5, 2, 2, 35, 36, 7, 3, 2, 2, 36, 41, 5, 4, 3, 6, 37, 38, 12, 4, 2, 2, 38, 39, 7, 4, 2, 2, 39, 41, 5, 4, 3, 5, 40, 34, 3, 2, 2, 2, 40, 37, 3, 2, 2, 2, 41, 44, 3, 2, 2, 2, 42, 40, 3, 2, 2, 2, 42, 43, 3, 2, 2, 2, 43, 5, 3, 2, 2, 2, 44, 42, 3, 2, 2, 2, 45, 51, 5, 10, 6, 2, 46, 47, 7, 9, 2, 2, 47, 48, 5, 4, 3, 2, 48, 49, 7, 10, 2, 2, 49, 51, 3, 2, 2, 2, 50, 45, 3, 2, 2, 2, 50, 46, 3, 2, 2, 2, 51, 7, 3, 2, 2, 2, 52, 59, 7, 6, 2, 2, 53, 55, 7, 7, 2, 2, 54, 53, 3, 2, 2, 2, 55, 56, 3, 2, 2, 2, 56, 54, 3, 2, 2, 2, 56, 57, 3, 2, 2, 2, 57, 59, 3, 2, 2, 2, 58, 52, 3, 2, 2, 2, 58, 54, 3, 2, 2, 2, 59, 9, 3, 2, 2, 2, 60, 61, 7, 11, 2, 2, 61, 62, 7, 8, 2, 2, 62, 67, 5, 12, 7, 2, 63, 64, 7, 12, 2, 2, 64, 65, 7, 8, 2, 2, 65, 67, 5, 12, 7, 2, 66, 60, 3, 2, 2, 2, 66, 63, 3, 2, 2, 2, 67, 11, 3, 2, 2, 2, 68, 69, 9, 2, 2, 2, 69, 13, 3, 2, 2, 2, 9, 32, 40, 42, 50, 56, 58, 66] \ No newline at end of file diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.tokens b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.tokens new file mode 100644 index 0000000000000..34097166bd470 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelection.tokens @@ -0,0 +1,23 @@ +AND=1 +OR=2 +NOT=3 +STAR=4 +PLUS=5 +COLON=6 +LPAREN=7 +RPAREN=8 +NAME=9 +NAME_SUBSTRING=10 +QUOTED_STRING=11 +UNQUOTED_STRING=12 +WS=13 +'and'=1 +'or'=2 +'not'=3 +'*'=4 +'+'=5 +':'=6 +'('=7 +')'=8 +'name'=9 +'name_substring'=10 diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.interp b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.interp new file mode 100644 index 0000000000000..8828f9b625b8b --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.interp @@ -0,0 +1,56 @@ +token literal names: +null +'and' +'or' +'not' +'*' +'+' +':' +'(' +')' +'name' +'name_substring' +null +null +null + +token symbolic names: +null +AND +OR +NOT +STAR +PLUS +COLON +LPAREN +RPAREN +NAME +NAME_SUBSTRING +QUOTED_STRING +UNQUOTED_STRING +WS + +rule names: +AND +OR +NOT +STAR +PLUS +COLON +LPAREN +RPAREN +NAME +NAME_SUBSTRING +QUOTED_STRING +UNQUOTED_STRING +WS + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 2, 15, 93, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 7, 12, 73, 10, 12, 12, 12, 14, 12, 76, 11, 12, 3, 12, 3, 12, 3, 13, 3, 13, 7, 13, 82, 10, 13, 12, 13, 14, 13, 85, 11, 13, 3, 14, 6, 14, 88, 10, 14, 13, 14, 14, 14, 89, 3, 14, 3, 14, 2, 2, 2, 15, 3, 2, 3, 5, 2, 4, 7, 2, 5, 9, 2, 6, 11, 2, 7, 13, 2, 8, 15, 2, 9, 17, 2, 10, 19, 2, 11, 21, 2, 12, 23, 2, 13, 25, 2, 14, 27, 2, 15, 3, 2, 6, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 5, 2, 67, 92, 97, 97, 99, 124, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 5, 2, 11, 12, 15, 15, 34, 34, 2, 95, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 3, 29, 3, 2, 2, 2, 5, 33, 3, 2, 2, 2, 7, 36, 3, 2, 2, 2, 9, 40, 3, 2, 2, 2, 11, 42, 3, 2, 2, 2, 13, 44, 3, 2, 2, 2, 15, 46, 3, 2, 2, 2, 17, 48, 3, 2, 2, 2, 19, 50, 3, 2, 2, 2, 21, 55, 3, 2, 2, 2, 23, 70, 3, 2, 2, 2, 25, 79, 3, 2, 2, 2, 27, 87, 3, 2, 2, 2, 29, 30, 7, 99, 2, 2, 30, 31, 7, 112, 2, 2, 31, 32, 7, 102, 2, 2, 32, 4, 3, 2, 2, 2, 33, 34, 7, 113, 2, 2, 34, 35, 7, 116, 2, 2, 35, 6, 3, 2, 2, 2, 36, 37, 7, 112, 2, 2, 37, 38, 7, 113, 2, 2, 38, 39, 7, 118, 2, 2, 39, 8, 3, 2, 2, 2, 40, 41, 7, 44, 2, 2, 41, 10, 3, 2, 2, 2, 42, 43, 7, 45, 2, 2, 43, 12, 3, 2, 2, 2, 44, 45, 7, 60, 2, 2, 45, 14, 3, 2, 2, 2, 46, 47, 7, 42, 2, 2, 47, 16, 3, 2, 2, 2, 48, 49, 7, 43, 2, 2, 49, 18, 3, 2, 2, 2, 50, 51, 7, 112, 2, 2, 51, 52, 7, 99, 2, 2, 52, 53, 7, 111, 2, 2, 53, 54, 7, 103, 2, 2, 54, 20, 3, 2, 2, 2, 55, 56, 7, 112, 2, 2, 56, 57, 7, 99, 2, 2, 57, 58, 7, 111, 2, 2, 58, 59, 7, 103, 2, 2, 59, 60, 7, 97, 2, 2, 60, 61, 7, 117, 2, 2, 61, 62, 7, 119, 2, 2, 62, 63, 7, 100, 2, 2, 63, 64, 7, 117, 2, 2, 64, 65, 7, 118, 2, 2, 65, 66, 7, 116, 2, 2, 66, 67, 7, 107, 2, 2, 67, 68, 7, 112, 2, 2, 68, 69, 7, 105, 2, 2, 69, 22, 3, 2, 2, 2, 70, 74, 7, 36, 2, 2, 71, 73, 10, 2, 2, 2, 72, 71, 3, 2, 2, 2, 73, 76, 3, 2, 2, 2, 74, 72, 3, 2, 2, 2, 74, 75, 3, 2, 2, 2, 75, 77, 3, 2, 2, 2, 76, 74, 3, 2, 2, 2, 77, 78, 7, 36, 2, 2, 78, 24, 3, 2, 2, 2, 79, 83, 9, 3, 2, 2, 80, 82, 9, 4, 2, 2, 81, 80, 3, 2, 2, 2, 82, 85, 3, 2, 2, 2, 83, 81, 3, 2, 2, 2, 83, 84, 3, 2, 2, 2, 84, 26, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 88, 9, 5, 2, 2, 87, 86, 3, 2, 2, 2, 88, 89, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 89, 90, 3, 2, 2, 2, 90, 91, 3, 2, 2, 2, 91, 92, 8, 14, 2, 2, 92, 28, 3, 2, 2, 2, 6, 2, 74, 83, 89, 3, 8, 2, 2] \ No newline at end of file diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.tokens b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.tokens new file mode 100644 index 0000000000000..34097166bd470 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.tokens @@ -0,0 +1,23 @@ +AND=1 +OR=2 +NOT=3 +STAR=4 +PLUS=5 +COLON=6 +LPAREN=7 +RPAREN=8 +NAME=9 +NAME_SUBSTRING=10 +QUOTED_STRING=11 +UNQUOTED_STRING=12 +WS=13 +'and'=1 +'or'=2 +'not'=3 +'*'=4 +'+'=5 +':'=6 +'('=7 +')'=8 +'name'=9 +'name_substring'=10 diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.ts new file mode 100644 index 0000000000000..3a01b871699a8 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionLexer.ts @@ -0,0 +1,170 @@ +// Generated from /Users/briantu/repos/dagster/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 by ANTLR 4.9.0-SNAPSHOT + +import {CharStream} from 'antlr4ts/CharStream'; +import {Lexer} from 'antlr4ts/Lexer'; +import {Vocabulary} from 'antlr4ts/Vocabulary'; +import {VocabularyImpl} from 'antlr4ts/VocabularyImpl'; +import {ATN} from 'antlr4ts/atn/ATN'; +import {ATNDeserializer} from 'antlr4ts/atn/ATNDeserializer'; +import {LexerATNSimulator} from 'antlr4ts/atn/LexerATNSimulator'; +import * as Utils from 'antlr4ts/misc/Utils'; + +export class OpSelectionLexer extends Lexer { + public static readonly AND = 1; + public static readonly OR = 2; + public static readonly NOT = 3; + public static readonly STAR = 4; + public static readonly PLUS = 5; + public static readonly COLON = 6; + public static readonly LPAREN = 7; + public static readonly RPAREN = 8; + public static readonly NAME = 9; + public static readonly NAME_SUBSTRING = 10; + public static readonly QUOTED_STRING = 11; + public static readonly UNQUOTED_STRING = 12; + public static readonly WS = 13; + + // tslint:disable:no-trailing-whitespace + public static readonly channelNames: string[] = ['DEFAULT_TOKEN_CHANNEL', 'HIDDEN']; + + // tslint:disable:no-trailing-whitespace + public static readonly modeNames: string[] = ['DEFAULT_MODE']; + + public static readonly ruleNames: string[] = [ + 'AND', + 'OR', + 'NOT', + 'STAR', + 'PLUS', + 'COLON', + 'LPAREN', + 'RPAREN', + 'NAME', + 'NAME_SUBSTRING', + 'QUOTED_STRING', + 'UNQUOTED_STRING', + 'WS', + ]; + + private static readonly _LITERAL_NAMES: Array = [ + undefined, + "'and'", + "'or'", + "'not'", + "'*'", + "'+'", + "':'", + "'('", + "')'", + "'name'", + "'name_substring'", + ]; + private static readonly _SYMBOLIC_NAMES: Array = [ + undefined, + 'AND', + 'OR', + 'NOT', + 'STAR', + 'PLUS', + 'COLON', + 'LPAREN', + 'RPAREN', + 'NAME', + 'NAME_SUBSTRING', + 'QUOTED_STRING', + 'UNQUOTED_STRING', + 'WS', + ]; + public static readonly VOCABULARY: Vocabulary = new VocabularyImpl( + OpSelectionLexer._LITERAL_NAMES, + OpSelectionLexer._SYMBOLIC_NAMES, + [], + ); + + // @Override + // @NotNull + public get vocabulary(): Vocabulary { + return OpSelectionLexer.VOCABULARY; + } + // tslint:enable:no-trailing-whitespace + + constructor(input: CharStream) { + super(input); + this._interp = new LexerATNSimulator(OpSelectionLexer._ATN, this); + } + + // @Override + public get grammarFileName(): string { + return 'OpSelection.g4'; + } + + // @Override + public get ruleNames(): string[] { + return OpSelectionLexer.ruleNames; + } + + // @Override + public get serializedATN(): string { + return OpSelectionLexer._serializedATN; + } + + // @Override + public get channelNames(): string[] { + return OpSelectionLexer.channelNames; + } + + // @Override + public get modeNames(): string[] { + return OpSelectionLexer.modeNames; + } + + public static readonly _serializedATN: string = + '\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x02\x0F]\b\x01\x04' + + '\x02\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04' + + '\x07\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f\t\f\x04\r\t\r' + + '\x04\x0E\t\x0E\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03\x03' + + '\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x03\x05\x03\x06\x03\x06\x03\x07' + + '\x03\x07\x03\b\x03\b\x03\t\x03\t\x03\n\x03\n\x03\n\x03\n\x03\n\x03\v\x03' + + '\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03' + + '\v\x03\v\x03\f\x03\f\x07\fI\n\f\f\f\x0E\fL\v\f\x03\f\x03\f\x03\r\x03\r' + + '\x07\rR\n\r\f\r\x0E\rU\v\r\x03\x0E\x06\x0EX\n\x0E\r\x0E\x0E\x0EY\x03\x0E' + + '\x03\x0E\x02\x02\x02\x0F\x03\x02\x03\x05\x02\x04\x07\x02\x05\t\x02\x06' + + '\v\x02\x07\r\x02\b\x0F\x02\t\x11\x02\n\x13\x02\v\x15\x02\f\x17\x02\r\x19' + + '\x02\x0E\x1B\x02\x0F\x03\x02\x06\x06\x02\f\f\x0F\x0F$$^^\x05\x02C\\aa' + + 'c|\x06\x022;C\\aac|\x05\x02\v\f\x0F\x0F""\x02_\x02\x03\x03\x02\x02\x02' + + '\x02\x05\x03\x02\x02\x02\x02\x07\x03\x02\x02\x02\x02\t\x03\x02\x02\x02' + + '\x02\v\x03\x02\x02\x02\x02\r\x03\x02\x02\x02\x02\x0F\x03\x02\x02\x02\x02' + + '\x11\x03\x02\x02\x02\x02\x13\x03\x02\x02\x02\x02\x15\x03\x02\x02\x02\x02' + + '\x17\x03\x02\x02\x02\x02\x19\x03\x02\x02\x02\x02\x1B\x03\x02\x02\x02\x03' + + '\x1D\x03\x02\x02\x02\x05!\x03\x02\x02\x02\x07$\x03\x02\x02\x02\t(\x03' + + '\x02\x02\x02\v*\x03\x02\x02\x02\r,\x03\x02\x02\x02\x0F.\x03\x02\x02\x02' + + '\x110\x03\x02\x02\x02\x132\x03\x02\x02\x02\x157\x03\x02\x02\x02\x17F\x03' + + '\x02\x02\x02\x19O\x03\x02\x02\x02\x1BW\x03\x02\x02\x02\x1D\x1E\x07c\x02' + + '\x02\x1E\x1F\x07p\x02\x02\x1F \x07f\x02\x02 \x04\x03\x02\x02\x02!"\x07' + + 'q\x02\x02"#\x07t\x02\x02#\x06\x03\x02\x02\x02$%\x07p\x02\x02%&\x07q\x02' + + "\x02&'\x07v\x02\x02'\b\x03\x02\x02\x02()\x07,\x02\x02)\n\x03\x02\x02" + + '\x02*+\x07-\x02\x02+\f\x03\x02\x02\x02,-\x07<\x02\x02-\x0E\x03\x02\x02' + + '\x02./\x07*\x02\x02/\x10\x03\x02\x02\x0201\x07+\x02\x021\x12\x03\x02\x02' + + '\x0223\x07p\x02\x0234\x07c\x02\x0245\x07o\x02\x0256\x07g\x02\x026\x14' + + '\x03\x02\x02\x0278\x07p\x02\x0289\x07c\x02\x029:\x07o\x02\x02:;\x07g\x02' + + '\x02;<\x07a\x02\x02<=\x07u\x02\x02=>\x07w\x02\x02>?\x07d\x02\x02?@\x07' + + 'u\x02\x02@A\x07v\x02\x02AB\x07t\x02\x02BC\x07k\x02\x02CD\x07p\x02\x02' + + 'DE\x07i\x02\x02E\x16\x03\x02\x02\x02FJ\x07$\x02\x02GI\n\x02\x02\x02HG' + + '\x03\x02\x02\x02IL\x03\x02\x02\x02JH\x03\x02\x02\x02JK\x03\x02\x02\x02' + + 'KM\x03\x02\x02\x02LJ\x03\x02\x02\x02MN\x07$\x02\x02N\x18\x03\x02\x02\x02' + + 'OS\t\x03\x02\x02PR\t\x04\x02\x02QP\x03\x02\x02\x02RU\x03\x02\x02\x02S' + + 'Q\x03\x02\x02\x02ST\x03\x02\x02\x02T\x1A\x03\x02\x02\x02US\x03\x02\x02' + + '\x02VX\t\x05\x02\x02WV\x03\x02\x02\x02XY\x03\x02\x02\x02YW\x03\x02\x02' + + '\x02YZ\x03\x02\x02\x02Z[\x03\x02\x02\x02[\\\b\x0E\x02\x02\\\x1C\x03\x02' + + '\x02\x02\x06\x02JSY\x03\b\x02\x02'; + public static __ATN: ATN; + public static get _ATN(): ATN { + if (!OpSelectionLexer.__ATN) { + OpSelectionLexer.__ATN = new ATNDeserializer().deserialize( + Utils.toCharArray(OpSelectionLexer._serializedATN), + ); + } + + return OpSelectionLexer.__ATN; + } +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionListener.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionListener.ts new file mode 100644 index 0000000000000..5c13bdbb60747 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionListener.ts @@ -0,0 +1,252 @@ +// Generated from /Users/briantu/repos/dagster/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 by ANTLR 4.9.0-SNAPSHOT + +import {ParseTreeListener} from 'antlr4ts/tree/ParseTreeListener'; + +import { + AllExpressionContext, + AndExpressionContext, + AttributeExprContext, + AttributeExpressionContext, + DownTraversalExpressionContext, + ExprContext, + NameExprContext, + NameSubstringExprContext, + NotExpressionContext, + OrExpressionContext, + ParenthesizedExpressionContext, + StartContext, + TraversalAllowedExprContext, + TraversalAllowedExpressionContext, + TraversalContext, + UpAndDownTraversalExpressionContext, + UpTraversalExpressionContext, + ValueContext, +} from './OpSelectionParser'; + +/** + * This interface defines a complete listener for a parse tree produced by + * `OpSelectionParser`. + */ +export interface OpSelectionListener extends ParseTreeListener { + /** + * Enter a parse tree produced by the `TraversalAllowedExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterTraversalAllowedExpression?: (ctx: TraversalAllowedExpressionContext) => void; + /** + * Exit a parse tree produced by the `TraversalAllowedExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitTraversalAllowedExpression?: (ctx: TraversalAllowedExpressionContext) => void; + + /** + * Enter a parse tree produced by the `UpAndDownTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterUpAndDownTraversalExpression?: (ctx: UpAndDownTraversalExpressionContext) => void; + /** + * Exit a parse tree produced by the `UpAndDownTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitUpAndDownTraversalExpression?: (ctx: UpAndDownTraversalExpressionContext) => void; + + /** + * Enter a parse tree produced by the `UpTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterUpTraversalExpression?: (ctx: UpTraversalExpressionContext) => void; + /** + * Exit a parse tree produced by the `UpTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitUpTraversalExpression?: (ctx: UpTraversalExpressionContext) => void; + + /** + * Enter a parse tree produced by the `DownTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterDownTraversalExpression?: (ctx: DownTraversalExpressionContext) => void; + /** + * Exit a parse tree produced by the `DownTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitDownTraversalExpression?: (ctx: DownTraversalExpressionContext) => void; + + /** + * Enter a parse tree produced by the `NotExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterNotExpression?: (ctx: NotExpressionContext) => void; + /** + * Exit a parse tree produced by the `NotExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitNotExpression?: (ctx: NotExpressionContext) => void; + + /** + * Enter a parse tree produced by the `AndExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterAndExpression?: (ctx: AndExpressionContext) => void; + /** + * Exit a parse tree produced by the `AndExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitAndExpression?: (ctx: AndExpressionContext) => void; + + /** + * Enter a parse tree produced by the `OrExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterOrExpression?: (ctx: OrExpressionContext) => void; + /** + * Exit a parse tree produced by the `OrExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitOrExpression?: (ctx: OrExpressionContext) => void; + + /** + * Enter a parse tree produced by the `AllExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterAllExpression?: (ctx: AllExpressionContext) => void; + /** + * Exit a parse tree produced by the `AllExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitAllExpression?: (ctx: AllExpressionContext) => void; + + /** + * Enter a parse tree produced by the `NameExpr` + * labeled alternative in `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + */ + enterNameExpr?: (ctx: NameExprContext) => void; + /** + * Exit a parse tree produced by the `NameExpr` + * labeled alternative in `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + */ + exitNameExpr?: (ctx: NameExprContext) => void; + + /** + * Enter a parse tree produced by the `NameSubstringExpr` + * labeled alternative in `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + */ + enterNameSubstringExpr?: (ctx: NameSubstringExprContext) => void; + /** + * Exit a parse tree produced by the `NameSubstringExpr` + * labeled alternative in `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + */ + exitNameSubstringExpr?: (ctx: NameSubstringExprContext) => void; + + /** + * Enter a parse tree produced by the `AttributeExpression` + * labeled alternative in `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + */ + enterAttributeExpression?: (ctx: AttributeExpressionContext) => void; + /** + * Exit a parse tree produced by the `AttributeExpression` + * labeled alternative in `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + */ + exitAttributeExpression?: (ctx: AttributeExpressionContext) => void; + + /** + * Enter a parse tree produced by the `ParenthesizedExpression` + * labeled alternative in `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + */ + enterParenthesizedExpression?: (ctx: ParenthesizedExpressionContext) => void; + /** + * Exit a parse tree produced by the `ParenthesizedExpression` + * labeled alternative in `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + */ + exitParenthesizedExpression?: (ctx: ParenthesizedExpressionContext) => void; + + /** + * Enter a parse tree produced by `OpSelectionParser.start`. + * @param ctx the parse tree + */ + enterStart?: (ctx: StartContext) => void; + /** + * Exit a parse tree produced by `OpSelectionParser.start`. + * @param ctx the parse tree + */ + exitStart?: (ctx: StartContext) => void; + + /** + * Enter a parse tree produced by `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + enterExpr?: (ctx: ExprContext) => void; + /** + * Exit a parse tree produced by `OpSelectionParser.expr`. + * @param ctx the parse tree + */ + exitExpr?: (ctx: ExprContext) => void; + + /** + * Enter a parse tree produced by `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + */ + enterTraversalAllowedExpr?: (ctx: TraversalAllowedExprContext) => void; + /** + * Exit a parse tree produced by `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + */ + exitTraversalAllowedExpr?: (ctx: TraversalAllowedExprContext) => void; + + /** + * Enter a parse tree produced by `OpSelectionParser.traversal`. + * @param ctx the parse tree + */ + enterTraversal?: (ctx: TraversalContext) => void; + /** + * Exit a parse tree produced by `OpSelectionParser.traversal`. + * @param ctx the parse tree + */ + exitTraversal?: (ctx: TraversalContext) => void; + + /** + * Enter a parse tree produced by `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + */ + enterAttributeExpr?: (ctx: AttributeExprContext) => void; + /** + * Exit a parse tree produced by `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + */ + exitAttributeExpr?: (ctx: AttributeExprContext) => void; + + /** + * Enter a parse tree produced by `OpSelectionParser.value`. + * @param ctx the parse tree + */ + enterValue?: (ctx: ValueContext) => void; + /** + * Exit a parse tree produced by `OpSelectionParser.value`. + * @param ctx the parse tree + */ + exitValue?: (ctx: ValueContext) => void; +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionParser.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionParser.ts new file mode 100644 index 0000000000000..a9c1c99063b14 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionParser.ts @@ -0,0 +1,1115 @@ +// Generated from /Users/briantu/repos/dagster/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 by ANTLR 4.9.0-SNAPSHOT + +import {FailedPredicateException} from 'antlr4ts/FailedPredicateException'; +import {NoViableAltException} from 'antlr4ts/NoViableAltException'; +import {Parser} from 'antlr4ts/Parser'; +import {ParserRuleContext} from 'antlr4ts/ParserRuleContext'; +import {RecognitionException} from 'antlr4ts/RecognitionException'; +import {RuleContext} from 'antlr4ts/RuleContext'; +//import { RuleVersion } from "antlr4ts/RuleVersion"; +import {Token} from 'antlr4ts/Token'; +import {TokenStream} from 'antlr4ts/TokenStream'; +import {Vocabulary} from 'antlr4ts/Vocabulary'; +import {VocabularyImpl} from 'antlr4ts/VocabularyImpl'; +import {ATN} from 'antlr4ts/atn/ATN'; +import {ATNDeserializer} from 'antlr4ts/atn/ATNDeserializer'; +import {ParserATNSimulator} from 'antlr4ts/atn/ParserATNSimulator'; +import * as Utils from 'antlr4ts/misc/Utils'; +import {TerminalNode} from 'antlr4ts/tree/TerminalNode'; + +import {OpSelectionListener} from './OpSelectionListener'; +import {OpSelectionVisitor} from './OpSelectionVisitor'; + +export class OpSelectionParser extends Parser { + public static readonly AND = 1; + public static readonly OR = 2; + public static readonly NOT = 3; + public static readonly STAR = 4; + public static readonly PLUS = 5; + public static readonly COLON = 6; + public static readonly LPAREN = 7; + public static readonly RPAREN = 8; + public static readonly NAME = 9; + public static readonly NAME_SUBSTRING = 10; + public static readonly QUOTED_STRING = 11; + public static readonly UNQUOTED_STRING = 12; + public static readonly WS = 13; + public static readonly RULE_start = 0; + public static readonly RULE_expr = 1; + public static readonly RULE_traversalAllowedExpr = 2; + public static readonly RULE_traversal = 3; + public static readonly RULE_attributeExpr = 4; + public static readonly RULE_value = 5; + // tslint:disable:no-trailing-whitespace + public static readonly ruleNames: string[] = [ + 'start', + 'expr', + 'traversalAllowedExpr', + 'traversal', + 'attributeExpr', + 'value', + ]; + + private static readonly _LITERAL_NAMES: Array = [ + undefined, + "'and'", + "'or'", + "'not'", + "'*'", + "'+'", + "':'", + "'('", + "')'", + "'name'", + "'name_substring'", + ]; + private static readonly _SYMBOLIC_NAMES: Array = [ + undefined, + 'AND', + 'OR', + 'NOT', + 'STAR', + 'PLUS', + 'COLON', + 'LPAREN', + 'RPAREN', + 'NAME', + 'NAME_SUBSTRING', + 'QUOTED_STRING', + 'UNQUOTED_STRING', + 'WS', + ]; + public static readonly VOCABULARY: Vocabulary = new VocabularyImpl( + OpSelectionParser._LITERAL_NAMES, + OpSelectionParser._SYMBOLIC_NAMES, + [], + ); + + // @Override + // @NotNull + public get vocabulary(): Vocabulary { + return OpSelectionParser.VOCABULARY; + } + // tslint:enable:no-trailing-whitespace + + // @Override + public get grammarFileName(): string { + return 'OpSelection.g4'; + } + + // @Override + public get ruleNames(): string[] { + return OpSelectionParser.ruleNames; + } + + // @Override + public get serializedATN(): string { + return OpSelectionParser._serializedATN; + } + + protected createFailedPredicateException( + predicate?: string, + message?: string, + ): FailedPredicateException { + return new FailedPredicateException(this, predicate, message); + } + + constructor(input: TokenStream) { + super(input); + this._interp = new ParserATNSimulator(OpSelectionParser._ATN, this); + } + // @RuleVersion(0) + public start(): StartContext { + const _localctx: StartContext = new StartContext(this._ctx, this.state); + this.enterRule(_localctx, 0, OpSelectionParser.RULE_start); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 12; + this.expr(0); + this.state = 13; + this.match(OpSelectionParser.EOF); + } + } catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } finally { + this.exitRule(); + } + return _localctx; + } + + public expr(): ExprContext; + public expr(_p: number): ExprContext; + // @RuleVersion(0) + public expr(_p?: number): ExprContext { + if (_p === undefined) { + _p = 0; + } + + const _parentctx: ParserRuleContext = this._ctx; + const _parentState: number = this.state; + let _localctx: ExprContext = new ExprContext(this._ctx, _parentState); + let _prevctx: ExprContext = _localctx; + const _startState: number = 2; + this.enterRecursionRule(_localctx, 2, OpSelectionParser.RULE_expr, _p); + try { + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 30; + this._errHandler.sync(this); + switch (this.interpreter.adaptivePredict(this._input, 0, this._ctx)) { + case 1: + { + _localctx = new TraversalAllowedExpressionContext(_localctx); + this._ctx = _localctx; + _prevctx = _localctx; + + this.state = 16; + this.traversalAllowedExpr(); + } + break; + + case 2: + { + _localctx = new UpAndDownTraversalExpressionContext(_localctx); + this._ctx = _localctx; + _prevctx = _localctx; + this.state = 17; + this.traversal(); + this.state = 18; + this.traversalAllowedExpr(); + this.state = 19; + this.traversal(); + } + break; + + case 3: + { + _localctx = new UpTraversalExpressionContext(_localctx); + this._ctx = _localctx; + _prevctx = _localctx; + this.state = 21; + this.traversal(); + this.state = 22; + this.traversalAllowedExpr(); + } + break; + + case 4: + { + _localctx = new DownTraversalExpressionContext(_localctx); + this._ctx = _localctx; + _prevctx = _localctx; + this.state = 24; + this.traversalAllowedExpr(); + this.state = 25; + this.traversal(); + } + break; + + case 5: + { + _localctx = new NotExpressionContext(_localctx); + this._ctx = _localctx; + _prevctx = _localctx; + this.state = 27; + this.match(OpSelectionParser.NOT); + this.state = 28; + this.expr(4); + } + break; + + case 6: + { + _localctx = new AllExpressionContext(_localctx); + this._ctx = _localctx; + _prevctx = _localctx; + this.state = 29; + this.match(OpSelectionParser.STAR); + } + break; + } + this._ctx._stop = this._input.tryLT(-1); + this.state = 40; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 2, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + if (this._parseListeners != null) { + this.triggerExitRuleEvent(); + } + _prevctx = _localctx; + { + this.state = 38; + this._errHandler.sync(this); + switch (this.interpreter.adaptivePredict(this._input, 1, this._ctx)) { + case 1: + { + _localctx = new AndExpressionContext(new ExprContext(_parentctx, _parentState)); + this.pushNewRecursionContext( + _localctx, + _startState, + OpSelectionParser.RULE_expr, + ); + this.state = 32; + if (!this.precpred(this._ctx, 3)) { + throw this.createFailedPredicateException('this.precpred(this._ctx, 3)'); + } + this.state = 33; + this.match(OpSelectionParser.AND); + this.state = 34; + this.expr(4); + } + break; + + case 2: + { + _localctx = new OrExpressionContext(new ExprContext(_parentctx, _parentState)); + this.pushNewRecursionContext( + _localctx, + _startState, + OpSelectionParser.RULE_expr, + ); + this.state = 35; + if (!this.precpred(this._ctx, 2)) { + throw this.createFailedPredicateException('this.precpred(this._ctx, 2)'); + } + this.state = 36; + this.match(OpSelectionParser.OR); + this.state = 37; + this.expr(3); + } + break; + } + } + } + this.state = 42; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 2, this._ctx); + } + } + } catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } finally { + this.unrollRecursionContexts(_parentctx); + } + return _localctx; + } + // @RuleVersion(0) + public traversalAllowedExpr(): TraversalAllowedExprContext { + let _localctx: TraversalAllowedExprContext = new TraversalAllowedExprContext( + this._ctx, + this.state, + ); + this.enterRule(_localctx, 4, OpSelectionParser.RULE_traversalAllowedExpr); + try { + this.state = 48; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case OpSelectionParser.NAME: + case OpSelectionParser.NAME_SUBSTRING: + _localctx = new AttributeExpressionContext(_localctx); + this.enterOuterAlt(_localctx, 1); + { + this.state = 43; + this.attributeExpr(); + } + break; + case OpSelectionParser.LPAREN: + _localctx = new ParenthesizedExpressionContext(_localctx); + this.enterOuterAlt(_localctx, 2); + { + this.state = 44; + this.match(OpSelectionParser.LPAREN); + this.state = 45; + this.expr(0); + this.state = 46; + this.match(OpSelectionParser.RPAREN); + } + break; + default: + throw new NoViableAltException(this); + } + } catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public traversal(): TraversalContext { + const _localctx: TraversalContext = new TraversalContext(this._ctx, this.state); + this.enterRule(_localctx, 6, OpSelectionParser.RULE_traversal); + try { + let _alt: number; + this.state = 56; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case OpSelectionParser.STAR: + this.enterOuterAlt(_localctx, 1); + { + this.state = 50; + this.match(OpSelectionParser.STAR); + } + break; + case OpSelectionParser.PLUS: + this.enterOuterAlt(_localctx, 2); + { + this.state = 52; + this._errHandler.sync(this); + _alt = 1; + do { + switch (_alt) { + case 1: + { + { + this.state = 51; + this.match(OpSelectionParser.PLUS); + } + } + break; + default: + throw new NoViableAltException(this); + } + this.state = 54; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 4, this._ctx); + } while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER); + } + break; + default: + throw new NoViableAltException(this); + } + } catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public attributeExpr(): AttributeExprContext { + let _localctx: AttributeExprContext = new AttributeExprContext(this._ctx, this.state); + this.enterRule(_localctx, 8, OpSelectionParser.RULE_attributeExpr); + try { + this.state = 64; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case OpSelectionParser.NAME: + _localctx = new NameExprContext(_localctx); + this.enterOuterAlt(_localctx, 1); + { + this.state = 58; + this.match(OpSelectionParser.NAME); + this.state = 59; + this.match(OpSelectionParser.COLON); + this.state = 60; + this.value(); + } + break; + case OpSelectionParser.NAME_SUBSTRING: + _localctx = new NameSubstringExprContext(_localctx); + this.enterOuterAlt(_localctx, 2); + { + this.state = 61; + this.match(OpSelectionParser.NAME_SUBSTRING); + this.state = 62; + this.match(OpSelectionParser.COLON); + this.state = 63; + this.value(); + } + break; + default: + throw new NoViableAltException(this); + } + } catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public value(): ValueContext { + const _localctx: ValueContext = new ValueContext(this._ctx, this.state); + this.enterRule(_localctx, 10, OpSelectionParser.RULE_value); + let _la: number; + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 66; + _la = this._input.LA(1); + if ( + !(_la === OpSelectionParser.QUOTED_STRING || _la === OpSelectionParser.UNQUOTED_STRING) + ) { + this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; + } + + this._errHandler.reportMatch(this); + this.consume(); + } + } + } catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } finally { + this.exitRule(); + } + return _localctx; + } + + public sempred(_localctx: RuleContext, ruleIndex: number, predIndex: number): boolean { + switch (ruleIndex) { + case 1: + return this.expr_sempred(_localctx as ExprContext, predIndex); + } + return true; + } + private expr_sempred(_localctx: ExprContext, predIndex: number): boolean { + switch (predIndex) { + case 0: + return this.precpred(this._ctx, 3); + + case 1: + return this.precpred(this._ctx, 2); + } + return true; + } + + public static readonly _serializedATN: string = + '\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x03\x0FG\x04\x02' + + '\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04\x07' + + '\t\x07\x03\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03' + + '\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03' + + '\x03\x03\x05\x03!\n\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03' + + '\x07\x03)\n\x03\f\x03\x0E\x03,\v\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03' + + '\x04\x05\x043\n\x04\x03\x05\x03\x05\x06\x057\n\x05\r\x05\x0E\x058\x05' + + '\x05;\n\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x05\x06C\n' + + '\x06\x03\x07\x03\x07\x03\x07\x02\x02\x03\x04\b\x02\x02\x04\x02\x06\x02' + + '\b\x02\n\x02\f\x02\x02\x03\x03\x02\r\x0E\x02K\x02\x0E\x03\x02\x02\x02' + + '\x04 \x03\x02\x02\x02\x062\x03\x02\x02\x02\b:\x03\x02\x02\x02\nB\x03\x02' + + '\x02\x02\fD\x03\x02\x02\x02\x0E\x0F\x05\x04\x03\x02\x0F\x10\x07\x02\x02' + + '\x03\x10\x03\x03\x02\x02\x02\x11\x12\b\x03\x01\x02\x12!\x05\x06\x04\x02' + + '\x13\x14\x05\b\x05\x02\x14\x15\x05\x06\x04\x02\x15\x16\x05\b\x05\x02\x16' + + '!\x03\x02\x02\x02\x17\x18\x05\b\x05\x02\x18\x19\x05\x06\x04\x02\x19!\x03' + + '\x02\x02\x02\x1A\x1B\x05\x06\x04\x02\x1B\x1C\x05\b\x05\x02\x1C!\x03\x02' + + '\x02\x02\x1D\x1E\x07\x05\x02\x02\x1E!\x05\x04\x03\x06\x1F!\x07\x06\x02' + + '\x02 \x11\x03\x02\x02\x02 \x13\x03\x02\x02\x02 \x17\x03\x02\x02\x02 \x1A' + + '\x03\x02\x02\x02 \x1D\x03\x02\x02\x02 \x1F\x03\x02\x02\x02!*\x03\x02\x02' + + '\x02"#\f\x05\x02\x02#$\x07\x03\x02\x02$)\x05\x04\x03\x06%&\f\x04\x02' + + "\x02&'\x07\x04\x02\x02')\x05\x04\x03\x05(\"\x03\x02\x02\x02(%\x03\x02" + + '\x02\x02),\x03\x02\x02\x02*(\x03\x02\x02\x02*+\x03\x02\x02\x02+\x05\x03' + + '\x02\x02\x02,*\x03\x02\x02\x02-3\x05\n\x06\x02./\x07\t\x02\x02/0\x05\x04' + + '\x03\x0201\x07\n\x02\x0213\x03\x02\x02\x022-\x03\x02\x02\x022.\x03\x02' + + '\x02\x023\x07\x03\x02\x02\x024;\x07\x06\x02\x0257\x07\x07\x02\x0265\x03' + + '\x02\x02\x0278\x03\x02\x02\x0286\x03\x02\x02\x0289\x03\x02\x02\x029;\x03' + + '\x02\x02\x02:4\x03\x02\x02\x02:6\x03\x02\x02\x02;\t\x03\x02\x02\x02<=' + + '\x07\v\x02\x02=>\x07\b\x02\x02>C\x05\f\x07\x02?@\x07\f\x02\x02@A\x07\b' + + '\x02\x02AC\x05\f\x07\x02B<\x03\x02\x02\x02B?\x03\x02\x02\x02C\v\x03\x02' + + '\x02\x02DE\t\x02\x02\x02E\r\x03\x02\x02\x02\t (*28:B'; + public static __ATN: ATN; + public static get _ATN(): ATN { + if (!OpSelectionParser.__ATN) { + OpSelectionParser.__ATN = new ATNDeserializer().deserialize( + Utils.toCharArray(OpSelectionParser._serializedATN), + ); + } + + return OpSelectionParser.__ATN; + } +} + +export class StartContext extends ParserRuleContext { + public expr(): ExprContext { + return this.getRuleContext(0, ExprContext); + } + public EOF(): TerminalNode { + return this.getToken(OpSelectionParser.EOF, 0); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { + return OpSelectionParser.RULE_start; + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterStart) { + listener.enterStart(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitStart) { + listener.exitStart(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitStart) { + return visitor.visitStart(this); + } else { + return visitor.visitChildren(this); + } + } +} + +export class ExprContext extends ParserRuleContext { + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { + return OpSelectionParser.RULE_expr; + } + public copyFrom(ctx: ExprContext): void { + super.copyFrom(ctx); + } +} +export class TraversalAllowedExpressionContext extends ExprContext { + public traversalAllowedExpr(): TraversalAllowedExprContext { + return this.getRuleContext(0, TraversalAllowedExprContext); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterTraversalAllowedExpression) { + listener.enterTraversalAllowedExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitTraversalAllowedExpression) { + listener.exitTraversalAllowedExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitTraversalAllowedExpression) { + return visitor.visitTraversalAllowedExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class UpAndDownTraversalExpressionContext extends ExprContext { + public traversal(): TraversalContext[]; + public traversal(i: number): TraversalContext; + public traversal(i?: number): TraversalContext | TraversalContext[] { + if (i === undefined) { + return this.getRuleContexts(TraversalContext); + } else { + return this.getRuleContext(i, TraversalContext); + } + } + public traversalAllowedExpr(): TraversalAllowedExprContext { + return this.getRuleContext(0, TraversalAllowedExprContext); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterUpAndDownTraversalExpression) { + listener.enterUpAndDownTraversalExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitUpAndDownTraversalExpression) { + listener.exitUpAndDownTraversalExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitUpAndDownTraversalExpression) { + return visitor.visitUpAndDownTraversalExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class UpTraversalExpressionContext extends ExprContext { + public traversal(): TraversalContext { + return this.getRuleContext(0, TraversalContext); + } + public traversalAllowedExpr(): TraversalAllowedExprContext { + return this.getRuleContext(0, TraversalAllowedExprContext); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterUpTraversalExpression) { + listener.enterUpTraversalExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitUpTraversalExpression) { + listener.exitUpTraversalExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitUpTraversalExpression) { + return visitor.visitUpTraversalExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class DownTraversalExpressionContext extends ExprContext { + public traversalAllowedExpr(): TraversalAllowedExprContext { + return this.getRuleContext(0, TraversalAllowedExprContext); + } + public traversal(): TraversalContext { + return this.getRuleContext(0, TraversalContext); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterDownTraversalExpression) { + listener.enterDownTraversalExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitDownTraversalExpression) { + listener.exitDownTraversalExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitDownTraversalExpression) { + return visitor.visitDownTraversalExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class NotExpressionContext extends ExprContext { + public NOT(): TerminalNode { + return this.getToken(OpSelectionParser.NOT, 0); + } + public expr(): ExprContext { + return this.getRuleContext(0, ExprContext); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterNotExpression) { + listener.enterNotExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitNotExpression) { + listener.exitNotExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitNotExpression) { + return visitor.visitNotExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class AndExpressionContext extends ExprContext { + public expr(): ExprContext[]; + public expr(i: number): ExprContext; + public expr(i?: number): ExprContext | ExprContext[] { + if (i === undefined) { + return this.getRuleContexts(ExprContext); + } else { + return this.getRuleContext(i, ExprContext); + } + } + public AND(): TerminalNode { + return this.getToken(OpSelectionParser.AND, 0); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterAndExpression) { + listener.enterAndExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitAndExpression) { + listener.exitAndExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitAndExpression) { + return visitor.visitAndExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class OrExpressionContext extends ExprContext { + public expr(): ExprContext[]; + public expr(i: number): ExprContext; + public expr(i?: number): ExprContext | ExprContext[] { + if (i === undefined) { + return this.getRuleContexts(ExprContext); + } else { + return this.getRuleContext(i, ExprContext); + } + } + public OR(): TerminalNode { + return this.getToken(OpSelectionParser.OR, 0); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterOrExpression) { + listener.enterOrExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitOrExpression) { + listener.exitOrExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitOrExpression) { + return visitor.visitOrExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class AllExpressionContext extends ExprContext { + public STAR(): TerminalNode { + return this.getToken(OpSelectionParser.STAR, 0); + } + constructor(ctx: ExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterAllExpression) { + listener.enterAllExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitAllExpression) { + listener.exitAllExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitAllExpression) { + return visitor.visitAllExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + +export class TraversalAllowedExprContext extends ParserRuleContext { + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { + return OpSelectionParser.RULE_traversalAllowedExpr; + } + public copyFrom(ctx: TraversalAllowedExprContext): void { + super.copyFrom(ctx); + } +} +export class AttributeExpressionContext extends TraversalAllowedExprContext { + public attributeExpr(): AttributeExprContext { + return this.getRuleContext(0, AttributeExprContext); + } + constructor(ctx: TraversalAllowedExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterAttributeExpression) { + listener.enterAttributeExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitAttributeExpression) { + listener.exitAttributeExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitAttributeExpression) { + return visitor.visitAttributeExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class ParenthesizedExpressionContext extends TraversalAllowedExprContext { + public LPAREN(): TerminalNode { + return this.getToken(OpSelectionParser.LPAREN, 0); + } + public expr(): ExprContext { + return this.getRuleContext(0, ExprContext); + } + public RPAREN(): TerminalNode { + return this.getToken(OpSelectionParser.RPAREN, 0); + } + constructor(ctx: TraversalAllowedExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterParenthesizedExpression) { + listener.enterParenthesizedExpression(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitParenthesizedExpression) { + listener.exitParenthesizedExpression(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitParenthesizedExpression) { + return visitor.visitParenthesizedExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + +export class TraversalContext extends ParserRuleContext { + public STAR(): TerminalNode | undefined { + return this.tryGetToken(OpSelectionParser.STAR, 0); + } + public PLUS(): TerminalNode[]; + public PLUS(i: number): TerminalNode; + public PLUS(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpSelectionParser.PLUS); + } else { + return this.getToken(OpSelectionParser.PLUS, i); + } + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { + return OpSelectionParser.RULE_traversal; + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterTraversal) { + listener.enterTraversal(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitTraversal) { + listener.exitTraversal(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitTraversal) { + return visitor.visitTraversal(this); + } else { + return visitor.visitChildren(this); + } + } +} + +export class AttributeExprContext extends ParserRuleContext { + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { + return OpSelectionParser.RULE_attributeExpr; + } + public copyFrom(ctx: AttributeExprContext): void { + super.copyFrom(ctx); + } +} +export class NameExprContext extends AttributeExprContext { + public NAME(): TerminalNode { + return this.getToken(OpSelectionParser.NAME, 0); + } + public COLON(): TerminalNode { + return this.getToken(OpSelectionParser.COLON, 0); + } + public value(): ValueContext { + return this.getRuleContext(0, ValueContext); + } + constructor(ctx: AttributeExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterNameExpr) { + listener.enterNameExpr(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitNameExpr) { + listener.exitNameExpr(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitNameExpr) { + return visitor.visitNameExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class NameSubstringExprContext extends AttributeExprContext { + public NAME_SUBSTRING(): TerminalNode { + return this.getToken(OpSelectionParser.NAME_SUBSTRING, 0); + } + public COLON(): TerminalNode { + return this.getToken(OpSelectionParser.COLON, 0); + } + public value(): ValueContext { + return this.getRuleContext(0, ValueContext); + } + constructor(ctx: AttributeExprContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterNameSubstringExpr) { + listener.enterNameSubstringExpr(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitNameSubstringExpr) { + listener.exitNameSubstringExpr(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitNameSubstringExpr) { + return visitor.visitNameSubstringExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} + +export class ValueContext extends ParserRuleContext { + public QUOTED_STRING(): TerminalNode | undefined { + return this.tryGetToken(OpSelectionParser.QUOTED_STRING, 0); + } + public UNQUOTED_STRING(): TerminalNode | undefined { + return this.tryGetToken(OpSelectionParser.UNQUOTED_STRING, 0); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { + return OpSelectionParser.RULE_value; + } + // @Override + public enterRule(listener: OpSelectionListener): void { + if (listener.enterValue) { + listener.enterValue(this); + } + } + // @Override + public exitRule(listener: OpSelectionListener): void { + if (listener.exitValue) { + listener.exitValue(this); + } + } + // @Override + public accept(visitor: OpSelectionVisitor): Result { + if (visitor.visitValue) { + return visitor.visitValue(this); + } else { + return visitor.visitChildren(this); + } + } +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionVisitor.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionVisitor.ts new file mode 100644 index 0000000000000..19e9f3b480257 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/generated/OpSelectionVisitor.ts @@ -0,0 +1,171 @@ +// Generated from /Users/briantu/repos/dagster/js_modules/dagster-ui/packages/ui-core/src/op-selection/OpSelection.g4 by ANTLR 4.9.0-SNAPSHOT + +import {ParseTreeVisitor} from 'antlr4ts/tree/ParseTreeVisitor'; + +import { + AllExpressionContext, + AndExpressionContext, + AttributeExprContext, + AttributeExpressionContext, + DownTraversalExpressionContext, + ExprContext, + NameExprContext, + NameSubstringExprContext, + NotExpressionContext, + OrExpressionContext, + ParenthesizedExpressionContext, + StartContext, + TraversalAllowedExprContext, + TraversalAllowedExpressionContext, + TraversalContext, + UpAndDownTraversalExpressionContext, + UpTraversalExpressionContext, + ValueContext, +} from './OpSelectionParser'; + +/** + * This interface defines a complete generic visitor for a parse tree produced + * by `OpSelectionParser`. + * + * @param The return type of the visit operation. Use `void` for + * operations with no return type. + */ +export interface OpSelectionVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by the `TraversalAllowedExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTraversalAllowedExpression?: (ctx: TraversalAllowedExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `UpAndDownTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitUpAndDownTraversalExpression?: (ctx: UpAndDownTraversalExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `UpTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitUpTraversalExpression?: (ctx: UpTraversalExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `DownTraversalExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDownTraversalExpression?: (ctx: DownTraversalExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `NotExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitNotExpression?: (ctx: NotExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `AndExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitAndExpression?: (ctx: AndExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `OrExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitOrExpression?: (ctx: OrExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `AllExpression` + * labeled alternative in `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitAllExpression?: (ctx: AllExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `NameExpr` + * labeled alternative in `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitNameExpr?: (ctx: NameExprContext) => Result; + + /** + * Visit a parse tree produced by the `NameSubstringExpr` + * labeled alternative in `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitNameSubstringExpr?: (ctx: NameSubstringExprContext) => Result; + + /** + * Visit a parse tree produced by the `AttributeExpression` + * labeled alternative in `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitAttributeExpression?: (ctx: AttributeExpressionContext) => Result; + + /** + * Visit a parse tree produced by the `ParenthesizedExpression` + * labeled alternative in `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitParenthesizedExpression?: (ctx: ParenthesizedExpressionContext) => Result; + + /** + * Visit a parse tree produced by `OpSelectionParser.start`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStart?: (ctx: StartContext) => Result; + + /** + * Visit a parse tree produced by `OpSelectionParser.expr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitExpr?: (ctx: ExprContext) => Result; + + /** + * Visit a parse tree produced by `OpSelectionParser.traversalAllowedExpr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTraversalAllowedExpr?: (ctx: TraversalAllowedExprContext) => Result; + + /** + * Visit a parse tree produced by `OpSelectionParser.traversal`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTraversal?: (ctx: TraversalContext) => Result; + + /** + * Visit a parse tree produced by `OpSelectionParser.attributeExpr`. + * @param ctx the parse tree + * @return the visitor result + */ + visitAttributeExpr?: (ctx: AttributeExprContext) => Result; + + /** + * Visit a parse tree produced by `OpSelectionParser.value`. + * @param ctx the parse tree + * @return the visitor result + */ + visitValue?: (ctx: ValueContext) => Result; +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/scripts/generateOpSelection.ts b/js_modules/dagster-ui/packages/ui-core/src/scripts/generateOpSelection.ts new file mode 100644 index 0000000000000..ff79e194f3a8d --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/scripts/generateOpSelection.ts @@ -0,0 +1,16 @@ +import {execSync} from 'child_process'; +import path from 'path'; + +const OP_SELECTION_GRAMMAR_FILE_PATH = path.resolve('./src/op-selection/OpSelection.g4'); +execSync(`antlr4ts -visitor -o ./src/op-selection/generated ${OP_SELECTION_GRAMMAR_FILE_PATH}`); + +const files = [ + 'OpSelectionLexer.ts', + 'OpSelectionListener.ts', + 'OpSelectionParser.ts', + 'OpSelectionVisitor.ts', +]; + +files.forEach((file) => { + execSync(`yarn prettier ./src/op-selection/generated/${file} --write`); +}); From db1b5f034f63c4895d077d831d93273a8636d56c Mon Sep 17 00:00:00 2001 From: Brian Tu Date: Fri, 13 Dec 2024 15:54:40 -0500 Subject: [PATCH 48/94] Implement AntlrOpSelectionVisitor on frontend (#26467) ## Summary & Motivation Implement visitor pattern for op selection syntax. ## How I Tested These Changes `AntlrOpSelection.test.ts` --- .../src/op-selection/AntlrOpSelection.ts | 42 ++++++ .../op-selection/AntlrOpSelectionVisitor.ts | 123 ++++++++++++++++++ .../__tests__/AntlrOpSelection.test.ts | 118 +++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelection.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelectionVisitor.ts create mode 100644 js_modules/dagster-ui/packages/ui-core/src/op-selection/__tests__/AntlrOpSelection.test.ts diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelection.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelection.ts new file mode 100644 index 0000000000000..614bde690e347 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelection.ts @@ -0,0 +1,42 @@ +import {CharStreams, CommonTokenStream} from 'antlr4ts'; + +import {AntlrOpSelectionVisitor} from './AntlrOpSelectionVisitor'; +import {GraphQueryItem} from '../app/GraphQueryImpl'; +import {AntlrInputErrorListener} from '../asset-selection/AntlrAssetSelection'; +import {OpSelectionLexer} from './generated/OpSelectionLexer'; +import {OpSelectionParser} from './generated/OpSelectionParser'; + +type OpSelectionQueryResult = { + all: GraphQueryItem[]; + focus: GraphQueryItem[]; +}; + +export const parseOpSelectionQuery = ( + all_ops: GraphQueryItem[], + query: string, +): OpSelectionQueryResult | Error => { + try { + const lexer = new OpSelectionLexer(CharStreams.fromString(query)); + lexer.removeErrorListeners(); + lexer.addErrorListener(new AntlrInputErrorListener()); + + const tokenStream = new CommonTokenStream(lexer); + + const parser = new OpSelectionParser(tokenStream); + parser.removeErrorListeners(); + parser.addErrorListener(new AntlrInputErrorListener()); + + const tree = parser.start(); + + const visitor = new AntlrOpSelectionVisitor(all_ops); + const all_selection = visitor.visit(tree); + const focus_selection = visitor.focus_ops; + + return { + all: Array.from(all_selection), + focus: Array.from(focus_selection), + }; + } catch (e) { + return e as Error; + } +}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelectionVisitor.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelectionVisitor.ts new file mode 100644 index 0000000000000..7af548928dfe6 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/AntlrOpSelectionVisitor.ts @@ -0,0 +1,123 @@ +import {AbstractParseTreeVisitor} from 'antlr4ts/tree/AbstractParseTreeVisitor'; + +import {GraphQueryItem, GraphTraverser} from '../app/GraphQueryImpl'; +import { + AllExpressionContext, + AndExpressionContext, + AttributeExpressionContext, + DownTraversalExpressionContext, + NameExprContext, + NameSubstringExprContext, + NotExpressionContext, + OrExpressionContext, + ParenthesizedExpressionContext, + StartContext, + TraversalAllowedExpressionContext, + UpAndDownTraversalExpressionContext, + UpTraversalExpressionContext, +} from './generated/OpSelectionParser'; +import {OpSelectionVisitor} from './generated/OpSelectionVisitor'; +import {getTraversalDepth, getValue} from '../asset-selection/AntlrAssetSelectionVisitor'; + +export class AntlrOpSelectionVisitor + extends AbstractParseTreeVisitor> + implements OpSelectionVisitor> +{ + all_ops: Set; + focus_ops: Set; + traverser: GraphTraverser; + + protected defaultResult() { + return new Set(); + } + + constructor(all_ops: GraphQueryItem[]) { + super(); + this.all_ops = new Set(all_ops); + this.focus_ops = new Set(); + this.traverser = new GraphTraverser(all_ops); + } + + visitStart(ctx: StartContext) { + return this.visit(ctx.expr()); + } + + visitTraversalAllowedExpression(ctx: TraversalAllowedExpressionContext) { + return this.visit(ctx.traversalAllowedExpr()); + } + + visitUpAndDownTraversalExpression(ctx: UpAndDownTraversalExpressionContext) { + const selection = this.visit(ctx.traversalAllowedExpr()); + const up_depth: number = getTraversalDepth(ctx.traversal(0)); + const down_depth: number = getTraversalDepth(ctx.traversal(1)); + const selection_copy = new Set(selection); + for (const item of selection_copy) { + this.traverser.fetchUpstream(item, up_depth).forEach((i) => selection.add(i)); + this.traverser.fetchDownstream(item, down_depth).forEach((i) => selection.add(i)); + } + return selection; + } + + visitUpTraversalExpression(ctx: UpTraversalExpressionContext) { + const selection = this.visit(ctx.traversalAllowedExpr()); + const traversal_depth: number = getTraversalDepth(ctx.traversal()); + const selection_copy = new Set(selection); + for (const item of selection_copy) { + this.traverser.fetchUpstream(item, traversal_depth).forEach((i) => selection.add(i)); + } + return selection; + } + + visitDownTraversalExpression(ctx: DownTraversalExpressionContext) { + const selection = this.visit(ctx.traversalAllowedExpr()); + const traversal_depth: number = getTraversalDepth(ctx.traversal()); + const selection_copy = new Set(selection); + for (const item of selection_copy) { + this.traverser.fetchDownstream(item, traversal_depth).forEach((i) => selection.add(i)); + } + return selection; + } + + visitNotExpression(ctx: NotExpressionContext) { + const selection = this.visit(ctx.expr()); + return new Set([...this.all_ops].filter((i) => !selection.has(i))); + } + + visitAndExpression(ctx: AndExpressionContext) { + const left = this.visit(ctx.expr(0)); + const right = this.visit(ctx.expr(1)); + return new Set([...left].filter((i) => right.has(i))); + } + + visitOrExpression(ctx: OrExpressionContext) { + const left = this.visit(ctx.expr(0)); + const right = this.visit(ctx.expr(1)); + return new Set([...left, ...right]); + } + + visitAllExpression(_ctx: AllExpressionContext) { + return this.all_ops; + } + + visitAttributeExpression(ctx: AttributeExpressionContext) { + return this.visit(ctx.attributeExpr()); + } + + visitParenthesizedExpression(ctx: ParenthesizedExpressionContext) { + return this.visit(ctx.expr()); + } + + visitNameExpr(ctx: NameExprContext) { + const value: string = getValue(ctx.value()); + const selection = [...this.all_ops].filter((i) => i.name === value); + selection.forEach((i) => this.focus_ops.add(i)); + return new Set(selection); + } + + visitNameSubstringExpr(ctx: NameSubstringExprContext) { + const value: string = getValue(ctx.value()); + const selection = [...this.all_ops].filter((i) => i.name.includes(value)); + selection.forEach((i) => this.focus_ops.add(i)); + return new Set(selection); + } +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/op-selection/__tests__/AntlrOpSelection.test.ts b/js_modules/dagster-ui/packages/ui-core/src/op-selection/__tests__/AntlrOpSelection.test.ts new file mode 100644 index 0000000000000..8150daefa203d --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/op-selection/__tests__/AntlrOpSelection.test.ts @@ -0,0 +1,118 @@ +/* eslint-disable jest/expect-expect */ + +import {GraphQueryItem} from '../../app/GraphQueryImpl'; +import {parseOpSelectionQuery} from '../AntlrOpSelection'; + +const TEST_GRAPH: GraphQueryItem[] = [ + // Top Layer + { + name: 'A', + inputs: [{dependsOn: []}], + outputs: [{dependedBy: [{solid: {name: 'B'}}, {solid: {name: 'B2'}}]}], + }, + // Second Layer + { + name: 'B', + inputs: [{dependsOn: [{solid: {name: 'A'}}]}], + outputs: [{dependedBy: [{solid: {name: 'C'}}]}], + }, + { + name: 'B2', + inputs: [{dependsOn: [{solid: {name: 'A'}}]}], + outputs: [{dependedBy: [{solid: {name: 'C'}}]}], + }, + // Third Layer + { + name: 'C', + inputs: [{dependsOn: [{solid: {name: 'B'}}, {solid: {name: 'B2'}}]}], + outputs: [{dependedBy: []}], + }, +]; + +function assertQueryResult(query: string, expectedNames: string[]) { + const result = parseOpSelectionQuery(TEST_GRAPH, query); + expect(result).not.toBeInstanceOf(Error); + if (result instanceof Error) { + throw result; + } + expect(result.all.length).toBe(expectedNames.length); + expect(new Set(result.all.map((op) => op.name))).toEqual(new Set(expectedNames)); +} + +// Most tests copied from AntlrAssetSelection.test.ts +describe('parseOpSelectionQuery', () => { + describe('invalid queries', () => { + it('should throw on invalid queries', () => { + expect(parseOpSelectionQuery(TEST_GRAPH, 'A')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'name:A name:B')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'not')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'and')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'name:A and')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'sinks(*)')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'roots(*)')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'notafunction()')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'tag:foo=')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'owner')).toBeInstanceOf(Error); + expect(parseOpSelectionQuery(TEST_GRAPH, 'owner:owner@owner.com')).toBeInstanceOf(Error); + }); + }); + + describe('valid queries', () => { + it('should parse star query', () => { + assertQueryResult('*', ['A', 'B', 'B2', 'C']); + }); + + it('should parse name query', () => { + assertQueryResult('name:A', ['A']); + }); + + it('should parse name_substring query', () => { + assertQueryResult('name_substring:A', ['A']); + assertQueryResult('name_substring:B', ['B', 'B2']); + }); + + it('should parse and query', () => { + assertQueryResult('name:A and name:B', []); + assertQueryResult('name:A and name:B and name:C', []); + }); + + it('should parse or query', () => { + assertQueryResult('name:A or name:B', ['A', 'B']); + assertQueryResult('name:A or name:B or name:C', ['A', 'B', 'C']); + assertQueryResult('(name:A or name:B) and (name:B or name:C)', ['B']); + }); + + it('should parse upstream plus query', () => { + assertQueryResult('+name:A', ['A']); + assertQueryResult('+name:B', ['A', 'B']); + assertQueryResult('+name:C', ['B', 'B2', 'C']); + assertQueryResult('++name:C', ['A', 'B', 'B2', 'C']); + }); + + it('should parse downstream plus query', () => { + assertQueryResult('name:A+', ['A', 'B', 'B2']); + assertQueryResult('name:A++', ['A', 'B', 'B2', 'C']); + assertQueryResult('name:C+', ['C']); + assertQueryResult('name:B+', ['B', 'C']); + }); + + it('should parse upstream star query', () => { + assertQueryResult('*name:A', ['A']); + assertQueryResult('*name:B', ['A', 'B']); + assertQueryResult('*name:C', ['A', 'B', 'B2', 'C']); + }); + + it('should parse downstream star query', () => { + assertQueryResult('name:A*', ['A', 'B', 'B2', 'C']); + assertQueryResult('name:B*', ['B', 'C']); + assertQueryResult('name:C*', ['C']); + }); + + it('should parse up and down traversal queries', () => { + assertQueryResult('name:A* and *name:C', ['A', 'B', 'B2', 'C']); + assertQueryResult('*name:B*', ['A', 'B', 'C']); + assertQueryResult('name:A* and *name:C and *name:B*', ['A', 'B', 'C']); + assertQueryResult('name:A* and *name:B* and *name:C', ['A', 'B', 'C']); + }); + }); +}); From fab34456323fde3eac26aa4491c4bf4a72b8bf17 Mon Sep 17 00:00:00 2001 From: colton Date: Fri, 13 Dec 2024 15:57:39 -0500 Subject: [PATCH 49/94] [docs-beta] add contributing migration section (#26483) ## Summary & Motivation - Adds some pointers on migrating between legacy and new docs ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --- docs/docs-beta/CONTRIBUTING.md | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 docs/docs-beta/CONTRIBUTING.md diff --git a/docs/docs-beta/CONTRIBUTING.md b/docs/docs-beta/CONTRIBUTING.md new file mode 100644 index 0000000000000..bddff1c929782 --- /dev/null +++ b/docs/docs-beta/CONTRIBUTING.md @@ -0,0 +1,100 @@ +# Contributing + +## Migration from legacy docs + +There are some features in the previous docs that require changes to be made to work in the new Docusaurus-based documentation site. + +### Images + +Before: + +``` +Highlighted Redeploy option in the dropdown menu next to a code location in Dagster+ +``` + +After: + +``` + +``` + +### Notes + +Before: + +``` +This guide is applicable to Dagster+. +``` + +After: + +``` +:::note +This guide is applicable to Dagster+ +::: +``` + +### Tabs + +Before: + +``` + + + ... + + +``` + +After: + +``` + + + ... + + +``` + +### Header boundaries + +Previously, horizontal rules had to be defined between each level-two header: `---`. + +This is no longer required, as the horizontal rule has been included in the CSS rules. + +### Reference tables + +Before: + +``` + + + A list of keys or key-value pairs to include in the task. If a value is not + specified, the value will be pulled from the agent task. +
+ In the example above, FOO_ENV_VAR will be set to{" "} + foo_value and BAR_ENV_VAR will be set to whatever + value it has in the agent task. +
+
+``` + +After: + +_There is not a replacement at this point in time..._ + +### Whitespace via `{" "}` + +Forcing empty space using the `{" "}` interpolation is not supported, and must be removed. From aa2f5c9f785254d23307506416adea108b60106b Mon Sep 17 00:00:00 2001 From: gibsondan Date: Fri, 13 Dec 2024 14:59:56 -0600 Subject: [PATCH 50/94] memoize inputs and outputs in op/graph snapshots (#26482) Summary: Iterating through big lists is slow, indexing into a mapping is fast. Test Plan: BK, speedscope on large multi-asset with many outputs ## Summary & Motivation ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --- .../dagster/dagster/_core/snap/node.py | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/python_modules/dagster/dagster/_core/snap/node.py b/python_modules/dagster/dagster/_core/snap/node.py index e05f6d972411a..df8fbc83034ee 100644 --- a/python_modules/dagster/dagster/_core/snap/node.py +++ b/python_modules/dagster/dagster/_core/snap/node.py @@ -1,3 +1,4 @@ +from functools import cached_property from typing import Mapping, NamedTuple, Optional, Sequence, Union import dagster._check as check @@ -233,6 +234,14 @@ def __new__( ), ) + @cached_property + def input_def_map(self) -> Mapping[str, InputDefSnap]: + return {input_def.name: input_def for input_def in self.input_def_snaps} + + @cached_property + def output_def_map(self) -> Mapping[str, OutputDefSnap]: + return {output_def.name: output_def for output_def in self.output_def_snaps} + def get_input_snap(self, name: str) -> InputDefSnap: return _get_input_snap(self, name) @@ -282,6 +291,14 @@ def __new__( ), ) + @cached_property + def input_def_map(self) -> Mapping[str, InputDefSnap]: + return {input_def.name: input_def for input_def in self.input_def_snaps} + + @cached_property + def output_def_map(self) -> Mapping[str, OutputDefSnap]: + return {output_def.name: output_def for output_def in self.output_def_snaps} + def get_input_snap(self, name: str) -> InputDefSnap: return _get_input_snap(self, name) @@ -387,9 +404,9 @@ def build_op_def_snap(op_def: OpDefinition) -> OpDefSnap: # shared impl for GraphDefSnap and OpDefSnap def _get_input_snap(node_def: Union[GraphDefSnap, OpDefSnap], name: str) -> InputDefSnap: check.str_param(name, "name") - for inp in node_def.input_def_snaps: - if inp.name == name: - return inp + inp = node_def.input_def_map.get(name) + if inp: + return inp check.failed(f"Could not find input {name} in op def {node_def.name}") @@ -397,8 +414,8 @@ def _get_input_snap(node_def: Union[GraphDefSnap, OpDefSnap], name: str) -> Inpu # shared impl for GraphDefSnap and OpDefSnap def _get_output_snap(node_def: Union[GraphDefSnap, OpDefSnap], name: str) -> OutputDefSnap: check.str_param(name, "name") - for out in node_def.output_def_snaps: - if out.name == name: - return out + inp = node_def.output_def_map.get(name) + if inp: + return inp check.failed(f"Could not find output {name} in node def {node_def.name}") From ef2817dcd4905fafd1468e0eedc1ee4bb7251d8e Mon Sep 17 00:00:00 2001 From: jamiedemaria Date: Fri, 13 Dec 2024 16:00:53 -0500 Subject: [PATCH 51/94] [ui] backfill preview modal - if an asset won't launch any partitions show a message instead of a spinner (#26080) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary & Motivation If you select a group of assets to backfill and select a range such that a subset of the assets have no partitions in that range, the Backfill Preview modal shows spinners for those assets For example - for the following asset graph Screenshot 2024-11-21 at 11 46 09 AM If you select only the latest hour to materialize, the daily asset will have no valid partitions to materialize (materializing today's asset isn't available until tomorrow) If you then click the "Backfill Preview" button, we show an infinite spinner for the daily asset ![image (19)](https://github.com/user-attachments/assets/ef08731b-8b8e-4f28-a53a-3eca5ad2b648) This PR adds a message when we know an asset wont have any partitions targeted by the backfill Screenshot 2024-11-21 at 11 41 39 AM ## How I Tested These Changes ## Changelog [ui] Fixed a bug in the Backfill Preview where a loading spinner would spin forever if an asset had no valid partitions targeted by the backfill --- .../packages/ui-core/src/assets/BackfillPreviewModal.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/BackfillPreviewModal.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/BackfillPreviewModal.tsx index 31607e4e01b28..f78dda46931d0 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/BackfillPreviewModal.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/BackfillPreviewModal.tsx @@ -57,7 +57,7 @@ export const BackfillPreviewModal = ({ skip: !isOpen, }, ); - const {data} = queryResult; + const {data, loading} = queryResult; const partitionsByAssetToken = useMemo(() => { return Object.fromEntries( @@ -107,8 +107,10 @@ export const BackfillPreviewModal = ({ {partitions ? ( - ) : ( + ) : loading ? ( + ) : ( + 'No partitions available to materialize' )} From be934a04d3006d7a8da5899040d67e7909c28847 Mon Sep 17 00:00:00 2001 From: Nikki Everett Date: Fri, 13 Dec 2024 16:13:13 -0600 Subject: [PATCH 52/94] Update beta-docs README and CONTRIBUTING (#26490) ## Summary & Motivation Update README and move formatting guidelines from README to CONTRIBUTING. ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --------- Signed-off-by: nikki everett --- docs/docs-beta/CONTRIBUTING.md | 35 +++++++++++++++++ docs/docs-beta/README.md | 71 ++++++++++++---------------------- 2 files changed, 59 insertions(+), 47 deletions(-) diff --git a/docs/docs-beta/CONTRIBUTING.md b/docs/docs-beta/CONTRIBUTING.md index bddff1c929782..f2b8d9d78c55b 100644 --- a/docs/docs-beta/CONTRIBUTING.md +++ b/docs/docs-beta/CONTRIBUTING.md @@ -98,3 +98,38 @@ _There is not a replacement at this point in time..._ ### Whitespace via `{" "}` Forcing empty space using the `{" "}` interpolation is not supported, and must be removed. + +--- + +## Diagrams + +You can use [Mermaid.js](https://mermaid.js.org/syntax/flowchart.html) to create diagrams. For example: + +```mermaid +flowchart LR + Start --> Stop +``` + +Refer to the [Mermaid.js documentation](https://mermaid.js.org/) for more info. + +--- + +## Code examples + +To include code snippets, use the following format: + +``` + +``` + +The `filePath` is relative to the `./examples/docs_beta_snippets/docs_beta_snippets/` directory. + +At minimum, all `.py` files in the `docs_beta_snippets` directory are tested by attempting to load the Python files. +You can write additional tests for them in the `docs_beta_snippets_test` folder. See the folder for more information. + +To type-check the code snippets during development, run the following command from the Dagster root folder. +This will run `pyright` on all new/changed files relative to the master branch. + +``` +make quick_pyright +``` diff --git a/docs/docs-beta/README.md b/docs/docs-beta/README.md index 33e2e5fbf0ae8..f07c8ddd61daa 100644 --- a/docs/docs-beta/README.md +++ b/docs/docs-beta/README.md @@ -5,6 +5,26 @@ The documentation site is built using [Docusaurus](https://docusaurus.io/), a mo --- +## Overview of the docs + +- `./src` contains custom components, styles, themes, and layouts. +- `./content-templates` contains the templates for the documentation pages. +- `./docs/` is the source of truth for the documentation. +- `/examples/docs_beta_snippets/docs_beta_snippets/` contains all code examples for the documentation. + +The docs are broken down into the following sections: + +- Docs - includes content from [getting-started](./docs/getting-started/) and [guides](./docs/guides/) +- [Integrations](./docs/integrations/) +- [Dagster+](./docs/dagster-plus/) +- [API reference](./docs/api/) + +`sidebar.ts` and `docusaurus.config.ts` are the main configuration files for the documentation. + +For formatting guidelines, see the [CONTRIBUTING](CONTRIBUTING.md) guide. + +--- + ## Installation The site uses [yarn](https://yarnpkg.com/) for package management. @@ -31,22 +51,6 @@ pip install vale --- -## Overview of the docs - -- `./src` contains custom components, styles, themes, and layouts. -- `./content-templates` contains the templates for the documentation pages. -- `./docs/` is the source of truth for the documentation. -- `/examples/docs_beta_snippets/docs_beta_snippets/` contains all code examples for the documentation. - -The docs are broken down into the following sections: - -- [Tutorials](./docs/tutorials/) -- [Guides](./docs/guides/) - -`sidebar.ts` and `docusaurus.config.ts` are the main configuration files for the documentation. - ---- - ## Local Development To start the local development server: @@ -72,37 +76,6 @@ yarn vale /path/to/file ## check individual file yarn vale --no-wrap ## remove wrapping from output ``` -### Diagrams - -You can use [Mermaid.js](https://mermaid.js.org/syntax/flowchart.html) to create diagrams. For example: - -```mermaid -flowchart LR - Start --> Stop -``` - -Refer to the [Mermaid.js documentation](https://mermaid.js.org/) for more info. - -### Code examples - -To include code snippets, use the following format: - -``` - -``` - -The `filePath` is relative to the `./examples/docs_beta_snippets/docs_beta_snippets/` directory. - -At minimum, all `.py` files in the `docs_beta_snippets` directory are tested by attempting to load the Python files. -You can write additional tests for them in the `docs_beta_snippets_test` folder. See the folder for more information. - -To type-check the code snippets during development, run the following command from the Dagster root folder. -This will run `pyright` on all new/changed files relative to the master branch. - -``` -make quick_pyright -``` - --- ## Build @@ -115,6 +88,8 @@ yarn build This command generates static content into the `build` directory and can be served using any static contents hosting service. This also checks for any broken links in the documentation. Note that you will need to store Algolia credentials in local environment variables to build the site for production. +--- + ## Deployment This site is built and deployed using Vercel. @@ -129,6 +104,8 @@ yarn sync-api-docs && yarn build This runs the `scripts/vercel-sync-api-docs.sh` script which builds the MDX files using the custom `sphinx-mdx-builder`, and copies the resulting MDX files to `docs/api/python-api`. +--- + ## Search Algolia search is used for search results on the website, as configured in `docusaurus.config.ts`. From 3d4e320eb61b1345352e26d205b5ce629243cbfa Mon Sep 17 00:00:00 2001 From: Tyler Eason Date: Sat, 14 Dec 2024 13:07:09 +0900 Subject: [PATCH 53/94] Add value flag to disable check-db-ready initContainers in Helm chart (#26343) ## Summary & Motivation Address #26311 (partially) and #26284 (duplicate issues) tl;dr: the `check-db-ready` container can be part of a race condition with other initContainers that are responsible for enabling the DB connection. Externally managed DBs (i.e. not the postgres container optionally included in this chart) can be validated before Helm installation so this step is not strictly required. ## How I Tested These Changes 1. Wrote some tests 2. Installed the chart to minikube with ``` helm install dagster . --set dagsterWebserver.image.tag=latest --set dagsterDaemon.image.tag=latest --set pipelineRun.image.tag=latest --set dagsterWebserver.checkDbReadyInitContainer=true ``` And observed the initContainers present. Then ran it again with `false` ``` helm install dagster . --set dagsterWebserver.image.tag=latest --set dagsterDaemon.image.tag=latest --set pipelineRun.image.tag=latest --set dagsterWebserver.checkDbReadyInitContainer=false ``` And observed the initContainers absent. ## Changelog - Added flag `checkDbReadyInitContainer` to optionally disable db check initContainer. --------- Co-authored-by: Tyler Eason --- .../schema/charts/dagster/subschema/daemon.py | 1 + .../schema/charts/dagster/subschema/flower.py | 1 + .../charts/dagster/subschema/run_launcher.py | 1 + .../charts/dagster/subschema/webserver.py | 1 + .../schema/schema_tests/test_celery_queues.py | 46 ++++++++++++++++++ .../dagster/schema/schema_tests/test_dagit.py | 31 ++++++++++++ .../schema_tests/test_dagster_daemon.py | 27 +++++++++++ .../templates/deployment-celery-queues.yaml | 2 + helm/dagster/templates/deployment-daemon.yaml | 2 + helm/dagster/templates/deployment-flower.yaml | 2 + .../helpers/_deployment-webserver.tpl | 2 + helm/dagster/values.schema.json | 48 +++++++++++++++++++ helm/dagster/values.yaml | 10 ++++ 13 files changed, 174 insertions(+) diff --git a/helm/dagster/schema/schema/charts/dagster/subschema/daemon.py b/helm/dagster/schema/schema/charts/dagster/subschema/daemon.py index 5f9a5524f54b8..04cfa9f039e22 100644 --- a/helm/dagster/schema/schema/charts/dagster/subschema/daemon.py +++ b/helm/dagster/schema/schema/charts/dagster/subschema/daemon.py @@ -94,6 +94,7 @@ class Daemon(BaseModel, extra="forbid"): podSecurityContext: kubernetes.PodSecurityContext securityContext: kubernetes.SecurityContext resources: kubernetes.Resources + checkDbReadyInitContainer: Optional[bool] = None livenessProbe: kubernetes.LivenessProbe readinessProbe: kubernetes.ReadinessProbe startupProbe: kubernetes.StartupProbe diff --git a/helm/dagster/schema/schema/charts/dagster/subschema/flower.py b/helm/dagster/schema/schema/charts/dagster/subschema/flower.py index 6742e3c090f4b..f2a93daae60f3 100644 --- a/helm/dagster/schema/schema/charts/dagster/subschema/flower.py +++ b/helm/dagster/schema/schema/charts/dagster/subschema/flower.py @@ -13,6 +13,7 @@ class Flower(BaseModel): tolerations: kubernetes.Tolerations podSecurityContext: kubernetes.PodSecurityContext securityContext: kubernetes.SecurityContext + checkDbReadyInitContainer: Optional[bool] = None resources: kubernetes.Resources livenessProbe: kubernetes.LivenessProbe startupProbe: kubernetes.StartupProbe diff --git a/helm/dagster/schema/schema/charts/dagster/subschema/run_launcher.py b/helm/dagster/schema/schema/charts/dagster/subschema/run_launcher.py index 7b6d9eaaa143f..c73e9132573c2 100644 --- a/helm/dagster/schema/schema/charts/dagster/subschema/run_launcher.py +++ b/helm/dagster/schema/schema/charts/dagster/subschema/run_launcher.py @@ -40,6 +40,7 @@ class CeleryK8sRunLauncherConfig(BaseModel): podSecurityContext: kubernetes.PodSecurityContext securityContext: kubernetes.SecurityContext resources: kubernetes.Resources + checkDbReadyInitContainer: Optional[bool] = None livenessProbe: kubernetes.LivenessProbe volumeMounts: List[kubernetes.VolumeMount] volumes: List[kubernetes.Volume] diff --git a/helm/dagster/schema/schema/charts/dagster/subschema/webserver.py b/helm/dagster/schema/schema/charts/dagster/subschema/webserver.py index fda17a8acf6fc..d84ddf8c27178 100644 --- a/helm/dagster/schema/schema/charts/dagster/subschema/webserver.py +++ b/helm/dagster/schema/schema/charts/dagster/subschema/webserver.py @@ -34,6 +34,7 @@ class Webserver(BaseModel, extra="forbid"): tolerations: kubernetes.Tolerations podSecurityContext: kubernetes.PodSecurityContext securityContext: kubernetes.SecurityContext + checkDbReadyInitContainer: Optional[bool] = None resources: kubernetes.Resources readinessProbe: kubernetes.ReadinessProbe livenessProbe: kubernetes.LivenessProbe diff --git a/helm/dagster/schema/schema_tests/test_celery_queues.py b/helm/dagster/schema/schema_tests/test_celery_queues.py index 7b84118c5a941..c9548112b795b 100644 --- a/helm/dagster/schema/schema_tests/test_celery_queues.py +++ b/helm/dagster/schema/schema_tests/test_celery_queues.py @@ -307,3 +307,49 @@ def test_scheduler_name(deployment_template: HelmTemplate): deployment = celery_queue_deployments[0] assert deployment.spec.template.spec.scheduler_name == "custom" + + +def test_check_db_container_toggle(deployment_template: HelmTemplate): + # Off test + helm_values = DagsterHelmValues.construct( + runLauncher=RunLauncher( + type=RunLauncherType.CELERY, + config=RunLauncherConfig( + celeryK8sRunLauncher=CeleryK8sRunLauncherConfig.construct( + checkDbReadyInitContainer=False + ) + ), + ) + ) + [daemon_deployment] = deployment_template.render(helm_values) + assert daemon_deployment.spec.template.spec.init_containers is None or "check-db-ready" not in [ + container.name for container in daemon_deployment.spec.template.spec.init_containers + ] + + # On test + helm_values = DagsterHelmValues.construct( + runLauncher=RunLauncher( + type=RunLauncherType.CELERY, + config=RunLauncherConfig( + celeryK8sRunLauncher=CeleryK8sRunLauncherConfig.construct( + checkDbReadyInitContainer=True + ) + ), + ) + ) + [daemon_deployment] = deployment_template.render(helm_values) + assert "check-db-ready" in [ + container.name for container in daemon_deployment.spec.template.spec.init_containers + ] + + # Default test + helm_values = DagsterHelmValues.construct( + runLauncher=RunLauncher( + type=RunLauncherType.CELERY, + config=RunLauncherConfig(celeryK8sRunLauncher=CeleryK8sRunLauncherConfig.construct()), + ) + ) + [daemon_deployment] = deployment_template.render(helm_values) + assert "check-db-ready" in [ + container.name for container in daemon_deployment.spec.template.spec.init_containers + ] diff --git a/helm/dagster/schema/schema_tests/test_dagit.py b/helm/dagster/schema/schema_tests/test_dagit.py index 85b2c9b9c44ab..67ade02507457 100644 --- a/helm/dagster/schema/schema_tests/test_dagit.py +++ b/helm/dagster/schema/schema_tests/test_dagit.py @@ -596,3 +596,34 @@ def test_env_configmap(configmap_template): assert len(cm.data) == 6 assert cm.data["DAGSTER_HOME"] == "/opt/dagster/dagster_home" assert cm.data["TEST_ENV"] == "test_value" + + +def test_check_db_container_toggle(deployment_template: HelmTemplate): + # Off test + helm_values = DagsterHelmValues.construct( + dagsterWebserver=Webserver.construct(checkDbReadyInitContainer=False) + ) + [webserver_deployment] = deployment_template.render(helm_values) + assert ( + webserver_deployment.spec.template.spec.init_containers is None + or "check-db-ready" + not in [ + container.name for container in webserver_deployment.spec.template.spec.init_containers + ] + ) + + # On test + helm_values = DagsterHelmValues.construct( + dagsterWebserver=Webserver.construct(checkDbReadyInitContainer=True) + ) + [webserver_deployment] = deployment_template.render(helm_values) + assert "check-db-ready" in [ + container.name for container in webserver_deployment.spec.template.spec.init_containers + ] + + # Default test + helm_values = DagsterHelmValues.construct(dagsterWebserver=Webserver.construct()) + [webserver_deployment] = deployment_template.render(helm_values) + assert "check-db-ready" in [ + container.name for container in webserver_deployment.spec.template.spec.init_containers + ] diff --git a/helm/dagster/schema/schema_tests/test_dagster_daemon.py b/helm/dagster/schema/schema_tests/test_dagster_daemon.py index eada9cc4d5a5f..00ce79f69c47d 100644 --- a/helm/dagster/schema/schema_tests/test_dagster_daemon.py +++ b/helm/dagster/schema/schema_tests/test_dagster_daemon.py @@ -679,3 +679,30 @@ def test_env_configmap(env_configmap_template): assert len(cm.data) == 6 assert cm.data["DAGSTER_HOME"] == "/opt/dagster/dagster_home" assert cm.data["TEST_ENV"] == "test_value" + + +def test_check_db_container_toggle(template: HelmTemplate): + # Off test + helm_values = DagsterHelmValues.construct( + dagsterDaemon=Daemon.construct(checkDbReadyInitContainer=False) + ) + [daemon_deployment] = template.render(helm_values) + assert daemon_deployment.spec.template.spec.init_containers is None or "check-db-ready" not in [ + container.name for container in daemon_deployment.spec.template.spec.init_containers + ] + + # On test + helm_values = DagsterHelmValues.construct( + dagsterDaemon=Daemon.construct(checkDbReadyInitContainer=True) + ) + [daemon_deployment] = template.render(helm_values) + assert "check-db-ready" in [ + container.name for container in daemon_deployment.spec.template.spec.init_containers + ] + + # Default test + helm_values = DagsterHelmValues.construct(dagsterDaemon=Daemon.construct()) + [daemon_deployment] = template.render(helm_values) + assert "check-db-ready" in [ + container.name for container in daemon_deployment.spec.template.spec.init_containers + ] diff --git a/helm/dagster/templates/deployment-celery-queues.yaml b/helm/dagster/templates/deployment-celery-queues.yaml index bbd8f1649be5a..c2f803376c99f 100644 --- a/helm/dagster/templates/deployment-celery-queues.yaml +++ b/helm/dagster/templates/deployment-celery-queues.yaml @@ -40,12 +40,14 @@ spec: securityContext: {{- toYaml $celeryK8sRunLauncherConfig.podSecurityContext | nindent 8 }} initContainers: + {{- if $celeryK8sRunLauncherConfig.checkDbReadyInitContainer }} - name: check-db-ready image: "{{- $.Values.postgresql.image.repository -}}:{{- $.Values.postgresql.image.tag -}}" imagePullPolicy: "{{- $.Values.postgresql.image.pullPolicy -}}" command: ['sh', '-c', {{ include "dagster.postgresql.pgisready" $ | squote }}] securityContext: {{- toYaml $celeryK8sRunLauncherConfig.securityContext | nindent 12 }} + {{- end }} {{- if $.Values.rabbitmq.enabled }} - name: check-rabbitmq-ready image: {{ include "dagster.externalImage.name" $.Values.busybox.image | quote }} diff --git a/helm/dagster/templates/deployment-daemon.yaml b/helm/dagster/templates/deployment-daemon.yaml index b28149be77e10..91b86b5c7ec73 100644 --- a/helm/dagster/templates/deployment-daemon.yaml +++ b/helm/dagster/templates/deployment-daemon.yaml @@ -49,6 +49,7 @@ spec: securityContext: {{- toYaml .Values.dagsterDaemon.podSecurityContext | nindent 8 }} initContainers: + {{- if .Values.dagsterDaemon.checkDbReadyInitContainer }} - name: check-db-ready image: {{ include "dagster.externalImage.name" $.Values.postgresql.image | quote }} imagePullPolicy: "{{- $.Values.postgresql.image.pullPolicy -}}" @@ -57,6 +58,7 @@ spec: {{- toYaml .Values.dagsterDaemon.securityContext | nindent 12 }} resources: {{- toYaml .Values.dagsterDaemon.initContainerResources | nindent 12 }} + {{- end }} {{- if (and $userDeployments.enabled $userDeployments.enableSubchart) }} {{- range $deployment := $userDeployments.deployments }} - name: "init-user-deployment-{{- $deployment.name -}}" diff --git a/helm/dagster/templates/deployment-flower.yaml b/helm/dagster/templates/deployment-flower.yaml index 18dd7b3d6a479..63b9c7d44a515 100644 --- a/helm/dagster/templates/deployment-flower.yaml +++ b/helm/dagster/templates/deployment-flower.yaml @@ -36,12 +36,14 @@ spec: securityContext: {{- toYaml .Values.flower.podSecurityContext | nindent 8 }} initContainers: + {{- if .Values.flower.checkDbReadyInitContainer }} - name: check-db-ready image: "{{- $.Values.postgresql.image.repository -}}:{{- $.Values.postgresql.image.tag -}}" imagePullPolicy: "{{- $.Values.postgresql.image.pullPolicy -}}" command: ['sh', '-c', {{ include "dagster.postgresql.pgisready" . | squote }}] securityContext: {{- toYaml .Values.flower.securityContext | nindent 12 }} + {{- end }} containers: - name: {{ .Chart.Name }} securityContext: diff --git a/helm/dagster/templates/helpers/_deployment-webserver.tpl b/helm/dagster/templates/helpers/_deployment-webserver.tpl index 2c5f649485d61..9427646bf4999 100644 --- a/helm/dagster/templates/helpers/_deployment-webserver.tpl +++ b/helm/dagster/templates/helpers/_deployment-webserver.tpl @@ -47,6 +47,7 @@ spec: securityContext: {{- toYaml $_.Values.dagsterWebserver.podSecurityContext | nindent 8 }} initContainers: + {{- if .Values.dagsterWebserver.checkDbReadyInitContainer }} - name: check-db-ready image: {{ include "dagster.externalImage.name" .Values.postgresql.image | quote }} imagePullPolicy: {{ .Values.postgresql.image.pullPolicy }} @@ -57,6 +58,7 @@ spec: resources: {{- toYaml $_.Values.dagsterWebserver.initContainerResources | nindent 12 }} {{- end }} + {{- end }} {{- if (and $userDeployments.enabled $userDeployments.enableSubchart) }} {{- range $deployment := $userDeployments.deployments }} - name: "init-user-deployment-{{- $deployment.name -}}" diff --git a/helm/dagster/values.schema.json b/helm/dagster/values.schema.json index dcf24a595a95d..eb73d8863ccc7 100644 --- a/helm/dagster/values.schema.json +++ b/helm/dagster/values.schema.json @@ -216,6 +216,18 @@ "resources": { "$ref": "#/$defs/Resources" }, + "checkDbReadyInitContainer": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Checkdbreadyinitcontainer" + }, "livenessProbe": { "$ref": "#/$defs/LivenessProbe" }, @@ -647,6 +659,18 @@ "resources": { "$ref": "#/$defs/Resources" }, + "checkDbReadyInitContainer": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Checkdbreadyinitcontainer" + }, "livenessProbe": { "$ref": "#/$defs/LivenessProbe" }, @@ -837,6 +861,18 @@ "securityContext": { "$ref": "#/$defs/SecurityContext" }, + "checkDbReadyInitContainer": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Checkdbreadyinitcontainer" + }, "resources": { "$ref": "#/$defs/Resources" }, @@ -3137,6 +3173,18 @@ "securityContext": { "$ref": "#/$defs/SecurityContext" }, + "checkDbReadyInitContainer": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Checkdbreadyinitcontainer" + }, "resources": { "$ref": "#/$defs/Resources" }, diff --git a/helm/dagster/values.yaml b/helm/dagster/values.yaml index ffd28ca0b84d5..3e7c6cb41c5da 100644 --- a/helm/dagster/values.yaml +++ b/helm/dagster/values.yaml @@ -165,6 +165,10 @@ dagsterWebserver: # Configure initContainer resources separately from main container initContainerResources: {} + + # Enable the check-db-ready initContainer + checkDbReadyInitContainer: true + # Override the default K8s scheduler # schedulerName: ~ @@ -689,6 +693,8 @@ runLauncher: # memory: 128Mi resources: {} + # Enable the check-db-ready initContainer + checkDbReadyInitContainer: true # Override the default K8s scheduler # schedulerName: ~ @@ -885,6 +891,8 @@ flower: podSecurityContext: {} securityContext: {} + # Enable the check-db-ready initContainer + checkDbReadyInitContainer: true # Override the default K8s scheduler # schedulerName: ~ @@ -1219,6 +1227,8 @@ dagsterDaemon: # Configure initContainer resources separately from main container initContainerResources: {} + # Enable the check-db-ready initContainer + checkDbReadyInitContainer: true # Override the default K8s scheduler # schedulerName: ~ From 3252fda10fb41cb144fd9ac6ed6bee394b50b23a Mon Sep 17 00:00:00 2001 From: Nick Schrock Date: Sat, 14 Dec 2024 06:14:34 -0500 Subject: [PATCH 54/94] [components] Refactor generate files to call explicit function to build component.yaml (#26439) ## Summary & Motivation I'm in the process of creating scaffolding for generic custom components and want to customize the scaffolding process more. This means giving more explicit control to users to define their own scaffolding to some degree. Hence I'm making it so that the user explicitly invokes the creation of a component.yaml file rather than having our framework do it. This lets the user customize the behavior. I also think this is more obvious and understandable, at the cost of an extra import. In order to ensure that a custom component author doesn't screw this up, we add a check after `generate_files` to ensure that `component.yaml` exists. ## How I Tested These Changes BK and manual --- .../dagster_components/__init__.py | 1 + .../dagster_components/core/component.py | 10 ++++- .../dagster_components/generate.py | 39 +++++++++++++------ .../dagster_components/lib/dbt_project.py | 7 ++-- .../lib/sling_replication.py | 6 ++- .../cli_tests/test_generate_commands.py | 11 +++++- 6 files changed, 55 insertions(+), 19 deletions(-) diff --git a/python_modules/libraries/dagster-components/dagster_components/__init__.py b/python_modules/libraries/dagster-components/dagster_components/__init__.py index ecb7d3be238a4..13b5b3d5758ad 100644 --- a/python_modules/libraries/dagster-components/dagster_components/__init__.py +++ b/python_modules/libraries/dagster-components/dagster_components/__init__.py @@ -1,5 +1,6 @@ from dagster_components.core.component import ( Component as Component, + ComponentGenerateRequest as ComponentGenerateRequest, ComponentLoadContext as ComponentLoadContext, ComponentRegistry as ComponentRegistry, component as component, diff --git a/python_modules/libraries/dagster-components/dagster_components/core/component.py b/python_modules/libraries/dagster-components/dagster_components/core/component.py index 4e9a75ffc856d..e7e53247d3dae 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/component.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/component.py @@ -4,6 +4,7 @@ import inspect import sys from abc import ABC, abstractmethod +from pathlib import Path from types import ModuleType from typing import ( TYPE_CHECKING, @@ -20,6 +21,7 @@ from dagster import _check as check from dagster._core.errors import DagsterError +from dagster._record import record from dagster._utils import snakecase from typing_extensions import Self @@ -30,13 +32,19 @@ class ComponentDeclNode: ... +@record +class ComponentGenerateRequest: + component_type_name: str + component_instance_root_path: Path + + class Component(ABC): name: ClassVar[Optional[str]] = None component_params_schema: ClassVar = None generate_params_schema: ClassVar = None @classmethod - def generate_files(cls, params: Any) -> Optional[Mapping[str, Any]]: ... + def generate_files(cls, request: ComponentGenerateRequest, params: Any) -> None: ... @abstractmethod def build_defs(self, context: "ComponentLoadContext") -> "Definitions": ... diff --git a/python_modules/libraries/dagster-components/dagster_components/generate.py b/python_modules/libraries/dagster-components/dagster_components/generate.py index 89aaf2d073104..5f6e9a369bf83 100644 --- a/python_modules/libraries/dagster-components/dagster_components/generate.py +++ b/python_modules/libraries/dagster-components/dagster_components/generate.py @@ -1,12 +1,12 @@ import os from pathlib import Path -from typing import Any, Type +from typing import Any, Mapping, Optional, Type import click import yaml -from dagster._utils import mkdir_p, pushd +from dagster._utils import mkdir_p -from dagster_components.core.component import Component +from dagster_components.core.component import Component, ComponentGenerateRequest class ComponentDumper(yaml.Dumper): @@ -17,6 +17,16 @@ def write_line_break(self) -> None: super().write_line_break() +def generate_component_yaml( + request: ComponentGenerateRequest, component_params: Optional[Mapping[str, Any]] +) -> None: + with open(request.component_instance_root_path / "component.yaml", "w") as f: + component_data = {"type": request.component_type_name, "params": component_params or {}} + yaml.dump( + component_data, f, Dumper=ComponentDumper, sort_keys=False, default_flow_style=False + ) + + def generate_component_instance( root_path: str, name: str, @@ -24,13 +34,20 @@ def generate_component_instance( component_type_name: str, generate_params: Any, ) -> None: - component_instance_root_path = os.path.join(root_path, name) + component_instance_root_path = Path(os.path.join(root_path, name)) click.echo(f"Creating a Dagster component instance folder at {component_instance_root_path}.") - mkdir_p(component_instance_root_path) - with pushd(component_instance_root_path): - component_params = component_type.generate_files(generate_params) - component_data = {"type": component_type_name, "params": component_params or {}} - with open(Path(component_instance_root_path) / "component.yaml", "w") as f: - yaml.dump( - component_data, f, Dumper=ComponentDumper, sort_keys=False, default_flow_style=False + mkdir_p(str(component_instance_root_path)) + component_type.generate_files( + ComponentGenerateRequest( + component_type_name=component_type_name, + component_instance_root_path=component_instance_root_path, + ), + generate_params, + ) + + component_yaml_path = component_instance_root_path / "component.yaml" + + if not component_yaml_path.exists(): + raise Exception( + f"Currently all components require a component.yaml file. Please ensure your implementation of generate_files writes this file at {component_yaml_path}." ) diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py index be79d0568856a..6eaa877c0692d 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py @@ -15,9 +15,10 @@ from typing_extensions import Self from dagster_components import Component, ComponentLoadContext -from dagster_components.core.component import component +from dagster_components.core.component import ComponentGenerateRequest, component from dagster_components.core.component_decl_builder import ComponentDeclNode, YamlComponentDecl from dagster_components.core.dsl_schema import AssetSpecProcessorModel, OpSpecBaseModel +from dagster_components.generate import generate_component_yaml class DbtNodeTranslatorParams(BaseModel): @@ -122,7 +123,7 @@ def _fn(context: AssetExecutionContext): return defs @classmethod - def generate_files(cls, params: DbtGenerateParams) -> Mapping[str, Any]: + def generate_files(cls, request: ComponentGenerateRequest, params: DbtGenerateParams) -> None: cwd = os.getcwd() if params.project_path: # NOTE: CWD is not set "correctly" above so we prepend "../../.." as a temporary hack to @@ -141,7 +142,7 @@ def generate_files(cls, params: DbtGenerateParams) -> Mapping[str, Any]: else: relative_path = None - return {"dbt": {"project_dir": relative_path}} + generate_component_yaml(request, {"dbt": {"project_dir": relative_path}}) def execute(self, context: AssetExecutionContext, dbt: DbtCliResource) -> Iterator: yield from dbt.cli(["build"], context=context).stream() diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py b/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py index 2ad4160f49ad2..e5db7f40db003 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py @@ -12,9 +12,10 @@ from typing_extensions import Self from dagster_components import Component, ComponentLoadContext -from dagster_components.core.component import component +from dagster_components.core.component import ComponentGenerateRequest, component from dagster_components.core.component_decl_builder import ComponentDeclNode, YamlComponentDecl from dagster_components.core.dsl_schema import AssetSpecProcessorModel, OpSpecBaseModel +from dagster_components.generate import generate_component_yaml class SlingReplicationParams(BaseModel): @@ -67,7 +68,8 @@ def _fn(context: AssetExecutionContext, sling: SlingResource): return defs @classmethod - def generate_files(cls, params: Any) -> None: + def generate_files(cls, request: ComponentGenerateRequest, params: Any) -> None: + generate_component_yaml(request, params) replication_path = Path(os.getcwd()) / "replication.yaml" with open(replication_path, "w") as f: yaml.dump( diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 6fa572e49eca5..09838048dddce 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -25,7 +25,13 @@ def _example_component_type_baz(): import click from dagster import AssetExecutionContext, Definitions, PipesSubprocessClient, asset - from dagster_components import Component, ComponentLoadContext, component + from dagster_components import ( + Component, + ComponentGenerateRequest, + ComponentLoadContext, + component, + ) + from dagster_components.generate import generate_component_yaml from pydantic import BaseModel _SAMPLE_PIPES_SCRIPT = """ @@ -49,7 +55,8 @@ class Baz(Component): generate_params_schema = BazGenerateParams @classmethod - def generate_files(cls, params: BazGenerateParams): + def generate_files(cls, request: ComponentGenerateRequest, params: BazGenerateParams): + generate_component_yaml(request, {}) with open(params.filename, "w") as f: f.write(_SAMPLE_PIPES_SCRIPT) From cf5d2569a51a836d5a53afaf74d7f55d7338d1ee Mon Sep 17 00:00:00 2001 From: jamiedemaria Date: Mon, 16 Dec 2024 09:05:06 -0500 Subject: [PATCH 55/94] [auto-reexecution] make run_failure_reason a parameter to determine if should retry (#26460) ## Summary & Motivation A reorganization of the `auto_reexecution_should_retry_run` function to take the run failure reason. This removes an implicit dependency on a tag's existence that was causing some errors in the associated internal pr associate internal pr https://github.com/dagster-io/internal/pull/13039 ## How I Tested These Changes existing tests --- .../dagster/_core/execution/retries.py | 30 ++++++++----------- .../dagster/_core/instance/__init__.py | 14 ++++++++- .../auto_run_reexecution.py | 20 +++++++++---- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/python_modules/dagster/dagster/_core/execution/retries.py b/python_modules/dagster/dagster/_core/execution/retries.py index 39dcf1d65d60e..342069dd6ad1f 100644 --- a/python_modules/dagster/dagster/_core/execution/retries.py +++ b/python_modules/dagster/dagster/_core/execution/retries.py @@ -9,15 +9,12 @@ _check as check, ) from dagster._core.storage.dagster_run import DagsterRun, DagsterRunStatus -from dagster._core.storage.tags import ( - MAX_RETRIES_TAG, - RETRY_ON_ASSET_OR_OP_FAILURE_TAG, - RUN_FAILURE_REASON_TAG, -) +from dagster._core.storage.tags import MAX_RETRIES_TAG, RETRY_ON_ASSET_OR_OP_FAILURE_TAG from dagster._serdes.serdes import whitelist_for_serdes from dagster._utils.tags import get_boolean_tag_value if TYPE_CHECKING: + from dagster._core.events import RunFailureReason from dagster._core.instance import DagsterInstance @@ -82,7 +79,9 @@ def snapshot_attempts(self) -> Mapping[str, int]: return dict(self._attempts) -def auto_reexecution_should_retry_run(instance: "DagsterInstance", run: DagsterRun): +def auto_reexecution_should_retry_run( + instance: "DagsterInstance", run: DagsterRun, run_failure_reason: Optional["RunFailureReason"] +): """Determines if a run will be retried by the automatic reexcution system. A run will retry if: - it is failed. @@ -120,6 +119,13 @@ def auto_reexecution_should_retry_run(instance: "DagsterInstance", run: DagsterR if run.status != DagsterRunStatus.FAILURE: return False + retry_on_asset_or_op_failure = get_boolean_tag_value( + run.tags.get(RETRY_ON_ASSET_OR_OP_FAILURE_TAG), + default_value=instance.run_retries_retry_on_asset_or_op_failure, + ) + if run_failure_reason == RunFailureReason.STEP_FAILURE and not retry_on_asset_or_op_failure: + return False + raw_max_retries_tag = run.tags.get(MAX_RETRIES_TAG) if raw_max_retries_tag is None: max_retries = instance.run_retries_max_retries @@ -136,15 +142,5 @@ def auto_reexecution_should_retry_run(instance: "DagsterInstance", run: DagsterR # since the original run is in the run group, the number of retries launched # so far is len(run_group_iter) - 1 if len(list(run_group_iter)) <= max_retries: - retry_on_asset_or_op_failure = get_boolean_tag_value( - run.tags.get(RETRY_ON_ASSET_OR_OP_FAILURE_TAG), - default_value=instance.run_retries_retry_on_asset_or_op_failure, - ) - if ( - run.tags.get(RUN_FAILURE_REASON_TAG) == RunFailureReason.STEP_FAILURE.value - and not retry_on_asset_or_op_failure - ): - return False - else: - return True + return True return False diff --git a/python_modules/dagster/dagster/_core/instance/__init__.py b/python_modules/dagster/dagster/_core/instance/__init__.py index fb42ffe3b8c2a..25d251bc30679 100644 --- a/python_modules/dagster/dagster/_core/instance/__init__.py +++ b/python_modules/dagster/dagster/_core/instance/__init__.py @@ -77,6 +77,7 @@ PARTITION_NAME_TAG, RESUME_RETRY_TAG, ROOT_RUN_ID_TAG, + RUN_FAILURE_REASON_TAG, TAGS_TO_MAYBE_OMIT_ON_RETRY, WILL_RETRY_TAG, ) @@ -2443,6 +2444,8 @@ def handle_new_event( event (EventLogEntry): The event to handle. batch_metadata (Optional[DagsterEventBatchMetadata]): Metadata for batch writing. """ + from dagster._core.events import RunFailureReason + if batch_metadata is None or not _is_batch_writing_enabled(): events = [event] else: @@ -2484,9 +2487,18 @@ def handle_new_event( if run and event.get_dagster_event().is_run_failure and self.run_retries_enabled: # Note that this tag is only applied to runs that fail. Successful runs will not # have a WILL_RETRY_TAG tag. + run_failure_reason = ( + RunFailureReason(run.tags.get(RUN_FAILURE_REASON_TAG)) + if run.tags.get(RUN_FAILURE_REASON_TAG) + else None + ) self.add_run_tags( run_id, - {WILL_RETRY_TAG: str(auto_reexecution_should_retry_run(self, run)).lower()}, + { + WILL_RETRY_TAG: str( + auto_reexecution_should_retry_run(self, run, run_failure_reason) + ).lower() + }, ) for sub in self._subscribers[run_id]: sub(event) diff --git a/python_modules/dagster/dagster/_daemon/auto_run_reexecution/auto_run_reexecution.py b/python_modules/dagster/dagster/_daemon/auto_run_reexecution/auto_run_reexecution.py index d9a1333edb1d2..65a21b0d8a1f4 100644 --- a/python_modules/dagster/dagster/_daemon/auto_run_reexecution/auto_run_reexecution.py +++ b/python_modules/dagster/dagster/_daemon/auto_run_reexecution/auto_run_reexecution.py @@ -25,12 +25,22 @@ def should_retry(run: DagsterRun, instance: DagsterInstance) -> bool: + """A more robust method of determining is a run should be retried by the daemon than just looking + at the WILL_RETRY_TAG. We account for the case where the code version is old and doesn't set the + WILL_RETRY_TAG. If the tag wasn't set for a run failure, we set it so that other daemons can use the + WILL_RETRY_TAG to determine if the run should be retried. + """ will_retry_tag_value = run.tags.get(WILL_RETRY_TAG) + run_failure_reason = ( + RunFailureReason(run.tags.get(RUN_FAILURE_REASON_TAG)) + if run.tags.get(RUN_FAILURE_REASON_TAG) + else None + ) if will_retry_tag_value is None: # If the run doesn't have the WILL_RETRY_TAG, and the run is failed, we # recalculate if the run should be retried to ensure backward compatibilty if run.status == DagsterRunStatus.FAILURE: - should_retry_run = auto_reexecution_should_retry_run(instance, run) + should_retry_run = auto_reexecution_should_retry_run(instance, run, run_failure_reason) # add the tag to the run so that it can be used in other parts of the system instance.add_run_tags(run.run_id, {WILL_RETRY_TAG: str(should_retry_run).lower()}) else: @@ -42,14 +52,14 @@ def should_retry(run: DagsterRun, instance: DagsterInstance) -> bool: if should_retry_run: return should_retry_run else: + # one of the reasons we may not retry a run is if it is a step failure and system is + # set to not retry on op/asset failures. In this case, we log + # an engine event retry_on_asset_or_op_failure = get_boolean_tag_value( run.tags.get(RETRY_ON_ASSET_OR_OP_FAILURE_TAG), default_value=instance.run_retries_retry_on_asset_or_op_failure, ) - if ( - run.tags.get(RUN_FAILURE_REASON_TAG) == RunFailureReason.STEP_FAILURE.value - and not retry_on_asset_or_op_failure - ): + if run_failure_reason == RunFailureReason.STEP_FAILURE and not retry_on_asset_or_op_failure: instance.report_engine_event( "Not retrying run since it failed due to an asset or op failure and run retries " "are configured with retry_on_asset_or_op_failure set to false.", From 830ca71c4bdef1a32460e04e09207ced75ff4253 Mon Sep 17 00:00:00 2001 From: Josh Taylor Date: Mon, 16 Dec 2024 23:00:52 +0800 Subject: [PATCH 56/94] Allow croniter 5.0.1, but not 4.0.0 (#26515) ## Summary & Motivation This allows installing Meltano alongside Dagster. See https://github.com/kiorky/croniter/blob/5.0.1/CHANGELOG.rst ## How I Tested These Changes I ran `make dev_install`. I believe this is valid syntax. ## Changelog > Allow croniter >= 5.0.1, but not 4.0.0, to reallow DayOfWeek as 7. --- python_modules/dagster/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_modules/dagster/setup.py b/python_modules/dagster/setup.py index 62c5322540faf..5b0634b8ca030 100644 --- a/python_modules/dagster/setup.py +++ b/python_modules/dagster/setup.py @@ -83,7 +83,7 @@ def get_version() -> str: # core (not explicitly expressed atm) # pin around issues in specific versions of alembic that broke our migrations "alembic>=1.2.1,!=1.6.3,!=1.7.0,!=1.11.0", - "croniter>=0.3.34,<4", + "croniter>=0.3.34,!=4.0.0,<6", f"grpcio>={GRPC_VERSION_FLOOR}", f"grpcio-health-checking>={GRPC_VERSION_FLOOR}", "packaging>=20.9", From 7d48a4d95abd790576a1249c04ff2f2809c916a8 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Mon, 16 Dec 2024 11:35:18 -0500 Subject: [PATCH 57/94] [components] Add dagster-dg to pyright env (#26519) ## Summary & Motivation Was an oversight that this is not present. ## How I Tested These Changes pyright --- pyright/master/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/pyright/master/requirements.txt b/pyright/master/requirements.txt index fe9ac899fec0a..066776fc53a73 100644 --- a/pyright/master/requirements.txt +++ b/pyright/master/requirements.txt @@ -52,6 +52,7 @@ -e python_modules/libraries/dagster-deltalake/ -e python_modules/libraries/dagster-deltalake-pandas/ -e python_modules/libraries/dagster-deltalake-polars/ +-e python_modules/libraries/dagster-dg/ -e python_modules/libraries/dagster-docker/ -e python_modules/libraries/dagster-duckdb/ -e python_modules/libraries/dagster-duckdb-pandas/ From 51bdd79c020e6542b90c2fbe40e5cc40894e0e56 Mon Sep 17 00:00:00 2001 From: Alex Langenfeld Date: Mon, 16 Dec 2024 10:37:57 -0600 Subject: [PATCH 58/94] [record] snap/node.py (#26487) ## How I Tested These Changes bk --- .../dagster/dagster/_core/snap/node.py | 265 +++++------------- 1 file changed, 70 insertions(+), 195 deletions(-) diff --git a/python_modules/dagster/dagster/_core/snap/node.py b/python_modules/dagster/dagster/_core/snap/node.py index df8fbc83034ee..e56fe51fc32dd 100644 --- a/python_modules/dagster/dagster/_core/snap/node.py +++ b/python_modules/dagster/dagster/_core/snap/node.py @@ -1,5 +1,5 @@ from functools import cached_property -from typing import Mapping, NamedTuple, Optional, Sequence, Union +from typing import Mapping, Optional, Sequence, Union import dagster._check as check from dagster._config import ConfigFieldSnap, snap_from_field @@ -21,6 +21,7 @@ DependencyStructureSnapshot, build_dep_structure_snapshot_from_graph_def, ) +from dagster._record import IHaveNew, record, record_custom from dagster._serdes import whitelist_for_serdes from dagster._utils.warnings import suppress_dagster_warnings @@ -30,17 +31,13 @@ field_serializers={"metadata": MetadataFieldSerializer}, skip_when_empty_fields={"metadata"}, ) -class InputDefSnap( - NamedTuple( - "_InputDefSnap", - [ - ("name", str), - ("dagster_type_key", str), - ("description", Optional[str]), - ("metadata", Mapping[str, MetadataValue]), - ], - ) -): +@record_custom +class InputDefSnap(IHaveNew): + name: str + dagster_type_key: str + description: Optional[str] + metadata: Mapping[str, MetadataValue] + def __new__( cls, name: str, @@ -48,11 +45,11 @@ def __new__( description: Optional[str], metadata: Optional[Mapping[str, MetadataValue]] = None, ): - return super(InputDefSnap, cls).__new__( + return super().__new__( cls, - name=check.str_param(name, "name"), - dagster_type_key=check.str_param(dagster_type_key, "dagster_type_key"), - description=check.opt_str_param(description, "description"), + name=name, + dagster_type_key=dagster_type_key, + description=description, metadata=normalize_metadata( check.opt_mapping_param(metadata, "metadata", key_type=str), allow_invalid=True ), @@ -64,19 +61,15 @@ def __new__( field_serializers={"metadata": MetadataFieldSerializer}, skip_when_empty_fields={"metadata"}, ) -class OutputDefSnap( - NamedTuple( - "_OutputDefSnap", - [ - ("name", str), - ("dagster_type_key", str), - ("description", Optional[str]), - ("is_required", bool), - ("metadata", Mapping[str, MetadataValue]), - ("is_dynamic", bool), - ], - ) -): +@record_custom +class OutputDefSnap(IHaveNew): + name: str + dagster_type_key: str + description: Optional[str] + is_required: bool + metadata: Mapping[str, MetadataValue] + is_dynamic: bool + def __new__( cls, name: str, @@ -86,42 +79,25 @@ def __new__( metadata: Optional[Mapping[str, MetadataValue]] = None, is_dynamic: bool = False, ): - return super(OutputDefSnap, cls).__new__( + return super().__new__( cls, - name=check.str_param(name, "name"), - dagster_type_key=check.str_param(dagster_type_key, "dagster_type_key"), - description=check.opt_str_param(description, "description"), - is_required=check.bool_param(is_required, "is_required"), + name=name, + dagster_type_key=dagster_type_key, + description=description, + is_required=is_required, metadata=normalize_metadata( check.opt_mapping_param(metadata, "metadata", key_type=str), allow_invalid=True ), - is_dynamic=check.bool_param(is_dynamic, "is_dynamic"), + is_dynamic=is_dynamic, ) @whitelist_for_serdes(storage_field_names={"mapped_node_name": "mapped_solid_name"}) -class OutputMappingSnap( - NamedTuple( - "_OutputMappingSnap", - [ - ("mapped_node_name", str), - ("mapped_output_name", str), - ("external_output_name", str), - ], - ) -): - def __new__( - cls, - mapped_node_name: str, - mapped_output_name: str, - external_output_name: str, - ): - return super(OutputMappingSnap, cls).__new__( - cls, - mapped_node_name=check.str_param(mapped_node_name, "mapped_node_name"), - mapped_output_name=check.str_param(mapped_output_name, "mapped_output_name"), - external_output_name=check.str_param(external_output_name, "external_output_name"), - ) +@record +class OutputMappingSnap: + mapped_node_name: str + mapped_output_name: str + external_output_name: str def build_output_mapping_snap(output_mapping: OutputMapping) -> OutputMappingSnap: @@ -133,23 +109,11 @@ def build_output_mapping_snap(output_mapping: OutputMapping) -> OutputMappingSna @whitelist_for_serdes(storage_field_names={"mapped_node_name": "mapped_solid_name"}) -class InputMappingSnap( - NamedTuple( - "_InputMappingSnap", - [ - ("mapped_node_name", str), - ("mapped_input_name", str), - ("external_input_name", str), - ], - ) -): - def __new__(cls, mapped_node_name: str, mapped_input_name: str, external_input_name: str): - return super(InputMappingSnap, cls).__new__( - cls, - mapped_node_name=check.str_param(mapped_node_name, "mapped_node_name"), - mapped_input_name=check.str_param(mapped_input_name, "mapped_input_name"), - external_input_name=check.str_param(external_input_name, "external_input_name"), - ) +@record +class InputMappingSnap: + mapped_node_name: str + mapped_input_name: str + external_input_name: str def build_input_mapping_snap(input_mapping: InputMapping) -> InputMappingSnap: @@ -183,56 +147,17 @@ def build_output_def_snap(output_def: OutputDefinition) -> OutputDefSnap: @whitelist_for_serdes(storage_name="CompositeSolidDefSnap") -class GraphDefSnap( - NamedTuple( - "_GraphDefSnap", - [ - ("name", str), - ("input_def_snaps", Sequence[InputDefSnap]), - ("output_def_snaps", Sequence[OutputDefSnap]), - ("description", Optional[str]), - ("tags", Mapping[str, object]), - ("config_field_snap", Optional[ConfigFieldSnap]), - ("dep_structure_snapshot", DependencyStructureSnapshot), - ("input_mapping_snaps", Sequence[InputMappingSnap]), - ("output_mapping_snaps", Sequence[OutputMappingSnap]), - ], - ) -): - def __new__( - cls, - name: str, - input_def_snaps: Sequence[InputDefSnap], - output_def_snaps: Sequence[OutputDefSnap], - description: Optional[str], - tags: Mapping[str, str], - config_field_snap: Optional[ConfigFieldSnap], - dep_structure_snapshot: DependencyStructureSnapshot, - input_mapping_snaps: Sequence[InputMappingSnap], - output_mapping_snaps: Sequence[OutputMappingSnap], - ): - return super(GraphDefSnap, cls).__new__( - cls, - dep_structure_snapshot=check.inst_param( - dep_structure_snapshot, "dep_structure_snapshot", DependencyStructureSnapshot - ), - input_mapping_snaps=check.sequence_param( - input_mapping_snaps, "input_mapping_snaps", of_type=InputMappingSnap - ), - output_mapping_snaps=check.sequence_param( - output_mapping_snaps, "output_mapping_snaps", of_type=OutputMappingSnap - ), - name=check.str_param(name, "name"), - input_def_snaps=check.sequence_param(input_def_snaps, "input_def_snaps", InputDefSnap), - output_def_snaps=check.sequence_param( - output_def_snaps, "output_def_snaps", OutputDefSnap - ), - description=check.opt_str_param(description, "description"), - tags=check.mapping_param(tags, "tags"), - config_field_snap=check.opt_inst_param( - config_field_snap, "config_field_snap", ConfigFieldSnap - ), - ) +@record +class GraphDefSnap: + name: str + input_def_snaps: Sequence[InputDefSnap] + output_def_snaps: Sequence[OutputDefSnap] + description: Optional[str] + tags: Mapping[str, str] + config_field_snap: Optional[ConfigFieldSnap] + dep_structure_snapshot: DependencyStructureSnapshot + input_mapping_snaps: Sequence[InputMappingSnap] + output_mapping_snaps: Sequence[OutputMappingSnap] @cached_property def input_def_map(self) -> Mapping[str, InputDefSnap]: @@ -250,46 +175,15 @@ def get_output_snap(self, name: str) -> OutputDefSnap: @whitelist_for_serdes(storage_name="SolidDefSnap") -class OpDefSnap( - NamedTuple( - "_OpDefSnap", - [ - ("name", str), - ("input_def_snaps", Sequence[InputDefSnap]), - ("output_def_snaps", Sequence[OutputDefSnap]), - ("description", Optional[str]), - ("tags", Mapping[str, object]), - ("required_resource_keys", Sequence[str]), - ("config_field_snap", Optional[ConfigFieldSnap]), - ], - ) -): - def __new__( - cls, - name: str, - input_def_snaps: Sequence[InputDefSnap], - output_def_snaps: Sequence[OutputDefSnap], - description: Optional[str], - tags: Mapping[str, str], - required_resource_keys: Sequence[str], - config_field_snap: Optional[ConfigFieldSnap], - ): - return super(OpDefSnap, cls).__new__( - cls, - required_resource_keys=check.sequence_param( - required_resource_keys, "required_resource_keys", str - ), - name=check.str_param(name, "name"), - input_def_snaps=check.sequence_param(input_def_snaps, "input_def_snaps", InputDefSnap), - output_def_snaps=check.sequence_param( - output_def_snaps, "output_def_snaps", OutputDefSnap - ), - description=check.opt_str_param(description, "description"), - tags=check.mapping_param(tags, "tags"), - config_field_snap=check.opt_inst_param( - config_field_snap, "config_field_snap", ConfigFieldSnap - ), - ) +@record +class OpDefSnap: + name: str + input_def_snaps: Sequence[InputDefSnap] + output_def_snaps: Sequence[OutputDefSnap] + description: Optional[str] + tags: Mapping[str, str] + required_resource_keys: Sequence[str] + config_field_snap: Optional[ConfigFieldSnap] @cached_property def input_def_map(self) -> Mapping[str, InputDefSnap]: @@ -313,35 +207,10 @@ def get_output_snap(self, name: str) -> OutputDefSnap: "graph_def_snaps": "composite_solid_def_snaps", }, ) -class NodeDefsSnapshot( - NamedTuple( - "_NodeDefsSnapshot", - [ - ("op_def_snaps", Sequence[OpDefSnap]), - ("graph_def_snaps", Sequence[GraphDefSnap]), - ], - ) -): - def __new__( - cls, - op_def_snaps: Sequence[OpDefSnap], - graph_def_snaps: Sequence[GraphDefSnap], - ): - return super(NodeDefsSnapshot, cls).__new__( - cls, - op_def_snaps=sorted( - check.sequence_param(op_def_snaps, "op_def_snaps", of_type=OpDefSnap), - key=lambda op_def: op_def.name, - ), - graph_def_snaps=sorted( - check.sequence_param( - graph_def_snaps, - "graph_def_snaps", - of_type=GraphDefSnap, - ), - key=lambda graph_def: graph_def.name, - ), - ) +@record +class NodeDefsSnapshot(IHaveNew): + op_def_snaps: Sequence[OpDefSnap] + graph_def_snaps: Sequence[GraphDefSnap] @suppress_dagster_warnings @@ -358,8 +227,14 @@ def build_node_defs_snapshot(job_def: JobDefinition) -> NodeDefsSnapshot: check.failed(f"Unexpected NodeDefinition type {node_def}") return NodeDefsSnapshot( - op_def_snaps=op_def_snaps, - graph_def_snaps=graph_def_snaps, + op_def_snaps=sorted( + op_def_snaps, + key=lambda op_def: op_def.name, + ), + graph_def_snaps=sorted( + graph_def_snaps, + key=lambda graph_def: graph_def.name, + ), ) From b9a50695a19b46bf50b5d64df7dc1f9082991981 Mon Sep 17 00:00:00 2001 From: Daniel Gafni Date: Mon, 16 Dec 2024 18:39:11 +0200 Subject: [PATCH 59/94] [pipes] small improvements to make Pipes more test-friendly (#26470) ## Summary & Motivation Small Pipes edits which makes it easier to test Pipes (needed for Java pipes tests) ## How I Tested These Changes Existing tests --- python_modules/dagster/dagster/_core/pipes/context.py | 5 ++--- python_modules/dagster/dagster/_core/pipes/utils.py | 9 +++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/python_modules/dagster/dagster/_core/pipes/context.py b/python_modules/dagster/dagster/_core/pipes/context.py index a0533ce3379f9..b5d82e9454927 100644 --- a/python_modules/dagster/dagster/_core/pipes/context.py +++ b/python_modules/dagster/dagster/_core/pipes/context.py @@ -132,9 +132,8 @@ def _resolve_metadata( k: self._resolve_metadata_value(v["raw_value"], v["type"]) for k, v in metadata.items() } - def _resolve_metadata_value( - self, value: Any, metadata_type: PipesMetadataType - ) -> MetadataValue: + @staticmethod + def _resolve_metadata_value(value: Any, metadata_type: PipesMetadataType) -> MetadataValue: if metadata_type == PIPES_METADATA_TYPE_INFER: return normalize_metadata_value(value) elif metadata_type == "text": diff --git a/python_modules/dagster/dagster/_core/pipes/utils.py b/python_modules/dagster/dagster/_core/pipes/utils.py index add8889626ca5..e161c6f2e3bba 100644 --- a/python_modules/dagster/dagster/_core/pipes/utils.py +++ b/python_modules/dagster/dagster/_core/pipes/utils.py @@ -134,13 +134,18 @@ class PipesFileMessageReader(PipesMessageReader): Args: path (str): The path of the file to which messages will be written. The file will be deleted on close of the pipes session. + include_stdio_in_messages (bool): Whether to include stdout/stderr logs in the messages produced by the message writer in the external process. + cleanup_file (bool): Whether to delete the file on close of the pipes session. """ - def __init__(self, path: str, include_stdio_in_messages: bool = False): + def __init__( + self, path: str, include_stdio_in_messages: bool = False, cleanup_file: bool = True + ): self._path = check.str_param(path, "path") self._include_stdio_in_messages = check.bool_param( include_stdio_in_messages, "include_stdio_in_messages" ) + self._cleanup_file = cleanup_file def on_launched(self, params: PipesLaunchedData) -> None: self.launched_payload = params @@ -178,7 +183,7 @@ def read_messages( is_session_closed.set() if thread: thread.join() - if os.path.exists(self._path): + if os.path.exists(self._path) and self._cleanup_file: os.remove(self._path) def _reader_thread(self, handler: "PipesMessageHandler", is_resource_complete: Event) -> None: From 7cf69b9ad5f92f1a4dcbe967570eccfe2fc1f1d9 Mon Sep 17 00:00:00 2001 From: gibsondan Date: Mon, 16 Dec 2024 10:44:19 -0600 Subject: [PATCH 60/94] Fix two other O(n^2) input callsites (#26493) Summary: Spiritual siblings to https://github.com/dagster-io/dagster/pull/26482 just in a slightly different callstack BK, speedscope on large asset graph ## Summary & Motivation ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --- .../dagster/_core/snap/dep_snapshot.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/python_modules/dagster/dagster/_core/snap/dep_snapshot.py b/python_modules/dagster/dagster/_core/snap/dep_snapshot.py index d5508723810ba..8174f35afc17c 100644 --- a/python_modules/dagster/dagster/_core/snap/dep_snapshot.py +++ b/python_modules/dagster/dagster/_core/snap/dep_snapshot.py @@ -1,4 +1,5 @@ from collections import defaultdict +from functools import cached_property from typing import DefaultDict, Dict, List, Mapping, NamedTuple, Sequence import dagster._check as check @@ -140,11 +141,7 @@ def get_upstream_outputs(self, node_name: str, input_name: str) -> Sequence["Out check.str_param(node_name, "node_name") check.str_param(input_name, "input_name") - for input_dep_snap in self.get_invocation(node_name).input_dep_snaps: - if input_dep_snap.input_name == input_name: - return input_dep_snap.upstream_output_snaps - - check.failed(f"Input {input_name} not found for node {node_name}") + return self.get_invocation(node_name).input_dep_snap(input_name).upstream_output_snaps def get_upstream_output(self, node_name: str, input_name: str) -> "OutputHandleSnap": check.str_param(node_name, "node_name") @@ -235,9 +232,13 @@ def __new__( is_dynamic_mapped=check.bool_param(is_dynamic_mapped, "is_dynamic_mapped"), ) + @cached_property + def input_dep_map(self) -> Mapping[str, InputDependencySnap]: + return {inp_snap.input_name: inp_snap for inp_snap in self.input_dep_snaps} + def input_dep_snap(self, input_name: str) -> InputDependencySnap: - for inp_snap in self.input_dep_snaps: - if inp_snap.input_name == input_name: - return inp_snap + inp_snap = self.input_dep_map.get(input_name) + if inp_snap: + return inp_snap - check.failed(f"No input found named {input_name}") + check.failed(f"Input {input_name} not found for node {self.node_name}") From bf640e81ec6ace1741e89e4e1c0f02475d8a1a34 Mon Sep 17 00:00:00 2001 From: Thierry Jean <68975210+zilto@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:46:54 -0500 Subject: [PATCH 61/94] [docstring] Replace inexistent object `DltDagsterResource` by `DagsterDltResource` (#26518) ## Summary & Motivation While going through the [API reference docs ](https://docs.dagster.io/_apidocs/libraries/dagster-embedded-elt#dlt-dagster-embedded-elt-dlt) I found code errors and it didn't match [the code snippet from the integration page](https://dagster.io/integrations/dagster-dlt). Searching the codebase for `dltdagster`, results were only found for this file while `dagsterdlt` had results in ~13 files. I modified the code snippet found in the docstring. ## How I Tested These Changes No test were conducted. --- .../dagster_embedded_elt/dlt/asset_decorator.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/asset_decorator.py b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/asset_decorator.py index b36785d8e4940..c4c556290d80c 100644 --- a/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/asset_decorator.py +++ b/python_modules/libraries/dagster-embedded-elt/dagster_embedded_elt/dlt/asset_decorator.py @@ -75,14 +75,17 @@ def dlt_assets( dlt_pipeline (Pipeline): The dlt Pipeline defining the destination parameters. name (Optional[str], optional): The name of the op. group_name (Optional[str], optional): The name of the asset group. - dagster_dlt_translator (DltDagsterTranslator, optional): Customization object for defining asset parameters from dlt resources. + dagster_dlt_translator (DagsterDltTranslator, optional): Customization object for defining asset parameters from dlt resources. Examples: Loading Hubspot data to Snowflake with an auto materialize policy using the dlt verified source: .. code-block:: python - class HubspotDltDagsterTranslator(DltDagsterTranslator): + from dagster_embedded_elt.dlt import DagsterDltResource, DagsterDltTranslator, dlt_assets + + + class HubspotDagsterDltTranslator(DagsterDltTranslator): @public def get_auto_materialize_policy(self, resource: DltResource) -> Optional[AutoMaterializePolicy]: return AutoMaterializePolicy.eager().with_rules( @@ -100,15 +103,18 @@ def get_auto_materialize_policy(self, resource: DltResource) -> Optional[AutoMat ), name="hubspot", group_name="hubspot", - dagster_dlt_translator=HubspotDltDagsterTranslator(), + dagster_dlt_translator=HubspotDagsterDltTranslator(), ) - def hubspot_assets(context: AssetExecutionContext, dlt: DltDagsterResource): + def hubspot_assets(context: AssetExecutionContext, dlt: DagsterDltResource): yield from dlt.run(context=context) Loading Github issues to snowflake: .. code-block:: python + from dagster_embedded_elt.dlt import DagsterDltResource, dlt_assets + + @dlt_assets( dlt_source=github_reactions( "dagster-io", "dagster", items_per_page=100, max_items=250 @@ -122,7 +128,7 @@ def hubspot_assets(context: AssetExecutionContext, dlt: DltDagsterResource): name="github", group_name="github", ) - def github_reactions_dagster_assets(context: AssetExecutionContext, dlt: DltDagsterResource): + def github_reactions_dagster_assets(context: AssetExecutionContext, dlt: DagsterDltResource): yield from dlt.run(context=context) """ From 388ae77cbfffaf081ffcf3debca1f27555649c3c Mon Sep 17 00:00:00 2001 From: prha <1040172+prha@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:58:30 -0800 Subject: [PATCH 62/94] reduce the number of logs queried for run stats in base implementation (#26479) ## Summary & Motivation This reduces the number of events fetched for the base implementation of `get_run_stats` ## How I Tested These Changes BK --- .../dagster/dagster/_core/execution/stats.py | 15 ++++++++++- .../dagster/_core/storage/event_log/base.py | 5 +++- .../_core/storage/event_log/sql_event_log.py | 25 ++++++++----------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/python_modules/dagster/dagster/_core/execution/stats.py b/python_modules/dagster/dagster/_core/execution/stats.py index 1175951de2eb6..7ae0756838f5d 100644 --- a/python_modules/dagster/dagster/_core/execution/stats.py +++ b/python_modules/dagster/dagster/_core/execution/stats.py @@ -4,11 +4,24 @@ import dagster._check as check from dagster._core.definitions import ExpectationResult -from dagster._core.events import MARKER_EVENTS, DagsterEventType, StepExpectationResultData +from dagster._core.events import ( + MARKER_EVENTS, + PIPELINE_EVENTS, + DagsterEventType, + StepExpectationResultData, +) from dagster._core.events.log import EventLogEntry from dagster._core.storage.dagster_run import DagsterRunStatsSnapshot from dagster._serdes import whitelist_for_serdes +RUN_STATS_EVENT_TYPES = { + *PIPELINE_EVENTS, + DagsterEventType.STEP_FAILURE, + DagsterEventType.STEP_SUCCESS, + DagsterEventType.ASSET_MATERIALIZATION, + DagsterEventType.STEP_EXPECTATION_RESULT, +} + STEP_STATS_EVENT_TYPES = { DagsterEventType.STEP_START, DagsterEventType.STEP_FAILURE, diff --git a/python_modules/dagster/dagster/_core/storage/event_log/base.py b/python_modules/dagster/dagster/_core/storage/event_log/base.py index 80b90313e6d39..34521a86a3247 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/base.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/base.py @@ -29,6 +29,7 @@ ) from dagster._core.events import DagsterEventType from dagster._core.execution.stats import ( + RUN_STATS_EVENT_TYPES, STEP_STATS_EVENT_TYPES, RunStepKeyStatsSnapshot, build_run_stats_from_events, @@ -255,7 +256,9 @@ def get_records_for_run( def get_stats_for_run(self, run_id: str) -> DagsterRunStatsSnapshot: """Get a summary of events that have ocurred in a run.""" - return build_run_stats_from_events(run_id, self.get_logs_for_run(run_id)) + return build_run_stats_from_events( + run_id, self.get_logs_for_run(run_id, of_type=RUN_STATS_EVENT_TYPES) + ) def get_step_stats_for_run( self, run_id: str, step_keys: Optional[Sequence[str]] = None diff --git a/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py b/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py index c23039a43b932..8ee510bfdea49 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py @@ -53,11 +53,15 @@ ASSET_CHECK_EVENTS, ASSET_EVENTS, EVENT_TYPE_TO_PIPELINE_RUN_STATUS, - MARKER_EVENTS, DagsterEventType, ) from dagster._core.events.log import EventLogEntry -from dagster._core.execution.stats import RunStepKeyStatsSnapshot, build_run_step_stats_from_events +from dagster._core.execution.stats import ( + RUN_STATS_EVENT_TYPES, + STEP_STATS_EVENT_TYPES, + RunStepKeyStatsSnapshot, + build_run_step_stats_from_events, +) from dagster._core.storage.asset_check_execution_record import ( COMPLETED_ASSET_CHECK_EXECUTION_RECORD_STATUSES, AssetCheckExecutionRecord, @@ -574,7 +578,9 @@ def get_stats_for_run(self, run_id: str) -> DagsterRunStatsSnapshot: .where( db.and_( SqlEventLogStorageTable.c.run_id == run_id, - SqlEventLogStorageTable.c.dagster_event_type != None, # noqa: E711 + SqlEventLogStorageTable.c.dagster_event_type.in_( + [event_type.value for event_type in RUN_STATS_EVENT_TYPES] + ), ) ) .group_by("dagster_event_type") @@ -647,18 +653,7 @@ def get_step_stats_for_run( .where(SqlEventLogStorageTable.c.step_key != None) # noqa: E711 .where( SqlEventLogStorageTable.c.dagster_event_type.in_( - [ - DagsterEventType.STEP_START.value, - DagsterEventType.STEP_SUCCESS.value, - DagsterEventType.STEP_SKIPPED.value, - DagsterEventType.STEP_FAILURE.value, - DagsterEventType.STEP_RESTARTED.value, - DagsterEventType.ASSET_MATERIALIZATION.value, - DagsterEventType.STEP_EXPECTATION_RESULT.value, - DagsterEventType.STEP_RESTARTED.value, - DagsterEventType.STEP_UP_FOR_RETRY.value, - ] - + [marker_event.value for marker_event in MARKER_EVENTS] + [event_type.value for event_type in STEP_STATS_EVENT_TYPES] ) ) .order_by(SqlEventLogStorageTable.c.id.asc()) From 131968279b36f65b05a0097314d5b16cef9c0cc2 Mon Sep 17 00:00:00 2001 From: Dragos Pop <63241202+dragos-pop@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:51:53 +0100 Subject: [PATCH 63/94] [ui] Add Google Drive icon for asset `kinds` tag (#26349) ## Summary & Motivation Add Google Drive icon (24x24 px; 1,100 bytes) for asset `kinds` tag. I often read files from Google Drive using the [google-api-python-client](https://github.com/googleapis/google-api-python-client) and having a dedicated icon instead of the generic [Google](https://github.com/dagster-io/dagster/blob/53a5ad52d668ef805d5cb2d087885595a04f236b/docs/next/public/images/concepts/metadata-tags/kinds/icons/tool-google-color.svg#L4) icon would enhance the UI experience. ## How I Tested These Changes Launched the documentation website locally and verified that the kind was visible in the `Supported Icons` section (as in the screenshot below). Screenshot 2024-12-09 at 15 03 47 ## Changelog > [ui] Add Google Drive icon for kind tags --- docs/content/concepts/metadata-tags/kind-tags.mdx | 1 + .../metadata-tags/kinds/icons/tool-googledrive-color.svg | 3 +++ js_modules/dagster-ui/packages/ui-core/src/graph/OpTags.tsx | 6 ++++++ .../src/graph/kindtag-images/tool-googledrive-color.svg | 3 +++ 4 files changed, 13 insertions(+) create mode 100644 docs/next/public/images/concepts/metadata-tags/kinds/icons/tool-googledrive-color.svg create mode 100644 js_modules/dagster-ui/packages/ui-core/src/graph/kindtag-images/tool-googledrive-color.svg diff --git a/docs/content/concepts/metadata-tags/kind-tags.mdx b/docs/content/concepts/metadata-tags/kind-tags.mdx index 3125a021b0c6e..d6bd0634af33b 100644 --- a/docs/content/concepts/metadata-tags/kind-tags.mdx +++ b/docs/content/concepts/metadata-tags/kind-tags.mdx @@ -124,6 +124,7 @@ Some kinds are given a branded icon in the UI. We currently support nearly 200 u | `go` | | | `google` | | | `googlecloud` | | +| `googledrive` | | | `googlesheets` | | | `graphql` | | | `greatexpectations` | | diff --git a/docs/next/public/images/concepts/metadata-tags/kinds/icons/tool-googledrive-color.svg b/docs/next/public/images/concepts/metadata-tags/kinds/icons/tool-googledrive-color.svg new file mode 100644 index 0000000000000..2d94beff46945 --- /dev/null +++ b/docs/next/public/images/concepts/metadata-tags/kinds/icons/tool-googledrive-color.svg @@ -0,0 +1,3 @@ + + + diff --git a/js_modules/dagster-ui/packages/ui-core/src/graph/OpTags.tsx b/js_modules/dagster-ui/packages/ui-core/src/graph/OpTags.tsx index 00ac437c859c8..b87007caaf369 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/graph/OpTags.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/graph/OpTags.tsx @@ -62,6 +62,7 @@ import gitlab from './kindtag-images/tool-gitlab-color.svg'; import go from './kindtag-images/tool-go-color.svg'; import google from './kindtag-images/tool-google-color.svg'; import googlecloud from './kindtag-images/tool-googlecloud-color.svg'; +import googledrive from './kindtag-images/tool-googledrive-color.svg'; import googlesheets from './kindtag-images/tool-googlesheets-color.svg'; import graphql from './kindtag-images/tool-graphql-color.svg'; import greatexpectations from './kindtag-images/tool-greatexpectations-color.svg'; @@ -248,6 +249,7 @@ export type KnownTagType = | 'powerbi' | 'gcp' | 'googlecloud' + | 'googledrive' | 'looker' | 'tableau' | 'segment' @@ -580,6 +582,10 @@ export const KNOWN_TAGS: Record = { icon: googlecloud, content: 'Google Cloud', }, + googledrive: { + icon: googledrive, + content: 'Google Drive', + }, looker: { icon: looker, content: 'Looker', diff --git a/js_modules/dagster-ui/packages/ui-core/src/graph/kindtag-images/tool-googledrive-color.svg b/js_modules/dagster-ui/packages/ui-core/src/graph/kindtag-images/tool-googledrive-color.svg new file mode 100644 index 0000000000000..2d94beff46945 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/graph/kindtag-images/tool-googledrive-color.svg @@ -0,0 +1,3 @@ + + + From 279d44aa2f325f2d2a883807da6f29bf3a2b10e1 Mon Sep 17 00:00:00 2001 From: Isaac Hellendag <2823852+hellendag@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:35:47 -0600 Subject: [PATCH 64/94] [ui] Fix endless log loading (#26446) ## Summary & Motivation We received a bug report from an org with some very, very long log output on some of their runs. Specifically, hundreds of thousands of large logs for individual runs. I noticed two issues during testing: - When a chunk of logs loads and indicates that there are more older logs left to stream, we consider that a "loading" state and simply don't show any logs in the logs table at all. - This is unnecessary, since we're streaming logs in. Instead, just show the loading state if there are no logs available yet at all. - First, we're using the spread-to-concat antipattern in the subscription handler reducer, which means iterating over the entire existing list of nodes before adding the newly received logs. - To resolve this, I'm changing the state array to track *chunks* of logs instead of flattened logs. This means we can more efficiently push chunks into state without mutating state or taking the time to copy entire chunks, then flatten them as needed for filtering/rendering. - I used `[].concat(...chunks)` as the flattening approach, based on benchmarking. it seems to be faster than `flat()`. ## How I Tested These Changes View run with neverending log loading. Verify that logs appear and stream in. Use Chrome profiler to determine that the chunking and flattening behavior appears to be performant at scale. The `filterLogs` function remains expensive, but I think in this case it's because the logs themselves are enormous and require a ton of JSON stringification to support text searching. ## Changelog [ui] Fix run log streaming for runs with a large volume of logs. --- .../ui-core/src/runs/LogsProvider.tsx | 36 ++++++++++--------- .../ui-core/src/runs/LogsScrollingTable.tsx | 10 +++--- .../ui-core/src/runs/RunMetadataProvider.tsx | 4 ++- .../ui-core/src/runs/StepLogsDialog.tsx | 8 +++-- .../packages/ui-core/src/runs/filterLogs.tsx | 3 +- .../ui-core/src/util/flattenOneLevel.tsx | 10 ++++++ 6 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 js_modules/dagster-ui/packages/ui-core/src/util/flattenOneLevel.tsx diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/LogsProvider.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/LogsProvider.tsx index 190bc51f035a0..96ff886b987af 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/LogsProvider.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/LogsProvider.tsx @@ -39,7 +39,7 @@ export interface LogFilter { } export interface LogsProviderLogs { - allNodes: LogNode[]; + allNodeChunks: LogNode[][]; counts: LogLevelCounts; loading: boolean; } @@ -72,7 +72,7 @@ const BATCH_INTERVAL = 100; const QUERY_LOG_LIMIT = 1000; type State = { - nodes: LogNode[]; + nodeChunks: LogNode[][]; cursor: string | null; counts: LogLevelCounts; loading: boolean; @@ -99,25 +99,29 @@ const reducer = (state: State, action: Action) => { ...node, clientsideKey: `csk${node.timestamp}-${ii}`, })); - const nodes = [...state.nodes, ...queuedNodes]; + + const copy = state.nodeChunks.slice(); + copy.push(queuedNodes); + const counts = {...state.counts}; queuedNodes.forEach((node) => { const level = logNodeLevel(node); counts[level]++; }); - return {nodes, counts, loading: action.hasMore, cursor: action.cursor}; + + return {nodeChunks: copy, counts, loading: action.hasMore, cursor: action.cursor}; } case 'set-cursor': return {...state, cursor: action.cursor}; case 'reset': - return {nodes: [], counts: emptyCounts, cursor: null, loading: true}; + return {nodeChunks: [], counts: emptyCounts, cursor: null, loading: true}; default: return state; } }; const initialState: State = { - nodes: [], + nodeChunks: [] as LogNode[][], counts: emptyCounts, cursor: null, loading: true, @@ -184,7 +188,7 @@ const useLogsProviderWithSubscription = (runId: string) => { }, BATCH_INTERVAL); }, [syncPipelineStatusToApolloCache]); - const {nodes, counts, cursor, loading} = state; + const {nodeChunks, counts, cursor, loading} = state; const {availability, disabled, status} = React.useContext(WebSocketContext); const lostWebsocket = !disabled && availability === 'available' && status === WebSocket.CLOSED; @@ -227,10 +231,10 @@ const useLogsProviderWithSubscription = (runId: string) => { return React.useMemo( () => - nodes !== null - ? {allNodes: nodes, counts, loading, subscriptionComponent} - : {allNodes: [], counts, loading, subscriptionComponent}, - [counts, loading, nodes, subscriptionComponent], + nodeChunks !== null + ? {allNodeChunks: nodeChunks, counts, loading, subscriptionComponent} + : {allNodeChunks: [], counts, loading, subscriptionComponent}, + [counts, loading, nodeChunks, subscriptionComponent], ); }; @@ -285,7 +289,7 @@ const POLL_INTERVAL = 5000; const LogsProviderWithQuery = (props: LogsProviderWithQueryProps) => { const {children, runId} = props; const [state, dispatch] = React.useReducer(reducer, initialState); - const {counts, cursor, nodes} = state; + const {counts, cursor, nodeChunks} = state; const dependency = useTraceDependency('RunLogsQuery'); @@ -332,9 +336,9 @@ const LogsProviderWithQuery = (props: LogsProviderWithQueryProps) => { return ( <> {children( - nodes !== null && nodes.length > 0 - ? {allNodes: nodes, counts, loading: false} - : {allNodes: [], counts, loading: true}, + nodeChunks !== null && nodeChunks.length > 0 + ? {allNodeChunks: nodeChunks, counts, loading: false} + : {allNodeChunks: [], counts, loading: true}, )} ); @@ -350,7 +354,7 @@ export const LogsProvider = (props: LogsProviderProps) => { } if (availability === 'attempting-to-connect') { - return <>{children({allNodes: [], counts: emptyCounts, loading: true})}; + return <>{children({allNodeChunks: [], counts: emptyCounts, loading: true})}; } return {children}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/LogsScrollingTable.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/LogsScrollingTable.tsx index 35ff1f61b5c7a..a89eac0f5b8c6 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/LogsScrollingTable.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/LogsScrollingTable.tsx @@ -1,4 +1,4 @@ -import {Box, Colors, NonIdealState, Row} from '@dagster-io/ui-components'; +import {Box, Colors, NonIdealState, Row, SpinnerWithText} from '@dagster-io/ui-components'; import {useVirtualizer} from '@tanstack/react-virtual'; import {useEffect, useRef} from 'react'; import styled from 'styled-components'; @@ -81,12 +81,10 @@ export const LogsScrollingTable = (props: Props) => { }, [totalHeight, virtualizer]); const content = () => { - if (logs.loading) { + if (logs.allNodeChunks.length === 0 && logs.loading) { return ( - - - - + + ); } diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx index b6f2f269f0068..c99bfc4106a6f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import {LogsProviderLogs} from './LogsProvider'; import {RunContext} from './RunContext'; import {gql} from '../apollo-client'; +import {flattenOneLevel} from '../util/flattenOneLevel'; import {RunFragment} from './types/RunFragments.types'; import {RunMetadataProviderMessageFragment} from './types/RunMetadataProvider.types'; import {StepEventStatus} from '../graphql/types'; @@ -371,7 +372,8 @@ export const RunMetadataProvider = ({logs, children}: IRunMetadataProviderProps) const run = React.useContext(RunContext); const runMetadata = React.useMemo(() => extractMetadataFromRun(run), [run]); const metadata = React.useMemo( - () => (logs.loading ? runMetadata : extractMetadataFromLogs(logs.allNodes)), + () => + logs.loading ? runMetadata : extractMetadataFromLogs(flattenOneLevel(logs.allNodeChunks)), [logs, runMetadata], ); return <>{children(metadata)}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/StepLogsDialog.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/StepLogsDialog.tsx index b8506ab6a6f2c..4f107eb164302 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/StepLogsDialog.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/StepLogsDialog.tsx @@ -8,7 +8,7 @@ import { Mono, Spinner, } from '@dagster-io/ui-components'; -import {useState} from 'react'; +import {useMemo, useState} from 'react'; import * as React from 'react'; import {Link} from 'react-router-dom'; import styled from 'styled-components'; @@ -22,6 +22,7 @@ import {IRunMetadataDict, RunMetadataProvider} from './RunMetadataProvider'; import {titleForRun} from './RunUtils'; import {useComputeLogFileKeyForSelection} from './useComputeLogFileKeyForSelection'; import {DagsterEventType} from '../graphql/types'; +import {flattenOneLevel} from '../util/flattenOneLevel'; export function useStepLogs({runId, stepKeys}: {runId?: string; stepKeys?: string[]}) { const [showingLogs, setShowingLogs] = React.useState<{runId: string; stepKeys: string[]} | null>( @@ -113,9 +114,12 @@ export const StepLogsModalContent = ({ const [logType, setComputeLogType] = useState(LogType.structured); const [computeLogUrl, setComputeLogUrl] = React.useState(null); - const firstLogForStep = logs.allNodes.find( + const flatLogs = useMemo(() => flattenOneLevel(logs.allNodeChunks), [logs]); + + const firstLogForStep = flatLogs.find( (l) => l.eventType === DagsterEventType.STEP_START && l.stepKey && stepKeys.includes(l.stepKey), ); + const firstLogForStepTime = firstLogForStep ? Number(firstLogForStep.timestamp) : 0; const [filter, setFilter] = useState({ diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/filterLogs.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/filterLogs.tsx index 368fadca1b641..0882ed53b3181 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/filterLogs.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/filterLogs.tsx @@ -3,9 +3,10 @@ import {eventTypeToDisplayType} from './getRunFilterProviders'; import {logNodeLevel} from './logNodeLevel'; import {LogNode} from './types'; import {weakmapMemoize} from '../app/Util'; +import {flattenOneLevel} from '../util/flattenOneLevel'; export function filterLogs(logs: LogsProviderLogs, filter: LogFilter, filterStepKeys: string[]) { - const filteredNodes = logs.allNodes.filter((node) => { + const filteredNodes = flattenOneLevel(logs.allNodeChunks).filter((node) => { // These events are used to determine which assets a run will materialize and are not intended // to be displayed in the Dagster UI. Pagination is offset based, so we remove these logs client-side. if ( diff --git a/js_modules/dagster-ui/packages/ui-core/src/util/flattenOneLevel.tsx b/js_modules/dagster-ui/packages/ui-core/src/util/flattenOneLevel.tsx new file mode 100644 index 0000000000000..18c8b12347bd5 --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/util/flattenOneLevel.tsx @@ -0,0 +1,10 @@ +/** + * Flattens a two-dimensional array into a one-dimensional array. + * + * @param nodeChunks - The two-dimensional array to flatten. + * @returns The flattened one-dimensional array. + */ +// https://jsbench.me/o8kqzo8olz/1 +export function flattenOneLevel(arrays: T[][]) { + return ([] as T[]).concat(...arrays); +} From 8e79df1d88af6d3112cf33a8eb32f356ec0f698e Mon Sep 17 00:00:00 2001 From: David Liu <48995019+dliu27@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:50:12 -0500 Subject: [PATCH 65/94] [ui] add pipelineName in consideration with launching all runs (#26525) ## Summary & Motivation Linear: https://linear.app/dagster-labs/issue/AD-728/sensor-triggered-asset-materialization-error Since useLaunchMultipleWithTelemetry is based off of useLaunchWithTelemetry, here is the relevant code in useLaunchWithTelemetry: https://github.com/dagster-io/dagster/blob/279d44aa2f325f2d2a883807da6f29bf3a2b10e1/js_modules/dagster-ui/packages/ui-core/src/launchpad/useLaunchWithTelemetry.oss.ts#L29-L31 ## How I Tested These Changes Tested locally --- .../src/launchpad/useLaunchMultipleRunsWithTelemetry.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/launchpad/useLaunchMultipleRunsWithTelemetry.ts b/js_modules/dagster-ui/packages/ui-core/src/launchpad/useLaunchMultipleRunsWithTelemetry.ts index d9b7d60528a77..9249da1025e91 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/launchpad/useLaunchMultipleRunsWithTelemetry.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/launchpad/useLaunchMultipleRunsWithTelemetry.ts @@ -29,7 +29,9 @@ export function useLaunchMultipleRunsWithTelemetry() { const executionParamsList = Array.isArray(variables.executionParamsList) ? variables.executionParamsList : [variables.executionParamsList]; - const jobNames = executionParamsList.map((params) => params.selector?.jobName); + const jobNames = executionParamsList.map( + (params) => params.selector.jobName || params.selector.pipelineName, + ); if ( jobNames.length !== executionParamsList.length || From d32aab757ce394fb943335eb8de8eafb8e709fbf Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:58:50 -0500 Subject: [PATCH 66/94] [dagster-fivetran][docs] Migrate Fivetran docs to new doc site (#26485) ## Summary & Motivation Copy and migrate new Fivetran docs to new site, see original PR #26026 Removing `docs-to-migrate` tag from the original PR ## How I Tested These Changes BK. --- .../docs/integrations/libraries/fivetran.md | 63 ++++++++++++++++--- .../integrations/fivetran.py | 18 ------ .../integrations/fivetran/__init__.py | 0 .../fivetran/customize_fivetran_asset_defs.py | 29 +++++++++ ...ustomize_fivetran_translator_asset_spec.py | 33 ++++++++++ .../fivetran/multiple_fivetran_workspaces.py | 26 ++++++++ .../fivetran/representing_fivetran_assets.py | 12 ++++ .../sync_and_materialize_fivetran_assets.py | 16 +++++ .../test_integration_files_load.py | 6 +- 9 files changed, 174 insertions(+), 29 deletions(-) delete mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran.py create mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/__init__.py create mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_asset_defs.py create mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_translator_asset_spec.py create mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/multiple_fivetran_workspaces.py create mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/representing_fivetran_assets.py create mode 100644 examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/sync_and_materialize_fivetran_assets.py diff --git a/docs/docs-beta/docs/integrations/libraries/fivetran.md b/docs/docs-beta/docs/integrations/libraries/fivetran.md index 9edbfbbee1dc3..3c533d3694ba3 100644 --- a/docs/docs-beta/docs/integrations/libraries/fivetran.md +++ b/docs/docs-beta/docs/integrations/libraries/fivetran.md @@ -2,9 +2,9 @@ layout: Integration status: published name: Fivetran -title: Dagster & Fivetran +title: Using Dagster with Fivetran sidebar_label: Fivetran -excerpt: Orchestrate Fivetran connectors and schedule syncs with upstream or downstream dependencies. +excerpt: Orchestrate Fivetran connectors syncs with upstream or downstream dependencies. date: 2022-11-07 apireflink: https://docs.dagster.io/_apidocs/libraries/dagster-fivetran docslink: https://docs.dagster.io/integrations/fivetran @@ -17,20 +17,63 @@ enables: tags: [dagster-supported, etl] --- +This guide provides instructions for using Dagster with Fivetran using the `dagster-fivetran` library. Your Fivetran connector tables can be represented as assets in the Dagster asset graph, allowing you to track lineage and dependencies between Fivetran assets and data assets you are already modeling in Dagster. You can also use Dagster to orchestrate Fivetran connectors, allowing you to trigger syncs for these on a cadence or based on upstream data changes. +## What you'll learn -The Dagster-Fivetran integration enables you to orchestrate data ingestion as part of a larger pipeline. Programmatically interact with the Fivetran REST API to initiate syncs and monitor their progress. +- How to represent Fivetran assets in the Dagster asset graph, including lineage to other Dagster assets. +- How to customize asset definition metadata for these Fivetran assets. +- How to materialize Fivetran connector tables from Dagster. +- How to customize how Fivetran connector tables are materialized. -### Installation +
+ Prerequisites -```bash -pip install dagster-fivetran -``` +- The `dagster` and `dagster-fivetran` libraries installed in your environment +- Familiarity with asset definitions and the Dagster asset graph +- Familiarity with Dagster resources +- Familiarity with Fivetran concepts, like connectors and connector tables +- A Fivetran workspace +- A Fivetran API key and API secret. For more information, see [Getting Started](https://fivetran.com/docs/rest-api/getting-started) in the Fivetran REST API documentation. -### Example +
- +## Represent Fivetran assets in the asset graph + +To load Fivetran assets into the Dagster asset graph, you must first construct a resource, which allows Dagster to communicate with your Fivetran workspace. You'll need to supply your account ID, API key and API secret. See [Getting Started](https://fivetran.com/docs/rest-api/getting-started) in the Fivetran REST API documentation for more information on how to create your API key and API secret. + +Dagster can automatically load all connector tables from your Fivetran workspace as asset specs. Call the function, which returns list of s representing your Fivetran assets. You can then include these asset specs in your object: + + + +### Sync and materialize Fivetran assets + +You can use Dagster to sync Fivetran connectors and materialize Fivetran connector tables. You can use the factory to create all assets definitions for your Fivetran workspace. + + + +### Customize the materialization of Fivetran assets + +If you want to customize the sync of your connectors, you can use the decorator to do so. This allows you to execute custom code before and after the call to the Fivetran sync. + + + +### Customize asset definition metadata for Fivetran assets + +By default, Dagster will generate asset specs for each Fivetran asset and populate default metadata. You can further customize asset properties by passing an instance of the custom to the function. + + + +Note that `super()` is called in each of the overridden methods to generate the default asset spec. It is best practice to generate the default asset spec before customizing it. + +You can pass an instance of the custom to the decorator or the factory. + +### Load Fivetran assets from multiple workspaces + +Definitions from multiple Fivetran workspaces can be combined by instantiating multiple resources and merging their specs. This lets you view all your Fivetran assets in a single asset graph: + + ### About Fivetran -**Fivetran** ingests data from SaaS applications, databases, and servers. The data is stored and typically used for analytics. +**Fivetran** ingests data from SaaS applications, databases, and servers. The data is stored and typically used for analytics. \ No newline at end of file diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran.py deleted file mode 100644 index 9446ff76d0ce6..0000000000000 --- a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -from dagster_fivetran import FivetranResource, load_assets_from_fivetran_instance - -import dagster as dg - -fivetran_assets = load_assets_from_fivetran_instance( - # Connect to your Fivetran instance - FivetranResource( - api_key="some_key", - api_secret=dg.EnvVar("FIVETRAN_SECRET"), - ) -) - - -defs = dg.Definitions( - assets=[fivetran_assets], -) diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/__init__.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_asset_defs.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_asset_defs.py new file mode 100644 index 0000000000000..b195ed0c134c3 --- /dev/null +++ b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_asset_defs.py @@ -0,0 +1,29 @@ +from dagster_fivetran import FivetranWorkspace, fivetran_assets + +import dagster as dg + +fivetran_workspace = FivetranWorkspace( + account_id=dg.EnvVar("FIVETRAN_ACCOUNT_ID"), + api_key=dg.EnvVar("FIVETRAN_API_KEY"), + api_secret=dg.EnvVar("FIVETRAN_API_SECRET"), +) + + +@fivetran_assets( + connector_id="fivetran_connector_id", + name="fivetran_connector_id", + group_name="fivetran_connector_id", + workspace=fivetran_workspace, +) +def fivetran_connector_assets( + context: dg.AssetExecutionContext, fivetran: FivetranWorkspace +): + # Do something before the materialization... + yield from fivetran.sync_and_poll(context=context) + # Do something after the materialization... + + +defs = dg.Definitions( + assets=[fivetran_connector_assets], + resources={"fivetran": fivetran_workspace}, +) diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_translator_asset_spec.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_translator_asset_spec.py new file mode 100644 index 0000000000000..8debde35e6eba --- /dev/null +++ b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/customize_fivetran_translator_asset_spec.py @@ -0,0 +1,33 @@ +from dagster_fivetran import ( + DagsterFivetranTranslator, + FivetranConnectorTableProps, + FivetranWorkspace, + load_fivetran_asset_specs, +) + +import dagster as dg + +fivetran_workspace = FivetranWorkspace( + account_id=dg.EnvVar("FIVETRAN_ACCOUNT_ID"), + api_key=dg.EnvVar("FIVETRAN_API_KEY"), + api_secret=dg.EnvVar("FIVETRAN_API_SECRET"), +) + + +# A translator class lets us customize properties of the built +# Fivetran assets, such as the owners or asset key +class MyCustomFivetranTranslator(DagsterFivetranTranslator): + def get_asset_spec(self, props: FivetranConnectorTableProps) -> dg.AssetSpec: + # We create the default asset spec using super() + default_spec = super().get_asset_spec(props) + # We customize the metadata and asset key prefix for all assets + return default_spec.replace_attributes( + key=default_spec.key.with_prefix("prefix"), + ).merge_attributes(metadata={"custom": "metadata"}) + + +fivetran_specs = load_fivetran_asset_specs( + fivetran_workspace, dagster_fivetran_translator=MyCustomFivetranTranslator() +) + +defs = dg.Definitions(assets=fivetran_specs, resources={"fivetran": fivetran_workspace}) diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/multiple_fivetran_workspaces.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/multiple_fivetran_workspaces.py new file mode 100644 index 0000000000000..d28203bf3bcdf --- /dev/null +++ b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/multiple_fivetran_workspaces.py @@ -0,0 +1,26 @@ +from dagster_fivetran import FivetranWorkspace, load_fivetran_asset_specs + +import dagster as dg + +sales_fivetran_workspace = FivetranWorkspace( + account_id=dg.EnvVar("FIVETRAN_SALES_ACCOUNT_ID"), + api_key=dg.EnvVar("FIVETRAN_SALES_API_KEY"), + api_secret=dg.EnvVar("FIVETRAN_SALES_API_SECRET"), +) +marketing_fivetran_workspace = FivetranWorkspace( + account_id=dg.EnvVar("FIVETRAN_MARKETING_ACCOUNT_ID"), + api_key=dg.EnvVar("FIVETRAN_MARKETING_API_KEY"), + api_secret=dg.EnvVar("FIVETRAN_MARKETING_API_SECRET"), +) + +sales_fivetran_specs = load_fivetran_asset_specs(sales_fivetran_workspace) +marketing_fivetran_specs = load_fivetran_asset_specs(marketing_fivetran_workspace) + +# Merge the specs into a single set of definitions +defs = dg.Definitions( + assets=[*sales_fivetran_specs, *marketing_fivetran_specs], + resources={ + "marketing_fivetran": marketing_fivetran_workspace, + "sales_fivetran": sales_fivetran_workspace, + }, +) diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/representing_fivetran_assets.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/representing_fivetran_assets.py new file mode 100644 index 0000000000000..7637330c175cd --- /dev/null +++ b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/representing_fivetran_assets.py @@ -0,0 +1,12 @@ +from dagster_fivetran import FivetranWorkspace, load_fivetran_asset_specs + +import dagster as dg + +fivetran_workspace = FivetranWorkspace( + account_id=dg.EnvVar("FIVETRAN_ACCOUNT_ID"), + api_key=dg.EnvVar("FIVETRAN_API_KEY"), + api_secret=dg.EnvVar("FIVETRAN_API_SECRET"), +) + +fivetran_specs = load_fivetran_asset_specs(fivetran_workspace) +defs = dg.Definitions(assets=fivetran_specs, resources={"fivetran": fivetran_workspace}) diff --git a/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/sync_and_materialize_fivetran_assets.py b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/sync_and_materialize_fivetran_assets.py new file mode 100644 index 0000000000000..65a3490f59486 --- /dev/null +++ b/examples/docs_beta_snippets/docs_beta_snippets/integrations/fivetran/sync_and_materialize_fivetran_assets.py @@ -0,0 +1,16 @@ +from dagster_fivetran import FivetranWorkspace, build_fivetran_assets_definitions + +import dagster as dg + +fivetran_workspace = FivetranWorkspace( + account_id=dg.EnvVar("FIVETRAN_ACCOUNT_ID"), + api_key=dg.EnvVar("FIVETRAN_API_KEY"), + api_secret=dg.EnvVar("FIVETRAN_API_SECRET"), +) + +all_fivetran_assets = build_fivetran_assets_definitions(workspace=fivetran_workspace) + +defs = dg.Definitions( + assets=all_fivetran_assets, + resources={"fivetran": fivetran_workspace}, +) diff --git a/examples/docs_beta_snippets/docs_beta_snippets_tests/test_integration_files_load.py b/examples/docs_beta_snippets/docs_beta_snippets_tests/test_integration_files_load.py index faaf20053a482..89c5039563a98 100644 --- a/examples/docs_beta_snippets/docs_beta_snippets_tests/test_integration_files_load.py +++ b/examples/docs_beta_snippets/docs_beta_snippets_tests/test_integration_files_load.py @@ -19,7 +19,11 @@ f"{snippets_folder}/sdf.py", f"{snippets_folder}/airbyte.py", f"{snippets_folder}/dlt.py", - f"{snippets_folder}/fivetran.py", + f"{snippets_folder}/fivetran/customize_fivetran_asset_defs.py", + f"{snippets_folder}/fivetran/customize_fivetran_translator_asset_spec.py", + f"{snippets_folder}/fivetran/multiple_fivetran_workspaces.py", + f"{snippets_folder}/fivetran/representing_fivetran_assets.py", + f"{snippets_folder}/fivetran/sync_and_materialize_fivetran_assets.py", # FIXME: this breaks on py3.8 and seems related to the non-dagster dependencies f"{snippets_folder}/pandera.py", } From 6b48bfb4d1f68fffeba5d7b8386c845f9d20d737 Mon Sep 17 00:00:00 2001 From: Maxime Armstrong <46797220+maximearmstrong@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:12:18 -0500 Subject: [PATCH 67/94] [dagster-fivetran][docs] Add setup env section in Fivetran docs (#26486) ## Summary & Motivation As title, in both current and new docs sites. ## How I Tested These Changes Docs preview --- docs/content/integrations/fivetran/fivetran.mdx | 8 ++++++++ docs/docs-beta/docs/integrations/libraries/fivetran.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/content/integrations/fivetran/fivetran.mdx b/docs/content/integrations/fivetran/fivetran.mdx index cd33c2331e76e..2c61ea9917b23 100644 --- a/docs/content/integrations/fivetran/fivetran.mdx +++ b/docs/content/integrations/fivetran/fivetran.mdx @@ -26,6 +26,14 @@ This guide provides instructions for using Dagster with Fivetran using the `dags
+## Set up your environment + +To get started, you'll need to install the `dagster` and `dagster-fivetran` Python packages: + +```bash +pip install dagster dagster-fivetran +``` + ## Represent Fivetran assets in the asset graph To load Fivetran assets into the Dagster asset graph, you must first construct a resource, which allows Dagster to communicate with your Fivetran workspace. You'll need to supply your account ID, API key and API secret. See [Getting Started](https://fivetran.com/docs/rest-api/getting-started) in the Fivetran REST API documentation for more information on how to create your API key and API secret. diff --git a/docs/docs-beta/docs/integrations/libraries/fivetran.md b/docs/docs-beta/docs/integrations/libraries/fivetran.md index 3c533d3694ba3..33baaa8275c07 100644 --- a/docs/docs-beta/docs/integrations/libraries/fivetran.md +++ b/docs/docs-beta/docs/integrations/libraries/fivetran.md @@ -38,6 +38,14 @@ This guide provides instructions for using Dagster with Fivetran using the `dags
+## Set up your environment + +To get started, you'll need to install the `dagster` and `dagster-fivetran` Python packages: + +```bash +pip install dagster dagster-fivetran +``` + ## Represent Fivetran assets in the asset graph To load Fivetran assets into the Dagster asset graph, you must first construct a resource, which allows Dagster to communicate with your Fivetran workspace. You'll need to supply your account ID, API key and API secret. See [Getting Started](https://fivetran.com/docs/rest-api/getting-started) in the Fivetran REST API documentation for more information on how to create your API key and API secret. From 16f75e82119483d8ccf891bc846dc6ff3b3cf3c2 Mon Sep 17 00:00:00 2001 From: Nikki Everett Date: Mon, 16 Dec 2024 17:24:25 -0600 Subject: [PATCH 68/94] DOC-629 remove outdated airflow pipeline observation doc (#26526) ## Summary & Motivation See [internal Slack discussion](https://dagsterlabs.slack.com/archives/C03AC5P8Z1T/p1734376793665229) -- this doc is out of date. ## How I Tested These Changes Staging deployment. ## Changelog > Insert changelog entry or delete this section. --------- Signed-off-by: nikki everett --- docs/content/_navigation.json | 4 - docs/content/guides/migrations.mdx | 1 - ...ve-your-airflow-pipelines-with-dagster.mdx | 105 ------------------ docs/content/integrations/airflow.mdx | 1 - 4 files changed, 111 deletions(-) delete mode 100644 docs/content/guides/migrations/observe-your-airflow-pipelines-with-dagster.mdx diff --git a/docs/content/_navigation.json b/docs/content/_navigation.json index 1186bd69ff960..a784329e9fc60 100644 --- a/docs/content/_navigation.json +++ b/docs/content/_navigation.json @@ -1341,10 +1341,6 @@ { "title": "Migrating from Airflow", "path": "/guides/migrations/migrating-airflow-to-dagster" - }, - { - "title": "Observe your Airflow pipelines with Dagster", - "path": "/guides/migrations/observe-your-airflow-pipelines-with-dagster" } ] }, diff --git a/docs/content/guides/migrations.mdx b/docs/content/guides/migrations.mdx index ece1d40fe8b3a..f968e1aa1dc9b 100644 --- a/docs/content/guides/migrations.mdx +++ b/docs/content/guides/migrations.mdx @@ -13,4 +13,3 @@ Explore your options for migrating from other platforms to Dagster. Curious how you can migrate your Airflow pipelines to Dagster? - Learn how to perform [a lift-and-shift migration of Airflow to Dagster](/guides/migrations/migrating-airflow-to-dagster) -- Learn how to leverage the features of [Dagster and Airflow together using Dagster Pipes](/guides/migrations/observe-your-airflow-pipelines-with-dagster) diff --git a/docs/content/guides/migrations/observe-your-airflow-pipelines-with-dagster.mdx b/docs/content/guides/migrations/observe-your-airflow-pipelines-with-dagster.mdx deleted file mode 100644 index ed2f0fe3cbfc6..0000000000000 --- a/docs/content/guides/migrations/observe-your-airflow-pipelines-with-dagster.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "Observe your Airflow pipelines with Dagster | Dagster Docs" -description: "Learn how to leverage the features of Dagster and Airflow together." ---- - -# Observe your Airflow pipelines with Dagster - -Dagster can act as a single entry point to all orchestration platforms in use at your organization. By injecting a small amount of code into your existing pipelines, you can report events to Dagster, where you can then visualize the full lineage of pipelines. This can be particularly useful if you have multiple Apache Airflow environments, and hope to build a catalog and observation platform through Dagster. - -## Emitting materialization events from Airflow to Dagster - -Imagine you have a large number of pipelines written in Apache Airflow and wish to introduce Dagster into your stack. By using custom Airflow operators, you can continue to run your existing pipelines while you work toward migrating them off Airflow, or while building new pipelines in Dagster that are tightly integrated with your legacy systems. - -To do this, we will define a `DagsterAssetOperator` operator downstream of your Airflow DAG to indicate that the pipeline's processing has concluded. The HTTP endpoint of the Dagster server, the `asset_key`, and additional metadata and descriptions are to be specified to inform Dagster of the materialization. - -```python -from typing import Dict, Optional - -from airflow.models import BaseOperator -from airflow.utils.decorators import apply_defaults -import requests - -class DagsterAssetOperator(BaseOperator): - @apply_defaults - def __init__( - self, - dagster_webserver_host: str, - dagster_webserver_port: str, - asset_key: str, - metadata: Optional[Dict] = None, - description: Optional[str] = None, - *args, - **kwargs, - ): - super().__init__(*args, **kwargs) - self.dagster_webserver_host = dagster_webserver_host - self.dagster_webserver_port = dagster_webserver_port - self.asset_key = asset_key - self.metadata = metadata or {} - self.description = description - - def execute(self, context): - url = f"http://{dagster_webserver_host}:{dagster_webserver_port}/report_asset_materialization/{self.asset_key}" - payload = {"metadata": self.metadata, "description": self.description} - headers = {"Content-Type": "application/json"} - - response = requests.post(url, json=payload, headers=headers) - response.raise_for_status() - - self.log.info( - f"Reported asset materialization to Dagster. Response: {response.text}" - ) -``` - -Then, we can append this to our Airflow DAG to indicate that a pipeline has run successfully. - -```python -import os - -dagster_webserver_host = os.environ.get("DAGSTER_WEBSERVER_HOST", "localhost") -dagster_webserver_port = os.environ.get("DAGSTER_WEBSERVER_PORT", "3000") - -dagster_op = DagsterAssetOperator( - task_id="report_dagster_asset_materialization", - dagster_webserver_host=dagster_webserver_host, - dagster_webserver_port=dagster_webserver_port, - asset_key="example_external_airflow_asset", - metadata={"airflow/tag": "example", "source": "external"}, -) -``` - -Once the events are emitted from Airflow, there are two options for scheduling Dagster materializations following the external Airflow materialization event: asset sensors and auto materialization policies. - -An external asset is created in Dagster, and an `asset_sensor` is used to identify the materialization events that are being sent from Airflow. - -```python -from dagster import external_asset_from_spec - -example_external_airflow_asset = external_asset_from_spec( - AssetSpec("example_external_airflow_asset", - group_name="External") -) -``` - -```python -from dagster import ( - AssetKey, - EventLogEntry, - RunRequest, - SensorEvaluationContext, - asset_sensor -) - -@asset_sensor( - asset_key=AssetKey("example_external_airflow_asset"), - job=example_external_airflow_asset_job -) -def example_external_airflow_asset_sensor( - context: SensorEvaluationContext, asset_event: EventLogEntry -): - assert asset_event.dagster_event and asset_event.dagster_event.asset_key - yield RunRequest(run_key=context.cursor) -``` - -Now, when a materialization event occurs on the external `example_external_airflow_asset` asset, the `example_external_airflow_asset_job` job will be triggered. Here, you can define logic that can build upon the DAG from your Airflow environment. diff --git a/docs/content/integrations/airflow.mdx b/docs/content/integrations/airflow.mdx index 41d0d0c53ab73..66a46614286fb 100644 --- a/docs/content/integrations/airflow.mdx +++ b/docs/content/integrations/airflow.mdx @@ -9,7 +9,6 @@ Migrating from Airflow to Dagster, or integrating Dagster into your existing wor - [Learning Dagster from Airflow](/integrations/airflow/from-airflow-to-dagster) - a step-by-step tutorial of mapping concepts from Airflow to Dagster - [Migrating from Airflow](/guides/migrations/migrating-airflow-to-dagster) - migration patterns for translating Airflow code to Dagster -- [Observe your Airflow pipelines with Dagster](/guides/migrations/observe-your-airflow-pipelines-with-dagster) - See how Dagster can act as the observation layer over all pipelines in your organization --- From 01082ddd0b799514a709d3bfa7d8f65c5534145c Mon Sep 17 00:00:00 2001 From: prha <1040172+prha@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:48:40 -0800 Subject: [PATCH 69/94] add job name filter support for run status sensors (#22760) ## Summary & Motivation We want to be able to increase the throughput of run status sensors that target specific jobs by filtering in the run status event DB query instead of filtering in memory, against storages that support such filtering ## How I Tested These Changes BK --- .../run_status_sensor_definition.py | 57 +++++++++++++++++ .../dagster/dagster/_core/event_api.py | 5 +- .../dagster/_core/storage/event_log/base.py | 4 ++ .../_core/storage/event_log/sql_event_log.py | 9 ++- .../event_log/sqlite/sqlite_event_log.py | 2 +- .../storage_tests/utils/event_log_storage.py | 64 ++++++++++++++++++- 6 files changed, 137 insertions(+), 4 deletions(-) diff --git a/python_modules/dagster/dagster/_core/definitions/run_status_sensor_definition.py b/python_modules/dagster/dagster/_core/definitions/run_status_sensor_definition.py index 05bc928f2b084..984881085ed08 100644 --- a/python_modules/dagster/dagster/_core/definitions/run_status_sensor_definition.py +++ b/python_modules/dagster/dagster/_core/definitions/run_status_sensor_definition.py @@ -766,6 +766,42 @@ def _wrapped_fn( ascending=True, limit=fetch_limit, ).records + elif ( + context.instance.event_log_storage.supports_run_status_change_job_name_filter + and monitored_jobs + and all( + [ + not isinstance(monitored, (RepositorySelector, CodeLocationSelector)) + for monitored in monitored_jobs + ] + ) + ): + # the event log storage supports run status change selectors... we should construct + # the appropriate job selectors so that we can filter the events by jobs in the + # storage layer instead of in memory. This should improve throughput since we will + # avoid fetching events that we will filter out later on. + job_names = _job_names_for_monitored( + cast( + Sequence[ + Union[ + JobDefinition, + GraphDefinition, + UnresolvedAssetJobDefinition, + "JobSelector", + ] + ], + monitored_jobs, + ) + ) + event_records = context.instance.fetch_run_status_changes( + records_filter=RunStatusChangeRecordsFilter( + event_type=cast(RunStatusChangeEventType, event_type), + after_storage_id=sensor_cursor.record_id, + job_names=job_names, + ), + ascending=True, + limit=fetch_limit, + ).records else: # the cursor storage id is globally unique, either because the event log storage is # not run sharded or because the cursor was set from an event returned from the @@ -1126,3 +1162,24 @@ def inner( ) return inner + + +def _job_names_for_monitored( + monitored: Sequence[ + Union[ + JobDefinition, + GraphDefinition, + UnresolvedAssetJobDefinition, + "JobSelector", + ] + ], +) -> Sequence[str]: + from dagster._core.definitions.selector import JobSelector + + job_names = [] + for m in monitored: + if isinstance(m, JobSelector): + job_names.append(m.job_name) + else: + job_names.append(m.name) + return job_names diff --git a/python_modules/dagster/dagster/_core/event_api.py b/python_modules/dagster/dagster/_core/event_api.py index 2590b525dc64b..65d1eac18ae31 100644 --- a/python_modules/dagster/dagster/_core/event_api.py +++ b/python_modules/dagster/dagster/_core/event_api.py @@ -349,6 +349,7 @@ class RunStatusChangeRecordsFilter( ("after_storage_id", PublicAttr[Optional[int]]), ("before_storage_id", PublicAttr[Optional[int]]), ("storage_ids", PublicAttr[Optional[Sequence[int]]]), + ("job_names", Optional[Sequence[str]]), ], ) ): @@ -376,6 +377,7 @@ def __new__( after_storage_id: Optional[int] = None, before_storage_id: Optional[int] = None, storage_ids: Optional[Sequence[int]] = None, + job_names: Optional[Sequence[str]] = None, ): if event_type not in EVENT_TYPE_TO_PIPELINE_RUN_STATUS: check.failed("Invalid event type for run status change event filter") @@ -388,9 +390,10 @@ def __new__( after_storage_id=check.opt_int_param(after_storage_id, "after_storage_id"), before_storage_id=check.opt_int_param(before_storage_id, "before_storage_id"), storage_ids=check.opt_nullable_sequence_param(storage_ids, "storage_ids", of_type=int), + job_names=check.opt_nullable_sequence_param(job_names, "job_names", of_type=str), ) - def to_event_records_filter( + def to_event_records_filter_without_job_names( self, cursor: Optional[str] = None, ascending: bool = False ) -> EventRecordsFilter: before_cursor_storage_id, after_cursor_storage_id = EventRecordsFilter.get_cursor_params( diff --git a/python_modules/dagster/dagster/_core/storage/event_log/base.py b/python_modules/dagster/dagster/_core/storage/event_log/base.py index 34521a86a3247..b82eae23ad458 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/base.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/base.py @@ -648,6 +648,10 @@ def fetch_observations( ) -> EventRecordsResult: raise NotImplementedError() + @property + def supports_run_status_change_job_name_filter(self) -> bool: + return False + @abstractmethod def fetch_run_status_changes( self, diff --git a/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py b/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py index 8ee510bfdea49..1bb1398ec7ef3 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/sql_event_log.py @@ -1112,12 +1112,19 @@ def fetch_run_status_changes( before_cursor, after_cursor = EventRecordsFilter.get_cursor_params(cursor, ascending) event_records_filter = ( - records_filter.to_event_records_filter(cursor, ascending) + records_filter.to_event_records_filter_without_job_names(cursor, ascending) if isinstance(records_filter, RunStatusChangeRecordsFilter) else EventRecordsFilter( event_type, before_cursor=before_cursor, after_cursor=after_cursor ) ) + has_job_name_filter = ( + isinstance(records_filter, RunStatusChangeRecordsFilter) and records_filter.job_names + ) + if has_job_name_filter and not self.supports_run_status_change_job_name_filter: + check.failed( + "Called fetch_run_status_changes with selectors, which are not supported with this storage." + ) return self._get_event_records_result(event_records_filter, limit, cursor, ascending) def get_logs_for_all_runs_by_log_id( diff --git a/python_modules/dagster/dagster/_core/storage/event_log/sqlite/sqlite_event_log.py b/python_modules/dagster/dagster/_core/storage/event_log/sqlite/sqlite_event_log.py index 14559adc9b396..69807391d07c9 100644 --- a/python_modules/dagster/dagster/_core/storage/event_log/sqlite/sqlite_event_log.py +++ b/python_modules/dagster/dagster/_core/storage/event_log/sqlite/sqlite_event_log.py @@ -412,7 +412,7 @@ def fetch_run_status_changes( before_cursor, after_cursor = EventRecordsFilter.get_cursor_params(cursor, ascending) event_records_filter = ( - records_filter.to_event_records_filter(cursor, ascending) + records_filter.to_event_records_filter_without_job_names(cursor, ascending) if isinstance(records_filter, RunStatusChangeRecordsFilter) else EventRecordsFilter( event_type, before_cursor=before_cursor, after_cursor=after_cursor diff --git a/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py b/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py index f46909236e75c..1bfbd2ec23fbc 100644 --- a/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py +++ b/python_modules/dagster/dagster_tests/storage_tests/utils/event_log_storage.py @@ -271,7 +271,13 @@ def _default_loggers(event_callback): # This exists to create synthetic events to test the store def _synthesize_events( - ops_fn_or_assets, run_id=None, check_success=True, instance=None, run_config=None, tags=None + ops_fn_or_assets, + run_id=None, + check_success=True, + instance=None, + run_config=None, + tags=None, + job_name=None, ) -> Tuple[List[EventLogEntry], JobExecutionResult]: events = [] @@ -290,6 +296,7 @@ def _append_event(event): else: # op_fn @job( + name=job_name, resource_defs=_default_resources(), logger_defs=_default_loggers(_append_event), executor_def=in_process_executor, @@ -2058,6 +2065,61 @@ def _get_storage_ids(result): ) assert _get_storage_ids(result) == [storage_id_3, storage_id_1] + def test_fetch_run_status_monitor_filters(self, storage, instance): + if not storage.supports_run_status_change_job_name_filter: + # test sqlite in test_get_event_records_sqlite + pytest.skip() + + @op + def my_op(_): + yield Output(1) + + def _ops(): + my_op() + + def _store_run_events(run_id, job_name=None): + events, _ = _synthesize_events(_ops, run_id=run_id, job_name=job_name) + for event in events: + storage.store_event(event) + + # store events for three runs + [run_id_1, run_id_2, run_id_3] = [ + make_new_run_id(), + make_new_run_id(), + make_new_run_id(), + ] + + with create_and_delete_test_runs(instance, [run_id_1, run_id_2, run_id_3]): + _store_run_events(run_id_1, "job_one") + _store_run_events(run_id_2, "job_two") + _store_run_events(run_id_3, "job_three") + + result = storage.fetch_run_status_changes( + DagsterEventType.RUN_SUCCESS, + limit=100, + ) + assert [r.event_log_entry.run_id for r in result.records] == [ + run_id_3, + run_id_2, + run_id_1, + ] + result = storage.fetch_run_status_changes( + RunStatusChangeRecordsFilter( + DagsterEventType.RUN_SUCCESS, + job_names=["job_one"], + ), + limit=100, + ) + assert [r.event_log_entry.run_id for r in result.records] == [run_id_1] + result = storage.fetch_run_status_changes( + RunStatusChangeRecordsFilter( + DagsterEventType.RUN_SUCCESS, + job_names=["job_one", "job_two"], + ), + limit=100, + ) + assert [r.event_log_entry.run_id for r in result.records] == [run_id_2, run_id_1] + def test_get_event_records_sqlite(self, storage, instance): if not self.is_sqlite(storage): pytest.skip() From a806ab6c91112c4e6ba968f68841196988e74e76 Mon Sep 17 00:00:00 2001 From: Thiago Azevedo <35049565+thiagoazcampos@users.noreply.github.com> Date: Tue, 17 Dec 2024 12:14:12 -0300 Subject: [PATCH 70/94] Enabling Dataproc cluster labels (#26481) ## Summary & Motivation It's currently not possible to attach labels to Dataproc clusters created with `DataprocResource`. This PR implements changes to `DataprocResource` so it accepts a `labels` optional parameter to be attached on cluster creation. ## How I Tested These Changes - Added a new test assessing the setting for `labels` on DataprocResource - Tested locally and verified that the labels were correctly attached ## Changelog > [dagster-gcp] `DataprocResource` now receives an optional parameter `labels` to be attached to Dataproc clusters. --- .../dagster_gcp/dataproc/configs.py | 13 ++++- .../dagster_gcp/dataproc/resources.py | 18 ++++++- .../dataproc_tests/test_resources.py | 54 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/configs.py b/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/configs.py index d969d7f820823..ca94099613767 100644 --- a/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/configs.py +++ b/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/configs.py @@ -1,4 +1,4 @@ -from dagster import Field, StringSource +from dagster import Field, Permissive, StringSource from dagster_gcp.dataproc.configs_dataproc_cluster import define_dataproc_cluster_config from dagster_gcp.dataproc.configs_dataproc_job import define_dataproc_job_config @@ -11,12 +11,23 @@ def define_dataproc_create_cluster_config(): Names of deleted clusters can be reused.""", is_required=True, ) + labels = Field( + Permissive(), + description="""Optional. The labels to associate with this cluster. Label keys must + contain 1 to 63 characters, and must conform to RFC 1035 + (https://www.ietf.org/rfc/rfc1035.txt). Label values may be empty, but, if + present, must contain 1 to 63 characters, and must conform to RFC 1035 + (https://www.ietf.org/rfc/rfc1035.txt). No more than 32 labels can be associated + with a cluster.""", + is_required=False, + ) return { "projectId": _define_project_id_config(), "region": _define_region_config(), "clusterName": cluster_name, "cluster_config": define_dataproc_cluster_config(), + "labels": labels, } diff --git a/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/resources.py b/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/resources.py index bd739f7197621..35db40399f0ea 100644 --- a/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/resources.py +++ b/python_modules/libraries/dagster-gcp/dagster_gcp/dataproc/resources.py @@ -33,8 +33,9 @@ def __init__(self, config): self.config = config - (self.project_id, self.region, self.cluster_name, self.cluster_config) = ( - self.config.get(k) for k in ("projectId", "region", "clusterName", "cluster_config") + (self.project_id, self.region, self.cluster_name, self.cluster_config, self.labels) = ( + self.config.get(k) + for k in ("projectId", "region", "clusterName", "cluster_config", "labels") ) @property @@ -60,6 +61,7 @@ def create_cluster(self): "projectId": self.project_id, "clusterName": self.cluster_name, "config": self.cluster_config, + "labels": self.labels, }, ).execute() ) @@ -177,6 +179,17 @@ def my_asset(dataproc: DataprocResource): " deleted clusters can be reused." ) ) + labels: Optional[dict[str, str]] = Field( + default=None, + description=( + "Optional. The labels to associate with this cluster. Label keys must" + " contain 1 to 63 characters, and must conform to RFC 1035" + " (https://www.ietf.org/rfc/rfc1035.txt). Label values may be empty, but, if" + " present, must contain 1 to 63 characters, and must conform to RFC 1035" + " (https://www.ietf.org/rfc/rfc1035.txt). No more than 32 labels can be associated" + " with a cluster." + ), + ) cluster_config_yaml_path: Optional[str] = Field( default=None, description=( @@ -249,6 +262,7 @@ def get_client(self) -> DataprocClient: "region": self.region, "clusterName": self.cluster_name, "cluster_config": cluster_config, + "labels": self.labels, } return DataprocClient(config=client_config_dict) diff --git a/python_modules/libraries/dagster-gcp/dagster_gcp_tests/dataproc_tests/test_resources.py b/python_modules/libraries/dagster-gcp/dagster_gcp_tests/dataproc_tests/test_resources.py index c1ff37fb269da..9cf0b1ea2147a 100644 --- a/python_modules/libraries/dagster-gcp/dagster_gcp_tests/dataproc_tests/test_resources.py +++ b/python_modules/libraries/dagster-gcp/dagster_gcp_tests/dataproc_tests/test_resources.py @@ -22,6 +22,7 @@ DATAPROC_CLUSTERS_URI = f"{DATAPROC_BASE_URI}/clusters" DATAPROC_JOBS_URI = f"{DATAPROC_BASE_URI}/jobs" DATAPROC_SCHEMA_URI = "https://www.googleapis.com/discovery/v1/apis/dataproc/v1/rest" +DATAPROC_LABELS = {"first_label": "true", "second_label": "true"} EXPECTED_RESULTS = [ # OAuth authorize credentials @@ -239,6 +240,59 @@ def test_dataproc(): assert result.success +@pytest.mark.integration +def test_dataproc_resource_labels(): + """Tests pydantic dataproc cluster creation/deletion. Requests are captured by the responses library, so + no actual HTTP requests are made here. + + Note that inspecting the HTTP requests can be useful for debugging, which can be done by adding: + + import httplib2 + httplib2.debuglevel = 4 + """ + with mock.patch("httplib2.Http", new=HttpSnooper): + + @job + def test_dataproc(): + configurable_dataproc_op() + + result = test_dataproc.execute_in_process( + run_config=RunConfig( + ops={ + "configurable_dataproc_op": DataprocOpConfig( + job_scoped_cluster=True, + project_id=PROJECT_ID, + region=REGION, + job_config={ + "reference": {"projectId": PROJECT_ID}, + "placement": {"clusterName": CLUSTER_NAME}, + "hiveJob": {"queryList": {"queries": ["SHOW DATABASES"]}}, + }, + ) + }, + ), + resources={ + "dataproc": DataprocResource( + project_id=PROJECT_ID, + cluster_name=CLUSTER_NAME, + region=REGION, + labels=DATAPROC_LABELS, + cluster_config_dict={ + "softwareConfig": { + "properties": { + # Create a single-node cluster + # This needs to be the string "true" when + # serialized, not a boolean true + "dataproc:dataproc.allow.zero.workers": "true" + } + } + }, + ) + }, + ) + assert result.success + + @pytest.mark.integration def test_wait_for_job_with_timeout_pydantic(): """Test submitting a job with timeout of 0 second so that it always fails.""" From 982b69a9464306f769adc0cb44a58a59e43f75d8 Mon Sep 17 00:00:00 2001 From: Gareth Brickman <50636644+garethbrickman@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:01:50 -0500 Subject: [PATCH 71/94] [docs] fix broken markdown hyperlink (#26544) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## How I Tested These Changes 👀 --- docs/content/deployment/run-monitoring.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/deployment/run-monitoring.mdx b/docs/content/deployment/run-monitoring.mdx index 5bafc1acdd697..6673fed36651e 100644 --- a/docs/content/deployment/run-monitoring.mdx +++ b/docs/content/deployment/run-monitoring.mdx @@ -39,7 +39,7 @@ When Dagster terminates a run, the run moves into CANCELING status and sends a t ## General run timeouts -After a run is marked as STARTED, it may hang indefinitely for various reasons (user API errors, network issues, etc.). You can configure a maximum runtime for every run in a deployment by setting the `run_monitoring.max_runtime_seconds` field in your dagster.yaml or (Dagster+ deployment settings)\[dagster-plus/managing-deployments/deployment-settings-reference] to the maximum runtime in seconds. If a run exceeds this timeout and run monitoring is enabled, it will be marked as failed. The `dagster/max_runtime` tag can also be used to set a timeout in seconds on a per-run basis. +After a run is marked as STARTED, it may hang indefinitely for various reasons (user API errors, network issues, etc.). You can configure a maximum runtime for every run in a deployment by setting the `run_monitoring.max_runtime_seconds` field in your dagster.yaml or [Dagster+ deployment settings](/dagster-plus/managing-deployments/deployment-settings-reference) to the maximum runtime in seconds. If a run exceeds this timeout and run monitoring is enabled, it will be marked as failed. The `dagster/max_runtime` tag can also be used to set a timeout in seconds on a per-run basis. For example, to configure a maximum of 2 hours for every run in your deployment: From 3c9b9aca0803e9320eae73bf379bc5a5b40d55f9 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Tue, 17 Dec 2024 14:02:23 -0500 Subject: [PATCH 72/94] [components] Set up test components (#26512) ## Summary & Motivation This PR is an overhaul of testing in `dagster-dg` with the aim of decoupling development of "real" components from the tests of `dg`. - Introduces an alternative set of test components in `dagster-components`. `dagster-components` will only ever load one of its builtin component libraries-- the test or the published components. Test components allow us to ensure coverage over cases like components with no summary/description/params. - Which library gets loaded is controlled via the `use_test_component_lib` to `ComponentRegistry.from_entry_point_discovery`. This in turn can be controlled via the `--use-test-component-lib` CLI param on both the `dagster-dg` and `dagster-components` CLIs. - Many tests are rewritten against the set of test components and are now more precise (for example, check the exact format of the output of the `dg info component-type` command output) - Introduced some new test utilities introduced in `dagster-dg` to make all this easier. ## How I Tested These Changes Unit tests --- .../dagster_components/cli/__init__.py | 13 +- .../dagster_components/cli/generate.py | 7 +- .../dagster_components/cli/list.py | 8 +- .../dagster_components/core/component.py | 57 +++- .../lib/pipes_subprocess_script_collection.py | 10 +- .../dagster_components/utils.py | 14 + .../cli_tests/test_commands.py | 103 ++++++ .../dagster_components_tests/lib/__init__.py | 7 + .../lib/all_metadata_empty_asset.py | 34 ++ .../lib/simple_asset.py | 55 +++ .../lib/simple_pipes_script_asset.py | 87 +++++ ...test_pipes_subprocess_script_collection.py | 2 +- .../dagster_components_tests/utils.py | 51 ++- .../libraries/dagster-components/setup.py | 1 + .../dagster-dg/dagster_dg/cli/__init__.py | 12 +- .../dagster-dg/dagster_dg/cli/generate.py | 13 +- .../dagster-dg/dagster_dg/cli/info.py | 18 +- .../dagster-dg/dagster_dg/cli/list.py | 11 +- .../dagster-dg/dagster_dg/context.py | 20 +- .../dagster-dg/dagster_dg/generate.py | 8 +- .../libraries/dagster-dg/dagster_dg/utils.py | 14 +- .../cli_tests/test_generate_commands.py | 319 +++++++----------- .../cli_tests/test_info_commands.py | 195 ++++++++--- .../cli_tests/test_list_commands.py | 94 +++--- .../dagster-dg/dagster_dg_tests/utils.py | 90 +++++ 25 files changed, 929 insertions(+), 314 deletions(-) create mode 100644 python_modules/libraries/dagster-components/dagster_components/utils.py create mode 100644 python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py create mode 100644 python_modules/libraries/dagster-components/dagster_components_tests/lib/__init__.py create mode 100644 python_modules/libraries/dagster-components/dagster_components_tests/lib/all_metadata_empty_asset.py create mode 100644 python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_asset.py create mode 100644 python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_pipes_script_asset.py create mode 100644 python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py diff --git a/python_modules/libraries/dagster-components/dagster_components/cli/__init__.py b/python_modules/libraries/dagster-components/dagster_components/cli/__init__.py index 025e67200f49c..bc123b3ddd2e0 100644 --- a/python_modules/libraries/dagster-components/dagster_components/cli/__init__.py +++ b/python_modules/libraries/dagster-components/dagster_components/cli/__init__.py @@ -3,6 +3,8 @@ from dagster_components.cli.generate import generate_cli from dagster_components.cli.list import list_cli +from dagster_components.core.component import BUILTIN_PUBLISHED_COMPONENT_ENTRY_POINT +from dagster_components.utils import CLI_BUILTIN_COMPONENT_LIB_KEY def create_dagster_components_cli(): @@ -15,9 +17,18 @@ def create_dagster_components_cli(): commands=commands, context_settings={"max_content_width": 120, "help_option_names": ["-h", "--help"]}, ) + @click.option( + "--builtin-component-lib", + type=str, + default=BUILTIN_PUBLISHED_COMPONENT_ENTRY_POINT, + help="Specify the builitin component library to load.", + ) @click.version_option(__version__, "--version", "-v") - def group(): + @click.pass_context + def group(ctx: click.Context, builtin_component_lib: str): """CLI tools for working with Dagster.""" + ctx.ensure_object(dict) + ctx.obj[CLI_BUILTIN_COMPONENT_LIB_KEY] = builtin_component_lib return group diff --git a/python_modules/libraries/dagster-components/dagster_components/cli/generate.py b/python_modules/libraries/dagster-components/dagster_components/cli/generate.py index 438d8ccb3b578..8405b5ec04e88 100644 --- a/python_modules/libraries/dagster-components/dagster_components/cli/generate.py +++ b/python_modules/libraries/dagster-components/dagster_components/cli/generate.py @@ -11,6 +11,7 @@ is_inside_code_location_project, ) from dagster_components.generate import generate_component_instance +from dagster_components.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="generate") @@ -23,12 +24,15 @@ def generate_cli() -> None: @click.argument("component_name", type=str) @click.option("--json-params", type=str, default=None) @click.argument("extra_args", nargs=-1, type=str) +@click.pass_context def generate_component_command( + ctx: click.Context, component_type: str, component_name: str, json_params: Optional[str], extra_args: Tuple[str, ...], ) -> None: + builtin_component_lib = ctx.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) if not is_inside_code_location_project(Path.cwd()): click.echo( click.style( @@ -38,7 +42,8 @@ def generate_component_command( sys.exit(1) context = CodeLocationProjectContext.from_path( - Path.cwd(), ComponentRegistry.from_entry_point_discovery() + Path.cwd(), + ComponentRegistry.from_entry_point_discovery(builtin_component_lib=builtin_component_lib), ) if not context.has_component_type(component_type): click.echo( diff --git a/python_modules/libraries/dagster-components/dagster_components/cli/list.py b/python_modules/libraries/dagster-components/dagster_components/cli/list.py index eb34c62ce9063..28957aaa33aad 100644 --- a/python_modules/libraries/dagster-components/dagster_components/cli/list.py +++ b/python_modules/libraries/dagster-components/dagster_components/cli/list.py @@ -10,6 +10,7 @@ CodeLocationProjectContext, is_inside_code_location_project, ) +from dagster_components.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="generate") @@ -18,8 +19,10 @@ def list_cli(): @list_cli.command(name="component-types") -def list_component_types_command() -> None: +@click.pass_context +def list_component_types_command(ctx: click.Context) -> None: """List registered Dagster components.""" + builtin_component_lib = ctx.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) if not is_inside_code_location_project(Path.cwd()): click.echo( click.style( @@ -29,7 +32,8 @@ def list_component_types_command() -> None: sys.exit(1) context = CodeLocationProjectContext.from_path( - Path.cwd(), ComponentRegistry.from_entry_point_discovery() + Path.cwd(), + ComponentRegistry.from_entry_point_discovery(builtin_component_lib=builtin_component_lib), ) output: Dict[str, Any] = {} for key, component_type in context.list_component_types(): diff --git a/python_modules/libraries/dagster-components/dagster_components/core/component.py b/python_modules/libraries/dagster-components/dagster_components/core/component.py index e7e53247d3dae..1c78031d600e0 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/component.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/component.py @@ -3,6 +3,7 @@ import importlib.metadata import inspect import sys +import textwrap from abc import ABC, abstractmethod from pathlib import Path from types import ModuleType @@ -25,6 +26,8 @@ from dagster._utils import snakecase from typing_extensions import Self +from dagster_components.utils import ensure_dagster_components_tests_import + if TYPE_CHECKING: from dagster._core.definitions.definitions_class import Definitions @@ -40,7 +43,7 @@ class ComponentGenerateRequest: class Component(ABC): name: ClassVar[Optional[str]] = None - component_params_schema: ClassVar = None + params_schema: ClassVar = None generate_params_schema: ClassVar = None @classmethod @@ -58,15 +61,15 @@ def from_decl_node( @classmethod def get_metadata(cls) -> "ComponentInternalMetadata": docstring = cls.__doc__ + clean_docstring = _clean_docstring(docstring) if docstring else None + return { - "summary": docstring.split("\n\n")[0] if docstring else None, - "description": docstring, + "summary": clean_docstring.split("\n\n")[0] if clean_docstring else None, + "description": clean_docstring if clean_docstring else None, "generate_params_schema": cls.generate_params_schema.schema() if cls.generate_params_schema else None, - "component_params_schema": cls.component_params_schema.schema() - if cls.component_params_schema - else None, + "component_params_schema": cls.params_schema.schema() if cls.params_schema else None, } @classmethod @@ -74,6 +77,16 @@ def get_description(cls) -> Optional[str]: return inspect.getdoc(cls) +def _clean_docstring(docstring: str) -> str: + lines = docstring.strip().splitlines() + first_line = lines[0] + if len(lines) == 1: + return first_line + else: + rest = textwrap.dedent("\n".join(lines[1:])) + return f"{first_line}\n{rest}" + + class ComponentInternalMetadata(TypedDict): summary: Optional[str] description: Optional[str] @@ -94,13 +107,43 @@ def get_entry_points_from_python_environment(group: str) -> Sequence[importlib.m COMPONENTS_ENTRY_POINT_GROUP = "dagster.components" +BUILTIN_COMPONENTS_ENTRY_POINT_BASE = "dagster_components" +BUILTIN_PUBLISHED_COMPONENT_ENTRY_POINT = BUILTIN_COMPONENTS_ENTRY_POINT_BASE +BUILTIN_TEST_COMPONENT_ENTRY_POINT = ".".join([BUILTIN_COMPONENTS_ENTRY_POINT_BASE, "test"]) class ComponentRegistry: @classmethod - def from_entry_point_discovery(cls) -> "ComponentRegistry": + def from_entry_point_discovery( + cls, builtin_component_lib: str = BUILTIN_PUBLISHED_COMPONENT_ENTRY_POINT + ) -> "ComponentRegistry": + """Discover components registered in the Python environment via the `dagster_components` entry point group. + + `dagster-components` itself registers multiple component entry points. We call these + "builtin" component libraries. The `dagster_components` entry point resolves to published + components and is loaded by default. Other entry points resolve to various sets of test + components. This method will only ever load one builtin component library. + + Args: + builtin-component-lib (str): Specifies the builtin components library to load. Builtin + copmonents libraries are defined under entry points with names matching the pattern + `dagster_components*`. Only one builtin component library can be loaded at a time. + Defaults to `dagster_components`, the standard set of published components. + """ components: Dict[str, Type[Component]] = {} for entry_point in get_entry_points_from_python_environment(COMPONENTS_ENTRY_POINT_GROUP): + # Skip builtin entry points that are not the specified builtin component library. + if ( + entry_point.name.startswith(BUILTIN_COMPONENTS_ENTRY_POINT_BASE) + and not entry_point.name == builtin_component_lib + ): + continue + elif entry_point.name == BUILTIN_TEST_COMPONENT_ENTRY_POINT: + if builtin_component_lib: + ensure_dagster_components_tests_import() + else: + continue + root_module = entry_point.load() if not isinstance(root_module, ModuleType): raise DagsterError( diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py index bacc8edb36dba..017fb8aa90dc0 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py @@ -77,21 +77,21 @@ def introspect_from_path(path: Path) -> "PipesSubprocessScriptCollection": @classmethod def from_decl_node( - cls, load_context: ComponentLoadContext, component_decl: ComponentDeclNode + cls, load_context: ComponentLoadContext, decl_node: ComponentDeclNode ) -> "PipesSubprocessScriptCollection": - assert isinstance(component_decl, YamlComponentDecl) + assert isinstance(decl_node, YamlComponentDecl) loaded_params = TypeAdapter(cls.params_schema).validate_python( - component_decl.component_file_model.params + decl_node.component_file_model.params ) path_specs = {} for script in loaded_params.scripts: - script_path = component_decl.path / script.path + script_path = decl_node.path / script.path if not script_path.exists(): raise FileNotFoundError(f"Script {script_path} does not exist") path_specs[script_path] = [spec.to_asset_spec() for spec in script.assets] - return cls(dirpath=component_decl.path, path_specs=path_specs) + return cls(dirpath=decl_node.path, path_specs=path_specs) def build_defs(self, load_context: "ComponentLoadContext") -> "Definitions": from dagster._core.definitions.definitions_class import Definitions diff --git a/python_modules/libraries/dagster-components/dagster_components/utils.py b/python_modules/libraries/dagster-components/dagster_components/utils.py new file mode 100644 index 0000000000000..5d4f19c11f694 --- /dev/null +++ b/python_modules/libraries/dagster-components/dagster_components/utils.py @@ -0,0 +1,14 @@ +import sys +from pathlib import Path + +CLI_BUILTIN_COMPONENT_LIB_KEY = "builtin_component_lib" + + +def ensure_dagster_components_tests_import() -> None: + from dagster_components import __file__ as dagster_components_init_py + + dagster_components_package_root = (Path(dagster_components_init_py) / ".." / "..").resolve() + assert ( + dagster_components_package_root / "dagster_components_tests" + ).exists(), "Could not find dagster_components_tests where expected" + sys.path.append(dagster_components_package_root.as_posix()) diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py b/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py new file mode 100644 index 0000000000000..1f4fad6c8c99c --- /dev/null +++ b/python_modules/libraries/dagster-components/dagster_components_tests/cli_tests/test_commands.py @@ -0,0 +1,103 @@ +import json +from pathlib import Path + +from click.testing import CliRunner +from dagster_components.cli import cli +from dagster_components.utils import ensure_dagster_components_tests_import + +ensure_dagster_components_tests_import() + +from dagster_components_tests.utils import temp_code_location_bar + + +# Test that the global --use-test-component-lib flag changes the registered components +def test_global_test_flag(): + runner: CliRunner = CliRunner() + + # standard + result = runner.invoke(cli, ["list", "component-types"]) + assert result.exit_code == 0 + default_result_keys = list(json.loads(result.output).keys()) + assert len(default_result_keys) > 0 + + result = runner.invoke( + cli, ["--builtin-component-lib", "dagster_components.test", "list", "component-types"] + ) + assert result.exit_code == 0 + test_result_keys = list(json.loads(result.output).keys()) + assert len(default_result_keys) > 0 + + assert default_result_keys != test_result_keys + + +def test_list_component_types_command(): + runner = CliRunner() + + result = runner.invoke( + cli, ["--builtin-component-lib", "dagster_components.test", "list", "component-types"] + ) + assert result.exit_code == 0 + result = json.loads(result.output) + + assert list(result.keys()) == [ + "dagster_components.test.all_metadata_empty_asset", + "dagster_components.test.simple_asset", + "dagster_components.test.simple_pipes_script_asset", + ] + + assert result["dagster_components.test.simple_asset"] == { + "name": "simple_asset", + "package": "dagster_components.test", + "summary": "A simple asset that returns a constant string value.", + "description": "A simple asset that returns a constant string value.", + "generate_params_schema": None, + "component_params_schema": { + "properties": { + "asset_key": {"title": "Asset Key", "type": "string"}, + "value": {"title": "Value", "type": "string"}, + }, + "required": ["asset_key", "value"], + "title": "SimpleAssetParams", + "type": "object", + }, + } + + pipes_script_params_schema = { + "properties": { + "asset_key": {"title": "Asset Key", "type": "string"}, + "filename": {"title": "Filename", "type": "string"}, + }, + "required": ["asset_key", "filename"], + "title": "SimplePipesScriptAssetParams", + "type": "object", + } + + assert result["dagster_components.test.simple_pipes_script_asset"] == { + "name": "simple_pipes_script_asset", + "package": "dagster_components.test", + "summary": "A simple asset that runs a Python script with the Pipes subprocess client.", + "description": "A simple asset that runs a Python script with the Pipes subprocess client.\n\nBecause it is a pipes asset, no value is returned.", + "generate_params_schema": pipes_script_params_schema, + "component_params_schema": pipes_script_params_schema, + } + + +def test_generate_component_command(): + runner = CliRunner() + + with temp_code_location_bar(): + result = runner.invoke( + cli, + [ + "--builtin-component-lib", + "dagster_components.test", + "generate", + "component", + "dagster_components.test.simple_pipes_script_asset", + "qux", + "--json-params", + '{"asset_key": "my_asset", "filename": "my_asset.py"}', + ], + ) + assert result.exit_code == 0 + assert Path("bar/components/qux/my_asset.py").exists() diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/lib/__init__.py b/python_modules/libraries/dagster-components/dagster_components_tests/lib/__init__.py new file mode 100644 index 0000000000000..f988bb8df7cae --- /dev/null +++ b/python_modules/libraries/dagster-components/dagster_components_tests/lib/__init__.py @@ -0,0 +1,7 @@ +from dagster_components_tests.lib.all_metadata_empty_asset import ( + AllMetadataEmptyAsset as AllMetadataEmptyAsset, +) +from dagster_components_tests.lib.simple_asset import SimpleAsset as SimpleAsset +from dagster_components_tests.lib.simple_pipes_script_asset import ( + SimplePipesScriptAsset as SimplePipesScriptAsset, +) diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/lib/all_metadata_empty_asset.py b/python_modules/libraries/dagster-components/dagster_components_tests/lib/all_metadata_empty_asset.py new file mode 100644 index 0000000000000..339f5761d21b8 --- /dev/null +++ b/python_modules/libraries/dagster-components/dagster_components_tests/lib/all_metadata_empty_asset.py @@ -0,0 +1,34 @@ +from typing import TYPE_CHECKING, Any + +from dagster._core.definitions.decorators.asset_decorator import asset +from dagster._core.definitions.definitions_class import Definitions +from dagster._core.execution.context.asset_execution_context import AssetExecutionContext +from dagster_components import Component, ComponentLoadContext, component +from dagster_components.core.component import ComponentGenerateRequest +from dagster_components.core.component_decl_builder import YamlComponentDecl +from dagster_components.generate import generate_component_yaml +from typing_extensions import Self + +if TYPE_CHECKING: + from dagster_components.core.component import ComponentDeclNode + + +@component(name="all_metadata_empty_asset") +class AllMetadataEmptyAsset(Component): + @classmethod + def from_decl_node( + cls, context: "ComponentLoadContext", decl_node: "ComponentDeclNode" + ) -> Self: + assert isinstance(decl_node, YamlComponentDecl) + return cls() + + @classmethod + def generate_files(cls, request: ComponentGenerateRequest, params: Any) -> None: + generate_component_yaml(request, params) + + def build_defs(self, context: ComponentLoadContext) -> Definitions: + @asset + def hardcoded_asset(context: AssetExecutionContext): + return 1 + + return Definitions(assets=[hardcoded_asset]) diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_asset.py b/python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_asset.py new file mode 100644 index 0000000000000..67f742064ee76 --- /dev/null +++ b/python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_asset.py @@ -0,0 +1,55 @@ +from typing import TYPE_CHECKING + +from dagster._core.definitions.asset_key import AssetKey +from dagster._core.definitions.decorators.asset_decorator import asset +from dagster._core.definitions.definitions_class import Definitions +from dagster._core.execution.context.asset_execution_context import AssetExecutionContext +from dagster_components import Component, ComponentLoadContext, component +from dagster_components.core.component import ComponentGenerateRequest +from dagster_components.core.component_decl_builder import YamlComponentDecl +from dagster_components.generate import generate_component_yaml +from pydantic import BaseModel, TypeAdapter +from typing_extensions import Self + +if TYPE_CHECKING: + from dagster_components.core.component import ComponentDeclNode + + +class SimpleAssetParams(BaseModel): + asset_key: str + value: str + + +@component(name="simple_asset") +class SimpleAsset(Component): + """A simple asset that returns a constant string value.""" + + params_schema = SimpleAssetParams + + @classmethod + def generate_files(cls, request: ComponentGenerateRequest, params: SimpleAssetParams) -> None: + generate_component_yaml(request, params.model_dump()) + + @classmethod + def from_decl_node( + cls, context: "ComponentLoadContext", decl_node: "ComponentDeclNode" + ) -> Self: + assert isinstance(decl_node, YamlComponentDecl) + loaded_params = TypeAdapter(cls.params_schema).validate_python( + decl_node.component_file_model.params + ) + return cls( + asset_key=AssetKey.from_user_string(loaded_params.asset_key), + value=loaded_params.value, + ) + + def __init__(self, asset_key: AssetKey, value: str): + self._asset_key = asset_key + self._value = value + + def build_defs(self, context: ComponentLoadContext) -> Definitions: + @asset(key=self._asset_key) + def dummy(context: AssetExecutionContext): + return self._value + + return Definitions(assets=[dummy]) diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_pipes_script_asset.py b/python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_pipes_script_asset.py new file mode 100644 index 0000000000000..a25b6b213d840 --- /dev/null +++ b/python_modules/libraries/dagster-components/dagster_components_tests/lib/simple_pipes_script_asset.py @@ -0,0 +1,87 @@ +import shutil +from pathlib import Path +from typing import TYPE_CHECKING + +import click +from dagster._core.definitions.asset_key import AssetKey +from dagster._core.definitions.decorators.asset_decorator import asset +from dagster._core.definitions.definitions_class import Definitions +from dagster._core.execution.context.asset_execution_context import AssetExecutionContext +from dagster._core.pipes.subprocess import PipesSubprocessClient +from dagster_components import Component, ComponentLoadContext, component +from dagster_components.core.component import ComponentGenerateRequest +from dagster_components.core.component_decl_builder import YamlComponentDecl +from dagster_components.generate import generate_component_yaml +from pydantic import BaseModel, TypeAdapter +from typing_extensions import Self + +if TYPE_CHECKING: + from dagster_components.core.component import ComponentDeclNode + + +# Same schema used for file generation and defs generation +class SimplePipesScriptAssetParams(BaseModel): + asset_key: str + filename: str + + @staticmethod + @click.command + @click.option("--asset-key", type=str) + @click.option("--filename", type=str) + def cli(asset_key: str, filename: str) -> "SimplePipesScriptAssetParams": + return SimplePipesScriptAssetParams(asset_key=asset_key, filename=filename) + + +_SCRIPT_TEMPLATE = """ +from dagster_pipes import open_dagster_pipes + +context = open_dagster_pipes() + +context.log.info("Materializing asset {asset_key} from pipes") +context.report_asset_materialization(asset_key="{asset_key}") +""" + + +@component(name="simple_pipes_script_asset") +class SimplePipesScriptAsset(Component): + """A simple asset that runs a Python script with the Pipes subprocess client. + + Because it is a pipes asset, no value is returned. + """ + + generate_params_schema = SimplePipesScriptAssetParams + params_schema = SimplePipesScriptAssetParams + + @classmethod + def generate_files( + cls, request: ComponentGenerateRequest, params: SimplePipesScriptAssetParams + ) -> None: + generate_component_yaml(request, params.model_dump()) + Path(request.component_instance_root_path, params.filename).write_text( + _SCRIPT_TEMPLATE.format(asset_key=params.asset_key) + ) + + @classmethod + def from_decl_node( + cls, context: "ComponentLoadContext", decl_node: "ComponentDeclNode" + ) -> Self: + assert isinstance(decl_node, YamlComponentDecl) + loaded_params = TypeAdapter(cls.params_schema).validate_python( + decl_node.component_file_model.params + ) + return cls( + asset_key=AssetKey.from_user_string(loaded_params.asset_key), + script_path=decl_node.path / loaded_params.filename, + ) + + def __init__(self, asset_key: AssetKey, script_path: Path): + self._asset_key = asset_key + self._script_path = script_path + + def build_defs(self, context: ComponentLoadContext) -> Definitions: + @asset(key=self._asset_key) + def _asset(context: AssetExecutionContext, pipes_client: PipesSubprocessClient): + cmd = [shutil.which("python"), self._script_path] + return pipes_client.run(command=cmd, context=context).get_results() + + return Definitions(assets=[_asset]) diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py index 65e61a54b312c..73955faa3291d 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py @@ -27,7 +27,7 @@ def test_python_native() -> None: def test_python_params() -> None: component = PipesSubprocessScriptCollection.from_decl_node( load_context=script_load_context(), - component_decl=YamlComponentDecl( + decl_node=YamlComponentDecl( path=LOCATION_PATH / "components" / "scripts", component_file_model=ComponentFileModel( type="pipes_subprocess_script_collection", diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/utils.py b/python_modules/libraries/dagster-components/dagster_components_tests/utils.py index 51bce9a14ea32..665aea9ea6e54 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/utils.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/utils.py @@ -1,4 +1,11 @@ +import textwrap +from contextlib import contextmanager +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import AbstractSet, Iterator + from dagster import AssetKey, DagsterInstance +from dagster._utils import pushd from dagster_components.core.component import Component, ComponentLoadContext, ComponentRegistry @@ -10,7 +17,7 @@ def script_load_context() -> ComponentLoadContext: return ComponentLoadContext(registry=registry(), resources={}) -def get_asset_keys(component: Component) -> set[AssetKey]: +def get_asset_keys(component: Component) -> AbstractSet[AssetKey]: return { key for key in component.build_defs(ComponentLoadContext.for_test()) @@ -26,3 +33,45 @@ def assert_assets(component: Component, expected_assets: int) -> None: instance=DagsterInstance.ephemeral() ) assert result.success + + +def generate_component_lib_pyproject_toml(name: str, is_code_location: bool = False) -> str: + pkg_name = name.replace("-", "_") + base = textwrap.dedent(f""" + [build-system] + requires = ["setuptools", "wheel"] + build-backend = "setuptools.build_meta" + + [project] + name = "{name}" + version = "0.1.0" + dependencies = [ + "dagster-components", + ] + + [project.entry-points] + "dagster.components" = {{ {pkg_name} = "{pkg_name}.lib"}} + """) + if is_code_location: + return base + textwrap.dedent(""" + [tool.dagster] + module_name = "{ pkg_name }.definitions" + project_name = "{ pkg_name }" + """) + else: + return base + + +@contextmanager +def temp_code_location_bar() -> Iterator[None]: + with TemporaryDirectory() as tmpdir, pushd(tmpdir): + Path("bar/bar/lib").mkdir(parents=True) + Path("bar/bar/components").mkdir(parents=True) + with open("bar/pyproject.toml", "w") as f: + f.write(generate_component_lib_pyproject_toml("bar", is_code_location=True)) + Path("bar/bar/__init__.py").touch() + Path("bar/bar/definitions.py").touch() + Path("bar/bar/lib/__init__.py").touch() + + with pushd("bar"): + yield diff --git a/python_modules/libraries/dagster-components/setup.py b/python_modules/libraries/dagster-components/setup.py index 0c009b3e36907..1c89e6f5f31f4 100644 --- a/python_modules/libraries/dagster-components/setup.py +++ b/python_modules/libraries/dagster-components/setup.py @@ -46,6 +46,7 @@ def get_version() -> str: ], "dagster.components": [ "dagster_components = dagster_components.lib", + "dagster_components.test = dagster_components_tests.lib", ], }, extras_require={ diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py index 38ac45544ae77..fd96f972ad707 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py @@ -3,6 +3,7 @@ from dagster_dg.cli.generate import generate_cli from dagster_dg.cli.info import info_cli from dagster_dg.cli.list import list_cli +from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY, DEFAULT_BUILTIN_COMPONENT_LIB from dagster_dg.version import __version__ @@ -18,8 +19,17 @@ def create_dg_cli(): context_settings={"max_content_width": 120, "help_option_names": ["-h", "--help"]}, ) @click.version_option(__version__, "--version", "-v") - def group(): + @click.option( + "--builtin-component-lib", + type=str, + default=DEFAULT_BUILTIN_COMPONENT_LIB, + help="Specify a builitin component library to use.", + ) + @click.pass_context + def group(context: click.Context, builtin_component_lib: bool): """CLI tools for working with Dagster components.""" + context.ensure_object(dict) + context.obj[CLI_BUILTIN_COMPONENT_LIB_KEY] = builtin_component_lib return group diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index 83d0ffd61f61d..9f94ea945f4ca 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -17,6 +17,7 @@ generate_component_type, generate_deployment, ) +from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="generate") @@ -139,7 +140,9 @@ def generate_component_type_command(name: str) -> None: @click.argument("component_name", type=str) @click.option("--json-params", type=str, default=None, help="JSON string of component parameters.") @click.argument("extra_args", nargs=-1, type=str) +@click.pass_context def generate_component_command( + context: click.Context, component_type: str, component_name: str, json_params: Optional[str], @@ -169,6 +172,7 @@ def generate_component_command( It is an error to pass both --json-params and EXTRA_ARGS. """ + builtin_component_lib = context.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -177,13 +181,13 @@ def generate_component_command( ) sys.exit(1) - context = CodeLocationDirectoryContext.from_path(Path.cwd()) - if not context.has_component_type(component_type): + dg_context = CodeLocationDirectoryContext.from_path(Path.cwd(), builtin_component_lib) + if not dg_context.has_component_type(component_type): click.echo( click.style(f"No component type `{component_type}` could be resolved.", fg="red") ) sys.exit(1) - elif context.has_component_instance(component_name): + elif dg_context.has_component_instance(component_name): click.echo( click.style(f"A component instance named `{component_name}` already exists.", fg="red") ) @@ -200,9 +204,10 @@ def generate_component_command( sys.exit(1) generate_component_instance( - Path(context.component_instances_root_path), + Path(dg_context.component_instances_root_path), component_name, component_type, json_params, extra_args, + builtin_component_lib=builtin_component_lib, ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py index 8cc094a0a34c3..28774eba6c826 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py @@ -6,6 +6,7 @@ import click from dagster_dg.context import CodeLocationDirectoryContext, is_inside_code_location_directory +from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="info") @@ -22,13 +23,16 @@ def _serialize_json_schema(schema: Mapping[str, Any]) -> str: @click.option("--description", is_flag=True, default=False) @click.option("--generate-params-schema", is_flag=True, default=False) @click.option("--component-params-schema", is_flag=True, default=False) +@click.pass_context def info_component_type_command( + context: click.Context, component_type: str, description: bool, generate_params_schema: bool, component_params_schema: bool, ) -> None: """Get detailed information on a registered Dagster component type.""" + builtin_component_lib = context.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -37,8 +41,10 @@ def info_component_type_command( ) sys.exit(1) - context = CodeLocationDirectoryContext.from_path(Path.cwd()) - if not context.has_component_type(component_type): + dg_context = CodeLocationDirectoryContext.from_path( + Path.cwd(), builtin_component_lib=builtin_component_lib + ) + if not dg_context.has_component_type(component_type): click.echo( click.style(f"No component type `{component_type}` could be resolved.", fg="red") ) @@ -53,8 +59,7 @@ def info_component_type_command( ) sys.exit(1) - context = CodeLocationDirectoryContext.from_path(Path.cwd()) - component_type_metadata = context.get_component_type(component_type) + component_type_metadata = dg_context.get_component_type(component_type) if description: if component_type_metadata.description: @@ -63,14 +68,15 @@ def info_component_type_command( click.echo("No description available.") elif generate_params_schema: if component_type_metadata.generate_params_schema: - click.echo(component_type_metadata.generate_params_schema) + click.echo(_serialize_json_schema(component_type_metadata.generate_params_schema)) else: click.echo("No generate params schema defined.") elif component_params_schema: if component_type_metadata.component_params_schema: - click.echo(component_type_metadata.component_params_schema) + click.echo(_serialize_json_schema(component_type_metadata.component_params_schema)) else: click.echo("No component params schema defined.") + # print all available metadata else: click.echo(component_type) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py index e8ad870233509..24e0f3f10d093 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py @@ -9,6 +9,7 @@ is_inside_code_location_directory, is_inside_deployment_directory, ) +from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="list") @@ -31,8 +32,10 @@ def list_code_locations_command() -> None: @list_cli.command(name="component-types") -def list_component_types_command() -> None: +@click.pass_context +def list_component_types_command(context: click.Context) -> None: """List registered Dagster components in the current code location environment.""" + builtin_component_lib = context.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -41,8 +44,10 @@ def list_component_types_command() -> None: ) sys.exit(1) - context = CodeLocationDirectoryContext.from_path(Path.cwd()) - for key, component_type in context.iter_component_types(): + dg_context = CodeLocationDirectoryContext.from_path( + Path.cwd(), builtin_component_lib=builtin_component_lib + ) + for key, component_type in dg_context.iter_component_types(): click.echo(key) if component_type.summary: click.echo(f" {component_type.summary}") diff --git a/python_modules/libraries/dagster-dg/dagster_dg/context.py b/python_modules/libraries/dagster-dg/dagster_dg/context.py index 2c105ae0a0efc..fbd0186ad7dfd 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/context.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/context.py @@ -1,14 +1,14 @@ import json import os from pathlib import Path -from typing import Final, Iterable, Mapping, Optional, Tuple +from typing import Final, Iterable, Optional, Tuple import tomli from typing_extensions import Self from dagster_dg.component import RemoteComponentRegistry, RemoteComponentType from dagster_dg.error import DgError -from dagster_dg.utils import execute_code_location_command +from dagster_dg.utils import DEFAULT_BUILTIN_COMPONENT_LIB, execute_code_location_command def is_inside_deployment_directory(path: Path) -> bool: @@ -89,13 +89,23 @@ def get_code_location_names(self) -> Iterable[str]: class CodeLocationDirectoryContext: - _components_registry: Mapping[str, RemoteComponentType] = {} + """Class encapsulating contextual information about a components code location directory. + + Args: + root_path (Path): The absolute path to the root of the code location directory. + name (str): The name of the code location python package. + component_registry (ComponentRegistry): The component registry for the code location. + deployment_context (Optional[DeploymentDirectoryContext]): The deployment context containing + the code location directory. Defaults to None. + """ @classmethod - def from_path(cls, path: Path) -> Self: + def from_path( + cls, path: Path, builtin_component_lib: str = DEFAULT_BUILTIN_COMPONENT_LIB + ) -> Self: root_path = _resolve_code_location_root_directory(path) component_registry_data = execute_code_location_command( - root_path, ["list", "component-types"] + root_path, ["list", "component-types"], builtin_component_lib=builtin_component_lib ) component_registry = RemoteComponentRegistry.from_dict(json.loads(component_registry_data)) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index e712f1c2b7984..c00901332c158 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -8,6 +8,7 @@ from dagster_dg.context import CodeLocationDirectoryContext from dagster_dg.utils import ( + DEFAULT_BUILTIN_COMPONENT_LIB, camelcase, execute_code_location_command, generate_subtree, @@ -150,6 +151,7 @@ def generate_component_instance( component_type: str, json_params: Optional[str], extra_args: Tuple[str, ...], + builtin_component_lib: str = DEFAULT_BUILTIN_COMPONENT_LIB, ) -> None: component_instance_root_path = root_path / name click.echo(f"Creating a Dagster component instance folder at {component_instance_root_path}.") @@ -162,4 +164,8 @@ def generate_component_instance( *(["--json-params", json_params] if json_params else []), *(["--", *extra_args] if extra_args else []), ) - execute_code_location_command(Path(component_instance_root_path), code_location_command) + execute_code_location_command( + Path(component_instance_root_path), + code_location_command, + builtin_component_lib=builtin_component_lib, + ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index a3999f10447a9..b0d2c917ff7d3 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -12,12 +12,22 @@ from dagster_dg.version import __version__ as dagster_version +CLI_BUILTIN_COMPONENT_LIB_KEY = "builtin_component_lib" +DEFAULT_BUILTIN_COMPONENT_LIB: Final = "dagster_components" + + _CODE_LOCATION_COMMAND_PREFIX: Final = ["uv", "run", "dagster-components"] -def execute_code_location_command(path: Path, cmd: Sequence[str]) -> str: +def execute_code_location_command( + path: Path, cmd: Sequence[str], builtin_component_lib: Optional[str] = None +) -> str: + full_cmd = [ + *_CODE_LOCATION_COMMAND_PREFIX, + *(["--builtin-component-lib", builtin_component_lib] if builtin_component_lib else []), + *cmd, + ] with pushd(path): - full_cmd = [*_CODE_LOCATION_COMMAND_PREFIX, *cmd] result = subprocess.run( full_cmd, stdout=subprocess.PIPE, env=get_uv_command_env(), check=True ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 09838048dddce..4158671adf31e 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -1,135 +1,30 @@ -import inspect import json import os import subprocess -import sys -import textwrap -from contextlib import contextmanager from pathlib import Path -from typing import Iterator import pytest import tomli from click.testing import CliRunner -from dagster_dg.cli.generate import ( - generate_code_location_command, - generate_component_command, - generate_component_type_command, - generate_deployment_command, -) +from dagster_dg.cli import cli as dg_cli from dagster_dg.context import CodeLocationDirectoryContext -from dagster_dg.utils import discover_git_root, pushd - - -# This is a holder for code that is intended to be written to a file -def _example_component_type_baz(): - import click - from dagster import AssetExecutionContext, Definitions, PipesSubprocessClient, asset - from dagster_components import ( - Component, - ComponentGenerateRequest, - ComponentLoadContext, - component, - ) - from dagster_components.generate import generate_component_yaml - from pydantic import BaseModel - - _SAMPLE_PIPES_SCRIPT = """ - from dagster_pipes import open_dagster_pipes - - context = open_dagster_pipes() - context.report_asset_materialization({"alpha": "beta"}) - """ - - class BazGenerateParams(BaseModel): - filename: str = "sample.py" - - @staticmethod - @click.command - @click.option("--filename", type=str, default="sample.py") - def cli(filename: str) -> "BazGenerateParams": - return BazGenerateParams(filename=filename) - - @component(name="baz") - class Baz(Component): - generate_params_schema = BazGenerateParams - - @classmethod - def generate_files(cls, request: ComponentGenerateRequest, params: BazGenerateParams): - generate_component_yaml(request, {}) - with open(params.filename, "w") as f: - f.write(_SAMPLE_PIPES_SCRIPT) - - def build_defs(self, context: ComponentLoadContext) -> Definitions: - @asset - def foo(context: AssetExecutionContext, client: PipesSubprocessClient): - client.run(context=context, command=["python", "sample.py"]) - - return Definitions(assets=[foo], resources={"client": PipesSubprocessClient()}) - - -@contextmanager -def isolated_example_deployment_foo(runner: CliRunner) -> Iterator[None]: - with runner.isolated_filesystem(): - runner.invoke(generate_deployment_command, ["foo"]) - with pushd("foo"): - yield - - -@contextmanager -def isolated_example_code_location_bar( - runner: CliRunner, in_deployment: bool = True -) -> Iterator[None]: - dagster_git_repo_dir = str(discover_git_root(Path(__file__))) - if in_deployment: - with isolated_example_deployment_foo(runner), clean_module_cache("bar"): - runner.invoke( - generate_code_location_command, - ["--use-editable-dagster", dagster_git_repo_dir, "bar"], - ) - with pushd("code_locations/bar"): - yield - else: - with runner.isolated_filesystem(), clean_module_cache("bar"): - runner.invoke( - generate_code_location_command, - ["--use-editable-dagster", dagster_git_repo_dir, "bar"], - ) - with pushd("bar"): - yield - - -@contextmanager -def isolated_example_code_location_bar_with_component_type_baz( - runner: CliRunner, in_deployment: bool = True -) -> Iterator[None]: - with isolated_example_code_location_bar(runner, in_deployment): - with open("bar/lib/__init__.py", "a") as f: - f.write("from bar.lib.baz import Baz\n") - with open("bar/lib/baz.py", "w") as f: - component_type_source = textwrap.dedent( - inspect.getsource(_example_component_type_baz).split("\n", 1)[1] - ) - f.write(component_type_source) - yield - - -@contextmanager -def clean_module_cache(module_name: str): - prefix = f"{module_name}." - keys_to_del = { - key for key in sys.modules.keys() if key == module_name or key.startswith(prefix) - } - for key in keys_to_del: - del sys.modules[key] - yield +from dagster_dg.utils import discover_git_root, ensure_dagster_dg_tests_import + +ensure_dagster_dg_tests_import() + +from dagster_dg_tests.utils import ( + ProxyRunner, + assert_runner_result, + isolated_example_code_location_bar, + isolated_example_deployment_foo, +) def test_generate_deployment_command_success() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): - result = runner.invoke(generate_deployment_command, ["foo"]) - assert result.exit_code == 0 + result = runner.invoke("generate", "deployment", "foo") + assert_runner_result(result) assert Path("foo").exists() assert Path("foo/.github").exists() assert Path("foo/.github/workflows").exists() @@ -139,19 +34,19 @@ def test_generate_deployment_command_success() -> None: def test_generate_deployment_command_already_exists_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): os.mkdir("foo") - result = runner.invoke(generate_deployment_command, ["foo"]) - assert result.exit_code != 0 + result = runner.invoke("generate", "deployment", "foo") + assert_runner_result(result, exit_0=False) assert "already exists" in result.output def test_generate_code_location_inside_deployment_success() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_deployment_foo(runner): - result = runner.invoke(generate_code_location_command, ["bar"]) - assert result.exit_code == 0 + result = runner.invoke("generate", "code-location", "bar") + assert_runner_result(result) assert Path("code_locations/bar").exists() assert Path("code_locations/bar/bar").exists() assert Path("code_locations/bar/bar/lib").exists() @@ -171,10 +66,10 @@ def test_generate_code_location_inside_deployment_success() -> None: def test_generate_code_location_outside_deployment_success() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): - result = runner.invoke(generate_code_location_command, ["bar"]) - assert result.exit_code == 0 + result = runner.invoke("generate", "code-location", "bar") + assert_runner_result(result) assert Path("bar").exists() assert Path("bar/bar").exists() assert Path("bar/bar/lib").exists() @@ -189,7 +84,7 @@ def test_generate_code_location_outside_deployment_success() -> None: @pytest.mark.parametrize("mode", ["env_var", "arg"]) def test_generate_code_location_editable_dagster_success(mode: str, monkeypatch) -> None: - runner = CliRunner() + runner = ProxyRunner.test() dagster_git_repo_dir = discover_git_root(Path(__file__)) if mode == "env_var": monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", str(dagster_git_repo_dir)) @@ -197,8 +92,8 @@ def test_generate_code_location_editable_dagster_success(mode: str, monkeypatch) else: editable_args = ["--use-editable-dagster", str(dagster_git_repo_dir)] with isolated_example_deployment_foo(runner): - result = runner.invoke(generate_code_location_command, [*editable_args, "bar"]) - assert result.exit_code == 0 + result = runner.invoke("generate", "code-location", *editable_args, "bar") + assert_runner_result(result) assert Path("code_locations/bar").exists() assert Path("code_locations/bar/pyproject.toml").exists() with open("code_locations/bar/pyproject.toml") as f: @@ -222,137 +117,172 @@ def test_generate_code_location_editable_dagster_success(mode: str, monkeypatch) def test_generate_code_location_editable_dagster_no_env_var_no_value_fails(monkeypatch) -> None: - runner = CliRunner() + runner = ProxyRunner.test() monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", "") with isolated_example_deployment_foo(runner): - result = runner.invoke( - generate_code_location_command, ["--use-editable-dagster", "--", "bar"] - ) - assert result.exit_code != 0 + result = runner.invoke("generate", "code-location", "--use-editable-dagster", "--", "bar") + assert_runner_result(result, exit_0=False) assert "requires the `DAGSTER_GIT_REPO_DIR`" in result.output def test_generate_code_location_already_exists_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_deployment_foo(runner): - result = runner.invoke(generate_code_location_command, ["bar"]) - assert result.exit_code == 0 - result = runner.invoke(generate_code_location_command, ["bar"]) - assert result.exit_code != 0 + result = runner.invoke("generate", "code-location", "bar") + assert_runner_result(result) + result = runner.invoke("generate", "code-location", "bar") + assert_runner_result(result, exit_0=False) assert "already exists" in result.output @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_type_success(in_deployment: bool) -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_code_location_bar(runner, in_deployment): - result = runner.invoke(generate_component_type_command, ["baz"]) - assert result.exit_code == 0 + result = runner.invoke("generate", "component-type", "baz") + assert_runner_result(result) assert Path("bar/lib/baz.py").exists() context = CodeLocationDirectoryContext.from_path(Path.cwd()) assert context.has_component_type("bar.baz") def test_generate_component_type_outside_code_location_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_deployment_foo(runner): - result = runner.invoke(generate_component_type_command, ["baz"]) - assert result.exit_code != 0 + result = runner.invoke("generate", "component-type", "baz") + assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_type_already_exists_fails(in_deployment: bool) -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_code_location_bar(runner, in_deployment): - result = runner.invoke(generate_component_type_command, ["baz"]) - assert result.exit_code == 0 - result = runner.invoke(generate_component_type_command, ["baz"]) - assert result.exit_code != 0 + result = runner.invoke("generate", "component-type", "baz") + assert_runner_result(result) + result = runner.invoke("generate", "component-type", "baz") + assert_runner_result(result, exit_0=False) assert "already exists" in result.output @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_no_params_success(in_deployment: bool) -> None: - runner = CliRunner() - with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): - result = runner.invoke(generate_component_command, ["bar.baz", "qux"]) - assert result.exit_code == 0 + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner, in_deployment): + result = runner.invoke( + "generate", + "component", + "dagster_components.test.all_metadata_empty_asset", + "qux", + ) + assert_runner_result(result) assert Path("bar/components/qux").exists() - assert Path("bar/components/qux/sample.py").exists() # default filename component_yaml_path = Path("bar/components/qux/component.yaml") assert component_yaml_path.exists() - assert "type: bar.baz" in component_yaml_path.read_text() + assert ( + "type: dagster_components.test.all_metadata_empty_asset" + in component_yaml_path.read_text() + ) @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_json_params_success(in_deployment: bool) -> None: - runner = CliRunner() - with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke( - generate_component_command, - ["bar.baz", "qux", "--json-params", '{"filename": "hello.py"}'], + "generate", + "component", + "dagster_components.test.simple_pipes_script_asset", + "qux", + "--json-params", + '{"asset_key": "foo", "filename": "hello.py"}', ) - assert result.exit_code == 0 + assert_runner_result(result) assert Path("bar/components/qux").exists() assert Path("bar/components/qux/hello.py").exists() component_yaml_path = Path("bar/components/qux/component.yaml") assert component_yaml_path.exists() - assert "type: bar.baz" in component_yaml_path.read_text() + assert ( + "type: dagster_components.test.simple_pipes_script_asset" + in component_yaml_path.read_text() + ) @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_extra_args_success(in_deployment: bool) -> None: - runner = CliRunner() - with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke( - generate_component_command, ["bar.baz", "qux", "--", "--filename=hello.py"] + "generate", + "component", + "dagster_components.test.simple_pipes_script_asset", + "qux", + "--", + "--asset-key=foo", + "--filename=hello.py", ) - assert result.exit_code == 0 + assert_runner_result(result) assert Path("bar/components/qux").exists() assert Path("bar/components/qux/hello.py").exists() component_yaml_path = Path("bar/components/qux/component.yaml") assert component_yaml_path.exists() - assert "type: bar.baz" in component_yaml_path.read_text() + assert ( + "type: dagster_components.test.simple_pipes_script_asset" + in component_yaml_path.read_text() + ) def test_generate_component_json_params_and_extra_args_fails() -> None: - runner = CliRunner() - with isolated_example_code_location_bar_with_component_type_baz(runner): + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner): result = runner.invoke( - generate_component_command, - [ - "bar.baz", - "qux", - "--json-params", - '{"filename": "hello.py"}', - "--", - "--filename=hello.py", - ], + "generate", + "component", + "dagster_components.test.simple_pipes_script_asset", + "qux", + "--json-params", + '{"filename": "hello.py"}', + "--", + "--filename=hello.py", ) - assert result.exit_code != 0 + assert_runner_result(result, exit_0=False) assert "Detected both --json-params and EXTRA_ARGS" in result.output def test_generate_component_outside_code_location_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_deployment_foo(runner): - result = runner.invoke(generate_component_command, ["bar.baz", "qux"]) - assert result.exit_code != 0 + result = runner.invoke("generate", "component", "bar.baz", "qux") + assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_already_exists_fails(in_deployment: bool) -> None: - runner = CliRunner() - with isolated_example_code_location_bar_with_component_type_baz(runner, in_deployment): - result = runner.invoke(generate_component_command, ["bar.baz", "qux"]) - assert result.exit_code == 0 - result = runner.invoke(generate_component_command, ["bar.baz", "qux"]) - assert result.exit_code != 0 + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner, in_deployment): + result = runner.invoke( + "generate", + "component", + "dagster_components.test.all_metadata_empty_asset", + "qux", + ) + assert_runner_result(result) + result = runner.invoke( + "generate", + "component", + "dagster_components.test.all_metadata_empty_asset", + "qux", + ) + assert_runner_result(result, exit_0=False) assert "already exists" in result.output +# ######################## +# ##### REAL COMPONENTS +# ######################## + + def test_generate_sling_replication_instance() -> None: runner = CliRunner() with isolated_example_code_location_bar(runner): @@ -362,9 +292,9 @@ def test_generate_sling_replication_instance() -> None: ["uv", "add", "dagster-components[sling]", "dagster-embedded-elt"], check=True ) result = runner.invoke( - generate_component_command, ["dagster_components.sling_replication", "file_ingest"] + dg_cli, ["generate", "component", "dagster_components.sling_replication", "file_ingest"] ) - assert result.exit_code == 0 + assert_runner_result(result) assert Path("bar/components/file_ingest").exists() component_yaml_path = Path("bar/components/file_ingest/component.yaml") @@ -393,9 +323,10 @@ def test_generate_dbt_project_instance(params) -> None: # direct dependencies will be resolved by uv.tool.sources. subprocess.run(["uv", "add", "dagster-components[dbt]", "dagster-dbt"], check=True) result = runner.invoke( - generate_component_command, ["dagster_components.dbt_project", "my_project", *params] + dg_cli, + ["generate", "component", "dagster_components.dbt_project", "my_project", *params], ) - assert result.exit_code == 0 + assert_runner_result(result) assert Path("bar/components/my_project").exists() component_yaml_path = Path("bar/components/my_project/component.yaml") diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py index 82a68cf6105d4..eb4305fae02ca 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py @@ -1,91 +1,204 @@ import textwrap -from click.testing import CliRunner -from dagster_dg.cli.info import info_component_type_command from dagster_dg.utils import ensure_dagster_dg_tests_import ensure_dagster_dg_tests_import() -from dagster_dg_tests.cli_tests.test_generate_commands import isolated_example_code_location_bar +from dagster_dg_tests.utils import ( + ProxyRunner, + assert_runner_result, + isolated_example_code_location_bar, +) def test_info_component_type_all_metadata_success(): - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_code_location_bar(runner): result = runner.invoke( - info_component_type_command, ["dagster_components.pipes_subprocess_script_collection"] + "info", + "component-type", + "dagster_components.test.simple_pipes_script_asset", + ) + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + dagster_components.test.simple_pipes_script_asset + + Description: + + A simple asset that runs a Python script with the Pipes subprocess client. + + Because it is a pipes asset, no value is returned. + + Generate params schema: + + { + "properties": { + "asset_key": { + "title": "Asset Key", + "type": "string" + }, + "filename": { + "title": "Filename", + "type": "string" + } + }, + "required": [ + "asset_key", + "filename" + ], + "title": "SimplePipesScriptAssetParams", + "type": "object" + } + + Component params schema: + + { + "properties": { + "asset_key": { + "title": "Asset Key", + "type": "string" + }, + "filename": { + "title": "Filename", + "type": "string" + } + }, + "required": [ + "asset_key", + "filename" + ], + "title": "SimplePipesScriptAssetParams", + "type": "object" + } + """).strip() ) - assert result.exit_code == 0 - assert result.output.startswith( - textwrap.dedent(""" - dagster_components.pipes_subprocess_script_collection - Description: - Assets that wrap Python scripts +def test_info_component_type_all_metadata_empty_success(): + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner): + result = runner.invoke( + "info", + "component-type", + "dagster_components.test.all_metadata_empty_asset", + ) + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + dagster_components.test.all_metadata_empty_asset """).strip() ) def test_info_component_type_flag_fields_success(): - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_code_location_bar(runner): result = runner.invoke( - info_component_type_command, - ["dagster_components.pipes_subprocess_script_collection", "--description"], + "info", + "component-type", + "dagster_components.test.simple_pipes_script_asset", + "--description", ) - assert result.exit_code == 0 - assert result.output.startswith( - textwrap.dedent(""" - Assets that wrap Python scripts + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + A simple asset that runs a Python script with the Pipes subprocess client. + + Because it is a pipes asset, no value is returned. """).strip() ) result = runner.invoke( - info_component_type_command, - ["dagster_components.pipes_subprocess_script_collection", "--generate-params-schema"], + "info", + "component-type", + "dagster_components.test.simple_pipes_script_asset", + "--generate-params-schema", ) - assert result.exit_code == 0 - assert result.output.startswith( - textwrap.dedent(""" - No generate params schema defined. + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + { + "properties": { + "asset_key": { + "title": "Asset Key", + "type": "string" + }, + "filename": { + "title": "Filename", + "type": "string" + } + }, + "required": [ + "asset_key", + "filename" + ], + "title": "SimplePipesScriptAssetParams", + "type": "object" + } """).strip() ) result = runner.invoke( - info_component_type_command, - ["dagster_components.pipes_subprocess_script_collection", "--component-params-schema"], + "info", + "component-type", + "dagster_components.test.simple_pipes_script_asset", + "--component-params-schema", ) - assert result.exit_code == 0 - assert result.output.startswith( - textwrap.dedent(""" - No component params schema defined. + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + { + "properties": { + "asset_key": { + "title": "Asset Key", + "type": "string" + }, + "filename": { + "title": "Filename", + "type": "string" + } + }, + "required": [ + "asset_key", + "filename" + ], + "title": "SimplePipesScriptAssetParams", + "type": "object" + } """).strip() ) def test_info_component_type_outside_code_location_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): result = runner.invoke( - info_component_type_command, ["dagster_components.pipes_subprocess_script_collection"] + "info", + "component-type", + "dagster_components.test.simple_pipes_script_asset", + "--component-params-schema", ) - assert result.exit_code != 0 + assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output def test_info_component_type_multiple_flags_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_code_location_bar(runner): result = runner.invoke( - info_component_type_command, - [ - "dagster_components.pipes_subprocess_script_collection", - "--description", - "--generate-params-schema", - ], + "info", + "component-type", + "dagster_components.test.simple_pipes_script_asset", + "--description", + "--generate-params-schema", ) - assert result.exit_code != 0 + assert_runner_result(result, exit_0=False) assert ( "Only one of --description, --generate-params-schema, and --component-params-schema can be specified." in result.output diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py index d50dc8c905764..5d9adb3a17d15 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py @@ -1,73 +1,89 @@ -import re +import textwrap -from click.testing import CliRunner -from dagster_dg.cli.generate import generate_code_location_command, generate_component_command -from dagster_dg.cli.list import ( - list_code_locations_command, - list_component_types_command, - list_components_command, -) from dagster_dg.utils import ensure_dagster_dg_tests_import ensure_dagster_dg_tests_import() -from dagster_dg_tests.cli_tests.test_generate_commands import ( +from dagster_dg_tests.utils import ( + ProxyRunner, + assert_runner_result, isolated_example_code_location_bar, - isolated_example_code_location_bar_with_component_type_baz, isolated_example_deployment_foo, ) def test_list_code_locations_success(): - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_deployment_foo(runner): - runner.invoke(generate_code_location_command, ["foo"]) - runner.invoke(generate_code_location_command, ["bar"]) - result = runner.invoke(list_code_locations_command) - assert result.exit_code == 0 - assert result.output == "bar\nfoo\n" + runner.invoke("generate", "code-location", "foo") + runner.invoke("generate", "code-location", "bar") + result = runner.invoke("list", "code-locations") + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + bar + foo + """).strip() + ) def test_list_code_locations_outside_deployment_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): - result = runner.invoke(list_code_locations_command) - assert result.exit_code != 0 + result = runner.invoke("list", "code-locations") + assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster deployment directory" in result.output def test_list_component_types_success(): - runner = CliRunner() + runner = ProxyRunner.test() with isolated_example_code_location_bar(runner): - result = runner.invoke(list_component_types_command) - assert result.exit_code == 0 - lines = result.output.strip().split("\n") - assert len(lines) == 2 - assert lines[0] == "dagster_components.pipes_subprocess_script_collection" - assert re.match(r" Assets that wrap.*", lines[1]) + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + dagster_components.test.all_metadata_empty_asset + dagster_components.test.simple_asset + A simple asset that returns a constant string value. + dagster_components.test.simple_pipes_script_asset + A simple asset that runs a Python script with the Pipes subprocess client. + """).strip() + ) def test_list_component_types_outside_code_location_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): - result = runner.invoke(list_component_types_command) - assert result.exit_code != 0 + result = runner.invoke("list", "component-types") + assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output def test_list_components_succeeds(): - runner = CliRunner() - # with isolated_example_code_location_bar(runner): - with isolated_example_code_location_bar_with_component_type_baz(runner): - result = runner.invoke(list_components_command) - runner.invoke(generate_component_command, ["bar.baz", "qux"]) - result = runner.invoke(list_components_command) - assert result.output == "qux\n" + runner = ProxyRunner.test() + with isolated_example_code_location_bar(runner): + result = runner.invoke( + "generate", + "component", + "dagster_components.test.all_metadata_empty_asset", + "qux", + ) + assert_runner_result(result) + result = runner.invoke("list", "components") + assert_runner_result(result) + assert ( + result.output.strip() + == textwrap.dedent(""" + qux + """).strip() + ) def test_list_components_command_outside_code_location_fails() -> None: - runner = CliRunner() + runner = ProxyRunner.test() with runner.isolated_filesystem(): - result = runner.invoke(list_components_command) - assert result.exit_code != 0 + result = runner.invoke("list", "components") + assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py new file mode 100644 index 0000000000000..0d32afe12494c --- /dev/null +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py @@ -0,0 +1,90 @@ +import traceback +from contextlib import contextmanager +from dataclasses import dataclass +from pathlib import Path +from types import TracebackType +from typing import Iterator, Optional, Sequence, Tuple, Type, Union + +from click.testing import CliRunner, Result +from dagster_dg.cli import cli as dg_cli +from dagster_dg.utils import discover_git_root, pushd + + +@contextmanager +def isolated_example_deployment_foo(runner: Union[CliRunner, "ProxyRunner"]) -> Iterator[None]: + runner = ProxyRunner(runner) if isinstance(runner, CliRunner) else runner + with runner.isolated_filesystem(): + runner.invoke("generate", "deployment", "foo") + with pushd("foo"): + yield + + +@contextmanager +def isolated_example_code_location_bar( + runner: Union[CliRunner, "ProxyRunner"], in_deployment: bool = True +) -> Iterator[None]: + runner = ProxyRunner(runner) if isinstance(runner, CliRunner) else runner + dagster_git_repo_dir = str(discover_git_root(Path(__file__))) + if in_deployment: + with isolated_example_deployment_foo(runner): + runner.invoke( + "generate", + "code-location", + "--use-editable-dagster", + dagster_git_repo_dir, + "bar", + ) + with pushd("code_locations/bar"): + yield + else: + with runner.isolated_filesystem(): + runner.invoke( + "generate", + "code-location", + "--use-editable-dagster", + dagster_git_repo_dir, + "bar", + ) + with pushd("bar"): + yield + + +@dataclass +class ProxyRunner: + original: CliRunner + prepend_args: Optional[Sequence[str]] = None + + @classmethod + def test(cls): + return cls(CliRunner(), ["--builtin-component-lib", "dagster_components.test"]) + + def invoke(self, *args: str): + all_args = [*(self.prepend_args or []), *args] + return self.original.invoke(dg_cli, all_args) + + @contextmanager + def isolated_filesystem(self) -> Iterator[None]: + with self.original.isolated_filesystem(): + yield + + +def assert_runner_result(result: Result, exit_0: bool = True) -> None: + try: + assert result.exit_code == 0 if exit_0 else result.exit_code != 0 + except AssertionError: + if result.output: + print(result.output) # noqa: T201 + if result.exc_info: + print_exception_info(result.exc_info) + raise + + +def print_exception_info( + exc_info: Tuple[Type[BaseException], BaseException, TracebackType], +) -> None: + """Prints a nicely formatted traceback for the current exception.""" + exc_type, exc_value, exc_traceback = exc_info + print("Exception Traceback (most recent call last):") # noqa: T201 + formatted_traceback = "".join(traceback.format_tb(exc_traceback)) + print(formatted_traceback) # noqa: T201 + print(f"{exc_type.__name__}: {exc_value}") # noqa: T201 From a748be61fe2a0771026b1baf04a937fb80b3927f Mon Sep 17 00:00:00 2001 From: Nikki Everett Date: Tue, 17 Dec 2024 13:23:00 -0600 Subject: [PATCH 73/94] Update new docs CONTRIBUTING: Current replacement is a markdown table (#26542) ## Summary & Motivation Looks like people have been using Markdown tables in new docs to replace `` elements in old docs, so I think that's the recommendation we should go with for now. ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. Signed-off-by: nikki everett --- docs/docs-beta/CONTRIBUTING.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/docs-beta/CONTRIBUTING.md b/docs/docs-beta/CONTRIBUTING.md index f2b8d9d78c55b..c0b8e52ba5712 100644 --- a/docs/docs-beta/CONTRIBUTING.md +++ b/docs/docs-beta/CONTRIBUTING.md @@ -80,20 +80,27 @@ Before: ``` - - A list of keys or key-value pairs to include in the task. If a value is not - specified, the value will be pulled from the agent task. -
- In the example above, FOO_ENV_VAR will be set to{" "} - foo_value and BAR_ENV_VAR will be set to whatever - value it has in the agent task. + + The name of the Dagster+ deployment. For example, prod. + + + If 1, the deployment is a{" "} + + branch deployment + + . Refer to the + Branch Deployment variables section + for a list of variables available in branch deployments.
``` After: -_There is not a replacement at this point in time..._ +| Key | Value | +|---|---| +| `DAGSTER_CLOUD_DEPLOYMENT_NAME` | The name of the Dagster+ deployment.

**Example:** `prod`. | +| `DAGSTER_CLOUD_IS_BRANCH_DEPLOYMENT` | `1` if the deployment is a [branch deployment](/dagster-plus/features/ci-cd/branch-deployments/index.md). | ### Whitespace via `{" "}` From 550d4737db839a291161f2df3c91397a131c888c Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Tue, 17 Dec 2024 15:46:54 -0500 Subject: [PATCH 74/94] [components] Add dagster-dg global config and AppContext (#26516) ## Summary & Motivation Add a global `AppContext` and `DgConfig` object in `dagster-dg`. The purpose of these abstractions is to capture global configuration and pass it throughout the system. Global configuration is supported via top-level options passed to `dg` on the command line. `AppContext` may appear premature in this PR, since it just wraps `DgConfig`. Upstack we add the cache to it. ## How I Tested These Changes Unit tests. --- .../dagster-dg/dagster_dg/cli/__init__.py | 13 ++- .../dagster-dg/dagster_dg/cli/generate.py | 30 +++--- .../dagster-dg/dagster_dg/cli/info.py | 19 ++-- .../dagster-dg/dagster_dg/cli/list.py | 24 ++--- .../libraries/dagster-dg/dagster_dg/config.py | 39 ++++++++ .../dagster-dg/dagster_dg/context.py | 98 ++++++++++--------- .../dagster-dg/dagster_dg/generate.py | 7 +- .../libraries/dagster-dg/dagster_dg/utils.py | 18 ++-- .../cli_tests/test_generate_commands.py | 4 +- 9 files changed, 156 insertions(+), 96 deletions(-) create mode 100644 python_modules/libraries/dagster-dg/dagster_dg/config.py diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py index fd96f972ad707..ea2e565da889e 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py @@ -3,7 +3,7 @@ from dagster_dg.cli.generate import generate_cli from dagster_dg.cli.info import info_cli from dagster_dg.cli.list import list_cli -from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY, DEFAULT_BUILTIN_COMPONENT_LIB +from dagster_dg.config import DgConfig, set_config_on_cli_context from dagster_dg.version import __version__ @@ -22,14 +22,19 @@ def create_dg_cli(): @click.option( "--builtin-component-lib", type=str, - default=DEFAULT_BUILTIN_COMPONENT_LIB, + default=DgConfig.builtin_component_lib, help="Specify a builitin component library to use.", ) @click.pass_context - def group(context: click.Context, builtin_component_lib: bool): + def group(context: click.Context, builtin_component_lib: str): """CLI tools for working with Dagster components.""" context.ensure_object(dict) - context.obj[CLI_BUILTIN_COMPONENT_LIB_KEY] = builtin_component_lib + set_config_on_cli_context( + context, + DgConfig( + builtin_component_lib=builtin_component_lib, + ), + ) return group diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py index 9f94ea945f4ca..e8111606e41a5 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/generate.py @@ -8,6 +8,7 @@ from dagster_dg.context import ( CodeLocationDirectoryContext, DeploymentDirectoryContext, + DgContext, is_inside_code_location_directory, is_inside_deployment_directory, ) @@ -17,7 +18,6 @@ generate_component_type, generate_deployment, ) -from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="generate") @@ -57,7 +57,10 @@ def generate_deployment_command(path: Path) -> None: " the location of the local Dagster clone will be read from the `DAGSTER_GIT_REPO_DIR` environment variable." ), ) -def generate_code_location_command(name: str, use_editable_dagster: Optional[str]) -> None: +@click.pass_context +def generate_code_location_command( + cli_context: click.Context, name: str, use_editable_dagster: Optional[str] +) -> None: """Generate a Dagster code location file structure and a uv-managed virtual environment scoped to the code location. @@ -81,8 +84,9 @@ def generate_code_location_command(name: str, use_editable_dagster: Optional[str component`). The `.lib` directory holds custom component types scoped to the code location (which can be created with `dg generate component-type`). """ + dg_context = DgContext.from_cli_context(cli_context) if is_inside_deployment_directory(Path.cwd()): - context = DeploymentDirectoryContext.from_path(Path.cwd()) + context = DeploymentDirectoryContext.from_path(Path.cwd(), dg_context) if context.has_code_location(name): click.echo(click.style(f"A code location named {name} already exists.", fg="red")) sys.exit(1) @@ -110,12 +114,14 @@ def generate_code_location_command(name: str, use_editable_dagster: Optional[str @generate_cli.command(name="component-type") @click.argument("name", type=str) -def generate_component_type_command(name: str) -> None: +@click.pass_context +def generate_component_type_command(cli_context: click.Context, name: str) -> None: """Generate a scaffold of a custom Dagster component type. This command must be run inside a Dagster code location directory. The component type scaffold will be generated in submodule `.lib.`. """ + dg_context = DgContext.from_cli_context(cli_context) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -123,7 +129,7 @@ def generate_component_type_command(name: str) -> None: ) ) sys.exit(1) - context = CodeLocationDirectoryContext.from_path(Path.cwd()) + context = CodeLocationDirectoryContext.from_path(Path.cwd(), dg_context) full_component_name = f"{context.name}.{name}" if context.has_component_type(full_component_name): click.echo(click.style(f"A component type named `{name}` already exists.", fg="red")) @@ -142,7 +148,7 @@ def generate_component_type_command(name: str) -> None: @click.argument("extra_args", nargs=-1, type=str) @click.pass_context def generate_component_command( - context: click.Context, + cli_context: click.Context, component_type: str, component_name: str, json_params: Optional[str], @@ -172,7 +178,7 @@ def generate_component_command( It is an error to pass both --json-params and EXTRA_ARGS. """ - builtin_component_lib = context.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) + dg_context = DgContext.from_cli_context(cli_context) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -181,13 +187,13 @@ def generate_component_command( ) sys.exit(1) - dg_context = CodeLocationDirectoryContext.from_path(Path.cwd(), builtin_component_lib) - if not dg_context.has_component_type(component_type): + context = CodeLocationDirectoryContext.from_path(Path.cwd(), dg_context) + if not context.has_component_type(component_type): click.echo( click.style(f"No component type `{component_type}` could be resolved.", fg="red") ) sys.exit(1) - elif dg_context.has_component_instance(component_name): + elif context.has_component_instance(component_name): click.echo( click.style(f"A component instance named `{component_name}` already exists.", fg="red") ) @@ -204,10 +210,10 @@ def generate_component_command( sys.exit(1) generate_component_instance( - Path(dg_context.component_instances_root_path), + Path(context.component_instances_root_path), component_name, component_type, json_params, extra_args, - builtin_component_lib=builtin_component_lib, + dg_context, ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py index 28774eba6c826..f509963606b3d 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/info.py @@ -5,8 +5,11 @@ import click -from dagster_dg.context import CodeLocationDirectoryContext, is_inside_code_location_directory -from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY +from dagster_dg.context import ( + CodeLocationDirectoryContext, + DgContext, + is_inside_code_location_directory, +) @click.group(name="info") @@ -25,14 +28,14 @@ def _serialize_json_schema(schema: Mapping[str, Any]) -> str: @click.option("--component-params-schema", is_flag=True, default=False) @click.pass_context def info_component_type_command( - context: click.Context, + cli_context: click.Context, component_type: str, description: bool, generate_params_schema: bool, component_params_schema: bool, ) -> None: """Get detailed information on a registered Dagster component type.""" - builtin_component_lib = context.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) + dg_context = DgContext.from_cli_context(cli_context) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -41,10 +44,8 @@ def info_component_type_command( ) sys.exit(1) - dg_context = CodeLocationDirectoryContext.from_path( - Path.cwd(), builtin_component_lib=builtin_component_lib - ) - if not dg_context.has_component_type(component_type): + context = CodeLocationDirectoryContext.from_path(Path.cwd(), dg_context) + if not context.has_component_type(component_type): click.echo( click.style(f"No component type `{component_type}` could be resolved.", fg="red") ) @@ -59,7 +60,7 @@ def info_component_type_command( ) sys.exit(1) - component_type_metadata = dg_context.get_component_type(component_type) + component_type_metadata = context.get_component_type(component_type) if description: if component_type_metadata.description: diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py index 24e0f3f10d093..055c5a827079f 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/list.py @@ -6,10 +6,10 @@ from dagster_dg.context import ( CodeLocationDirectoryContext, DeploymentDirectoryContext, + DgContext, is_inside_code_location_directory, is_inside_deployment_directory, ) -from dagster_dg.utils import CLI_BUILTIN_COMPONENT_LIB_KEY @click.group(name="list") @@ -18,24 +18,26 @@ def list_cli(): @list_cli.command(name="code-locations") -def list_code_locations_command() -> None: +@click.pass_context +def list_code_locations_command(cli_context: click.Context) -> None: """List code locations in the current deployment.""" + dg_context = DgContext.from_cli_context(cli_context) if not is_inside_deployment_directory(Path.cwd()): click.echo( click.style("This command must be run inside a Dagster deployment directory.", fg="red") ) sys.exit(1) - context = DeploymentDirectoryContext.from_path(Path.cwd()) + context = DeploymentDirectoryContext.from_path(Path.cwd(), dg_context) for code_location in context.get_code_location_names(): click.echo(code_location) @list_cli.command(name="component-types") @click.pass_context -def list_component_types_command(context: click.Context) -> None: +def list_component_types_command(cli_context: click.Context) -> None: """List registered Dagster components in the current code location environment.""" - builtin_component_lib = context.obj.get(CLI_BUILTIN_COMPONENT_LIB_KEY, False) + dg_context = DgContext.from_cli_context(cli_context) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -44,18 +46,18 @@ def list_component_types_command(context: click.Context) -> None: ) sys.exit(1) - dg_context = CodeLocationDirectoryContext.from_path( - Path.cwd(), builtin_component_lib=builtin_component_lib - ) - for key, component_type in dg_context.iter_component_types(): + context = CodeLocationDirectoryContext.from_path(Path.cwd(), dg_context) + for key, component_type in context.iter_component_types(): click.echo(key) if component_type.summary: click.echo(f" {component_type.summary}") @list_cli.command(name="components") -def list_components_command() -> None: +@click.pass_context +def list_components_command(cli_context: click.Context) -> None: """List Dagster component instances defined in the current code location.""" + dg_context = DgContext.from_cli_context(cli_context) if not is_inside_code_location_directory(Path.cwd()): click.echo( click.style( @@ -64,6 +66,6 @@ def list_components_command() -> None: ) sys.exit(1) - context = CodeLocationDirectoryContext.from_path(Path.cwd()) + context = CodeLocationDirectoryContext.from_path(Path.cwd(), dg_context) for component_name in context.get_component_instance_names(): click.echo(component_name) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/config.py b/python_modules/libraries/dagster-dg/dagster_dg/config.py new file mode 100644 index 0000000000000..1266ff1b050e8 --- /dev/null +++ b/python_modules/libraries/dagster-dg/dagster_dg/config.py @@ -0,0 +1,39 @@ +from dataclasses import dataclass + +import click +from typing_extensions import Self + +from dagster_dg.error import DgError + +DEFAULT_BUILTIN_COMPONENT_LIB = "dagster_components" + + +@dataclass +class DgConfig: + """Global configuration for Dg. + + Attributes: + builitin_component_lib (str): The name of the builtin component library to load. + """ + + builtin_component_lib: str = DEFAULT_BUILTIN_COMPONENT_LIB + + @classmethod + def from_cli_context(cls, cli_context: click.Context) -> Self: + if _CLI_CONTEXT_CONFIG_KEY not in cli_context.obj: + raise DgError( + "Attempted to extract DgConfig from CLI context but nothing stored under designated key `{_CLI_CONTEXT_CONFIG_KEY}`." + ) + return cli_context.obj[_CLI_CONTEXT_CONFIG_KEY] + + @classmethod + def default(cls) -> "DgConfig": + return cls() + + +_CLI_CONTEXT_CONFIG_KEY = "config" + + +def set_config_on_cli_context(cli_context: click.Context, config: DgConfig) -> None: + cli_context.ensure_object(dict) + cli_context.obj[_CLI_CONTEXT_CONFIG_KEY] = config diff --git a/python_modules/libraries/dagster-dg/dagster_dg/context.py b/python_modules/libraries/dagster-dg/dagster_dg/context.py index fbd0186ad7dfd..6cd7aa6aa8add 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/context.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/context.py @@ -1,14 +1,17 @@ import json import os +from dataclasses import dataclass from pathlib import Path from typing import Final, Iterable, Optional, Tuple +import click import tomli from typing_extensions import Self from dagster_dg.component import RemoteComponentRegistry, RemoteComponentType +from dagster_dg.config import DgConfig from dagster_dg.error import DgError -from dagster_dg.utils import DEFAULT_BUILTIN_COMPONENT_LIB, execute_code_location_command +from dagster_dg.utils import execute_code_location_command def is_inside_deployment_directory(path: Path) -> bool: @@ -65,29 +68,44 @@ def _is_code_location_root_directory(path: Path) -> bool: _CODE_LOCATION_COMPONENT_INSTANCES_DIR: Final = "components" -class DeploymentDirectoryContext: +@dataclass +class DgContext: + config: DgConfig + @classmethod - def from_path(cls, path: Path) -> Self: - return cls(root_path=_resolve_deployment_root_directory(path)) + def from_cli_context(cls, cli_context: click.Context) -> Self: + return cls.from_config(config=DgConfig.from_cli_context(cli_context)) - def __init__(self, root_path: Path): - self._root_path = root_path + @classmethod + def from_config(cls, config: DgConfig) -> Self: + return cls(config=config) - @property - def root_path(self) -> Path: - return self._root_path + @classmethod + def default(cls) -> Self: + return cls.from_config(DgConfig.default()) + + +@dataclass +class DeploymentDirectoryContext: + root_path: Path + dg_context: DgContext + + @classmethod + def from_path(cls, path: Path, dg_context: DgContext) -> Self: + return cls(root_path=_resolve_deployment_root_directory(path), dg_context=dg_context) @property def code_location_root_path(self) -> Path: - return self._root_path / _DEPLOYMENT_CODE_LOCATIONS_DIR + return self.root_path / _DEPLOYMENT_CODE_LOCATIONS_DIR def has_code_location(self, name: str) -> bool: - return (self._root_path / "code_locations" / name).is_dir() + return (self.root_path / "code_locations" / name).is_dir() def get_code_location_names(self) -> Iterable[str]: - return [loc.name for loc in sorted((self._root_path / "code_locations").iterdir())] + return [loc.name for loc in sorted((self.root_path / "code_locations").iterdir())] +@dataclass class CodeLocationDirectoryContext: """Class encapsulating contextual information about a components code location directory. @@ -97,15 +115,20 @@ class CodeLocationDirectoryContext: component_registry (ComponentRegistry): The component registry for the code location. deployment_context (Optional[DeploymentDirectoryContext]): The deployment context containing the code location directory. Defaults to None. + dg_context (DgContext): The global application context. """ + root_path: Path + name: str + component_registry: "RemoteComponentRegistry" + deployment_context: Optional[DeploymentDirectoryContext] + dg_context: DgContext + @classmethod - def from_path( - cls, path: Path, builtin_component_lib: str = DEFAULT_BUILTIN_COMPONENT_LIB - ) -> Self: + def from_path(cls, path: Path, dg_context: DgContext) -> Self: root_path = _resolve_code_location_root_directory(path) component_registry_data = execute_code_location_command( - root_path, ["list", "component-types"], builtin_component_lib=builtin_component_lib + root_path, ["list", "component-types"], dg_context ) component_registry = RemoteComponentRegistry.from_dict(json.loads(component_registry_data)) @@ -113,62 +136,43 @@ def from_path( root_path=root_path, name=path.name, component_registry=component_registry, - deployment_context=DeploymentDirectoryContext.from_path(path) + deployment_context=DeploymentDirectoryContext.from_path(path, dg_context) if is_inside_deployment_directory(path) else None, + dg_context=dg_context, ) - def __init__( - self, - root_path: Path, - name: str, - component_registry: "RemoteComponentRegistry", - deployment_context: Optional[DeploymentDirectoryContext], - ): - self._deployment_context = deployment_context - self._root_path = root_path - self._name = name - self._component_registry = component_registry - - @property - def name(self) -> str: - return self._name - - @property - def deployment_context(self) -> Optional[DeploymentDirectoryContext]: - return self._deployment_context - @property - def component_registry(self) -> "RemoteComponentRegistry": - return self._component_registry + def config(self) -> DgConfig: + return self.dg_context.config @property def local_component_types_root_path(self) -> str: - return os.path.join(self._root_path, self._name, _CODE_LOCATION_CUSTOM_COMPONENTS_DIR) + return os.path.join(self.root_path, self.name, _CODE_LOCATION_CUSTOM_COMPONENTS_DIR) @property def local_component_types_root_module_name(self) -> str: - return f"{self._name}.{_CODE_LOCATION_CUSTOM_COMPONENTS_DIR}" + return f"{self.name}.{_CODE_LOCATION_CUSTOM_COMPONENTS_DIR}" def iter_component_types(self) -> Iterable[Tuple[str, RemoteComponentType]]: - for key in sorted(self._component_registry.keys()): - yield key, self._component_registry.get(key) + for key in sorted(self.component_registry.keys()): + yield key, self.component_registry.get(key) def has_component_type(self, name: str) -> bool: - return self._component_registry.has(name) + return self.component_registry.has(name) def get_component_type(self, name: str) -> RemoteComponentType: if not self.has_component_type(name): raise DgError(f"No component type named {name}") - return self._component_registry.get(name) + return self.component_registry.get(name) @property def component_instances_root_path(self) -> Path: - return self._root_path / self._name / _CODE_LOCATION_COMPONENT_INSTANCES_DIR + return self.root_path / self.name / _CODE_LOCATION_COMPONENT_INSTANCES_DIR @property def component_instances_root_module_name(self) -> str: - return f"{self._name}.{_CODE_LOCATION_COMPONENT_INSTANCES_DIR}" + return f"{self.name}.{_CODE_LOCATION_COMPONENT_INSTANCES_DIR}" def get_component_instance_names(self) -> Iterable[str]: return [ diff --git a/python_modules/libraries/dagster-dg/dagster_dg/generate.py b/python_modules/libraries/dagster-dg/dagster_dg/generate.py index c00901332c158..46a198f56f7a7 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/generate.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/generate.py @@ -6,9 +6,8 @@ import click -from dagster_dg.context import CodeLocationDirectoryContext +from dagster_dg.context import CodeLocationDirectoryContext, DgContext from dagster_dg.utils import ( - DEFAULT_BUILTIN_COMPONENT_LIB, camelcase, execute_code_location_command, generate_subtree, @@ -151,7 +150,7 @@ def generate_component_instance( component_type: str, json_params: Optional[str], extra_args: Tuple[str, ...], - builtin_component_lib: str = DEFAULT_BUILTIN_COMPONENT_LIB, + dg_context: "DgContext", ) -> None: component_instance_root_path = root_path / name click.echo(f"Creating a Dagster component instance folder at {component_instance_root_path}.") @@ -167,5 +166,5 @@ def generate_component_instance( execute_code_location_command( Path(component_instance_root_path), code_location_command, - builtin_component_lib=builtin_component_lib, + dg_context, ) diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index b0d2c917ff7d3..79f69e95ffacd 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -5,26 +5,30 @@ import subprocess import sys from pathlib import Path -from typing import Any, Final, Iterator, List, Mapping, Optional, Sequence, Union +from typing import TYPE_CHECKING, Any, Final, Iterator, List, Mapping, Optional, Sequence, Union import click import jinja2 from dagster_dg.version import __version__ as dagster_version -CLI_BUILTIN_COMPONENT_LIB_KEY = "builtin_component_lib" -DEFAULT_BUILTIN_COMPONENT_LIB: Final = "dagster_components" +if TYPE_CHECKING: + from dagster_dg.context import DgContext + +CLI_CONFIG_KEY = "config" _CODE_LOCATION_COMMAND_PREFIX: Final = ["uv", "run", "dagster-components"] -def execute_code_location_command( - path: Path, cmd: Sequence[str], builtin_component_lib: Optional[str] = None -) -> str: +def execute_code_location_command(path: Path, cmd: Sequence[str], dg_context: "DgContext") -> str: full_cmd = [ *_CODE_LOCATION_COMMAND_PREFIX, - *(["--builtin-component-lib", builtin_component_lib] if builtin_component_lib else []), + *( + ["--builtin-component-lib", dg_context.config.builtin_component_lib] + if dg_context.config.builtin_component_lib + else [] + ), *cmd, ] with pushd(path): diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 4158671adf31e..3e149a59abe38 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -7,7 +7,7 @@ import tomli from click.testing import CliRunner from dagster_dg.cli import cli as dg_cli -from dagster_dg.context import CodeLocationDirectoryContext +from dagster_dg.context import CodeLocationDirectoryContext, DgContext from dagster_dg.utils import discover_git_root, ensure_dagster_dg_tests_import ensure_dagster_dg_tests_import() @@ -142,7 +142,7 @@ def test_generate_component_type_success(in_deployment: bool) -> None: result = runner.invoke("generate", "component-type", "baz") assert_runner_result(result) assert Path("bar/lib/baz.py").exists() - context = CodeLocationDirectoryContext.from_path(Path.cwd()) + context = CodeLocationDirectoryContext.from_path(Path.cwd(), DgContext.default()) assert context.has_component_type("bar.baz") From 6edff7496f529dbbe412cd48950e7a8ee3374212 Mon Sep 17 00:00:00 2001 From: Sean Mackesey Date: Tue, 17 Dec 2024 15:48:20 -0500 Subject: [PATCH 75/94] [components] Add cache to dagster-dg (#26517) ## Summary & Motivation Initial implementation of a cache for `dagster-dg`. Currently just caches the registered components for a code location. Cache key is (code loc abs path, env hash, type of payload). The environment hash is calculated over the file metadata of `uv.lock` and the content of `pkg.lib` (i.e. where local component types can be defined). ## How I Tested These Changes New unit tests + manual testing (running `dg list component-types` multiple times in the same code loc, observing speedup). --- .../libraries/dagster-dg/dagster_dg/cache.py | 74 +++++++++++++++ .../dagster-dg/dagster_dg/cli/__init__.py | 59 ++++++++++-- .../libraries/dagster-dg/dagster_dg/config.py | 21 +++++ .../dagster-dg/dagster_dg/context.py | 58 ++++++++++-- .../libraries/dagster-dg/dagster_dg/utils.py | 23 +++++ .../cli_tests/test_generate_commands.py | 71 ++++++-------- .../cli_tests/test_info_commands.py | 15 +-- .../cli_tests/test_list_commands.py | 18 ++-- .../dagster-dg/dagster_dg_tests/test_cache.py | 93 +++++++++++++++++++ .../dagster-dg/dagster_dg_tests/utils.py | 21 ++++- 10 files changed, 372 insertions(+), 81 deletions(-) create mode 100644 python_modules/libraries/dagster-dg/dagster_dg/cache.py create mode 100644 python_modules/libraries/dagster-dg/dagster_dg_tests/test_cache.py diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cache.py b/python_modules/libraries/dagster-dg/dagster_dg/cache.py new file mode 100644 index 0000000000000..71afef32046e9 --- /dev/null +++ b/python_modules/libraries/dagster-dg/dagster_dg/cache.py @@ -0,0 +1,74 @@ +import shutil +import sys +from pathlib import Path +from typing import Final, Literal, Optional, Tuple + +from typing_extensions import Self, TypeAlias + +from dagster_dg.config import DgConfig + +_CACHE_CONTAINER_DIR_NAME: Final = "dg-cache" + +CachableDataType: TypeAlias = Literal["component_registry_data"] + + +def get_default_cache_dir() -> Path: + if sys.platform == "win32": + return Path.home() / "AppData" / "dg" / "cache" + elif sys.platform == "darwin": + return Path.home() / "Library" / "Caches" / "dg" + else: + return Path.home() / ".cache" / "dg" + + +class DgCache: + @classmethod + def from_default(cls) -> Self: + return cls.from_parent_path(get_default_cache_dir()) + + @classmethod + def from_config(cls, config: DgConfig) -> Self: + return cls.from_parent_path( + parent_path=config.cache_dir, + logging_enabled=config.verbose, + ) + + # This is the preferred constructor to use when creating a cache. It ensures that all data is + # stored inside an additional container directory inside the user-specified cache directory. + # When we clear the cache, we only delete this container directory. This is to avoid accidents + # when the user mistakenly specifies a cache directory that contains other data. + @classmethod + def from_parent_path(cls, parent_path: Path, logging_enabled: bool = False) -> Self: + root_path = parent_path / _CACHE_CONTAINER_DIR_NAME + return cls(root_path, logging_enabled) + + def __init__(self, root_path: Path, logging_enabled: bool): + self._root_path = root_path + self._root_path.mkdir(parents=True, exist_ok=True) + self._logging_enabled = logging_enabled + + def clear(self) -> None: + shutil.rmtree(self._root_path) + self.log(f"CACHE [clear]: {self._root_path}") + + def get(self, key: Tuple[str, ...]) -> Optional[str]: + path = self._get_path(key) + if path.exists(): + self.log(f"CACHE [hit]: {path}") + return path.read_text() + else: + self.log(f"CACHE [miss]: {path}") + return None + + def set(self, key: Tuple[str, ...], value: str) -> None: + path = self._get_path(key) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(value) + self.log(f"CACHE [write]: {path}") + + def _get_path(self, key: Tuple[str, ...]) -> Path: + return Path(self._root_path, *key) + + def log(self, message: str) -> None: + if self._logging_enabled: + print(message) # noqa: T201 diff --git a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py index ea2e565da889e..d8cd4041ec23c 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/cli/__init__.py @@ -1,5 +1,8 @@ +from pathlib import Path + import click +from dagster_dg.cache import DgCache from dagster_dg.cli.generate import generate_cli from dagster_dg.cli.info import info_cli from dagster_dg.cli.list import list_cli @@ -14,27 +17,69 @@ def create_dg_cli(): "list": list_cli, } + # Defaults are defined on the DgConfig object. @click.group( commands=commands, context_settings={"max_content_width": 120, "help_option_names": ["-h", "--help"]}, + invoke_without_command=True, ) - @click.version_option(__version__, "--version", "-v") @click.option( "--builtin-component-lib", type=str, default=DgConfig.builtin_component_lib, help="Specify a builitin component library to use.", ) + @click.option( + "--verbose", + is_flag=True, + default=DgConfig.verbose, + help="Enable verbose output for debugging.", + ) + @click.option( + "--disable-cache", + is_flag=True, + default=DgConfig.disable_cache, + help="Disable caching of component registry data.", + ) + @click.option( + "--clear-cache", + is_flag=True, + help="Clear the cache before running the command.", + default=False, + ) + @click.option( + "--cache-dir", + type=Path, + default=DgConfig.cache_dir, + help="Specify a directory to use for the cache.", + ) + @click.version_option(__version__, "--version", "-v") @click.pass_context - def group(context: click.Context, builtin_component_lib: str): + def group( + context: click.Context, + builtin_component_lib: str, + verbose: bool, + disable_cache: bool, + cache_dir: Path, + clear_cache: bool, + ): """CLI tools for working with Dagster components.""" context.ensure_object(dict) - set_config_on_cli_context( - context, - DgConfig( - builtin_component_lib=builtin_component_lib, - ), + config = DgConfig( + builtin_component_lib=builtin_component_lib, + verbose=verbose, + disable_cache=disable_cache, + cache_dir=cache_dir, ) + if clear_cache: + DgCache.from_config(config).clear() + if context.invoked_subcommand is None: + context.exit(0) + elif context.invoked_subcommand is None: + click.echo(context.get_help()) + context.exit(0) + + set_config_on_cli_context(context, config) return group diff --git a/python_modules/libraries/dagster-dg/dagster_dg/config.py b/python_modules/libraries/dagster-dg/dagster_dg/config.py index 1266ff1b050e8..d5a7abd9adaa4 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/config.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/config.py @@ -1,4 +1,6 @@ +import sys from dataclasses import dataclass +from pathlib import Path import click from typing_extensions import Self @@ -8,14 +10,33 @@ DEFAULT_BUILTIN_COMPONENT_LIB = "dagster_components" +def _get_default_cache_dir() -> Path: + if sys.platform == "win32": + return Path.home() / "AppData" / "dg" / "cache" + elif sys.platform == "darwin": + return Path.home() / "Library" / "Caches" / "dg" + else: + return Path.home() / ".cache" / "dg" + + +DEFAULT_CACHE_DIR = _get_default_cache_dir() + + @dataclass class DgConfig: """Global configuration for Dg. Attributes: + disable_cache (bool): If True, disable caching. Defaults to False. + cache_dir (Optional[str]): The directory to use for caching. If None, the default cache will + be used. + verbose (bool): If True, log debug information. builitin_component_lib (str): The name of the builtin component library to load. """ + disable_cache: bool = False + cache_dir: Path = DEFAULT_CACHE_DIR + verbose: bool = False builtin_component_lib: str = DEFAULT_BUILTIN_COMPONENT_LIB @classmethod diff --git a/python_modules/libraries/dagster-dg/dagster_dg/context.py b/python_modules/libraries/dagster-dg/dagster_dg/context.py index 6cd7aa6aa8add..af25fcd73ff06 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/context.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/context.py @@ -1,3 +1,4 @@ +import hashlib import json import os from dataclasses import dataclass @@ -8,10 +9,15 @@ import tomli from typing_extensions import Self +from dagster_dg.cache import CachableDataType, DgCache from dagster_dg.component import RemoteComponentRegistry, RemoteComponentType from dagster_dg.config import DgConfig from dagster_dg.error import DgError -from dagster_dg.utils import execute_code_location_command +from dagster_dg.utils import ( + execute_code_location_command, + hash_directory_metadata, + hash_file_metadata, +) def is_inside_deployment_directory(path: Path) -> bool: @@ -64,13 +70,14 @@ def _is_code_location_root_directory(path: Path) -> bool: _DEPLOYMENT_CODE_LOCATIONS_DIR: Final = "code_locations" # Code location -_CODE_LOCATION_CUSTOM_COMPONENTS_DIR: Final = "lib" +_CODE_LOCATION_COMPONENTS_LIB_DIR: Final = "lib" _CODE_LOCATION_COMPONENT_INSTANCES_DIR: Final = "components" @dataclass class DgContext: config: DgConfig + cache: Optional[DgCache] = None @classmethod def from_cli_context(cls, cli_context: click.Context) -> Self: @@ -78,7 +85,8 @@ def from_cli_context(cls, cli_context: click.Context) -> Self: @classmethod def from_config(cls, config: DgConfig) -> Self: - return cls(config=config) + cache = None if config.disable_cache else DgCache.from_config(config) + return cls(config=config, cache=cache) @classmethod def default(cls) -> Self: @@ -105,6 +113,27 @@ def get_code_location_names(self) -> Iterable[str]: return [loc.name for loc in sorted((self.root_path / "code_locations").iterdir())] +def get_code_location_env_hash(code_location_root_path: Path) -> str: + uv_lock_path = code_location_root_path / "uv.lock" + if not uv_lock_path.exists(): + raise DgError(f"uv.lock file not found in {code_location_root_path}") + local_components_path = ( + code_location_root_path / code_location_root_path.name / _CODE_LOCATION_COMPONENTS_LIB_DIR + ) + if not local_components_path.exists(): + raise DgError(f"Local components directory not found in {code_location_root_path}") + hasher = hashlib.md5() + hash_file_metadata(hasher, uv_lock_path) + hash_directory_metadata(hasher, local_components_path) + return hasher.hexdigest() + + +def make_cache_key(code_location_path: Path, data_type: CachableDataType) -> Tuple[str, str, str]: + path_parts = [str(part) for part in code_location_path.parts if part != "/"] + env_hash = get_code_location_env_hash(code_location_path) + return ("_".join(path_parts), env_hash, data_type) + + @dataclass class CodeLocationDirectoryContext: """Class encapsulating contextual information about a components code location directory. @@ -127,10 +156,21 @@ class CodeLocationDirectoryContext: @classmethod def from_path(cls, path: Path, dg_context: DgContext) -> Self: root_path = _resolve_code_location_root_directory(path) - component_registry_data = execute_code_location_command( - root_path, ["list", "component-types"], dg_context - ) - component_registry = RemoteComponentRegistry.from_dict(json.loads(component_registry_data)) + + cache = dg_context.cache + if cache: + cache_key = make_cache_key(root_path, "component_registry_data") + + raw_registry_data = cache.get(cache_key) if cache else None + if not raw_registry_data: + raw_registry_data = execute_code_location_command( + root_path, ["list", "component-types"], dg_context + ) + if cache: + cache.set(cache_key, raw_registry_data) + + registry_data = json.loads(raw_registry_data) + component_registry = RemoteComponentRegistry.from_dict(registry_data) return cls( root_path=root_path, @@ -148,11 +188,11 @@ def config(self) -> DgConfig: @property def local_component_types_root_path(self) -> str: - return os.path.join(self.root_path, self.name, _CODE_LOCATION_CUSTOM_COMPONENTS_DIR) + return os.path.join(self.root_path, self.name, _CODE_LOCATION_COMPONENTS_LIB_DIR) @property def local_component_types_root_module_name(self) -> str: - return f"{self.name}.{_CODE_LOCATION_CUSTOM_COMPONENTS_DIR}" + return f"{self.name}.{_CODE_LOCATION_COMPONENTS_LIB_DIR}" def iter_component_types(self) -> Iterable[Tuple[str, RemoteComponentType]]: for key in sorted(self.component_registry.keys()): diff --git a/python_modules/libraries/dagster-dg/dagster_dg/utils.py b/python_modules/libraries/dagster-dg/dagster_dg/utils.py index 79f69e95ffacd..57be0cc34e53f 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg/utils.py @@ -4,14 +4,20 @@ import re import subprocess import sys +from fnmatch import fnmatch from pathlib import Path from typing import TYPE_CHECKING, Any, Final, Iterator, List, Mapping, Optional, Sequence, Union import click import jinja2 +from typing_extensions import TypeAlias from dagster_dg.version import __version__ as dagster_version +# There is some weirdness concerning the availabilty of hashlib.HASH between different Python +# versions, so for nowe we avoid trying to import it and just alias the type to Any. +Hash: TypeAlias = Any + if TYPE_CHECKING: from dagster_dg.context import DgContext @@ -84,6 +90,7 @@ def snakecase(string: str) -> str: "__pycache__", ".pytest_cache", "*.egg-info", + "*.cpython-*", ".DS_Store", ".ruff_cache", "tox.ini", @@ -188,3 +195,19 @@ def ensure_dagster_dg_tests_import() -> None: dagster_dg_package_root / "dagster_dg_tests" ).exists(), "Could not find dagster_dg_tests where expected" sys.path.append(dagster_dg_package_root.as_posix()) + + +def hash_directory_metadata(hasher: Hash, path: Union[str, Path]) -> None: + for root, dirs, files in os.walk(path): + for name in dirs + files: + if any(fnmatch(name, pattern) for pattern in _DEFAULT_EXCLUDES): + continue + filepath = os.path.join(root, name) + hash_file_metadata(hasher, filepath) + + +def hash_file_metadata(hasher: Hash, path: Union[str, Path]) -> None: + stat = os.stat(path=path) + hasher.update(str(path).encode()) + hasher.update(str(stat.st_mtime).encode()) # Last modified time + hasher.update(str(stat.st_size).encode()) # File size diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py index 3e149a59abe38..7db275b8b0b92 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_generate_commands.py @@ -5,8 +5,6 @@ import pytest import tomli -from click.testing import CliRunner -from dagster_dg.cli import cli as dg_cli from dagster_dg.context import CodeLocationDirectoryContext, DgContext from dagster_dg.utils import discover_git_root, ensure_dagster_dg_tests_import @@ -21,8 +19,7 @@ def test_generate_deployment_command_success() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): result = runner.invoke("generate", "deployment", "foo") assert_runner_result(result) assert Path("foo").exists() @@ -34,8 +31,7 @@ def test_generate_deployment_command_success() -> None: def test_generate_deployment_command_already_exists_fails() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): os.mkdir("foo") result = runner.invoke("generate", "deployment", "foo") assert_runner_result(result, exit_0=False) @@ -43,8 +39,7 @@ def test_generate_deployment_command_already_exists_fails() -> None: def test_generate_code_location_inside_deployment_success() -> None: - runner = ProxyRunner.test() - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): result = runner.invoke("generate", "code-location", "bar") assert_runner_result(result) assert Path("code_locations/bar").exists() @@ -66,8 +61,7 @@ def test_generate_code_location_inside_deployment_success() -> None: def test_generate_code_location_outside_deployment_success() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): result = runner.invoke("generate", "code-location", "bar") assert_runner_result(result) assert Path("bar").exists() @@ -84,14 +78,13 @@ def test_generate_code_location_outside_deployment_success() -> None: @pytest.mark.parametrize("mode", ["env_var", "arg"]) def test_generate_code_location_editable_dagster_success(mode: str, monkeypatch) -> None: - runner = ProxyRunner.test() dagster_git_repo_dir = discover_git_root(Path(__file__)) if mode == "env_var": monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", str(dagster_git_repo_dir)) editable_args = ["--use-editable-dagster", "--"] else: editable_args = ["--use-editable-dagster", str(dagster_git_repo_dir)] - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): result = runner.invoke("generate", "code-location", *editable_args, "bar") assert_runner_result(result) assert Path("code_locations/bar").exists() @@ -117,17 +110,15 @@ def test_generate_code_location_editable_dagster_success(mode: str, monkeypatch) def test_generate_code_location_editable_dagster_no_env_var_no_value_fails(monkeypatch) -> None: - runner = ProxyRunner.test() monkeypatch.setenv("DAGSTER_GIT_REPO_DIR", "") - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): result = runner.invoke("generate", "code-location", "--use-editable-dagster", "--", "bar") assert_runner_result(result, exit_0=False) assert "requires the `DAGSTER_GIT_REPO_DIR`" in result.output def test_generate_code_location_already_exists_fails() -> None: - runner = ProxyRunner.test() - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): result = runner.invoke("generate", "code-location", "bar") assert_runner_result(result) result = runner.invoke("generate", "code-location", "bar") @@ -137,8 +128,7 @@ def test_generate_code_location_already_exists_fails() -> None: @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_type_success(in_deployment: bool) -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner, in_deployment): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke("generate", "component-type", "baz") assert_runner_result(result) assert Path("bar/lib/baz.py").exists() @@ -147,8 +137,7 @@ def test_generate_component_type_success(in_deployment: bool) -> None: def test_generate_component_type_outside_code_location_fails() -> None: - runner = ProxyRunner.test() - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): result = runner.invoke("generate", "component-type", "baz") assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output @@ -156,8 +145,7 @@ def test_generate_component_type_outside_code_location_fails() -> None: @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_type_already_exists_fails(in_deployment: bool) -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner, in_deployment): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke("generate", "component-type", "baz") assert_runner_result(result) result = runner.invoke("generate", "component-type", "baz") @@ -167,8 +155,7 @@ def test_generate_component_type_already_exists_fails(in_deployment: bool) -> No @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_no_params_success(in_deployment: bool) -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner, in_deployment): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke( "generate", "component", @@ -187,8 +174,7 @@ def test_generate_component_no_params_success(in_deployment: bool) -> None: @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_json_params_success(in_deployment: bool) -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner, in_deployment): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke( "generate", "component", @@ -210,8 +196,7 @@ def test_generate_component_json_params_success(in_deployment: bool) -> None: @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_extra_args_success(in_deployment: bool) -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner, in_deployment): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke( "generate", "component", @@ -233,8 +218,7 @@ def test_generate_component_extra_args_success(in_deployment: bool) -> None: def test_generate_component_json_params_and_extra_args_fails() -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke( "generate", "component", @@ -250,8 +234,7 @@ def test_generate_component_json_params_and_extra_args_fails() -> None: def test_generate_component_outside_code_location_fails() -> None: - runner = ProxyRunner.test() - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): result = runner.invoke("generate", "component", "bar.baz", "qux") assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output @@ -259,8 +242,7 @@ def test_generate_component_outside_code_location_fails() -> None: @pytest.mark.parametrize("in_deployment", [True, False]) def test_generate_component_already_exists_fails(in_deployment: bool) -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner, in_deployment): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner, in_deployment): result = runner.invoke( "generate", "component", @@ -284,15 +266,17 @@ def test_generate_component_already_exists_fails(in_deployment: bool) -> None: def test_generate_sling_replication_instance() -> None: - runner = CliRunner() - with isolated_example_code_location_bar(runner): + with ( + ProxyRunner.test(use_test_component_lib=False) as runner, + isolated_example_code_location_bar(runner), + ): # We need to add dagster-embedded-elt also because we are using editable installs. Only # direct dependencies will be resolved by uv.tool.sources. subprocess.run( ["uv", "add", "dagster-components[sling]", "dagster-embedded-elt"], check=True ) result = runner.invoke( - dg_cli, ["generate", "component", "dagster_components.sling_replication", "file_ingest"] + "generate", "component", "dagster_components.sling_replication", "file_ingest" ) assert_runner_result(result) assert Path("bar/components/file_ingest").exists() @@ -317,14 +301,19 @@ def test_generate_sling_replication_instance() -> None: ], ) def test_generate_dbt_project_instance(params) -> None: - runner = CliRunner() - with isolated_example_code_location_bar(runner): + with ( + ProxyRunner.test(use_test_component_lib=False) as runner, + isolated_example_code_location_bar(runner), + ): # We need to add dagster-dbt also because we are using editable installs. Only # direct dependencies will be resolved by uv.tool.sources. subprocess.run(["uv", "add", "dagster-components[dbt]", "dagster-dbt"], check=True) result = runner.invoke( - dg_cli, - ["generate", "component", "dagster_components.dbt_project", "my_project", *params], + "generate", + "component", + "dagster_components.dbt_project", + "my_project", + *params, ) assert_runner_result(result) assert Path("bar/components/my_project").exists() diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py index eb4305fae02ca..27d9005156ccb 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_info_commands.py @@ -12,8 +12,7 @@ def test_info_component_type_all_metadata_success(): - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke( "info", "component-type", @@ -77,8 +76,7 @@ def test_info_component_type_all_metadata_success(): def test_info_component_type_all_metadata_empty_success(): - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke( "info", "component-type", @@ -94,8 +92,7 @@ def test_info_component_type_all_metadata_empty_success(): def test_info_component_type_flag_fields_success(): - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke( "info", "component-type", @@ -176,8 +173,7 @@ def test_info_component_type_flag_fields_success(): def test_info_component_type_outside_code_location_fails() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): result = runner.invoke( "info", "component-type", @@ -189,8 +185,7 @@ def test_info_component_type_outside_code_location_fails() -> None: def test_info_component_type_multiple_flags_fails() -> None: - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke( "info", "component-type", diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py index 5d9adb3a17d15..abb22d8934b93 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/cli_tests/test_list_commands.py @@ -13,8 +13,7 @@ def test_list_code_locations_success(): - runner = ProxyRunner.test() - with isolated_example_deployment_foo(runner): + with ProxyRunner.test() as runner, isolated_example_deployment_foo(runner): runner.invoke("generate", "code-location", "foo") runner.invoke("generate", "code-location", "bar") result = runner.invoke("list", "code-locations") @@ -29,16 +28,14 @@ def test_list_code_locations_success(): def test_list_code_locations_outside_deployment_fails() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): result = runner.invoke("list", "code-locations") assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster deployment directory" in result.output def test_list_component_types_success(): - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke("list", "component-types") assert_runner_result(result) assert ( @@ -54,16 +51,14 @@ def test_list_component_types_success(): def test_list_component_types_outside_code_location_fails() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): result = runner.invoke("list", "component-types") assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output def test_list_components_succeeds(): - runner = ProxyRunner.test() - with isolated_example_code_location_bar(runner): + with ProxyRunner.test() as runner, isolated_example_code_location_bar(runner): result = runner.invoke( "generate", "component", @@ -82,8 +77,7 @@ def test_list_components_succeeds(): def test_list_components_command_outside_code_location_fails() -> None: - runner = ProxyRunner.test() - with runner.isolated_filesystem(): + with ProxyRunner.test() as runner, runner.isolated_filesystem(): result = runner.invoke("list", "components") assert_runner_result(result, exit_0=False) assert "must be run inside a Dagster code location directory" in result.output diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/test_cache.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/test_cache.py new file mode 100644 index 0000000000000..4636259c921fc --- /dev/null +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/test_cache.py @@ -0,0 +1,93 @@ +import subprocess +from pathlib import Path + +import pytest + +from dagster_dg_tests.utils import ( + ProxyRunner, + assert_runner_result, + isolated_example_code_location_bar, +) + + +def test_load_from_cache(): + with ProxyRunner.test(verbose=True) as runner, isolated_example_code_location_bar(runner): + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + assert "CACHE [write]" in result.output + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [hit]" in result.output + + +def test_cache_invalidation_uv_lock(): + with ProxyRunner.test(verbose=True) as runner, isolated_example_code_location_bar(runner): + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + assert "CACHE [write]" in result.output + + subprocess.run(["uv", "add", "dagster-components[dbt]"], check=True) + + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + + +def test_cache_invalidation_modified_lib(): + with ProxyRunner.test(verbose=True) as runner, isolated_example_code_location_bar(runner): + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + assert "CACHE [write]" in result.output + + result = runner.invoke("generate", "component-type", "my_component") + assert_runner_result(result) + + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + + +def test_cache_no_invalidation_modified_pkg(): + with ProxyRunner.test(verbose=True) as runner, isolated_example_code_location_bar(runner): + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + assert "CACHE [write]" in result.output + + Path("bar/submodule.py").write_text("print('hello')") + + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [hit]" in result.output + + +@pytest.mark.parametrize("with_command", [True, False]) +def test_cache_clear(with_command: bool): + with ProxyRunner.test(verbose=True) as runner, isolated_example_code_location_bar(runner): + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE [miss]" in result.output + assert "CACHE [write]" in result.output + + if with_command: + result = runner.invoke("--clear-cache", "list", "component-types") + else: + result = runner.invoke("--clear-cache") + assert_runner_result(result) + result = runner.invoke("list", "component-types") + + assert_runner_result(result) + assert "CACHE [miss]" in result.output + + +def test_cache_disabled(): + with ( + ProxyRunner.test(verbose=True, disable_cache=True) as runner, + isolated_example_code_location_bar(runner), + ): + result = runner.invoke("list", "component-types") + assert_runner_result(result) + assert "CACHE" not in result.output diff --git a/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py b/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py index 0d32afe12494c..d3628b5e229ed 100644 --- a/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py +++ b/python_modules/libraries/dagster-dg/dagster_dg_tests/utils.py @@ -2,12 +2,14 @@ from contextlib import contextmanager from dataclasses import dataclass from pathlib import Path +from tempfile import TemporaryDirectory from types import TracebackType from typing import Iterator, Optional, Sequence, Tuple, Type, Union from click.testing import CliRunner, Result from dagster_dg.cli import cli as dg_cli from dagster_dg.utils import discover_git_root, pushd +from typing_extensions import Self @contextmanager @@ -55,8 +57,23 @@ class ProxyRunner: prepend_args: Optional[Sequence[str]] = None @classmethod - def test(cls): - return cls(CliRunner(), ["--builtin-component-lib", "dagster_components.test"]) + @contextmanager + def test( + cls, use_test_component_lib: bool = True, verbose: bool = False, disable_cache: bool = False + ) -> Iterator[Self]: + with TemporaryDirectory() as cache_dir: + prepend_args = [ + *( + ["--builtin-component-lib", "dagster_components.test"] + if use_test_component_lib + else [] + ), + "--cache-dir", + str(cache_dir), + *(["--verbose"] if verbose else []), + *(["--disable-cache"] if disable_cache else []), + ] + yield cls(CliRunner(), prepend_args=prepend_args) def invoke(self, *args: str): all_args = [*(self.prepend_args or []), *args] From 1ca47d01c4b5532749679f5130a4272b910e76b5 Mon Sep 17 00:00:00 2001 From: Anurag Anjaria Date: Tue, 17 Dec 2024 16:20:11 -0500 Subject: [PATCH 76/94] Add sql syntax highlighting to dbt asset descriptions (#26393) ## Summary & Motivation Adds SQL syntax highlighting to raw sql code in dbt asset descriptions. Only for dbt assets, when the dbt asset exposes the raw sql. ## How I Tested These Changes Spun up the sample dbt project and navigated to a dbt asset. The sql code in the description has syntax highlighting. Light mode: image Dark mode: image > @salazarm we had discussed using custom CSS to make the blue text stand out more in dark mode, but it appears to be fairly readable in my browser. Let me know if you feel we still need custom CSS here. ## Changelog > Not sure if this needs a changelog? I can add one if necessary. --- python_modules/libraries/dagster-dbt/dagster_dbt/asset_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_modules/libraries/dagster-dbt/dagster_dbt/asset_utils.py b/python_modules/libraries/dagster-dbt/dagster_dbt/asset_utils.py index 5b2d8f9cb7d5b..68fdaea3e2629 100644 --- a/python_modules/libraries/dagster-dbt/dagster_dbt/asset_utils.py +++ b/python_modules/libraries/dagster-dbt/dagster_dbt/asset_utils.py @@ -573,7 +573,7 @@ def default_description_fn(dbt_resource_props: Mapping[str, Any], display_raw_sq or f"dbt {dbt_resource_props['resource_type']} {dbt_resource_props['name']}", ] if display_raw_sql: - description_sections.append(f"#### Raw SQL:\n```\n{code_block}\n```") + description_sections.append(f"#### Raw SQL:\n```sql\n{code_block}\n```") return "\n\n".join(filter(None, description_sections)) From 8b83349e720ea273fa1cc1e1d7d552883f777554 Mon Sep 17 00:00:00 2001 From: Anurag Anjaria Date: Tue, 17 Dec 2024 16:23:40 -0500 Subject: [PATCH 77/94] Add custom colors to markdown code block for syntax highlighting (#26554) ## Summary & Motivation Default syntax highlighting colors from `highlight.js` were not always clearly visible in dark mode. Adding our custom colors improves the contrast and ensures we'll always have good contrast in light and dark mode. ## How I Tested These Changes run `dagster dev` on the sample dbt project and look at dbt asset descriptions. Below are screenshots of various sql code blocks from the dbt asset descriptions, illustrating the new colors in light and dark mode. ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/DyC7O5ZxCGGdPTWXzKVQ/b551ca49-bcf6-4f36-adf0-2389377b82fe.png) ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/DyC7O5ZxCGGdPTWXzKVQ/2c545b00-d04f-4178-aa0b-f32ac139c4ca.png) ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/DyC7O5ZxCGGdPTWXzKVQ/91bfe071-ca6d-4f15-862d-1af9ee5e0c11.png) ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/DyC7O5ZxCGGdPTWXzKVQ/2918b815-dd8d-4317-8f62-9c643133e117.png) ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/DyC7O5ZxCGGdPTWXzKVQ/dc19ca55-4e47-4f77-a90e-ab092aa0c1fa.png) ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/DyC7O5ZxCGGdPTWXzKVQ/f5e48aae-177e-47b1-aab3-a79c6a986dc7.png) ## Changelog > Insert changelog entry or delete this section. --- .../ui-core/src/pipelines/Description.tsx | 2 +- .../ui-core/src/ui/MarkdownWithPlugins.tsx | 46 ++++++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/pipelines/Description.tsx b/js_modules/dagster-ui/packages/ui-core/src/pipelines/Description.tsx index d44e41b7178ed..ba9834a38808c 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/pipelines/Description.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/pipelines/Description.tsx @@ -91,7 +91,7 @@ export const Description = ({maxHeight, description, fontSize}: IDescriptionProp )}
- {removeLeadingSpaces(description.replace('```', '```sql'))} + {removeLeadingSpaces(description)}
); diff --git a/js_modules/dagster-ui/packages/ui-core/src/ui/MarkdownWithPlugins.tsx b/js_modules/dagster-ui/packages/ui-core/src/ui/MarkdownWithPlugins.tsx index 835c306b35374..d4050b7c3f0a2 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/ui/MarkdownWithPlugins.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/ui/MarkdownWithPlugins.tsx @@ -1,8 +1,9 @@ +import {Colors} from '@dagster-io/ui-components'; import ReactMarkdown from 'react-markdown'; import rehypeHighlight from 'rehype-highlight'; import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'; import gfm from 'remark-gfm'; - +import {createGlobalStyle} from 'styled-components'; import 'highlight.js/styles/github.css'; const sanitizeConfig = { @@ -62,17 +63,50 @@ const sanitizeConfig = { }, }; +const GlobalStyle = createGlobalStyle` +.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_ { + color: ${Colors.accentRed()} +} + +.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_ { + color: ${Colors.dataVizBlurple()} +} + +.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable { + color: ${Colors.dataVizBlue()} +} + +.hljs-meta .hljs-string,.hljs-regexp,.hljs-string { + color: ${Colors.accentBlue()} +} + +.hljs-built_in,.hljs-symbol { + color: ${Colors.dataVizOrange()} +} + +.hljs-code,.hljs-comment,.hljs-formula { + color: ${Colors.dataVizGray()} +} + +.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag { + color: ${Colors.dataVizGreen()} +} +`; + interface Props { children: string; } export const MarkdownWithPlugins = (props: Props) => { return ( - + <> + + + ); }; From 452713ccc2ce67def35153f741ffdc500b7c0795 Mon Sep 17 00:00:00 2001 From: colton Date: Tue, 17 Dec 2024 16:57:48 -0500 Subject: [PATCH 78/94] [devrel] atproto demo ingestion (#26038) ## Summary & Motivation Scaffolds project for atproto dashboard demo. ``` dagster project scaffold --name project_atproto_dashboard ``` Adds ingestion for Bluesky; snapshots starter pack and user feeds. See upstream PRs that were squashed for context. ## How I Tested These Changes ## Changelog > Insert changelog entry or delete this section. --------- Co-authored-by: Alex Noonan --- .../project_atproto_dashboard/.env.example | 17 +++ examples/project_atproto_dashboard/.gitignore | 5 + examples/project_atproto_dashboard/README.md | 52 +++++++ .../architecture-diagram.png | Bin 0 -> 81974 bytes .../project_atproto_dashboard/dagster.yaml | 6 + .../dbt_project/.gitignore | 0 .../dbt_project/.sqlfluff | 2 + .../dbt_project/dbt_project.yml | 13 ++ .../models/analysis/activity_over_time.sql | 14 ++ .../models/analysis/all_profiles.sql | 105 +++++++++++++ .../dbt_project/models/analysis/calendar.sql | 45 ++++++ .../models/analysis/latest_feed.sql | 57 ++++++++ .../dbt_project/models/analysis/schema.yml | 18 +++ .../models/analysis/top_daily_posts.sql | 46 ++++++ .../models/analysis/top_external_links.sql | 73 +++++++++ .../dbt_project/models/sources.yml | 14 ++ .../dbt_project/models/staging/schema.yml | 7 + .../models/staging/stg_feed_snapshots.sql | 5 + .../models/staging/stg_profiles.sql | 5 + .../dbt_project/profiles.yml | 27 ++++ .../project_atproto_dashboard/lineage.svg | 3 + .../project_atproto_dashboard/__init__.py | 1 + .../dashboard/__init__.py | 0 .../dashboard/definitions.py | 49 +++++++ .../project_atproto_dashboard/definitions.py | 9 ++ .../ingestion/__init__.py | 0 .../ingestion/definitions.py | 138 ++++++++++++++++++ .../ingestion/resources.py | 29 ++++ .../ingestion/utils/__init__.py | 0 .../ingestion/utils/atproto.py | 59 ++++++++ .../modeling/__init__.py | 0 .../modeling/definitions.py | 45 ++++++ .../__init__.py | 1 + .../test_assets.py | 1 + .../project_atproto_dashboard/pyproject.toml | 34 +++++ pyright/alt-1/requirements-pinned.txt | 40 ++--- pyright/master/requirements-pinned.txt | 86 +++++------ pyright/master/requirements.txt | 1 + 38 files changed, 946 insertions(+), 61 deletions(-) create mode 100644 examples/project_atproto_dashboard/.env.example create mode 100644 examples/project_atproto_dashboard/.gitignore create mode 100644 examples/project_atproto_dashboard/README.md create mode 100644 examples/project_atproto_dashboard/architecture-diagram.png create mode 100644 examples/project_atproto_dashboard/dagster.yaml create mode 100644 examples/project_atproto_dashboard/dbt_project/.gitignore create mode 100644 examples/project_atproto_dashboard/dbt_project/.sqlfluff create mode 100644 examples/project_atproto_dashboard/dbt_project/dbt_project.yml create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/activity_over_time.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/all_profiles.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/calendar.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/latest_feed.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/schema.yml create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/top_daily_posts.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/analysis/top_external_links.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/sources.yml create mode 100644 examples/project_atproto_dashboard/dbt_project/models/staging/schema.yml create mode 100644 examples/project_atproto_dashboard/dbt_project/models/staging/stg_feed_snapshots.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/models/staging/stg_profiles.sql create mode 100644 examples/project_atproto_dashboard/dbt_project/profiles.yml create mode 100644 examples/project_atproto_dashboard/lineage.svg create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/__init__.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/__init__.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/definitions.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/definitions.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/__init__.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/definitions.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/resources.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/__init__.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/atproto.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/modeling/__init__.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard/modeling/definitions.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard_tests/__init__.py create mode 100644 examples/project_atproto_dashboard/project_atproto_dashboard_tests/test_assets.py create mode 100644 examples/project_atproto_dashboard/pyproject.toml diff --git a/examples/project_atproto_dashboard/.env.example b/examples/project_atproto_dashboard/.env.example new file mode 100644 index 0000000000000..4ea1e239f6bb6 --- /dev/null +++ b/examples/project_atproto_dashboard/.env.example @@ -0,0 +1,17 @@ +AWS_ENDPOINT_URL= +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_BUCKET_NAME= +AWS_ACCOUNT_ID= + +MOTHERDUCK_TOKEN= + +BSKY_LOGIN= +BSKY_APP_PASSWORD= + +DBT_TARGET= + +AZURE_POWERBI_CLIENT_ID= +AZURE_POWERBI_CLIENT_SECRET= +AZURE_POWERBI_TENANT_ID= +AZURE_POWERBI_WORKSPACE_ID= diff --git a/examples/project_atproto_dashboard/.gitignore b/examples/project_atproto_dashboard/.gitignore new file mode 100644 index 0000000000000..ace8bc76e6a41 --- /dev/null +++ b/examples/project_atproto_dashboard/.gitignore @@ -0,0 +1,5 @@ +tmp*/ +storage/ +schedules/ +history/ +atproto-session.txt diff --git a/examples/project_atproto_dashboard/README.md b/examples/project_atproto_dashboard/README.md new file mode 100644 index 0000000000000..4c15d93cc89cf --- /dev/null +++ b/examples/project_atproto_dashboard/README.md @@ -0,0 +1,52 @@ +# project_atproto_dashboard + +An end-to-end demonstration of ingestion data from the ATProto API, modeling it with dbt, and presenting it with Power BI. + +![Architecture Diagram](./architecture-diagram.png) + +![Project asset lineage](./lineage.svg) + +## Features used + +1. Ingestion of data-related Bluesky posts + - Dynamic partitions + - Declarative automation + - Concurrency limits +2. Modelling data using _dbt_ +3. Representing data in a dashboard + +## Getting started + +### Environment Setup + +Ensure the following environments have been populated in your `.env` file. Start by copying the +template. + +``` +cp .env.example .env +``` + +And then populate the fields. + +### Development + +Install the project dependencies: + + pip install -e ".[dev]" + +Start Dagster: + + DAGSTER_HOME=$(pwd) dagster dev + +### Unit testing + +Tests are in the `project_atproto_dashboard_tests` directory and you can run tests using `pytest`: + + pytest project_atproto_dashboard_tests + +## Resources + +- https://docs.bsky.app/docs/tutorials/viewing-feeds +- https://docs.bsky.app/docs/advanced-guides/rate-limits +- https://atproto.blue/en/latest/atproto_client/auth.html#session-string +- https://tenacity.readthedocs.io/en/latest/#waiting-before-retrying diff --git a/examples/project_atproto_dashboard/architecture-diagram.png b/examples/project_atproto_dashboard/architecture-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..af16cc6c57430fa742d215eae14e8dbc45d778dc GIT binary patch literal 81974 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 literal 0 HcmV?d00001 diff --git a/examples/project_atproto_dashboard/dagster.yaml b/examples/project_atproto_dashboard/dagster.yaml new file mode 100644 index 0000000000000..c9705420e83ca --- /dev/null +++ b/examples/project_atproto_dashboard/dagster.yaml @@ -0,0 +1,6 @@ +run_coordinator: + module: dagster.core.run_coordinator + class: QueuedRunCoordinator + +concurrency: + default_op_concurrency_limit: 1 diff --git a/examples/project_atproto_dashboard/dbt_project/.gitignore b/examples/project_atproto_dashboard/dbt_project/.gitignore new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/examples/project_atproto_dashboard/dbt_project/.sqlfluff b/examples/project_atproto_dashboard/dbt_project/.sqlfluff new file mode 100644 index 0000000000000..6fffb098b0115 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/.sqlfluff @@ -0,0 +1,2 @@ +[sqlfluff:rules:capitalisation.keywords] +capitalisation_policy = upper diff --git a/examples/project_atproto_dashboard/dbt_project/dbt_project.yml b/examples/project_atproto_dashboard/dbt_project/dbt_project.yml new file mode 100644 index 0000000000000..5dc13e8c3997a --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/dbt_project.yml @@ -0,0 +1,13 @@ +name: "dbt_project" +version: "1.0.0" +config-version: 2 + +profile: "bluesky" + +target-path: "target" +clean-targets: + - "target" + - "dbt_packages" + +models: + +materialized: table diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/activity_over_time.sql b/examples/project_atproto_dashboard/dbt_project/models/analysis/activity_over_time.sql new file mode 100644 index 0000000000000..794065c8723e7 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/activity_over_time.sql @@ -0,0 +1,14 @@ +WITH final AS ( + SELECT + date_trunc('day', created_at) AS post_date, + count(DISTINCT post_text) AS unique_posts, + count(DISTINCT author_handle) AS active_authors, + sum(likes) AS total_likes, + sum(replies) AS total_comments, + sum(quotes) AS total_quotes + FROM {{ ref("latest_feed") }} + GROUP BY date_trunc('day', created_at) + ORDER BY date_trunc('day', created_at) DESC +) + +SELECT * FROM final diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/all_profiles.sql b/examples/project_atproto_dashboard/dbt_project/models/analysis/all_profiles.sql new file mode 100644 index 0000000000000..5f4e21734bff1 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/all_profiles.sql @@ -0,0 +1,105 @@ +WITH max_profile_data AS ( + SELECT + json_extract_string(json, '$.subject.did') AS profile_did, + max( + strptime( + regexp_extract( + filename, + 'dagster-demo/atproto_starter_pack_snapshot/(\d{4}-\d{2}-\d{2}/\d{2}/\d{2})', + 1 + ), + '%Y-%m-%d/%H/%M' + ) + ) AS max_extracted_timestamp + FROM {{ ref("stg_profiles") }} + GROUP BY + json_extract_string(json, '$.subject.did') +), + +profiles AS ( + SELECT + json_extract_string(json, '$.subject.handle') AS handle_subject, + json_extract_string(json, '$.subject.did') AS profile_did, + json_extract_string(json, '$.subject.avatar') AS profile_avatar, + json_extract_string(json, '$.subject.display_name') + AS profile_display_name, + json_extract_string(json, '$.subject.created_at') + AS profile_created_date, + json_extract_string(json, '$.subject.description') + AS profile_description + FROM {{ ref("stg_profiles") }} stg_prof + JOIN max_profile_data + ON + json_extract_string(stg_prof.json, '$.subject.did') + = max_profile_data.profile_did + AND strptime( + regexp_extract( + stg_prof.filename, + 'dagster-demo/atproto_starter_pack_snapshot/(\d{4}-\d{2}-\d{2}/\d{2}/\d{2})', + 1 + ), + '%Y-%m-%d/%H/%M' + ) + = max_profile_data.max_extracted_timestamp +), + +user_aggregates AS ( + SELECT + replace(author_handle, '"', '') AS author_handle, + count(*) AS num_posts, + avg(cast(lf.likes AS int)) AS average_likes, + sum(cast(lf.likes AS int)) AS total_likes, + sum(cast(lf.replies AS int)) AS total_replies, + sum(cast(lf.likes AS int)) / count(*) AS total_likes_by_num_of_posts, + round( + count(*) + / count(DISTINCT date_trunc('day', cast(created_at AS timestamp))), + 2 + ) AS avg_posts_per_day, + ntile(100) + OVER ( + ORDER BY sum(cast(lf.likes AS int)) + ) + AS likes_percentile, + ntile(100) + OVER ( + ORDER BY sum(cast(lf.replies AS int)) + ) + AS replies_percentile, + ntile(100) OVER ( + ORDER BY count(*) + ) AS posts_percentile, + (ntile(100) OVER ( + ORDER BY sum(cast(lf.likes AS int))) + ntile(100) OVER ( + ORDER BY sum(cast(lf.replies AS int))) + ntile(100) OVER ( + ORDER BY count(*) + )) + / 3.0 AS avg_score + FROM {{ ref("latest_feed") }} lf + GROUP BY replace(author_handle, '"', '') +), + +final AS ( + SELECT DISTINCT + profiles.handle_subject AS profile_handle, + profiles.profile_did, + profiles.profile_display_name, + profiles.profile_avatar, + profiles.profile_created_date, + profiles.profile_description, + user_aggregates.num_posts, + user_aggregates.average_likes, + user_aggregates.total_likes, + user_aggregates.total_replies, + user_aggregates.total_likes_by_num_of_posts, + user_aggregates.avg_posts_per_day, + user_aggregates.likes_percentile, + user_aggregates.replies_percentile, + user_aggregates.posts_percentile, + user_aggregates.avg_score + FROM profiles + LEFT JOIN user_aggregates + ON user_aggregates.author_handle = profiles.handle_subject +) + +SELECT * FROM final diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/calendar.sql b/examples/project_atproto_dashboard/dbt_project/models/analysis/calendar.sql new file mode 100644 index 0000000000000..91f1ae0ea62e0 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/calendar.sql @@ -0,0 +1,45 @@ +WITH date_spine AS ( + SELECT CAST(range AS DATE) AS date_key + FROM RANGE( + (SELECT MIN(created_at) FROM {{ ref("latest_feed") }}), + CURRENT_DATE(), + INTERVAL 1 DAY + ) +) + +SELECT + date_key AS date_key, + DAYOFYEAR(date_key) AS day_of_year, + WEEKOFYEAR(date_key) AS week_of_year, + DAYOFWEEK(date_key) AS day_of_week, + ISODOW(date_key) AS iso_day_of_week, + DAYNAME(date_key) AS day_name, + DATE_TRUNC('week', date_key) AS first_day_of_week, + DATE_TRUNC('week', date_key) + 6 AS last_day_of_week, + YEAR(date_key) || RIGHT('0' || MONTH(date_key), 2) AS month_key, + MONTH(date_key) AS month_of_year, + DAYOFMONTH(date_key) AS day_of_month, + LEFT(MONTHNAME(date_key), 3) AS month_name_short, + MONTHNAME(date_key) AS month_name, + DATE_TRUNC('month', date_key) AS first_day_of_month, + LAST_DAY(date_key) AS last_day_of_month, + CAST(YEAR(date_key) || QUARTER(date_key) AS INT) AS quarter_key, + QUARTER(date_key) AS quarter_of_year, + CAST(date_key - DATE_TRUNC('Quarter', date_key) + 1 AS INT) + AS day_of_quarter, + ('Q' || QUARTER(date_key)) AS quarter_desc_short, + ('Quarter ' || QUARTER(date_key)) AS quarter_desc, + DATE_TRUNC('quarter', date_key) AS first_day_of_quarter, + LAST_DAY(DATE_TRUNC('quarter', date_key) + INTERVAL 2 MONTH) + AS last_day_of_quarter, + CAST(YEAR(date_key) AS INT) AS year_key, + DATE_TRUNC('Year', date_key) AS first_day_of_year, + DATE_TRUNC('Year', date_key) - 1 + INTERVAL 1 YEAR AS last_day_of_year, + ROW_NUMBER() + OVER ( + PARTITION BY YEAR(date_key), MONTH(date_key), DAYOFWEEK(date_key) + ORDER BY date_key + ) + AS ordinal_weekday_of_month +FROM date_spine +WHERE CAST(YEAR(date_key) AS INT) >= 2020 diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/latest_feed.sql b/examples/project_atproto_dashboard/dbt_project/models/analysis/latest_feed.sql new file mode 100644 index 0000000000000..09f0e23ab1855 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/latest_feed.sql @@ -0,0 +1,57 @@ +WITH max_update AS ( + SELECT + max( + strptime( + regexp_extract( + filename, + 'dagster-demo/atproto_actor_feed_snapshot/(\d{4}-\d{2}-\d{2}/\d{2}/\d{2})', + 1 + ), + '%Y-%m-%d/%H/%M' + ) + ) AS max_extracted_timestamp, + regexp_extract(filename, 'did:(.*?)\.json') AS profile_id + FROM {{ ref("stg_feed_snapshots") }} + GROUP BY + regexp_extract(filename, 'did:(.*?)\.json') +), + +final AS ( + SELECT + json_extract_string(sfs.json, '$.post.author.handle') AS author_handle, + json_extract_string(sfs.json, '$.post.author.did') AS author_id, + cast(sfs.json.post.like_count AS int) AS likes, + cast(sfs.json.post.quote_count AS int) AS quotes, + cast(sfs.json.post.reply_count AS int) AS replies, + json_extract_string(sfs.json, '$.post.record.text') AS post_text, + sfs.json.post.record.embed, + json_extract_string( + sfs.json, '$.post.record.embed.external.description' + ) AS external_embed_description, + json_extract_string(sfs.json, '$.post.record.embed.external.uri') + AS external_embed_link, + sfs.json.post.record.embed.external.thumb AS external_embed_thumbnail, + cast(sfs.json.post.record.created_at AS timestamp) AS created_at, + CASE + WHEN json_extract_string(sfs.json.post.record.embed, '$.images[0].image.ref.link') IS NULL THEN NULL + ELSE concat('https://cdn.bsky.app/img/feed_thumbnail/plain/', json_extract_string(sfs.json, '$.post.author.did') ,'/' ,json_extract_string(sfs.json.post.record.embed, '$.images[0].image.ref.link'), '@jpeg') + END AS image_url, + max_update.max_extracted_timestamp, + max_update.profile_id + FROM {{ ref("stg_feed_snapshots") }} sfs + JOIN max_update + ON + max_update.profile_id + = regexp_extract(sfs.filename, 'did:(.*?)\.json') + AND max_update.max_extracted_timestamp + = strptime( + regexp_extract( + sfs.filename, + 'dagster-demo/atproto_actor_feed_snapshot/(\d{4}-\d{2}-\d{2}/\d{2}/\d{2})', + 1 + ), + '%Y-%m-%d/%H/%M' + ) +) + +SELECT * FROM final diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/schema.yml b/examples/project_atproto_dashboard/dbt_project/models/analysis/schema.yml new file mode 100644 index 0000000000000..404d89541a5db --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/schema.yml @@ -0,0 +1,18 @@ +version: 2 + +models: + - name: all_profiles + description: "table showing data for all the profiles posts are collected from and some high level statistics" + columns: + - name: profile_handle + data_tests: + - unique + - not_null + - name: latest_feed + description: "the latest feed of posts" + - name: activity_over_time + description: "daily activity of posts overtime" + - name: top_daily_posts + description: "top posts ranked for a given day" + - name: top_external_links + description: "top external content grouped by type shared in the community" diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/top_daily_posts.sql b/examples/project_atproto_dashboard/dbt_project/models/analysis/top_daily_posts.sql new file mode 100644 index 0000000000000..a53c8435f60c6 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/top_daily_posts.sql @@ -0,0 +1,46 @@ +WITH distinct_posts AS ( + SELECT DISTINCT ON (author_handle, post_text, date_trunc('day', created_at)) + author_handle, + post_text, + likes, + quotes, + replies, + image_url, + external_embed_link, + external_embed_thumbnail, + external_embed_description, + created_at + FROM {{ ref("latest_feed") }} +), + +scored_posts AS ( + SELECT + *, + (likes * 0.2) + (quotes * 0.4) + (replies * 0.4) AS engagement_score, + date_trunc('day', created_at) AS post_date, + row_number() OVER ( + PARTITION BY date_trunc('day', created_at) + ORDER BY (likes * 0.2) + (quotes * 0.4) + (replies * 0.4) DESC + ) AS daily_rank + FROM distinct_posts +), + +final AS ( + SELECT + post_date, + author_handle, + post_text, + likes, + quotes, + replies, + image_url, + external_embed_link, + external_embed_thumbnail, + external_embed_description, + round(engagement_score, 2) AS engagement_score, + daily_rank + FROM scored_posts + WHERE daily_rank <= 10 +) + +SELECT * FROM final diff --git a/examples/project_atproto_dashboard/dbt_project/models/analysis/top_external_links.sql b/examples/project_atproto_dashboard/dbt_project/models/analysis/top_external_links.sql new file mode 100644 index 0000000000000..5e207b0d664be --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/analysis/top_external_links.sql @@ -0,0 +1,73 @@ +WITH distinct_posts AS ( + SELECT DISTINCT ON (author_handle, post_text, date_trunc('day', created_at)) + author_handle, + post_text, + likes, + quotes, + replies, + created_at, + image_url, + embed, + external_embed_link, + external_embed_thumbnail, + external_embed_description, + CASE + WHEN external_embed_link LIKE '%youtu%' THEN 'YouTube' + WHEN external_embed_link LIKE '%docs%' THEN 'Docs' + WHEN external_embed_link LIKE '%github%' THEN 'GitHub' + WHEN external_embed_link LIKE '%substack%' THEN 'SubStack' + WHEN external_embed_link LIKE '%twitch%' THEN 'Twitch' + WHEN external_embed_link LIKE '%msnbc%' THEN 'News' + WHEN external_embed_link LIKE '%theguardian%' THEN 'News' + WHEN external_embed_link LIKE '%foreignpolicy%' THEN 'News' + WHEN external_embed_link LIKE '%nytimes%' THEN 'News' + WHEN external_embed_link LIKE '%wsj%' THEN 'News' + WHEN external_embed_link LIKE '%bloomberg%' THEN 'News' + WHEN external_embed_link LIKE '%theverge%' THEN 'News' + WHEN external_embed_link LIKE '%cnbc%' THEN 'News' + WHEN external_embed_link LIKE '%.ft.%' THEN 'News' + WHEN external_embed_link LIKE '%washingtonpost%' THEN 'News' + WHEN external_embed_link LIKE '%newrepublic%' THEN 'News' + WHEN external_embed_link LIKE '%huffpost%' THEN 'News' + WHEN external_embed_link LIKE '%wired%' THEN 'News' + WHEN external_embed_link LIKE '%medium%' THEN 'Medium' + WHEN external_embed_link LIKE '%reddit%' THEN 'Reddit' + WHEN external_embed_link LIKE '%/blog/%' THEN 'Blog' + ELSE 'Other' + END AS external_link_type + FROM {{ ref("latest_feed") }} + WHERE external_embed_link IS NOT null +), + +scored_posts AS ( + SELECT + *, + (likes * 0.2) + (quotes * 0.4) + (replies * 0.4) AS engagement_score, + date_trunc('day', created_at) AS post_date, + row_number() OVER ( + PARTITION BY date_trunc('day', created_at), external_link_type + ORDER BY (likes * 0.2) + (quotes * 0.4) + (replies * 0.4) DESC + ) AS daily_rank + FROM distinct_posts +), + +final AS ( + SELECT + post_date, + author_handle, + post_text, + likes, + quotes, + replies, + round(engagement_score, 2) AS engagement_score, + daily_rank, + embed, + external_embed_link, + external_embed_thumbnail, + external_embed_description, + external_link_type + FROM scored_posts + WHERE daily_rank <= 10 +) + +SELECT * FROM final diff --git a/examples/project_atproto_dashboard/dbt_project/models/sources.yml b/examples/project_atproto_dashboard/dbt_project/models/sources.yml new file mode 100644 index 0000000000000..8b9e72a31b2bc --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/sources.yml @@ -0,0 +1,14 @@ +version: 2 + +sources: + - name: r2_bucket + tables: + - name: actor_feed_snapshot + description: "external r2 bucket with json files of actor feeds" + meta: + external_location: "read_ndjson_objects('r2://dagster-demo/atproto_actor_feed_snapshot/**/*.json', filename=true)" + - name: starter_pack_snapshot + description: "external r2 bucket with json files for feed snapshots" + meta: + external_location: "read_ndjson_objects('r2://dagster-demo/atproto_starter_pack_snapshot/**/*.json', filename=true)" + diff --git a/examples/project_atproto_dashboard/dbt_project/models/staging/schema.yml b/examples/project_atproto_dashboard/dbt_project/models/staging/schema.yml new file mode 100644 index 0000000000000..61f4b3d774b18 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/staging/schema.yml @@ -0,0 +1,7 @@ +version: 2 + +models: + - name: stg_profiles + description: "raw data from r2 bucket" + - name: stg_feed_snapshots + description: "raw posts data from r2 bucket" \ No newline at end of file diff --git a/examples/project_atproto_dashboard/dbt_project/models/staging/stg_feed_snapshots.sql b/examples/project_atproto_dashboard/dbt_project/models/staging/stg_feed_snapshots.sql new file mode 100644 index 0000000000000..92674ee054769 --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/staging/stg_feed_snapshots.sql @@ -0,0 +1,5 @@ +WITH raw AS ( + SELECT * FROM {{ source('r2_bucket', 'actor_feed_snapshot') }} +) + +SELECT * FROM raw diff --git a/examples/project_atproto_dashboard/dbt_project/models/staging/stg_profiles.sql b/examples/project_atproto_dashboard/dbt_project/models/staging/stg_profiles.sql new file mode 100644 index 0000000000000..7e4eeba113e2c --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/models/staging/stg_profiles.sql @@ -0,0 +1,5 @@ +WITH raw AS ( + SELECT * FROM {{ source('r2_bucket', 'starter_pack_snapshot') }} +) + +SELECT * FROM raw diff --git a/examples/project_atproto_dashboard/dbt_project/profiles.yml b/examples/project_atproto_dashboard/dbt_project/profiles.yml new file mode 100644 index 0000000000000..462a3a6a9e31b --- /dev/null +++ b/examples/project_atproto_dashboard/dbt_project/profiles.yml @@ -0,0 +1,27 @@ +bluesky: + target: prod + outputs: + dev: + type: duckdb + schema: bluesky_dev + path: "local.duckdb" + threads: 16 + extensions: + - httpfs + settings: + s3_region: "auto" + s3_access_key_id: "{{ env_var('AWS_ACCESS_KEY_ID') }}" + s3_secret_access_key: "{{ env_var('AWS_SECRET_ACCESS_KEY') }}" + s3_endpoint: "{{ env_var('AWS_ENDPOINT_URL') | replace('https://', '') }}" + prod: + type: duckdb + schema: bluesky + path: "md:prod_bluesky?MOTHERDUCK_TOKEN={{ env_var('MOTHERDUCK_TOKEN') }}" + threads: 16 + extensions: + - httpfs + settings: + s3_region: "auto" + s3_access_key_id: "{{ env_var('AWS_ACCESS_KEY_ID') }}" + s3_secret_access_key: "{{ env_var('AWS_SECRET_ACCESS_KEY') }}" + s3_endpoint: "{{ env_var('AWS_ENDPOINT_URL') | replace('https://', '') }}" diff --git a/examples/project_atproto_dashboard/lineage.svg b/examples/project_atproto_dashboard/lineage.svg new file mode 100644 index 0000000000000..578247eaff975 --- /dev/null +++ b/examples/project_atproto_dashboard/lineage.svg @@ -0,0 +1,3 @@ +
default
project_atproto_dashboard.definitions
staging
project_atproto_dashboard.definitions
analysis
project_atproto_dashboard.definitions
ingestion
project_atproto_dashboard.definitions
reporting
project_atproto_dashboard.definitions
Daily Rank
No description
Loading...
activity_over_time
daily activity of posts overtime
Never materialized
dbt
DuckDB
actor_feed_snapshot
Snapshot of full user feed written to S3 storage.
Loading...
Python
all_profiles
table showing data for all the profiles posts are collected from and some high level statistics
Never materialized
Checks
2
dbt
DuckDB
calendar
dbt model calendar
Never materialized
dbt
DuckDB
latest_feed
the latest feed of posts
Never materialized
dbt
DuckDB
powerbi_bluesky_report
No description
Power BI
Report
powerbi_bluesky_model
No description
Power BI
Semantic Model
starter_pack_snapshot
Snapshot of members in a Bluesky starter pack partitioned by starter pack ID and written to S3 storage.
Loading...
Python
stg_feed_snapshots
raw posts data from r2 bucket
Never materialized
dbt
DuckDB
stg_profiles
raw data from r2 bucket
Never materialized
dbt
DuckDB
top_daily_posts
top posts ranked for a given day
Never materialized
dbt
DuckDB
top_external_links
top external content grouped by type shared in the community
Never materialized
dbt
DuckDB
\ No newline at end of file diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/__init__.py b/examples/project_atproto_dashboard/project_atproto_dashboard/__init__.py new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/__init__.py b/examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/definitions.py b/examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/definitions.py new file mode 100644 index 0000000000000..dba89ead146d3 --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/dashboard/definitions.py @@ -0,0 +1,49 @@ +import dagster as dg +from dagster_powerbi import ( + DagsterPowerBITranslator, + PowerBIServicePrincipal, + PowerBIWorkspace, + load_powerbi_asset_specs, +) +from dagster_powerbi.translator import PowerBIContentData + +power_bi_workspace = PowerBIWorkspace( + credentials=PowerBIServicePrincipal( + client_id=dg.EnvVar("AZURE_POWERBI_CLIENT_ID"), + client_secret=dg.EnvVar("AZURE_POWERBI_CLIENT_SECRET"), + tenant_id=dg.EnvVar("AZURE_POWERBI_TENANT_ID"), + ), + workspace_id=dg.EnvVar("AZURE_POWERBI_WORKSPACE_ID"), +) + + +class CustomDagsterPowerBITranslator(DagsterPowerBITranslator): + def get_report_spec(self, data: PowerBIContentData) -> dg.AssetSpec: + return ( + super() + .get_report_spec(data) + .replace_attributes( + group_name="reporting", + ) + ) + + def get_semantic_model_spec(self, data: PowerBIContentData) -> dg.AssetSpec: + upsteam_table_deps = [ + dg.AssetKey(table.get("name")) for table in data.properties.get("tables", []) + ] + return ( + super() + .get_semantic_model_spec(data) + .replace_attributes( + group_name="reporting", + deps=upsteam_table_deps, + ) + ) + + +power_bi_specs = load_powerbi_asset_specs( + power_bi_workspace, + dagster_powerbi_translator=CustomDagsterPowerBITranslator, +) + +defs = dg.Definitions(assets=[*power_bi_specs], resources={"power_bi": power_bi_workspace}) diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/definitions.py b/examples/project_atproto_dashboard/project_atproto_dashboard/definitions.py new file mode 100644 index 0000000000000..f2a2b5ebd5f2e --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/definitions.py @@ -0,0 +1,9 @@ +import dagster as dg + +import project_atproto_dashboard.dashboard.definitions as dashboard_definitions +import project_atproto_dashboard.ingestion.definitions as ingestion_definitions +import project_atproto_dashboard.modeling.definitions as modeling_definitions + +defs = dg.Definitions.merge( + ingestion_definitions.defs, modeling_definitions.defs, dashboard_definitions.defs +) diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/__init__.py b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/definitions.py b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/definitions.py new file mode 100644 index 0000000000000..41b2f2e969c6b --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/definitions.py @@ -0,0 +1,138 @@ +import os +from datetime import datetime + +import dagster as dg +from dagster_aws.s3 import S3Resource + +from project_atproto_dashboard.ingestion.resources import ATProtoResource +from project_atproto_dashboard.ingestion.utils.atproto import ( + get_all_feed_items, + get_all_starter_pack_members, +) + +AWS_BUCKET_NAME = os.environ.get("AWS_BUCKET_NAME", "dagster-demo") + + +atproto_did_dynamic_partition = dg.DynamicPartitionsDefinition(name="atproto_did_dynamic_partition") + + +@dg.asset( + partitions_def=dg.StaticPartitionsDefinition( + partition_keys=[ + "at://did:plc:lc5jzrr425fyah724df3z5ik/app.bsky.graph.starterpack/3l7cddlz5ja24", # https://bsky.app/starter-pack/christiannolan.bsky.social/3l7cddlz5ja24 + ] + ), + automation_condition=dg.AutomationCondition.on_cron("0 0 * * *"), # Midnight + kinds={"python"}, + group_name="ingestion", +) +def starter_pack_snapshot( + context: dg.AssetExecutionContext, + atproto_resource: ATProtoResource, + s3_resource: S3Resource, +) -> dg.MaterializeResult: + """Snapshot of members in a Bluesky starter pack partitioned by starter pack ID and written to S3 storage. + + Args: + context (AssetExecutionContext) Dagster context + atproto_resource (ATProtoResource) Resource for interfacing with atmosphere protocol + s3_resource (S3Resource) Resource for uploading files to S3 storage + + """ + atproto_client = atproto_resource.get_client() + + starter_pack_uri = context.partition_key + + list_items = get_all_starter_pack_members(atproto_client, starter_pack_uri) + + _bytes = os.linesep.join([member.model_dump_json() for member in list_items]).encode("utf-8") + + datetime_now = datetime.now() + object_key = "/".join( + ( + "atproto_starter_pack_snapshot", + datetime_now.strftime("%Y-%m-%d"), + datetime_now.strftime("%H"), + datetime_now.strftime("%M"), + f"{starter_pack_uri}.json", + ) + ) + + s3_resource.get_client().put_object(Body=_bytes, Bucket=AWS_BUCKET_NAME, Key=object_key) + + context.instance.add_dynamic_partitions( + partitions_def_name="atproto_did_dynamic_partition", + partition_keys=[list_item_view.subject.did for list_item_view in list_items], + ) + + return dg.MaterializeResult( + metadata={ + "len_members": len(list_items), + "s3_object_key": object_key, + } + ) + + +@dg.asset( + partitions_def=atproto_did_dynamic_partition, + deps=[dg.AssetDep(starter_pack_snapshot, partition_mapping=dg.AllPartitionMapping())], + automation_condition=dg.AutomationCondition.eager(), + kinds={"python"}, + group_name="ingestion", + op_tags={"dagster/concurrency_key": "ingestion"}, +) +def actor_feed_snapshot( + context: dg.AssetExecutionContext, + atproto_resource: ATProtoResource, + s3_resource: S3Resource, +) -> dg.MaterializeResult: + """Snapshot of full user feed written to S3 storage.""" + client = atproto_resource.get_client() + actor_did = context.partition_key + + # NOTE: we may need to yield chunks to be more memory efficient + items = get_all_feed_items(client, actor_did) + + datetime_now = datetime.now() + + object_key = "/".join( + ( + "atproto_actor_feed_snapshot", + datetime_now.strftime("%Y-%m-%d"), + datetime_now.strftime("%H"), + datetime_now.strftime("%M"), + f"{actor_did}.json", + ) + ) + + _bytes = os.linesep.join([item.model_dump_json() for item in items]).encode("utf-8") + + s3_resource.get_client().put_object(Body=_bytes, Bucket=AWS_BUCKET_NAME, Key=object_key) + + return dg.MaterializeResult( + metadata={ + "len_feed_items": len(items), + "s3_object_key": object_key, + } + ) + + +atproto_resource = ATProtoResource( + login=dg.EnvVar("BSKY_LOGIN"), password=dg.EnvVar("BSKY_APP_PASSWORD") +) + +s3_resource = S3Resource( + endpoint_url=dg.EnvVar("AWS_ENDPOINT_URL"), + aws_access_key_id=dg.EnvVar("AWS_ACCESS_KEY_ID"), + aws_secret_access_key=dg.EnvVar("AWS_SECRET_ACCESS_KEY"), + region_name="auto", +) + + +defs = dg.Definitions( + assets=[starter_pack_snapshot, actor_feed_snapshot], + resources={ + "atproto_resource": atproto_resource, + "s3_resource": s3_resource, + }, +) diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/resources.py b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/resources.py new file mode 100644 index 0000000000000..38163e85896df --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/resources.py @@ -0,0 +1,29 @@ +import os + +import dagster as dg +from atproto import Client + + +class ATProtoResource(dg.ConfigurableResource): + login: str + password: str + session_cache_path: str = "atproto-session.txt" + + def _login(self, client): + """Create a re-usable session to be used across resource instances; we are rate limited to 30/5 minutes or 300/day session.""" + if os.path.exists(self.session_cache_path): + with open(self.session_cache_path, "r") as f: + session_string = f.read() + client.login(session_string=session_string) + else: + client.login(login=self.login, password=self.password) + session_string = client.export_session_string() + with open(self.session_cache_path, "w") as f: + f.write(session_string) + + def get_client( + self, + ) -> Client: + client = Client() + self._login(client) + return client diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/__init__.py b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/atproto.py b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/atproto.py new file mode 100644 index 0000000000000..fe8fadb7e857a --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/ingestion/utils/atproto.py @@ -0,0 +1,59 @@ +from typing import TYPE_CHECKING, List, Optional + +from atproto import Client + +if TYPE_CHECKING: + from atproto_client import models + + +def get_all_feed_items(client: Client, actor: str) -> List["models.AppBskyFeedDefs.FeedViewPost"]: + """Retrieves all author feed items for a given `actor`. + + Args: + client (Client): AT Protocol client + actor (str): author identifier (did) + + Returns: + List['models.AppBskyFeedDefs.FeedViewPost'] list of feed + + """ + import math + + import tenacity + + @tenacity.retry( + stop=tenacity.stop_after_attempt(5), + wait=tenacity.wait_fixed(math.ceil(60 * 2.5)), + ) + def _get_feed_with_retries(client: Client, actor: str, cursor: Optional[str]): + return client.get_author_feed(actor=actor, cursor=cursor, limit=100) + + feed = [] + cursor = None + while True: + data = _get_feed_with_retries(client, actor, cursor) + feed.extend(data.feed) + cursor = data.cursor + if not cursor: + break + + return feed + + +def get_all_list_members(client: Client, list_uri: str): + cursor = None + members = [] + while True: + response = client.app.bsky.graph.get_list( + {"list": list_uri, "cursor": cursor, "limit": 100} + ) + members.extend(response.items) + if not response.cursor: + break + cursor = response.cursor + return members + + +def get_all_starter_pack_members(client: Client, starter_pack_uri: str): + response = client.app.bsky.graph.get_starter_pack({"starter_pack": starter_pack_uri}) + return get_all_list_members(client, response.starter_pack.list.uri) diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/modeling/__init__.py b/examples/project_atproto_dashboard/project_atproto_dashboard/modeling/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard/modeling/definitions.py b/examples/project_atproto_dashboard/project_atproto_dashboard/modeling/definitions.py new file mode 100644 index 0000000000000..6e7acf2d55f78 --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard/modeling/definitions.py @@ -0,0 +1,45 @@ +import os +from pathlib import Path +from typing import Any, Mapping, Optional + +import dagster as dg +from dagster_dbt import DagsterDbtTranslator, DbtCliResource, DbtProject, dbt_assets + +dbt_project = DbtProject( + project_dir=Path(__file__).joinpath("..", "..", "..", "dbt_project").resolve(), + target=os.getenv("DBT_TARGET"), +) +dbt_project.prepare_if_dev() +dbt_resource = DbtCliResource(project_dir=dbt_project) + + +class CustomizedDagsterDbtTranslator(DagsterDbtTranslator): + def get_group_name(self, dbt_resource_props: Mapping[str, Any]) -> Optional[str]: + asset_path = dbt_resource_props["fqn"][1:-1] + if asset_path: + return "_".join(asset_path) + return "default" + + def get_asset_key(self, dbt_resource_props): + resource_type = dbt_resource_props["resource_type"] + name = dbt_resource_props["name"] + if resource_type == "source": + return dg.AssetKey(name) + else: + return super().get_asset_key(dbt_resource_props) + + +@dbt_assets( + manifest=dbt_project.manifest_path, + dagster_dbt_translator=CustomizedDagsterDbtTranslator(), +) +def dbt_bluesky(context: dg.AssetExecutionContext, dbt: DbtCliResource): + yield from (dbt.cli(["build"], context=context).stream().fetch_row_counts()) + + +defs = dg.Definitions( + assets=[dbt_bluesky], + resources={ + "dbt": dbt_resource, + }, +) diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard_tests/__init__.py b/examples/project_atproto_dashboard/project_atproto_dashboard_tests/__init__.py new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard_tests/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/project_atproto_dashboard/project_atproto_dashboard_tests/test_assets.py b/examples/project_atproto_dashboard/project_atproto_dashboard_tests/test_assets.py new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/examples/project_atproto_dashboard/project_atproto_dashboard_tests/test_assets.py @@ -0,0 +1 @@ + diff --git a/examples/project_atproto_dashboard/pyproject.toml b/examples/project_atproto_dashboard/pyproject.toml new file mode 100644 index 0000000000000..068f8e743f8a5 --- /dev/null +++ b/examples/project_atproto_dashboard/pyproject.toml @@ -0,0 +1,34 @@ +[project] +name = "project_atproto_dashboard" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.9,<3.13" +dependencies = [ + "atproto", + "dagster", + "dagster-aws", + "dagster-dbt", + "dagster-duckdb", + "dagster-powerbi", + "dbt-duckdb", + "tenacity", +] + +[project.optional-dependencies] +dev = [ + "dagster-webserver", + "pytest", + "ruff", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.dagster] +module_name = "project_atproto_dashboard.definitions" +project_name = "project_atproto_dashboard" + +[tool.setuptools.packages.find] +exclude=["project_atproto_dashboard_tests"] diff --git a/pyright/alt-1/requirements-pinned.txt b/pyright/alt-1/requirements-pinned.txt index 6865024a2edaf..9c55cd90ee281 100644 --- a/pyright/alt-1/requirements-pinned.txt +++ b/pyright/alt-1/requirements-pinned.txt @@ -4,7 +4,7 @@ aiofile==3.9.0 aiohappyeyeballs==2.4.4 aiohttp==3.11.10 aioitertools==0.12.0 -aiosignal==1.3.1 +aiosignal==1.3.2 alembic==1.14.0 annotated-types==0.7.0 antlr4-python3-runtime==4.13.2 @@ -18,7 +18,7 @@ asn1crypto==1.5.1 astroid==3.3.6 asttokens==3.0.0 async-lru==2.0.4 -attrs==24.2.0 +attrs==24.3.0 babel==2.16.0 backoff==2.2.1 backports-tarfile==1.2.0 @@ -27,11 +27,11 @@ bleach==6.2.0 boto3==1.35.36 boto3-stubs-lite==1.35.70 botocore==1.35.36 -botocore-stubs==1.35.78 +botocore-stubs==1.35.82 buildkite-test-collector==0.1.9 cachetools==5.5.0 caio==0.9.17 -certifi==2024.8.30 +certifi==2024.12.14 cffi==1.17.1 chardet==5.2.0 charset-normalizer==3.4.0 @@ -41,7 +41,7 @@ coloredlogs==14.0 comm==0.2.2 contourpy==1.3.1 coverage==7.6.9 -croniter==3.0.4 +croniter==5.0.1 cryptography==44.0.0 cycler==0.12.1 daff==1.3.46 @@ -73,7 +73,7 @@ dbt-duckdb==1.9.1 dbt-extractor==0.5.1 dbt-semantic-interfaces==0.5.1 dbt-snowflake==1.9.0 -debugpy==1.8.9 +debugpy==1.8.11 decopatch==1.4.10 decorator==5.1.1 deepdiff==7.0.1 @@ -95,8 +95,8 @@ frozenlist==1.5.0 fsspec==2024.3.0 gcsfs==0.8.0 google-api-core==2.24.0 -google-api-python-client==2.154.0 -google-auth==2.36.0 +google-api-python-client==2.155.0 +google-auth==2.37.0 google-auth-httplib2==0.2.0 google-auth-oauthlib==1.2.1 google-cloud-bigquery==3.27.0 @@ -141,7 +141,7 @@ jsonschema==4.23.0 jsonschema-specifications==2024.10.1 jupyter-client==8.6.3 jupyter-core==5.7.2 -jupyter-events==0.10.0 +jupyter-events==0.11.0 jupyter-lsp==2.2.5 jupyter-server==2.14.2 jupyter-server-terminals==0.5.3 @@ -157,7 +157,7 @@ mako==1.3.8 markdown-it-py==3.0.0 markupsafe==3.0.2 mashumaro==3.14 -matplotlib==3.9.3 +matplotlib==3.10.0 matplotlib-inline==0.1.7 mccabe==0.7.0 mdurl==0.1.2 @@ -171,10 +171,10 @@ multimethod==1.12 mypy==1.13.0 mypy-boto3-ecs==1.35.77 mypy-boto3-emr==1.35.68 -mypy-boto3-emr-serverless==1.35.25 -mypy-boto3-glue==1.35.74 -mypy-boto3-logs==1.35.72 -mypy-boto3-s3==1.35.76.post1 +mypy-boto3-emr-serverless==1.35.79 +mypy-boto3-glue==1.35.80 +mypy-boto3-logs==1.35.81 +mypy-boto3-s3==1.35.81 mypy-extensions==1.0.0 mypy-protobuf==3.6.0 nbclient==0.10.1 @@ -231,14 +231,14 @@ pyproject-api==1.8.0 pyright==1.1.379 pyspark==3.5.3 pytest==8.3.4 -pytest-asyncio==0.24.0 +pytest-asyncio==0.25.0 pytest-cases==3.8.6 pytest-cov==5.0.0 pytest-mock==3.14.0 pytest-xdist==3.6.1 python-dateutil==2.9.0.post0 python-dotenv==1.0.1 -python-json-logger==2.0.7 +python-json-logger==3.2.1 python-slugify==8.0.4 pytimeparse==1.1.8 pytz==2024.2 @@ -275,7 +275,7 @@ sqlglot==26.0.0 sqlglotrs==0.3.0 sqlparse==0.5.3 stack-data==0.6.3 -starlette==0.41.3 +starlette==0.42.0 structlog==24.4.0 syrupy==4.8.0 tabulate==0.9.0 @@ -292,7 +292,7 @@ tqdm==4.67.1 traitlets==5.14.3 typeguard==4.4.1 typer==0.15.1 -types-awscrt==0.23.4 +types-awscrt==0.23.5 types-backports==0.1.3 types-certifi==2021.10.8.3 types-cffi==1.16.0.20240331 @@ -318,11 +318,11 @@ typing-extensions==4.12.2 typing-inspect==0.9.0 tzdata==2024.2 ujson==5.10.0 -universal-pathlib==0.2.5 +universal-pathlib==0.2.6 uri-template==1.3.0 uritemplate==4.1.1 urllib3==2.2.3 -uvicorn==0.32.1 +uvicorn==0.34.0 uvloop==0.21.0 virtualenv==20.28.0 watchdog==5.0.3 diff --git a/pyright/master/requirements-pinned.txt b/pyright/master/requirements-pinned.txt index 18552e740a2a3..f3383f88c3e96 100644 --- a/pyright/master/requirements-pinned.txt +++ b/pyright/master/requirements-pinned.txt @@ -5,7 +5,7 @@ aiohappyeyeballs==2.4.4 aiohttp==3.10.11 aiohttp-retry==2.8.3 aioresponses==0.7.7 -aiosignal==1.3.1 +aiosignal==1.3.2 alabaster==1.0.0 alembic==1.14.0 altair==4.2.2 @@ -36,7 +36,8 @@ asn1crypto==1.5.1 -e examples/assets_pandas_pyspark asttokens==3.0.0 async-lru==2.0.4 -attrs==24.2.0 +atproto==0.0.56 +attrs==24.3.0 autodocsumm==0.2.14 autoflake==2.3.1 -e python_modules/automation @@ -57,10 +58,10 @@ billiard==4.2.1 bleach==6.2.0 blinker==1.9.0 bokeh==3.6.2 -boto3==1.35.78 +boto3==1.35.82 boto3-stubs-lite==1.35.70 -botocore==1.35.78 -botocore-stubs==1.35.78 +botocore==1.35.82 +botocore-stubs==1.35.82 buildkite-test-collector==0.1.9 cachecontrol==0.14.1 cached-property==2.0.1 @@ -70,9 +71,9 @@ caio==0.9.17 callee==0.3.1 cattrs==23.1.2 celery==5.4.0 -certifi==2024.8.30 +certifi==2024.12.14 cffi==1.17.1 -cfn-lint==1.22.0 +cfn-lint==1.22.2 chardet==5.2.0 charset-normalizer==3.4.0 click==8.1.7 @@ -93,8 +94,8 @@ connexion==2.14.2 contourpy==1.3.1 coverage==7.6.9 cron-descriptor==1.4.5 -croniter==3.0.4 -cryptography==44.0.0 +croniter==5.0.1 +cryptography==43.0.3 cssselect==1.2.0 cssutils==2.11.1 cycler==0.12.1 @@ -121,6 +122,7 @@ dagster-contrib-modal==0.0.2 -e python_modules/libraries/dagster-deltalake -e python_modules/libraries/dagster-deltalake-pandas -e python_modules/libraries/dagster-deltalake-polars +-e python_modules/libraries/dagster-dg -e examples/experimental/dagster-dlift -e python_modules/libraries/dagster-docker -e python_modules/libraries/dagster-duckdb @@ -189,7 +191,7 @@ dbt-duckdb==1.9.1 -e examples/starlift-demo dbt-extractor==0.5.1 dbt-semantic-interfaces==0.5.1 -debugpy==1.8.9 +debugpy==1.8.11 decopatch==1.4.10 decorator==5.1.1 deepdiff==7.0.1 @@ -221,7 +223,7 @@ execnet==2.1.1 executing==2.1.0 expandvars==0.12.0 faiss-cpu==1.8.0 -fastapi==0.115.6 +fastapi==0.1.17 fastavro==1.9.7 fastjsonschema==2.21.1 -e examples/feature_graph_backed_assets @@ -250,8 +252,8 @@ gitdb==4.0.11 gitpython==3.1.43 giturlparse==0.12.0 google-api-core==2.24.0 -google-api-python-client==2.154.0 -google-auth==2.36.0 +google-api-python-client==2.155.0 +google-auth==2.37.0 google-auth-httplib2==0.2.0 google-auth-oauthlib==1.2.1 google-cloud-bigquery==3.27.0 @@ -281,7 +283,7 @@ html5lib==1.1 httpcore==1.0.7 httplib2==0.22.0 httptools==0.6.4 -httpx==0.28.1 +httpx==0.27.2 httpx-sse==0.4.0 humanfriendly==10.0 humanize==4.11.0 @@ -321,7 +323,7 @@ jsonschema-path==0.3.3 jsonschema-specifications==2023.12.1 jupyter-client==7.4.9 jupyter-core==5.7.2 -jupyter-events==0.10.0 +jupyter-events==0.11.0 jupyter-lsp==2.2.5 jupyter-server==2.14.2 jupyter-server-terminals==0.5.3 @@ -333,17 +335,18 @@ keyring==25.5.0 -e python_modules/libraries/dagster-airlift/kitchen-sink kiwisolver==1.4.7 kombu==5.4.2 -kopf==1.37.3 +kopf==1.37.4 kubernetes==31.0.0 kubernetes-asyncio==31.1.1 langchain==0.3.7 langchain-community==0.3.5 -langchain-core==0.3.24 +langchain-core==0.3.25 langchain-openai==0.2.5 -langchain-text-splitters==0.3.2 +langchain-text-splitters==0.3.3 langsmith==0.1.147 lazy-object-proxy==1.10.0 leather==0.4.0 +libipld==3.0.0 limits==3.14.1 linkify-it-py==2.0.3 lkml==1.3.6 @@ -361,7 +364,7 @@ marshmallow==3.23.1 marshmallow-oneofschema==3.1.1 marshmallow-sqlalchemy==0.26.1 mashumaro==3.15 -matplotlib==3.9.3 +matplotlib==3.10.0 matplotlib-inline==0.1.3 mbstrdecoder==1.1.3 mdit-py-plugins==0.4.2 @@ -370,7 +373,7 @@ minimal-snowplow-tracker==0.0.2 mistune==3.0.2 mixpanel==4.10.1 mlflow==1.27.0 -modal==0.67.46 +modal==0.68.26 more-itertools==10.5.0 morefs==0.2.2 moto==4.2.14 @@ -382,10 +385,10 @@ multidict==6.1.0 multimethod==1.12 mypy-boto3-ecs==1.35.77 mypy-boto3-emr==1.35.68 -mypy-boto3-emr-serverless==1.35.25 -mypy-boto3-glue==1.35.74 -mypy-boto3-logs==1.35.72 -mypy-boto3-s3==1.35.76.post1 +mypy-boto3-emr-serverless==1.35.79 +mypy-boto3-glue==1.35.80 +mypy-boto3-logs==1.35.81 +mypy-boto3-s3==1.35.81 mypy-extensions==1.0.0 mypy-protobuf==3.6.0 mysql-connector-python==9.1.0 @@ -395,7 +398,7 @@ nbconvert==7.16.4 nbformat==5.10.4 nest-asyncio==1.6.0 networkx==3.4.2 -nh3==0.2.19 +nh3==0.2.20 nodeenv==1.9.1 notebook==7.3.1 notebook-shim==0.2.4 @@ -406,7 +409,7 @@ objgraph==3.6.2 onnx==1.17.0 onnxconverter-common==1.13.0 onnxruntime==1.20.1 -openai==1.57.2 +openai==1.57.4 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 opentelemetry-api==1.29.0 @@ -451,6 +454,7 @@ portalocker==2.10.1 premailer==3.10.0 prison==0.2.1 progressbar2==4.5.0 +-e examples/project_atproto_dashboard -e examples/project_dagster_modal_pipes prometheus-client==0.21.1 prometheus-flask-exporter==0.23.1 @@ -471,7 +475,7 @@ pyasn1-modules==0.4.1 pycparser==2.22 pydantic==2.10.3 pydantic-core==2.27.1 -pydantic-settings==2.6.1 +pydantic-settings==2.7.0 pydata-google-auth==1.9.0 pyflakes==3.2.0 pygments==2.18.0 @@ -487,7 +491,7 @@ pysocks==1.7.1 pyspark==3.5.3 pytablereader==0.31.4 pytest==8.3.4 -pytest-asyncio==0.24.0 +pytest-asyncio==0.25.0 pytest-cases==3.8.6 pytest-cov==5.0.0 pytest-mock==3.14.0 @@ -497,9 +501,9 @@ python-dateutil==2.9.0.post0 python-dotenv==1.0.1 python-frontmatter==1.1.0 python-jose==3.3.0 -python-json-logger==2.0.7 +python-json-logger==3.2.1 python-liquid==1.12.1 -python-multipart==0.0.19 +python-multipart==0.0.20 python-nvd3==0.16.0 python-slugify==8.0.4 python-utils==3.9.1 @@ -529,7 +533,7 @@ rpds-py==0.22.3 rsa==4.9 ruamel-yaml==0.17.40 ruamel-yaml-clib==0.2.12 -ruff==0.8.2 +ruff==0.8.3 s3transfer==0.10.4 scikit-learn==1.6.0 scipy==1.14.1 @@ -550,8 +554,8 @@ six==1.17.0 skein==0.8.2 skl2onnx==1.17.0 slack-sdk==3.33.5 -sling==1.3.2 -sling-mac-arm64==1.3.2 +sling==1.3.3 +sling-mac-arm64==1.3.3 smmap==5.0.1 sniffio==1.3.1 snowballstemmer==2.2.0 @@ -580,10 +584,10 @@ sqlparse==0.5.3 sshpubkeys==3.3.1 sshtunnel==0.4.0 stack-data==0.6.3 -starlette==0.41.3 +starlette==0.42.0 structlog==24.4.0 sympy==1.13.1 -synchronicity==0.9.5 +synchronicity==0.9.6 syrupy==4.8.0 tableauserverclient==0.34 tabledata==1.3.3 @@ -611,12 +615,12 @@ trio==0.27.0 trio-websocket==0.11.1 -e examples/airlift-migration-tutorial -e examples/tutorial_notebook_assets -twilio==9.3.8 +twilio==9.4.1 twine==6.0.1 typeguard==4.4.1 typepy==1.3.2 typer==0.15.1 -types-awscrt==0.23.4 +types-awscrt==0.23.5 types-backports==0.1.3 types-certifi==2021.10.8.3 types-cffi==1.16.0.20240331 @@ -645,23 +649,23 @@ tzdata==2024.2 tzlocal==5.2 uc-micro-py==1.0.3 unicodecsv==0.14.1 -universal-pathlib==0.2.5 +universal-pathlib==0.2.6 uri-template==1.3.0 uritemplate==4.1.1 urllib3==2.2.3 -e examples/use_case_repository -uvicorn==0.32.1 +uvicorn==0.34.0 uvloop==0.21.0 vine==5.1.0 virtualenv==20.28.0 -wandb==0.19.0 +wandb==0.19.1 watchdog==5.0.3 watchfiles==1.0.3 wcwidth==0.2.13 webcolors==24.11.1 webencodings==0.5.1 websocket-client==1.8.0 -websockets==14.1 +websockets==13.1 werkzeug==2.2.3 wheel==0.45.1 widgetsnbextension==4.0.13 diff --git a/pyright/master/requirements.txt b/pyright/master/requirements.txt index 066776fc53a73..1d9b6d64ff895 100644 --- a/pyright/master/requirements.txt +++ b/pyright/master/requirements.txt @@ -142,4 +142,5 @@ types-sqlalchemy==1.4.53.34 -e python_modules/libraries/dagster-airlift/perf-harness -e examples/airlift-migration-tutorial -e examples/use_case_repository[dev] +-e examples/project_atproto_dashboard -e examples/project_dagster_modal_pipes From d0ea5ad87a338eafb39377af3824373b82a16e44 Mon Sep 17 00:00:00 2001 From: David Liu <48995019+dliu27@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:22:15 -0500 Subject: [PATCH 79/94] [ui] add sorting order to show more assets and asset checks (#26474) ## Summary & Motivation Linear: https://linear.app/dagster-labs/issue/FE-692/implement-ordering-for-asset-checks-in-run-view ## How I Tested These Changes Tested locally --- .../ui-core/src/runs/AssetTagCollections.tsx | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/AssetTagCollections.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/AssetTagCollections.tsx index ca9220bf5177f..803ee593749e0 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/AssetTagCollections.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/AssetTagCollections.tsx @@ -24,6 +24,14 @@ import {TagActionsPopover} from '../ui/TagActions'; import {VirtualizedItemListForDialog} from '../ui/VirtualizedItemListForDialog'; import {numberFormatter} from '../ui/formatters'; +const sortItemAssetKey = (a: AssetKey, b: AssetKey) => { + return displayNameForAssetKey(a).localeCompare(displayNameForAssetKey(b)); +}; + +const sortItemAssetCheck = (a: Check, b: Check) => { + return labelForAssetCheck(a).localeCompare(labelForAssetCheck(b)); +}; + const renderItemAssetKey = (assetKey: AssetKey) => ( @@ -149,10 +157,20 @@ export function useAdjustChildVisibilityToFill(moreLabelFn: (count: number) => s export const AssetKeyTagCollection = React.memo((props: AssetKeyTagCollectionProps) => { const {assetKeys, useTags, maxRows, dialogTitle = 'Assets in run'} = props; - const {setShowMore, dialog} = useShowMoreDialog(dialogTitle, assetKeys, renderItemAssetKey); const count = assetKeys?.length ?? 0; const rendered = maxRows ? 10 : count === 1 ? 1 : 0; + + const {sortedAssetKeys, slicedSortedAssetKeys} = React.useMemo(() => { + const sortedAssetKeys = assetKeys?.slice().sort(sortItemAssetKey) ?? []; + return { + sortedAssetKeys, + slicedSortedAssetKeys: sortedAssetKeys?.slice(0, rendered) ?? [], + }; + }, [assetKeys, rendered]); + + const {setShowMore, dialog} = useShowMoreDialog(dialogTitle, sortedAssetKeys, renderItemAssetKey); + const moreLabelFn = React.useCallback( (displayed: number) => displayed === 0 @@ -165,7 +183,7 @@ export const AssetKeyTagCollection = React.memo((props: AssetKeyTagCollectionPro const {containerRef, moreLabelRef} = useAdjustChildVisibilityToFill(moreLabelFn); - if (!assetKeys || !assetKeys.length) { + if (!count) { return null; } @@ -180,7 +198,7 @@ export const AssetKeyTagCollection = React.memo((props: AssetKeyTagCollectionPro overflow: 'hidden', }} > - {assetKeys.slice(0, rendered).map((assetKey) => ( + {slicedSortedAssetKeys.map((assetKey) => ( // Outer span ensures the popover target is in the right place if the // parent is a flexbox. @@ -263,10 +281,24 @@ interface AssetCheckTagCollectionProps { export const AssetCheckTagCollection = React.memo((props: AssetCheckTagCollectionProps) => { const {assetChecks, maxRows, useTags, dialogTitle = 'Asset checks in run'} = props; - const {setShowMore, dialog} = useShowMoreDialog(dialogTitle, assetChecks, renderItemAssetCheck); const count = assetChecks?.length ?? 0; const rendered = maxRows ? 10 : count === 1 ? 1 : 0; + + const {sortedAssetChecks, slicedSortedAssetChecks} = React.useMemo(() => { + const sortedAssetChecks = assetChecks?.slice().sort(sortItemAssetCheck) ?? []; + return { + sortedAssetChecks, + slicedSortedAssetChecks: sortedAssetChecks?.slice(0, rendered) ?? [], + }; + }, [assetChecks, rendered]); + + const {setShowMore, dialog} = useShowMoreDialog( + dialogTitle, + sortedAssetChecks, + renderItemAssetCheck, + ); + const moreLabelFn = React.useCallback( (displayed: number) => displayed === 0 @@ -279,7 +311,7 @@ export const AssetCheckTagCollection = React.memo((props: AssetCheckTagCollectio const {containerRef, moreLabelRef} = useAdjustChildVisibilityToFill(moreLabelFn); - if (!assetChecks || !assetChecks.length) { + if (!count) { return null; } @@ -294,7 +326,7 @@ export const AssetCheckTagCollection = React.memo((props: AssetCheckTagCollectio overflow: 'hidden', }} > - {assetChecks.slice(0, rendered).map((check) => ( + {slicedSortedAssetChecks.map((check) => ( Date: Tue, 17 Dec 2024 16:45:31 -0600 Subject: [PATCH 80/94] DOC-621 Clean up Serverless docs and Dagster+ getting started page (#26552) ## Summary & Motivation * Clean up formatting of Serverless docs * Clean up Dagster+ "Getting started" page (copyedits, formatting, language) ## How I Tested These Changes Tested locally. ## Changelog > Insert changelog entry or delete this section. --------- Signed-off-by: nikki everett --- .../serverless/ci-cd-in-serverless.md | 2 -- .../deployment-types/serverless/index.md | 12 +++------- .../serverless/run-isolation.md | 2 -- .../serverless/runtime-environment.md | 24 +++++++++---------- .../deployment-types/serverless/security.md | 4 +--- .../docs/dagster-plus/getting-started.md | 22 +++++++++-------- 6 files changed, 28 insertions(+), 38 deletions(-) diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md index 265a378ea82b0..dc094da1f98fb 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/ci-cd-in-serverless.md @@ -83,5 +83,3 @@ dagster-cloud serverless deploy-python-executable ./my-dagster-project \ - ---- diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md index 02b9ce40ada82..672ded0e54bbc 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/index.md @@ -8,9 +8,7 @@ sidebar_position: 10 Dagster+ Serverless is a fully managed version of Dagster+ and is the easiest way to get started with Dagster. With a Serverless deployment, you can run your Dagster jobs without spinning up any infrastructure yourself. ---- - -## When to choose Serverless \{#when-to-choose-serverless} +## Serverless vs Hybrid Serverless works best with workloads that primarily orchestrate other services or perform light computation. Most workloads fit into this category, especially those that orchestrate third-party SaaS products like cloud data warehouses and ETL tools. @@ -21,9 +19,7 @@ If any of the following are applicable, you should select [Hybrid deployment](/d - You need to distribute computation across many nodes for a single run. Dagster+ runs currently execute on a single node with 4 CPUs - You don't want to add Dagster Labs as a data processor ---- - -## Limitations \{#limitations} +## Limitations Serverless is subject to the following limitations: @@ -36,8 +32,6 @@ Serverless is subject to the following limitations: Dagster+ Pro customers may request a quota increase by [contacting Sales](https://dagster.io/contact). ---- - ## Next steps -To start using Dagster+ Serverless, follow our [Getting started with Dagster+](/dagster-plus/getting-started) guide. +To start using Dagster+ Serverless, follow the steps in [Getting started with Dagster+](/dagster-plus/getting-started). diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md index c9c5d04ab6756..ec45953a7632f 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/run-isolation.md @@ -15,8 +15,6 @@ To follow the steps in this guide, you'll need: - An understanding of [Dagster+ deployment settings](/dagster-plus/deployment/management/settings/deployment-settings)
---- - ## Differences between isolated and non-isolated runs - [**Isolated runs**](#isolated-runs-default) execute in their own container. They're the default and are intended for production and compute-heavy use cases. diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md index 750eefa59919a..ae13107a69f9b 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/runtime-environment.md @@ -7,13 +7,13 @@ sidebar_position: 100 By default, Dagster+ Serverless will package your code as PEX files and deploys them on Docker images. Using PEX files significantly reduces the time to deploy since it does not require building a new Docker image and provisioning a new container for every code change. However you are able to customize the Serverless runtime environment in various ways: - [Add dependencies](#add-dependencies) -- [Use a different Python version](#python-version) -- [Use a different base image](#base-image) -- [Include data files](#data-files) -- [Disable PEX deploys](#disable-pex) -- [Use private Python packages](#private-packages) +- [Use a different Python version](#use-a-different-python-version) +- [Use a different base image](#use-a-different-base-image) +- [Include data files](#include-data-files) +- [Disable PEX deploys](#disable-pex-deploys) +- [Use private Python packages](#use-private-python-packages) -## Add dependencies \{#add-dependencies} +## Add dependencies You can add dependencies by including the corresponding Python libraries in your Dagster project's `setup.py` file. These should follow [PEP 508](https://peps.python.org/pep-0508/). @@ -39,9 +39,9 @@ setup( ) ``` -To add a package from a private GitHub repository, see: [Use private Python packages](#private-packages) +To add a package from a private GitHub repository, see [Use private Python packages](#use-private-python-packages) -## Use a different Python version \{#python-version} +## Use a different Python version The default Python version for Dagster+ Serverless is Python 3.9. Python versions 3.10 through 3.12 are also supported. You can specify the Python version you want to use in your GitHub or GitLab workflow, or by using the `dagster-cloud` CLI. @@ -70,7 +70,7 @@ dagster-cloud serverless deploy-python-executable --python-version=3.11 --locati -## Use a different base image \{#base-image} +## Use a different base image Dagster+ runs your code on a Docker image that we build as follows: @@ -117,7 +117,7 @@ Setting a custom base image isn't supported for GitLab CI/CD workflows out of th -## Include data files \{#data-files} +## Include data files To add data files to your deployment, use the [Data Files Support](https://setuptools.pypa.io/en/latest/userguide/datafiles.html) built into Python's `setup.py`. This requires adding a `package_data` or `include_package_data` keyword in the call to `setup()` in `setup.py`. For example, given this directory structure: @@ -134,7 +134,7 @@ To add data files to your deployment, use the [Data Files Support](https://setup If you want to include the data folder, modify your `setup.py` to add the `package_data` line: -## Disable PEX deploys \{#disable-pex} +## Disable PEX deploys You have the option to disable PEX-based deploys and deploy using a Docker image instead of PEX. You can disable PEX in your GitHub or GitLab workflow, or by using the `dagster-cloud` CLI. @@ -200,7 +200,7 @@ Setting a custom base image isn't supported for GitLab CI/CD workflows out of th -## Use private Python packages \{#private-packages} +## Use private Python packages If you use PEX deploys in your workflow (`ENABLE_FAST_DEPLOYS: 'true'`), the following steps can install a package from a private GitHub repository, e.g. `my-org/private-repo`, as a dependency: diff --git a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md index bd1b23f2e1c6e..1996c5fd07abf 100644 --- a/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md +++ b/docs/docs-beta/docs/dagster-plus/deployment/deployment-types/serverless/security.md @@ -32,8 +32,6 @@ To prevent this, you can use [another I/O manager](/guides/build/configure/io-ma You must have [boto3](https://pypi.org/project/boto3/) or `dagster-cloud[serverless]` installed as a project dependency otherwise the Dagster+ managed storage can fail and silently fall back to using the default I/O manager. ::: -## Adding environment variables and secrets \{#adding-secrets} +## Adding environment variables and secrets Often you'll need to securely access secrets from your jobs. Dagster+ supports several methods for adding secrets—refer to the [Dagster+ environment variables documentation](/dagster-plus/deployment/management/environment-variables) for more information. - ---- diff --git a/docs/docs-beta/docs/dagster-plus/getting-started.md b/docs/docs-beta/docs/dagster-plus/getting-started.md index fb4214b62e4ce..b515b01891a63 100644 --- a/docs/docs-beta/docs/dagster-plus/getting-started.md +++ b/docs/docs-beta/docs/dagster-plus/getting-started.md @@ -2,12 +2,16 @@ title: "Getting started with Dagster+" --- -First [create a Dagster+ organization](https://dagster.plus/signup). Note: you can sign up with: +To get started with Dagster+, you will need to create a Dagster+ organization and choose your deployment type (Serverless or Hybrid). + +## Create a Dagster+ organization + +First, [create a Dagster+ organization](https://dagster.plus/signup). You can sign up with: - a Google email address - a GitHub account -- a one-time email link, great if you are using a corporate email. You can setup SSO after completing these steps. +- a one-time email link (ideal if you are using a corporate email). You can set up SSO after completing these steps. -Next, pick your deployment type. Not sure? +## Choose your deployment type - [Dagster+ Serverless](/dagster-plus/deployment/deployment-types/serverless) is the easiest way to get started and is great for teams with limited DevOps support. In Dagster+ Serverless, your Dagster code is executed in Dagster+. You will need to be okay [giving Dagster+ the credentials](/dagster-plus/deployment/management/environment-variables) to connect to the tools you want to orchestrate. @@ -20,14 +24,12 @@ The remaining steps depend on your deployment type. We recommend following the steps in Dagster+ to add a new project. -![Screenshot of Dagster+ serverless NUX](/img/placeholder.svg) - -The Dagster+ on-boarding will guide you through: +The Dagster+ onboarding will guide you through: - creating a Git repository containing your Dagster code - setting up the necessary CI/CD actions to deploy that repository to Dagster+ :::tip -If you don't have any Dagster code yet, you will have the option to select an example quickstart project or import an existing dbt project +If you don't have any Dagster code yet, you can select an example project or import an existing dbt project. ::: See the guide on [adding code locations](/dagster-plus/deployment/code-locations) for details. @@ -35,12 +37,12 @@ See the guide on [adding code locations](/dagster-plus/deployment/code-locations -## Install a Dagster+ Hybrid agent +**Install a Dagster+ Hybrid agent** -Follow [these guides](/dagster-plus/deployment/deployment-types/hybrid) for installing a Dagster+ Hybrid agent. Not sure which agent to pick? We recommend using the Dagster+ Kubernetes agent in most cases. +Follow [these guides](/dagster-plus/deployment/deployment-types/hybrid) for installing a Dagster+ Hybrid agent. If you're not sure which agent to use, we recommend the [Dagster+ Kubernetes agent](/dagster-plus/deployment/deployment-types/hybrid/kubernetes/index.md) in most cases. -## Setup CI/CD +**Set up CI/CD** In most cases, your CI/CD process will be responsible for: - building your Dagster code into a Docker image From 54998739045485b95f8d0135b7f794e97149bb51 Mon Sep 17 00:00:00 2001 From: OwenKephart Date: Tue, 17 Dec 2024 15:38:31 -0800 Subject: [PATCH 81/94] [components] cleanup component loading (#26556) ## Summary & Motivation Simplifies the load path a few ways: 1. `from_decl_node()` -> `load()`: this is just one fewer concept for the user to think about 2. just pass in `context`: same as above 3. adds a load_params() method to ComponentLoadContext: this is something we were doing in all subclasses anyway, this is just simpler to manage ## How I Tested These Changes ## Changelog NOCHANGELOG --- .../dagster_components/core/component.py | 52 +++++++++++---- .../core/component_defs_builder.py | 36 +++++------ .../dagster_components/lib/dbt_project.py | 13 ++-- .../lib/pipes_subprocess_script_collection.py | 25 ++------ .../lib/sling_replication.py | 12 ++-- .../integration_tests/test_dbt_project.py | 20 +++--- .../test_sling_integration_test.py | 64 +++++++++---------- .../test_templated_custom_keys_dbt_project.py | 48 +++++++------- ...test_pipes_subprocess_script_collection.py | 48 +++++++------- .../dagster_components_tests/utils.py | 13 ++-- 10 files changed, 164 insertions(+), 167 deletions(-) diff --git a/python_modules/libraries/dagster-components/dagster_components/core/component.py b/python_modules/libraries/dagster-components/dagster_components/core/component.py index 1c78031d600e0..86dea3815b03e 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/component.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/component.py @@ -1,14 +1,15 @@ import copy +import dataclasses import importlib import importlib.metadata import inspect import sys import textwrap from abc import ABC, abstractmethod +from dataclasses import dataclass from pathlib import Path from types import ModuleType from typing import ( - TYPE_CHECKING, Any, ClassVar, Dict, @@ -18,19 +19,19 @@ Sequence, Type, TypedDict, + TypeVar, ) from dagster import _check as check +from dagster._core.definitions.definitions_class import Definitions from dagster._core.errors import DagsterError from dagster._record import record from dagster._utils import snakecase +from pydantic import TypeAdapter from typing_extensions import Self from dagster_components.utils import ensure_dagster_components_tests_import -if TYPE_CHECKING: - from dagster._core.definitions.definitions_class import Definitions - class ComponentDeclNode: ... @@ -50,13 +51,11 @@ class Component(ABC): def generate_files(cls, request: ComponentGenerateRequest, params: Any) -> None: ... @abstractmethod - def build_defs(self, context: "ComponentLoadContext") -> "Definitions": ... + def build_defs(self, context: "ComponentLoadContext") -> Definitions: ... @classmethod @abstractmethod - def from_decl_node( - cls, context: "ComponentLoadContext", decl_node: "ComponentDeclNode" - ) -> Self: ... + def load(cls, context: "ComponentLoadContext") -> Self: ... @classmethod def get_metadata(cls) -> "ComponentInternalMetadata": @@ -189,21 +188,50 @@ def get_registered_components_in_module(module: ModuleType) -> Iterable[Type[Com yield component +T = TypeVar("T") + + +@dataclass class ComponentLoadContext: - def __init__(self, *, resources: Mapping[str, object], registry: ComponentRegistry): - self.registry = registry - self.resources = resources + resources: Mapping[str, object] + registry: ComponentRegistry + decl_node: Optional[ComponentDeclNode] @staticmethod def for_test( *, resources: Optional[Mapping[str, object]] = None, registry: Optional[ComponentRegistry] = None, + decl_node: Optional[ComponentDeclNode] = None, ) -> "ComponentLoadContext": return ComponentLoadContext( - resources=resources or {}, registry=registry or ComponentRegistry.empty() + resources=resources or {}, + registry=registry or ComponentRegistry.empty(), + decl_node=decl_node, ) + @property + def path(self) -> Path: + from dagster_components.core.component_decl_builder import YamlComponentDecl + + if not isinstance(self.decl_node, YamlComponentDecl): + check.failed(f"Unsupported decl_node type {type(self.decl_node)}") + + return self.decl_node.path + + def for_decl_node(self, decl_node: ComponentDeclNode) -> "ComponentLoadContext": + return dataclasses.replace(self, decl_node=decl_node) + + def _raw_params(self) -> Optional[Mapping[str, Any]]: + from dagster_components.core.component_decl_builder import YamlComponentDecl + + if not isinstance(self.decl_node, YamlComponentDecl): + check.failed(f"Unsupported decl_node type {type(self.decl_node)}") + return self.decl_node.component_file_model.params + + def load_params(self, params_schema: Type[T]) -> T: + return TypeAdapter(params_schema).validate_python(self._raw_params()) + COMPONENT_REGISTRY_KEY_ATTR = "__dagster_component_registry_key" diff --git a/python_modules/libraries/dagster-components/dagster_components/core/component_defs_builder.py b/python_modules/libraries/dagster-components/dagster_components/core/component_defs_builder.py index 3d3e7ab4d7851..047e458fab79f 100644 --- a/python_modules/libraries/dagster-components/dagster_components/core/component_defs_builder.py +++ b/python_modules/libraries/dagster-components/dagster_components/core/component_defs_builder.py @@ -9,7 +9,6 @@ from dagster_components.core.component import ( Component, - ComponentDeclNode, ComponentLoadContext, ComponentRegistry, get_component_name, @@ -39,24 +38,22 @@ def load_module_from_path(module_name, path) -> ModuleType: return module -def build_components_from_decl_node( - context: ComponentLoadContext, decl_node: ComponentDeclNode -) -> Sequence[Component]: - if isinstance(decl_node, YamlComponentDecl): - component_type = component_type_from_yaml_decl(context, decl_node) - return [component_type.from_decl_node(context, decl_node)] - elif isinstance(decl_node, ComponentFolder): +def load_components_from_context(context: ComponentLoadContext) -> Sequence[Component]: + if isinstance(context.decl_node, YamlComponentDecl): + component_type = component_type_from_yaml_decl(context.registry, context.decl_node) + return [component_type.load(context)] + elif isinstance(context.decl_node, ComponentFolder): components = [] - for sub_decl in decl_node.sub_decls: - components.extend(build_components_from_decl_node(context, sub_decl)) + for sub_decl in context.decl_node.sub_decls: + components.extend(load_components_from_context(context.for_decl_node(sub_decl))) return components - raise NotImplementedError(f"Unknown component type {decl_node}") + raise NotImplementedError(f"Unknown component type {context.decl_node}") def component_type_from_yaml_decl( - context: ComponentLoadContext, decl_node: YamlComponentDecl -) -> Type: + registry: ComponentRegistry, decl_node: YamlComponentDecl +) -> Type[Component]: parsed_defs = decl_node.component_file_model if parsed_defs.type.startswith("."): component_registry_key = parsed_defs.type[1:] @@ -79,16 +76,15 @@ def component_type_from_yaml_decl( f"Could not find component type {component_registry_key} in {decl_node.path}" ) - return context.registry.get(parsed_defs.type) + return registry.get(parsed_defs.type) def build_components_from_component_folder( - context: ComponentLoadContext, - path: Path, + context: ComponentLoadContext, path: Path ) -> Sequence[Component]: component_folder = path_to_decl_node(path) assert isinstance(component_folder, ComponentFolder) - return build_components_from_decl_node(context, component_folder) + return load_components_from_context(context.for_decl_node(component_folder)) def build_defs_from_component_path( @@ -97,12 +93,12 @@ def build_defs_from_component_path( resources: Mapping[str, object], ) -> "Definitions": """Build a definitions object from a folder within the components hierarchy.""" - context = ComponentLoadContext(resources=resources, registry=registry) - decl_node = path_to_decl_node(path=path) if not decl_node: raise Exception(f"No component found at path {path}") - components = build_components_from_decl_node(context, decl_node) + + context = ComponentLoadContext(resources=resources, registry=registry, decl_node=decl_node) + components = load_components_from_context(context) return defs_from_components(resources=resources, context=context, components=components) diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py index 6eaa877c0692d..6add407cad677 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/dbt_project.py @@ -11,12 +11,11 @@ from dagster_dbt import DagsterDbtTranslator, DbtCliResource, DbtProject, dbt_assets from dbt.cli.main import dbtRunner from jinja2 import Template -from pydantic import BaseModel, Field, TypeAdapter +from pydantic import BaseModel, Field from typing_extensions import Self from dagster_components import Component, ComponentLoadContext from dagster_components.core.component import ComponentGenerateRequest, component -from dagster_components.core.component_decl_builder import ComponentDeclNode, YamlComponentDecl from dagster_components.core.dsl_schema import AssetSpecProcessorModel, OpSpecBaseModel from dagster_components.generate import generate_component_yaml @@ -86,14 +85,10 @@ def __init__( self.asset_transforms = asset_transforms @classmethod - def from_decl_node(cls, context: ComponentLoadContext, decl_node: ComponentDeclNode) -> Self: - assert isinstance(decl_node, YamlComponentDecl) - + def load(cls, context: ComponentLoadContext) -> Self: # all paths should be resolved relative to the directory we're in - with pushd(str(decl_node.path)): - loaded_params = TypeAdapter(cls.params_schema).validate_python( - decl_node.component_file_model.params - ) + with pushd(str(context.path)): + loaded_params = context.load_params(cls.params_schema) return cls( dbt_resource=loaded_params.dbt, op_spec=loaded_params.op, diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py index 017fb8aa90dc0..75a8a83730505 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/pipes_subprocess_script_collection.py @@ -9,15 +9,9 @@ from dagster._core.execution.context.asset_execution_context import AssetExecutionContext from dagster._core.pipes.subprocess import PipesSubprocessClient from dagster._utils.warnings import suppress_dagster_warnings -from pydantic import BaseModel, TypeAdapter - -from dagster_components.core.component import ( - Component, - ComponentDeclNode, - ComponentLoadContext, - component, -) -from dagster_components.core.component_decl_builder import YamlComponentDecl +from pydantic import BaseModel + +from dagster_components.core.component import Component, ComponentLoadContext, component from dagster_components.core.dsl_schema import AutomationConditionModel if TYPE_CHECKING: @@ -76,22 +70,17 @@ def introspect_from_path(path: Path) -> "PipesSubprocessScriptCollection": return PipesSubprocessScriptCollection(dirpath=path, path_specs=path_specs) @classmethod - def from_decl_node( - cls, load_context: ComponentLoadContext, decl_node: ComponentDeclNode - ) -> "PipesSubprocessScriptCollection": - assert isinstance(decl_node, YamlComponentDecl) - loaded_params = TypeAdapter(cls.params_schema).validate_python( - decl_node.component_file_model.params - ) + def load(cls, context: ComponentLoadContext) -> "PipesSubprocessScriptCollection": + loaded_params = context.load_params(cls.params_schema) path_specs = {} for script in loaded_params.scripts: - script_path = decl_node.path / script.path + script_path = context.path / script.path if not script_path.exists(): raise FileNotFoundError(f"Script {script_path} does not exist") path_specs[script_path] = [spec.to_asset_spec() for spec in script.assets] - return cls(dirpath=decl_node.path, path_specs=path_specs) + return cls(dirpath=context.path, path_specs=path_specs) def build_defs(self, load_context: "ComponentLoadContext") -> "Definitions": from dagster._core.definitions.definitions_class import Definitions diff --git a/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py b/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py index e5db7f40db003..f08c5df648e14 100644 --- a/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py +++ b/python_modules/libraries/dagster-components/dagster_components/lib/sling_replication.py @@ -8,12 +8,11 @@ from dagster._core.definitions.result import MaterializeResult from dagster_embedded_elt.sling import SlingResource, sling_assets from dagster_embedded_elt.sling.resources import AssetExecutionContext -from pydantic import BaseModel, TypeAdapter +from pydantic import BaseModel from typing_extensions import Self from dagster_components import Component, ComponentLoadContext from dagster_components.core.component import ComponentGenerateRequest, component -from dagster_components.core.component_decl_builder import ComponentDeclNode, YamlComponentDecl from dagster_components.core.dsl_schema import AssetSpecProcessorModel, OpSpecBaseModel from dagster_components.generate import generate_component_yaml @@ -41,13 +40,10 @@ def __init__( self.asset_transforms = asset_transforms @classmethod - def from_decl_node(cls, context: ComponentLoadContext, decl_node: ComponentDeclNode) -> Self: - assert isinstance(decl_node, YamlComponentDecl) - loaded_params = TypeAdapter(cls.params_schema).validate_python( - decl_node.component_file_model.params - ) + def load(cls, context: ComponentLoadContext) -> Self: + loaded_params = context.load_params(cls.params_schema) return cls( - dirpath=decl_node.path, + dirpath=context.path, resource=loaded_params.sling or SlingResource(), op_spec=loaded_params.op, asset_transforms=loaded_params.asset_attributes or [], diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py index b71fc6a17c469..13f3e05af6bdf 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_dbt_project.py @@ -44,19 +44,17 @@ def dbt_path() -> Generator[Path, None, None]: def test_python_params(dbt_path: Path) -> None: - component = DbtProjectComponent.from_decl_node( - context=script_load_context(), - decl_node=YamlComponentDecl( - path=dbt_path / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="dbt_project", - params={ - "dbt": {"project_dir": "jaffle_shop"}, - "op": {"name": "some_op", "tags": {"tag1": "value"}}, - }, - ), + decl_node = YamlComponentDecl( + path=dbt_path / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="dbt_project", + params={ + "dbt": {"project_dir": "jaffle_shop"}, + "op": {"name": "some_op", "tags": {"tag1": "value"}}, + }, ), ) + component = DbtProjectComponent.load(context=script_load_context(decl_node)) assert get_asset_keys(component) == JAFFLE_SHOP_KEYS defs = component.build_defs(script_load_context()) assert defs.get_assets_def("stg_customers").op.name == "some_op" diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py index 494e4255aa853..d6fcf590b64ea 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_sling_integration_test.py @@ -66,17 +66,15 @@ def _update_defs(data: Dict[str, Any]) -> Mapping[str, Any]: def test_python_params(sling_path: Path) -> None: - context = script_load_context() - component = SlingReplicationComponent.from_decl_node( - context=context, - decl_node=YamlComponentDecl( - path=sling_path / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="sling_replication", - params={"sling": {}}, - ), + decl_node = YamlComponentDecl( + path=sling_path / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="sling_replication", + params={"sling": {}}, ), ) + context = script_load_context(decl_node) + component = SlingReplicationComponent.load(context) assert component.op_spec is None assert get_asset_keys(component) == { AssetKey("input_csv"), @@ -89,17 +87,15 @@ def test_python_params(sling_path: Path) -> None: def test_python_params_op_name(sling_path: Path) -> None: - context = script_load_context() - component = SlingReplicationComponent.from_decl_node( - context=context, - decl_node=YamlComponentDecl( - path=sling_path / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="sling_replication", - params={"sling": {}, "op": {"name": "my_op"}}, - ), + decl_node = YamlComponentDecl( + path=sling_path / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="sling_replication", + params={"sling": {}, "op": {"name": "my_op"}}, ), ) + context = script_load_context(decl_node) + component = SlingReplicationComponent.load(context=context) assert component.op_spec assert component.op_spec.name == "my_op" defs = component.build_defs(context) @@ -112,17 +108,15 @@ def test_python_params_op_name(sling_path: Path) -> None: def test_python_params_op_tags(sling_path: Path) -> None: - context = script_load_context() - component = SlingReplicationComponent.from_decl_node( - context=context, - decl_node=YamlComponentDecl( - path=sling_path / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="sling_replication", - params={"sling": {}, "op": {"tags": {"tag1": "value1"}}}, - ), + decl_node = YamlComponentDecl( + path=sling_path / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="sling_replication", + params={"sling": {}, "op": {"tags": {"tag1": "value1"}}}, ), ) + context = script_load_context(decl_node) + component = SlingReplicationComponent.load(context=context) assert component.op_spec assert component.op_spec.tags == {"tag1": "value1"} defs = component.build_defs(context) @@ -150,16 +144,16 @@ def execute( ) -> Iterator[Union[AssetMaterialization, MaterializeResult]]: return sling.replicate(context=context, debug=True) - component_inst = DebugSlingReplicationComponent.from_decl_node( - context=script_load_context(), - decl_node=YamlComponentDecl( - path=STUB_LOCATION_PATH / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="debug_sling_replication", - params={"sling": {}}, - ), + decl_node = YamlComponentDecl( + path=STUB_LOCATION_PATH / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="debug_sling_replication", + params={"sling": {}}, ), ) + component_inst = DebugSlingReplicationComponent.load( + context=script_load_context(decl_node), + ) assert get_asset_keys(component_inst) == { AssetKey("input_csv"), AssetKey("input_duckdb"), diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_templated_custom_keys_dbt_project.py b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_templated_custom_keys_dbt_project.py index 5b21bed30e642..60f89a8d3efd6 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_templated_custom_keys_dbt_project.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/integration_tests/test_templated_custom_keys_dbt_project.py @@ -62,42 +62,40 @@ def dbt_path() -> Generator[Path, None, None]: def test_python_params_node_rename(dbt_path: Path) -> None: - component = DbtProjectComponent.from_decl_node( - context=script_load_context(), - decl_node=YamlComponentDecl( - path=dbt_path / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="dbt_project", - params={ - "dbt": {"project_dir": "jaffle_shop"}, - "translator": { - "key": "some_prefix/{{ node.name }}", - }, + decl_node = YamlComponentDecl( + path=dbt_path / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="dbt_project", + params={ + "dbt": {"project_dir": "jaffle_shop"}, + "translator": { + "key": "some_prefix/{{ node.name }}", }, - ), + }, ), ) + component = DbtProjectComponent.load( + context=script_load_context(decl_node), + ) assert get_asset_keys(component) == JAFFLE_SHOP_KEYS_WITH_PREFIX def test_python_params_group(dbt_path: Path) -> None: - comp = DbtProjectComponent.from_decl_node( - context=script_load_context(), - decl_node=YamlComponentDecl( - path=dbt_path / COMPONENT_RELPATH, - component_file_model=ComponentFileModel( - type="dbt_project", - params={ - "dbt": {"project_dir": "jaffle_shop"}, - "translator": { - "group": "some_group", - }, + decl_node = YamlComponentDecl( + path=dbt_path / COMPONENT_RELPATH, + component_file_model=ComponentFileModel( + type="dbt_project", + params={ + "dbt": {"project_dir": "jaffle_shop"}, + "translator": { + "group": "some_group", }, - ), + }, ), ) + comp = DbtProjectComponent.load(context=script_load_context(decl_node)) assert get_asset_keys(comp) == JAFFLE_SHOP_KEYS - defs: Definitions = comp.build_defs(script_load_context()) + defs: Definitions = comp.build_defs(script_load_context(None)) for key in get_asset_keys(comp): assert defs.get_assets_def(key).get_asset_spec(key).group_name == "some_group" diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py index 73955faa3291d..69409ae590a51 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/unit_tests/test_pipes_subprocess_script_collection.py @@ -25,34 +25,32 @@ def test_python_native() -> None: def test_python_params() -> None: - component = PipesSubprocessScriptCollection.from_decl_node( - load_context=script_load_context(), - decl_node=YamlComponentDecl( - path=LOCATION_PATH / "components" / "scripts", - component_file_model=ComponentFileModel( - type="pipes_subprocess_script_collection", - params={ - "scripts": [ - { - "path": "script_one.py", - "assets": [ - {"key": "a", "automation_condition": {"type": "eager"}}, - { - "key": "b", - "automation_condition": { - "type": "on_cron", - "params": {"cron_schedule": "@daily"}, - }, - "deps": ["up1", "up2"], + component_decl = YamlComponentDecl( + path=LOCATION_PATH / "components" / "scripts", + component_file_model=ComponentFileModel( + type="pipes_subprocess_script_collection", + params={ + "scripts": [ + { + "path": "script_one.py", + "assets": [ + {"key": "a", "automation_condition": {"type": "eager"}}, + { + "key": "b", + "automation_condition": { + "type": "on_cron", + "params": {"cron_schedule": "@daily"}, }, - ], - }, - {"path": "subdir/script_three.py", "assets": [{"key": "key_override"}]}, - ] - }, - ), + "deps": ["up1", "up2"], + }, + ], + }, + {"path": "subdir/script_three.py", "assets": [{"key": "key_override"}]}, + ] + }, ), ) + component = PipesSubprocessScriptCollection.load(context=script_load_context(component_decl)) assert get_asset_keys(component) == { AssetKey("a"), AssetKey("b"), diff --git a/python_modules/libraries/dagster-components/dagster_components_tests/utils.py b/python_modules/libraries/dagster-components/dagster_components_tests/utils.py index 665aea9ea6e54..87a9e94f1e266 100644 --- a/python_modules/libraries/dagster-components/dagster_components_tests/utils.py +++ b/python_modules/libraries/dagster-components/dagster_components_tests/utils.py @@ -2,19 +2,24 @@ from contextlib import contextmanager from pathlib import Path from tempfile import TemporaryDirectory -from typing import AbstractSet, Iterator +from typing import AbstractSet, Iterator, Optional from dagster import AssetKey, DagsterInstance from dagster._utils import pushd -from dagster_components.core.component import Component, ComponentLoadContext, ComponentRegistry +from dagster_components.core.component import ( + Component, + ComponentDeclNode, + ComponentLoadContext, + ComponentRegistry, +) def registry() -> ComponentRegistry: return ComponentRegistry.from_entry_point_discovery() -def script_load_context() -> ComponentLoadContext: - return ComponentLoadContext(registry=registry(), resources={}) +def script_load_context(decl_node: Optional[ComponentDeclNode] = None) -> ComponentLoadContext: + return ComponentLoadContext(registry=registry(), resources={}, decl_node=decl_node) def get_asset_keys(component: Component) -> AbstractSet[AssetKey]: From 82e2189e9d660bcd439546f6329691ae958226f0 Mon Sep 17 00:00:00 2001 From: Daniel Gafni Date: Wed, 18 Dec 2024 01:48:03 +0200 Subject: [PATCH 82/94] [dagster-aws] add ECS Task executor (#26098) ## Summary & Motivation This PR ads a new ECS Tasks Executor. Currently a `ECSRunLauncher` is required in order to use the new `ecs_executor` and most of the ECS config comes from the run launcher. The executor can override a few important fields (such as resources and container overrides). Resolve #9671 ## How I Tested These Changes - manual testing in personal AWS account - adding tests with mocks. Heavily using the existing run launcher testing infra since the executor currently requires it anyway ## Changelog [dagster-aws] new `ecs_executor` which executes Dagster steps via AWS ECS tasks. Initially, we expect it to be used in conjunction with `ECSRunLauncher`. --- docs/content/api/modules.json.gz | Bin 1423465 -> 1436937 bytes docs/content/api/searchindex.json.gz | Bin 85780 -> 85861 bytes docs/content/api/sections.json.gz | Bin 481870 -> 483922 bytes docs/next/public/objects.inv | Bin 25120 -> 25125 bytes .../api/apidocs/libraries/dagster-aws.rst | 3 + .../dagster-aws/dagster_aws/ecs/__init__.py | 1 + .../dagster-aws/dagster_aws/ecs/executor.py | 446 ++++++++++++++++++ .../dagster-aws/dagster_aws/ecs/launcher.py | 66 +-- .../dagster-aws/dagster_aws/ecs/utils.py | 34 ++ .../test_example_executor_mode_def.py | 26 + .../executor_tests/test_executor.py | 245 ++++++++++ 11 files changed, 778 insertions(+), 43 deletions(-) create mode 100644 python_modules/libraries/dagster-aws/dagster_aws/ecs/executor.py create mode 100644 python_modules/libraries/dagster-aws/dagster_aws_tests/ecs_tests/launcher_tests/executor_tests/test_example_executor_mode_def.py create mode 100644 python_modules/libraries/dagster-aws/dagster_aws_tests/ecs_tests/launcher_tests/executor_tests/test_executor.py diff --git a/docs/content/api/modules.json.gz b/docs/content/api/modules.json.gz index babd11583e37416056f16fa95aba3c443bc36c70..00caf49d509e0809799a11fd36f96a38f29b69c2 100644 GIT binary patch delta 1433315 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%0AE>C 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Ⓢ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

fXRd$S6pl3#(PIGT1vlM%)bA)Vw4UJ+a= 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%0D) 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ÿt~%nf6^C(UX^Kso!M(He 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

5hQb>s{MxLuKk8Oyl$s7v;aR^G*61-?&#) z1hWVY>6;ld&;5|Opx4m*9}owrbI3xdSyHaObM3`Nz33-1gGS7ON97;e;{faawM$UF zoIuS(yc-ap%HabwLlxbt0N3K@I)nH_cit9av*!AVJynaI#T@OHpOrVOb}iUSeI+m~ zc&`2Nx&rlK56d^=;8V~ftKX#~l#)rHW99yKFJuZaN)dyaTKe36i?BK*VW_dl<~o=8NcEIVO@(U)Tr%CP-l7B|6F zdOMKmLMw8v+|R331MIf_d89>|a5n`*dU#(JE*q?>AmonbC>LOtb`m*+d(<2{-&IR~ zH)x&55p@TpuQCMb+R+KuS2^KPLvbAcw^B!(y-jzg5~0^qZlLMbJ6smp?qqjWpf{)T zt3tPGtEo=EKS@Ck-d^sDSBKhQI;UKAPWJapUSuJk+v#$&=j1l)7EPazEz@ev66sMkTxB2N<5U!zW#C z&pY|8xgK!kqgU0~X`}CDo=4;y=Oa$13Xqw#@~iw*lvyZ~s@Mq0%~HYqMpYU!bNUl6?syZm&3h@SZLw;qO~P_JM-Hryu; zgpT2XT!+CT7*;#rmqbkJ*WUOTrVwraJtft8A`bGv#OIJZ@8cE^rz;U+oB~svWg$k2 zim;HaI<0hG%ys^LnF}u&I*41i@@N-U3l5d(HpSa$3~0i#KG@mD48$0EoH`9GtUW1inu*AxA5JANgM&KJQl<2I zoDQ;Q=tt!{!f&e@ZvGV##5r=4&Sy&0f1exq;Q)r(x!E5jW0zs;YH#XVQV|n~yTCTS zTz^i4jp-Yf>xhS6P3KaW?ER4}`8-L%Nt?~pF7yBg{j{nB-eu*0fN(Kj~8(CHPY^ z8Zg1g0gjLa5?Xtx%onfKVUG$u?{XsME@F;v!GShKZta%4Hs;()3o_$6*Nt35evoBl zXLB#tB$v9G`@-P7UNl}_httk+;=f93od>v#g&MEL20g=!%y)7pMAyy7U4AAHCyl8j zeuRA|$lcrm3b%Pk6kaD;Hj>Wtdk{Hr1MFVX@4UDpI8okPk+ZeDv}`*D@pj7KYDp7V z!ZwKS0&$h+9@;h=is(7<)EF#J(Wg5;M0dIz#09?D)7Ts@z1nLxMxXLClsSoj?lM-< zD+WBTUqEx2_4-B(3T4ry(u#35uLg-B1uTuzyj;teXYP%k{XTu^hL;(W=g%YC1^kmC zvzSxbaKgI#g&+Dxx~e}z*2Y@rX6(WF50bZlaOv0Vg;Xd`B6H^ChC>xp`ArQ0o5$1{ zH|3wQPr>TAS@&_}RSqf*=oHT@o`@gM>-C+wtRM4#vK~)o0!L)S3bDGAR;AEDqr+XqeEC8@hBIuX7}bs zqD}uV9+Oib@3K84D8q{JWfmXXyL8w^?E7o)QR2fD!BTQ1>a20=UBW7y#=92;(cV0k&dNpDyn~|q;;bo-jJ}C48LWPw?7-#VRD^3M>-NXP%idh z6!{p{hLXR44V13E%VEsMkV|q6(~~g;Hegt8vSh96sLfoH)_Gc(xN%7<_U(@H+H3RT zgb9W`dPqW_w%j9&!vJpZ{1ZG#$NP~FmWL{~EmVKt$smqOchegV% zoLQCWUD@t6d_}T2NIKF9xzt-s0@D5(9kxS85;RvgXHT_s?f|e(lr1{T)Lb&WRwXyH z7B=my;zE@wL>Of8k@#HLE=JJkS0iXmCaB0a@w&cNqc{mc5^qFa8&Q!^Y=*ZWRuT1f zLJ(1LBnjIXOnkm2Q=V5oi2HYd$31SH1H!?Pu#m&-`2|g&AzDb>Ws&0-k&rb_k>A8w z_}B}@+x^q2Q~{nDq)(aP8(<^@D-2u}z!0AICG16NDkP4@!zSg&Y7Ri{5}W%v;@PMJ zKl51*%yM*Y^)FY$Tb3PQ+73mf$_~7cE>X^7{I;3SHAd>K0@B`K_Q7?zUP^!L${(i( z2u3;7Cqs46SVX<4M;8!IA4;Jws+*9bag?dBk-zNOb zH4c^g=7>RGP0>?CdM!d}JG9=OHgFupC?QBK_nbwDs;c^>mBeZmS{^EpiEc|^-=A{PyY zLc5%=$Wja)>n26}Hvle`vE2JISQvJnN#I`w$LqEcT{Qg^ zyMTs>et72UrReEa|G56_qWhWC(}m$+v5W5W46(Z!3*y)TVmIRR%z4GFi~MGu?(NjQZAt^1ezrW7%K& zPRXQ}E;gwbsIf?m8*gPO+Z(j90{st*f&f!1j)-|&0skmyjKj}YjrwhLTESZ)>j|&V0zDpeXWxHh#3~lzz zy;plHaG@|dE%2izN^x0PHqNb<-nC8wczSRVHd>#H}H<-^KTh$zJ!RQ8ZPF^{*c zhv;E3c9Cn|fH0=NtK*y?LmiPbvP<-eY&OCwUxveqp{3D>lhW>XjY z4ylhuobv<|_hFyTVijH~JHV~Xa2v6zS*Covu${G>As)5`7qphNsi+7 zVx??jZ$Ahg=ZSkh0`KGNQKB{lLTg~Uip8`#()l}Nii;AikZlQ7F=briZS)QNb&}&} zW%6ioyPdnU19g1#jz%IY?b(z3o*DU}yq6D!5?f(S%8)-})+q%d0ph){6~WjB4aVCW z$A~1}*U0JTEPnAJ&aWYkKnO@KIxG3_i7;u=QMK)Yads2(9pD~4YVl$Jj9Q&ghUK$u zaAa6$JcU^uOV*6RYE0@S36*p!RiG5~l#wgIBj+n#M`JP4*WlBOX|`HeVkR6zKLgZT zLl%QwoXzzx1=!mKAdm&ZA=e#4)_OmW6)*zpx#d0A!)7&}PnLq9D9Z~x(Sk0Dvi183 zr+i<5oplz7Pn5?Q?7E6d^)YgUqD`kd0<28t+YSq6=@x!9$wek(Hj}cZa*e1iuPo}0 zGa%t!9gq| z>>V_k2{PLl&S&87q>OJX>=NAX3k2}`z76zz(^C;DUt+Ts>E(ahjFrnwtug&*L%@!S z@pHP?`(QzY2lzYS==E!E?~@P+5%6Kk&Ae1wr|fPb%i;Kc&W+5R9k%UdS1KXvNZsit zV*&R9N9!^g06bCN3#S_E@(F5|BvWH!3$HOX;I^vkDu@zIq_1&JEyC@un~&Fs=*w^n zp6~To$WBe^lI3mt^Zg^T_Eb*SNGr!>U#gqg5-cGmVN0 z9h08Ng;-&e)TT7YrDEA&&ep9Itvt49y@stmDI6VFfNesq_w;A4u7?%2f{XnGWG%-_ zv+=fwG(lEVaD|QsOcm4nU^M)c%lEI+^j(tGGt|(f8UHp!U?Eaj*o$tHYc;K@ z{?Kbv0r$5szyF{N+plM9BpH8=F#iJMi4#`<-^P3F9wdIAEt2cm9ea!x!e7{>tb3}M zvV~M)ZK&`X!4ZVG8rMYo+7LyC+517{Y>Ek+AG-ZBF>%1RN$luiVt@v{{^sU+@vF&j z-*AdJjh(($7?A63f;F1H{vn<#USiXCKwKh%0#xWq$XhSlORsMD-k3-1WkD6zgHYYD z<5zs024B%HIV6WkT}Ty@7=rl>8D%pfPiOK>!2XsgHW#Q^DmAeTn4GTAI91VAgAQqz znww!#;ZG`hEOnqr)w>Z^sa?MiE?F$|Riuxg8mTZsTf( z)?0ufy4cLu7(QrY@1w4_k=h#Kc78Lp6A2cqtL{6BX86Vs+Q@t_=LOwep3oZJxFM%u z4WHTBI_tqDnhok(!bjLTx@;ZjT+R4&0OROnz9BfJnCsrLgp~@>JRa@aWqKFIo-1g< z8La21q}}RT>%2+AT?j$_XrY{8KR>6s<~b8c5wk#QbD~U^WwO(`K#fC$Q$~g__=&4K z@o7yFroWoipl$&-u@J8Z^z-Kvq@KE=hOhxd(Lejszqc>!=ShYi#WLUQ*Qd%7MT zW1~k}JUy;7WZ2&~NRZBma6D6E%BPzs^M!n&%lu4^0z#i;Rbd$Y&+#CzV^9uM4tqgrIIsuFNht+jBNkcN{MH%}1;hm#dEjS*>fb~4hcVVG_@)iK<%x|P~z7fVpvV z%#}K)Gmpo)q-(cRaTHza>zY?ui;)$W7Pa!olCrYcr$kobKlE#bm~rdyj0ahBH8tbq z&yQ@A4%5WaL@`AzW-I81D!>`F40b?Jq(ZU27bCfpN=C{#O5Vpa6NfO7gLonEXV8aH zZY*$ctDWfOmV3@`dasz%fJc`wC(B;y0mvPUQXN{Ts_GxSD1g!;uW6ayqx7=e?JjibMi5psg*7_aD`YKM#h% z?0rT_yT1KQRKvaT7-W$priE81JC)-{L)x7CE1%cuc&tkxraO4FQ9Y}6J@>%?&^u^X z8v(V9W86PCZHRCabRKcZ?chOQEFuK1)+wC!`q-vb#hEpleVFsE1RZD_Tm+SVmm3;)=8tx&u_#%nx>SXDj>J#Xvb8=BI94@U^=vc}4X5 zO{Y~B?yIdiE4%-3?X%3A?*l?qU9>EPw}2 z(L@mY%PdhD5Wm^DfMSX4FdN;BW-$1QbyS-5=NhNib?l$v1I!Kho*kWbsopVZ+$PTZ zSSa_y6U<-^$;01UgmGa88Z;=Mo6kBd8EZO{LI+STN^;>;r&udA!M}(Hb`M|80ksXc za;0tGhwF-1;vvqJUAZ9YA5@$=TASs_>N7gl?CG!601Ft-#^lILmS2c21S%wWclcvb zbAy^lLpWlUP-8-5FmE7)Mh{lGL@qaJ=bQHrgi&Bb$>7Ug2nrtQPnH6~$R#ql`_gBr zb5;mlpr^>`Y5*xK99_MML^4)#XxTJo$`tH^<%gos11yN%C23z7K}vj&aGA6v(usIU z1J)85K-w&M&4KE;+I+I>i{in!%qtmXhP+a2`x!O)MO}2gR5&YKh6agG9D}2DeQt__ zFkQb=!&RW06nnc`X)C;|5eHgoO^9n)>$FC?o=n9zQKIBSNl93Z<4#k_pCCsGfg@FW zh+9SJmD6(7VhpGVI&^`Jx>^+ZmoIEZ=9iuvz(f@#9{a{tJdZy}`EN}v`3u>TtC6a= zNLuyj5fS9EJ>cn=&S@4_F|3Fix$rMdxP1oS~6SDouTIUkGzCf%X7 zM;tf$XK|2Jz8G~0xGUMuwUZm9YLoX{05e>%y0ik<>WjHD;Mq92?7$bTmDez{$y>Kt zgV>LTCKHJzCh~y%(O*Y4b@}U?WA+ot%lV;>>RWK1Y&xrU*q1{=Lp`Ci)K+plN~_2x zA!{wpl>|`5lj-XhO-kPh2q%>isUX!U(1$5KA2#}(b^M(^k8dBt&-UAy`e#B~0G-%L z1D^Z#3U_v6oJ_HX^J1jodQpct zYYm%%2rWp+HSEeC9zqfu%^nsVYaDmYGnLBQO6b&!?Dy2buTPH6QdDS9fbVQOvL|tq zyU0V>Z;dYh3!QOP#aE~!k5a2pZ+4&*{LL%s4fQ+t2?*wG;luZeWm`I^gWcv@S+%YM z1jTXCXB|z3E-Avl`Qt^)uBcYwTQ@!wB5wr~$!v}0mS{O?CDo`rnw}F@)A3lYz~9)D zlL~d@Oom5M{RNW)UxoWWl1}LUsF+-NzU|Zcxpl+@;{0Kxkv}tCst(E%UMsrz=i&A* zxACim-Pd*idS}c}!8~({fXeCT*gV_DV5>%T>pN*eD`kK38H5vI=BV1Q=}bv0#P1LX zi?ah<`~Inc{qDmUSO+> zRJHM9^mc39{bf?UZ7!kp4{1ZEnkqw@9^IJp-trK(V*EW*g>y}Z0}cmOBcI*1U(jt! zCbg`uY@Kl-GSwNWfPm8WgFiO-6Ahg;w4PTan-E|IBHpSa!lysu{QNHDdZo;oYP3I6hy}zMSfKN7Uzp|`W_(GczXV~xM zOv`zk?;6Rl!tmgBrCDr}ZIj$aW`zkjFv$>=7OwW+_Ky#DPOlMyc6PdAk60`&=fAq% zr`KK7&eQ-1>hk?gy8iC73@Mi&|`T5%;UDtv}rK=%N zsZmoAhXzfyouXA>IB=rc`QJfLpU4sG@nK$5>7jqj9T&0Z$^-fzLuBrWVXhT(71`DJ zC-`9o&SC_wv|FKU-j3E2DR7f#D0B!fwRg>&J9#Z403azN!#=QLZ)qnK6qMN6@66l( z8rR)~pWFCqe394qj5|IN>d%tW|h+f+jGa{-GqzN=F;v7cdOADXii@M?Z$@;vG+X z0kBp8=FbR4m1(akA`WvjMV!Z{L*65SL^~X;F zRv?7<;9X2Lx8MmVP2a|B}^ zRnR}=zoJjf_}18S=a$RJ`o*PJ*m%j9i3~dh%8g;Z{N2LZ4&CrhuA^FH^ssVPF^9T( z@`S(!=OPMW0}+u#pd%f(OEP$%&Kqi-SyDuSs`h$>y7yM*mXNF#Gd!JKvP#PUeV%ii z&R8Rc8x&Sw$oVPC&dZS@2SxPRo1ut5I{(;Y{NPMo3>uS0;cZtz7^k&kk>;bk3)jMe zo+PM&869I`Z0d4j!J!9dLsaSaHs26R<*yG5gY4vdMm8J@SR9ba>#Dz_AfSw}3BIvv z;rlN)Jh$~d1cD9ck8#$AjGRC-F(Gm!plf(ogEi?0&l3HRtBIYr;N{75|o)7sU{Rj&i9m=~21=a@F@*by_KhxAY)8AJVC1ciL%< zvy}Ms5|zoObpFSN47xLepisbAQ3T5S*l@m?P#Sz%S3W2LfM0bN=&lA4h@-(|56ebT zFoRQqhyC;w47;^`yjOLKl66L}f8@Uff6~6ULMo15Q#OyEi$+5H;^g~QkzXzKt1@9Q zd;TrM08n13Gpvc~_ljlpdqgLak(UFQP@a=@^X2>F2odo1i_i2~(I0YXAhqB=Zyafj z8$s)z6J4++fb;ay^E@@{Z)K9a8jvaB+IY&)C!GQ6@Wr3$&J*1BSeGBQy@*n%a;sni4NTn>Iucr1*(LQqUB=X2Y*Yw(lA zLCa`lu>~kw8oDtO{nd#`>y8RGZnLe))Iv8lA}C!G!1f`r<>~HunkH};9F1F1p-^n9)lXDxyRFYoxZma7FZRc1Rz) zd2$l@4HMg*-!~`QX|SA(a6C-aIRqMe+x)0W>^drcvU{f{^dLW1~kn zjq40wM4rn5O${{(A$P=Vk_dJ-AUE?62Ky`zfQ4W;h)f*r^z*KEw9|$3f}cj$MN>(?&RcHDV18V{ zK(mi7akkYp$`@Ab=7!)*kjoQ=NRFyz0G-QI&e0AT4zt4{v@O52mUL9ShyMYNKyklT z!!tqeiiXRkp5sdwTznUWyW6|$qd(?(v!hGzbN#J1FW-jWHGKYuhR^@2;qyPTe_!=- zt#V|4Q8O<=9ZQ=_x4D^^h}K%wZy17E*HA+bX@knDUu31c2>q8$QI!lVx0b!9RFR^D zuugxkX@lORgs>=X=$-5k`!RT0vK|}GhzyIVjR&%J^K_l<#rLzlpm2c9p|{FM(HsfO z-3QLbTj#p8+0dW~HNNo6&O-#!`fxn}u4eUIp{sMVYk3tR=L@;nO09lX7btfGzFRz3 zgfXk@2k*KbE6=eXoG7q`29T7LUqE%Nk??=lvd}EElifU@7 zIZ#8Cir=gQYl!>tnDpjGOkw=F#iT9y`nvM|*EA$dXUCAkNQ6N|`+un@QYdg2t=y7F z=L8YyVX^J=Q@lvev&LkLcGPG*&b7)>JfnYS z?`4zEjU2X@_5QNi6oxvA8!^|?eMEO+r7!%@2^Fv`7F(9XBv#C=?DxNhE1v6}{z&C? z{-*opG-F-PJGV+{>>;RnU1(K!Txt zjb|;l5jx54hy^^Ztt4Mx#87M{$mwg_>aJ^X@*&(}+R1nCA>YL`pM8f>^z;@5@G8i) z*dnv;#&^y=vQ`KMR)p4J`#9 zoQ3rUVedBJt(!fvL=jP?V38NrFJz_3cz5BB%n(4`0{Oq>mqeRmm=1sJ)meA;MQ^Fk zg<~{K8gcRH_TQ|skMSz=I0y8#7(Ch(#RE0DCo@z z2Ujeq&F&DLl=N;cfVUy-B2Qx!@6r$em6CJz>H8IV*?ay85n<=QZPA*^(MyDPeq8BH zvkKikh+o>BUNxA-1SfwN>pbx!m3>SS6V(?vQG#EWRG;N9PCSQZ^$!Ssj2X%udS>1c^7}ZS}@*vdkZH1^B?_tAkZ*pNL>I~exvq~-AhiiXAEh$|h;v;Zdm)j^Q z>k36wWdzTmpxAMp*cr%)Q9tuQ?u?qrHH46wkCeNFly;x(ply=Yan#Fkyq>vNu4^TS7Q8}a?lh)BnH%f+ z*gnxH4f%GJVMcF=4&rTnM8g=^+M^ho8gELA&S-Q6qA1M!M~L2$LHh9HrOSL)2(J?%l=$ZI8{x#Uv%Z7Bvb|89DJPb! zvqE0YtlDUXZ$vg_j*4U_B1AzR1AosLggp`_EyC#<2Rvmvy4`I+)o??^B5g^qi7f3l z3hzA^;#Gfz*JXa!T^w$R(h7UAhaWR?*t2vVIz63wp}gjqM5ZJp<(?#sd( z&pM`J<@~!$MJ%AgF)E4ToX3L_Zg`t8)E{R(b#AD!AJjFrHU@ZdNo<|S*%&y#q()DJ z36g)ak&_|JL4~0Dl!#GX&?n_|YCSV(n2ig!u}x?<-Z&NWO}=-zQM8bjRBfo^SW6Y# zPvIP7qbRRsFL^zkmD9EJ(HMAH1ZTa4tWr5H;+b0kKV!7uF5Y;Lt-DeF2}^T^QjR*!tUD0RBXdEX0lfUErd~-zzq5 zfi0=&=-XfSKiwL_x-DUTzU)OUyeIFmsZxI$P!D549U^ZZ?d@Q5(HxR|4E_XtQPBx|-JR-U2PG=e&Bui#^9ro|s!N=*Kr+gkv_?+(PmCRADB!5xV!n z9k%)Vlc9D&-10(k5ne~$3fbf7@T%TK?3i~`Y2jzBYgcY*rfaIA3<%LsoOM8`1{LG# z5N%G61Ve$z=6rmR2IMmBhGUv~Hhp#|EK!Oc4I#l1ns&{wD=L zRF@Ew$)pv`1iC^C>jKd9X}StS^PAH?VCnMNEWXiBZ(rO zJHmr1hKX88$(~^B`yZOPts2!$X~`qJUY5;Iq0Go{7=z@xGz@Gt)bZ$8t|_vwv_#cT&8#tj z?Y&yzIC9qUM*)y(b8e2*?bHi4Fs+?J6t^fL0N1#;)7s!T%(s#6*2g4PojUhGwGf^% zs~d};bY};2^0&6LRRn)R7bo4rHr}l;>LH6~h=z|9tr5`p>HEY`()M#0BL-j@=SmEA z$`&|9HG#yTfQss;9tx?bX7(X5n7b>0Qg_wn{9gI8`cp`5VR`vfid1u4Qb9xU@flu+ zxtrXm5cX)j8P81NTowQ>9WP0 z-h0_e=c+=^C~43Zn7e|kn3=*rZ#%y0g$wAkHHYeJXFPvzfaD=(+qT!H@;*J<`}0+D z5X`So@iuB*plqv-XMTsHqxGL9Btnv5JrbY1#HYif~g(c(XLgG4*$g=jI5Sj_Z1?c-?+*qQDkL zj-;ggf{}GySk;D#F&VG-s+Bcu`xKiwVrL7^rGBIvOpVDzi@FN9H5Da>G_8`P+sfJ8nbJ?**9roYc@m4tX1QaoLtc67P3(Qn>8pR)+?*CnMlyj0Z9=^wC5?oshc-&N4RQh*B>< zc^mXkFL1+$R5jpe$VBTTpV;Be4SDwE(-(7#jGX;*)~~eDmJfBWFA)>-+J_Ew;h%rl zb$_Bst)1HZs;2v_FLxQXp~0K|K+pfd{bmAcCI?yv4z%3rj@psd#0Qf{t*h8+cIgj_ z9Rk~Gv29KLXxXlpng=rUF}2I);>OyCJL|y-Xw$)m$cqtt!hKWl8QyJaXS`?^1T;^I zBAML4)fj^EK+e76=c%CxX_)-fNAQ1;k~RlKK+!5-5MEy^vi0?K-p7<}4Xq_%t?T7<-GqRnPnQ(H(lee? zO!@p?C$X&bMFD-va46m>G94=M5IRV{4gLf4z>b|{p zsu}%+_Ls2ghbX+O5Fy6QvCdP>dH4;vS8E~zrxatVJrh}gsWzNc6Dv}RFd2oDrkKV_ z<-kYD8JuDpQ*5JUVq95l83i`RV>(r?D&|Uf*%08jAE$`G6cK-Tj0yG?QE-?v z`vx+)Nwz<2Np(;mIeEJ$Z}*r|{>7TjBrPT%v8gv}+z#U5@wsG_42st!B<9iMcO8{K zks*4O+=)z(va5uM*FY_EI0%EMAT_+(UAV*6`fe9|Nn|;j=5+m$^!iiUu5s`n7?)j?Fz72i4D6^xLcql)W{EhqtrmWyo^qlRsWYdwe;ku{3 z9=TX7Cg&nk%!_L|m`YC1CuiRx36pK##tUi2r!5WQx(z%=Q~1!Xz#xPYuj$~9{@^|r z9Nhn!JY$n*>{vWw`P1CId5^$x*5!$Ql&&)q_llyIWY#-w?V*2NW+QQyO>VM-gP#@? zeYng_^sJ;SZox^$n_@C#R2^4V-yW9U?MuhzhY0U=UWQIE)!oCS(G?>pbxwr%DeBgI5nc7UXgYYV0Z^Kc{9B zkEzh6mP;nv^`w7n*Tcc?6fc+2V=wg0M^nknR5EkKAX=r&dY&bP1P7;UyOH%^`P8eyEz zn1H+SCNb75ljgW$UXk_2om(qnv3Us&c!NZ2Sb^*{^C%&LF+_sL)W29^#vc7`2h2IB z5^-p6+mv-MdLNlQ3Bkjo%0HM~Ia3Ly3{oP&_FxqXTIn=LgSLSu;NK}9sdwOCJh`tX%-{Ce>G*Wuen0E=gsFV~ zhlbDptKoBw%5gO%I!%dAj|m$X9~>4KpFSe+!G(X>@d(|i-fyb+8&SOM3CtQYAiGpiRc;1E)xD#2jxo{ZzI^W1{tFhZKH;x-EoZe&N~ zQJhQ8QtvoCcnm;1cqB+XcuI;pQD?Y1qL0dzs1N#cWFGYrbakCWeZsAtyuVZO;)J2p zyLo?i+Q_#@;z^(IttWiz>40}}z@Il9%#IKKPF-sEg8_be z&P{CN-3mTYcMi!?rE9%Ds=3kaywJ_G&kpH}#5P#mHnX@7U#Qze%%KW)Yw0;kALSSm ze=`kW(6Zl>kExunT5wHKjyNS}V*^hY`{jS-SLk4_#!ILxBHBP;A*d9BhKR@miz*@M zCiMOAfi5GNE{=9cNmqDEy^y)>weB3Ky2+NE47o5HiIwl<%WzoUtYg(^yM?OrNUgEs zJIIi#9f8h6W~7_>3DgN7|r&jjq5o}qWdrmlbf zJOB5v?b;?!^yG=2gph(4Y7#<|uYB^AkHS|jmP^Om+GLVVD)0QqenE_mvgJ!Re$c^t zzkm~-zeyC{qX0632XbsTOx=kaoBa&^wk5J-Lu8QSxAJ+{kvgP@TMn|cY<`$t7(Xch zH0e91-)|Y#iEbh;g*=L#5AwzADJ6fG`PkCwEx7BVjg#O((yuomj;#o-3H#)3At$+R z$W%IxZ!L#my5H7WvU{_o^;6dVlZkww^x@81-+||lNX*DX_xaaSbt1DYWo7D;UH@F% z!>gtBL3u@WE~%QuPuF0PP;XrWP}enhz_SH<0H-ws3<}s9Rtl-52E723mq>qz0Nug` zS9TnRR_MF118|o(UeLf-i(X>i3{nb+85HeKSUe&R`}$-#acsMUe-gYVyYLqMAkdj3 zcc~@`lo8{!k?I6Hse@EkGcWQ*2z2B^j+`~$l8k}vn<(7as=HPR`&N6SB=TXtwePxsN zb7zmker+kw)WlL-(Ney-i@#XEAV2xWx(JvbWJ7FJ$Wb6`l58XS)P;CIRoQ^?$&tKw z{2k4iaIKApA#a2Ni-NJZ1`sb+=!1UWqd!;#PLK#B!&7jnSGC?p1Hyl-WTM(AHV zFGARk_gm!J?5bpOfX;ufBty#(vZ_{L=xe~{9-{|Hz7zFq+aWVlXSQh~ki9_|JGW>o z9MQs8pi#7Y%*>>?lWnxuAtlGWnNPkoxh>SVdU*i$)3&?inrr_W@z@oU?pRfgd72?M z)R}LlAoOtz=%pJJ--T{lkF-2nUXOorIn7mXy(GU`DuZDe!Iyu~@JdV}WT67WIuTl= zoU}+nkn38^kxQHXL-gtRH|?{oGHYi&8fGo~Bs9O^DKtrF zWcHuK#5}jEd=JUxcuh1lJ-BtV-T>JK=-%Th2=RYEnOjd1rrZ*VMq`an zmev!SSWr73;b(vRC_bY{F^lFsy;jGA`g#hrKcYEiP|AoS!?_uk?3*#@f zY$TVS@B?UQK&)ll;1p4j@#H!uBN&SCsuRAZT;_j2oZGK|Jb(Su#m|3Jgtn@2nFf2~ zXSv{b=LCP`Xhp`uT##J{_;lj|-iityWe@YjDdXp*+O})}Da4a(fL{WUUrF}#+EH3O zu@Y!<#w zb<=tl%oF4A7Oh*X5Osim%*N=JL~1?Z9)+%Qgh_umz`J6Mz1?8%R~SY2?FM=sqG%0q zlTV?>8;WE?m%B=gNC$lAeeP?t^5V#e_V4&yZLfu7oPU4|-guNt=RtR%p*E!kb+m<8 zNb{Hp=UwK;>Xznw-eQ){*n;dz$#Q#osRyPFO*!My_uO~Iv!ivFD4C%hym6}PZ+$0N zkUxL@Ht)aMdA@5$2vhrl!JKRgDrzf|DS3;MfnY*s0O?W?Iw!P(Sz5gGYqTnfPeaWf zSc-gcZ4Ot9mH2zOQfT=-H)oh+Dg^IRj#5j=13cf*Ni_rsDP!dV9*sWoudpNi1m{MU>`i1pwpN@ZYmj0zz zcnmeqg)KRQ9F)10mOK{-oCCkKL(pk>M3BhaB(_-Ai(z7Z-ziCrL>ocn9g^T*!`1N- z9qj_!bB~JTnk&<&;zaB>Zk(P=(L+p4WPfDeq5y)fM7?W6g3L*7xOoCkkD51Jy89eR z+q0RxNJilnGnFzJd>O>wPg`SrrMbzauCyxXcWwFL)A1M*VJ zshfc)I{AIEGZRqn9?4ZZNskOZ%`Q(23#I&+3zhcP?0hF**D`pbr1iH_WGZPaVs z%+EtD)yRETLoY{HuCRZ>IsOPeQ$w#&HQVM$9A85()QJ6QgWsu>o37rLIMhbqfw#cK z$}@13%tsRrQ(}TcalujhfQMeJBa6BXy*#7$ybrw~eL3_s-{S|z$L(IEP((IqF+>uy z&kH#oEk>un@gNr&M?I`mbqme($&FF#|EKxH-Ge9fSL}50nuUM4@ZVUjRA|QFwIx&C zmd=za9=ofZl!8UIhf&Mqz8=(6>ET`o%(<)eh^uWU-XUQnU%DP~rH6YVu;AdC?%>ca+n&sf?(N_&+^g>=S5THk5@!5X#fm-LhreaV#Mt_=V(Rpd0ovv%D`#UDI z>>1Oevix)}Buac$dK60rGl7Hcn^E8bbpm&o$#tH;bFhD{=YJDvysh5kgxr9K+|jya z6deiVV>GT!*OLbI?`wn!y`r$s!d`E(24J$Nr-qYA$#d4z6`jj z>b(US>w~=Je>3@W41!6J{5c6FOgD8BNa{Q!6h>W087cV3XeG_S z2V0WaJsoarZM`k>y@2)doldzPLybl4kRX5HJOahTa}%|Lti>_t9KxE8NiboHEzl&9 zbofXlj})5eHs_0U+VMrX=gT1NUTTV6l4dVj-seN#0n#d@fp3AK3vj!>RotwWmnv`~3` zI)Qp8P!$?uI(@R!$Nik-%M?Svg4Wn0GB%76Ze&&2rN+%VM8Tt78WH~+?kp!lZ@u;oA>>0u@w3`}mOo2Gl$?xKL zi#g7 z_!oF&`g>iS{W$nlf(Cj3Wg*xP>StsNu#2c8EX~Ad<6Z2Hi%NyvBT+lW*o?z6kQr`c zA8eJ`3u*Mc)0CbzKwvEZu=1nVNHLSfQRnoV+%texKRkg;UlCNO_ub8AI&m1@qJ>EX&mJ`wSlOb(hhPclmV2z2ci79{Dc$uQtk zfTMO3`hNHTbl^QOBm>k!OSO-<&NLiy6_7l4q9JEmLF; zpbFuUDM5gPEblOPfQqDCW48WPp-Z~$*aEmL%e#TxS(emFPUC+HQGO?f5xH|Kgaq0L zB1)`?KSPo77S=2Nfprg^yx>d~A@l_LjTg8cWUgbT;FF(m<%?#Z!9TZULXI%UR)*Ft z(w)Q?O%;E49A|5E=SrokV;@$=^>s4s^>yOcVdpDJ(#`WWNci*&jL3D}hJhc8@}I8J zsvAmMzw0U z6pmKD^W#CuYuP&jZ~~h6TxDH+XOAL-r*Dx-YLi^An6>Gjffd?b3EN4?Sm04yln$hD z$_kq6AwJTLfIL$g%V)Brel!oNHVk=%KK!+rO6Gp>VqSkLV|t}$uY}wKWDpjZaa{K- zc-6;d9efng)T4O-^Ah`@2a{m@*Jhup=5#lIX0Er7D{dN%V2uje*y~!A_l||Dvb|vJp;BOA|0|EeBZipJU@XGxY-dgh>RzX z_Ml3ID+qsUSr2fR?8)l~2oOOM*aPZU&98&$Y(Eg)Y(p+6@=|0zA1^JfGT;C6r{~X) zC19!8>~TT_&X#HNf$8(qnBrn;jX6&}HulduL_uRHg!wLtP!LnlJ{qXb8FujDgrPCk zi@n0n)9rqww|j5WSfwTH=>=&=E98fUWK9>sDl~ts$Rz$Ew{wE5gG{x~Gb6LihC+PC!}+^>G6TnK29|kyx~iwEx-&noo)Or> z3p{_IPg3Xkx&vktV~QV)0Xy0YI}WMTLLeXayHAac=0}zTIe7-ko`D2I8P=(tTOdD@ zbw}eJ*?iq4qxSI#BT$L{4yvO7M?m>L-`O@u@R42X)eBCck!<=}$E* zHtPF)v^S_th46@y9n<9fpV0nNNL&AxYIc7?4R^IpSKo-zji2CqoZgXQMfR%#F(4z%jv$9-j|c-d%7xxcO5n?e7UV~n(YOO_K#?R zCM`fs3z#cPGIvkL@z(hbr}0e94z&l|7HDYdh;Hz?p0ylgZk@kP| ziBR=VF;TrVB_PvUY%x+LC|5EZ-gKxI@qVFv%nbbt?%X)qp{0sS^pwK-cA{O?48?N^ z^Jy{^K+LhS{i%m(h%85C&UZUM_G(9<^8kt)Y)K(e#|1=VKnR|6#uL&R3xa6U9Vgwf zM+K|EYe(m4k>By4B1gM`fqbSwk7<8T$Y}DC=xYbR#GdcPduVWb7t+*HvdR=<)Az~I z=Aio78Yg&z5Ke!%3w^*eB+>^%ntsxfQ|0~w&QGuz)Km?)#d*umjGR23P~+&~7}OcH z5uaMu*T7Gndwsp6lG1Y%y#?|H9`3yLU4pC1k<-g03xPr zu&ZQ+_}Zw>3=9*~x{@7 zhp1{x>p#Ew!=L`lFkk4OGgW{6m!-NcRhK4_3!lj$pIeK?;%aHVvV0H6rDHa?yaigY z$`^OecArAz!41zhGbe1j)fI==z8dv`>q4ROLUsjQ7xkfq^$XFOlobN;yoFha4UHUk zp|qST$#d%$pSwaAIq?^Z;^n zXvRYdTW(tC;3akQ2Xj=hH9J7+>0FPiehFyL_+*oki-vJ?Dx*_ATb7xD+zLg$)UNE% z=gi~gjO0c+LEcDSZQ_nD%#~B(465rKnk$4dxfwalw0*B(^QO*j9kWG}h^LcSrqVl_ zEtKG-p2Q+)IZlT2?rwirCpF>rby3zK?&l^sX!GXXm-3$AS>cw<53|-+t=*MJx6=7n z{@(TO(=YEm^so+H^mOHiYx3IU3M8M3>^3qQ8N;a=!Jz}(Md*fnyjVOd{g3TzJvUtA zXI}V}H=V)XaM$xfGUI1>ki3NRmllyyHRtH$3Vj@|(2E-yzhr;WsGQ4?`R^tt>Et9G zm6McgP6Ml6U-PcGWEpF^9-#c$uviR~?#b47)+o=yg4v6^H4?w>8F%cEZR0C2o2LeS z-pOnC>f|lS7CgYA;{)R%&6Qq=_%2u;>+4e&>2C9!ok$bDp6Vj^H&mDJW8*% zu->q2Qj4=ql9`5g+ie)d33@NPJ^AK9-dpE@PU0h3u`ATYU9*Cp+XMb)X+RGvzMoXS zjm?7X5jdlT%e6Bf=t1~s^ll5WS8QBfJH>s|N>U?+RN#LOn1iPB_T4lIs;=;@3z#Rl(Z&Ji)m`$Eeq|(R6IBrd8EuDIOd!?7jqun0MhYsv66?`aqPnzFK~Pd z`Dg?FMdp9URPsjimtR)tpzI*=NAD%w{@2AgSB-34A*Byw&SymCD}aa3dDZfxe9+Q?r10L>6#wILBifTz=^6xm4P*V zh@$b<8`Qf;p=apxM!om76HpIX%wn+g(y1i6v8Y#a$FkDOAk3~Pi5F?sq0z?nb28nI z&U9iHFH@H5JQpX*j@URkTF*^+3Cjl`Qw!tRL%}Dzju~8UzzX1mc&8y$&O^pd>ei_i508ZmoZ` z8SQyaNSoz-Q`ODGQn;Vy#^~aUV%}`)o{6slRWUxB9nw=^D|Jj?4vf5&)#eMER2B@}o#yZk$)^lMR0O&*q*mlWlE4dv;CXcif&`IDNwZI7#ws;aYrzC8S z&c~^gl=w@4e%qooBmgq=#Uwwmd3k@O$%(@_PN5cMw?QJ#JB+XNB8H-nFw%5&fewhsJ-RVZOpV zUR<7~GCX;cm?31A274fbv2hmG8-%^vfG0zHWKkjruajk^uHlG`cNgx+3;}sIV&Hg$ zVlTK4zo5M5WYJqKhsf~kDfzQ_a+`?jZU)VCQI)(~#uow$zr3<-qC||rRpp)8dRFtl z#}Gwo>pWKV7<6F+TwV3h5I2AF$gVSS!;8WMBKZMDD3ONup2LJ-RT2wj$S;!NDdQvV z$psOe_vR9D1!O9U{cpcb9j4!YtM*7+hpEI_y4rbuiVl{#B-^=AJ9D4*<2qd|7V7T; zB*X~Ec99OfSvR+l^|G)aGo8oz>yjbrc1v$8Ldv4}Dts8NQOH%FH-&!)W$RqnwjjJU z$t&_4jQpAD^`K3#zsR{O&+pw>nY-kSept`Mvnw5H@|@Cjrdn?;cB>|;Q9RjkQ${2D znBzLJGel&$e%gUz%r%n_8Eux%DF`_8`oyktRs_^uIuGwS!T)gl9XkFH^DCFwJ(lZH z{0AqZ;o@XZk}`WHJ6(T06pCb>EOID`dP59NH&rNzHS_?<(mXc&Cvss?4;>K~nS_UHhb;3Mo^fa=KSGYXXD-s@ zS4$&jyyE(5dFFrH_qOQqxas-oeph%US}O7FVa0|jx`KdKppiAG-v5OJ3zh)L*1lx2l-yJ3VbgT`~+ zHfTBV`VsNELP%7``&|Y{OT5!MN~#KjrxHl5qfH!9RhfTXA?R9~*iQCA8iiGve@uZ| zhM+iXpjIXe$F3fJZF!MM*BvBF7%5PY*OSV;p#|_F%NIKnHBN=7bOK0fZ+$1w^{(cu ziSuNj4`duIWU(qyzlN*E{>N(6{5@P{?J`?ZLv}p$?+Nn(J``E+8}GISWtV)k%U$rA zj@6Pnnl*pOnSlx97Q}rdgRz*yk94TED<=lj61eQ&Z>f{i@4U`bMl#fkYzhv}A?U8= ze7y~CxqDQW_@%@ks_DSJyb^F#Djw=Odm6kI97^a*g%9&em&x>P-$RBpIL0$#+^e_F zySoZQU;8$v@vk2oQQofXB~)XXJ#4_pLy}i!+o695INO!wnLCVyD7oZ7%4|Zdn5as$ zkVABzk!|Cpq=0vS@g|RcPmRQF6uP@La&xfhb8628h{zf2M4rDdJfUo_@f4W^VV=XE zOHC7rSyF$~7MnEblD4C4{Y+F=D^_E;! zsTF^}aJa=?i!kvPnZTWgE|O`+vn!?B0=HT5@_uQpGn-!ObQH$s>Rv%5F4uT>wpk20 zG4d0iT;WVlmc3ZdXTRELLGSn*6e4xKG39H#p3h1vc3^>T)SF(@Zl0;Bl8rta$zq7S z9r9HG@z(D3`;w{Vhls2OJxK2GFQ(H#uLgh0IZUOIX*eVIe z9VC&%`E@Xp;&Z8_Y808`$vczNvVgXUt~@SS+bVrof~R>z?2rfH7MZAQVz^UNp(B4; zKv77q^?h9%LG8gV=!##ueOZ%}X$WpIws!MkA)%%dY4(3VPq84p_zp!@Isrfg(hiA< zqc9G^O-Rlflt9KtfTa;yBai5XvW@nxyJ1E?2L{vI$$DW8z>+HMxKv(6 z;-h#eI};KovkD2}R>;|XoQal>!V!50GuD=0W%U8Jc)vwU%exK22wB!Q)){|KU>bjQKpI&y59l@IY>e}+o1bppnw)u?Y)#7q-BpBWM>^X~ z*5(NMZt=V&EspDYET7J%$HGAH=CLm^vaW0N;D$CSW*KYxnfrBYXUs!VJM$39qrD~% zYMRQAXbp5szA2@3h#eVW@xuXDL8poMi7$m&=}^m4`6}3tOHQfSs6&4g*nA=c$ci@( zus&m~2RVfBRJ2)7;wppZ!qu;69gpk=J3x)qwEQZ5;@*X1-V-`PDJgg4^uw92LlmvO zm5)A!N!#*Kt&3X!<416Za9@Asu92y!lg%`h0UDM8{uO*W33^eQ;z9vlk|Y<4y894O zJFx=J%k_1go9O!5T9bcYCk1>CP7-+>>t+|MS^G+8Wu211ot`xPrhJz-PR=0fB4jx} z4$DJf`c0O)L*@^f$=&R5oTt~3&0Qv3zEsM9t% zwn&Z$SVm3+`)(KU2D_Y%bapRi80V(QS*yuZ^cQr?GR!oU8MtX#UBoj;4UD`ESv|*} z(K(Xe7T8m1mXd$vCgVU_5X~P+7C43;#9xR6x_3O^A=*}gmZi*rUXT;T3o;2=sU6-q zzP~4*Mr6Wm7!aAwfvfqvskG)Fr*x@STf={T=)l0)nXU*kg~h|UWlNzZ%FBfX3sprG zlaT!by*X~Zdm_-uftp+Ua7XVOz9{Ks6IjkVCM#(rEd_sg<7j3<@f#>1QFZoAbSV+c zETh~S<;|63nX)lcE^aBxQ>$ZXr8DPxN&f`PmbA8^XKQZ3|Gi@L(5I=e$~X`Z6ZK@P z2Dt@eAV)ILw6s3P5zKxMN+8)Uq9{ixns_q((K7t$6*sN!4=-t5$o1 zCE+@`E}(w}k=_;_UD9nt`aDIwtQ{mh-Y=_w<4KA@lF^&|_UjDvEB>us8=26?Az;;I zW{7}#El7w~xaBS2%JagYQ}WV6y+yJQ>j=>c-~KgRwV;?1%aD8l$1wC!DS@gR`ayBP ziy9Aniw5JLvQZ@E;-D!xRUpFsC&1j05D^_j6u2E*H%;7ZV?dV_+j(6d^D*Vf!<|9Or8MM;h z+NZ3@@*X=mFv1du4k_#)c~52U3kfL4ad9YC&3vC5J#1=7upp z6ID%Le=CY(57M$;Msa^c+$F)2%-d6?GRzIzDx*U19hbHW7EQefan` zu8@m!B$tRJe@MPxYyk7ks&T~WuY5bCCt-hCeAE@x9;+ zj8m%nhu@Kx^64D!=oB>9H_(wV{VZ_q zy;~aNPd|!~@37wL$tP|YI5A@Xyvl#iF3BHQ@E7|ElkdqdH{_w;pE$m=a;WI%5(|cU zv3S0C4wF^BC06212(R;EZapXe0~D-6cMnf}fA``qACu%dm!&?+h+>p{|BO6ZfNZ$) zZtr~ZzkrkQJ!~&e6ZwlyvNTP_+a#M3#11iWX&zQeN16r9GRkn4k({(@O!9y87@@+9 zq@TkWx<*EONc!5MDBfE%9~EI_Ww<}+w{3`7-e2SdZn&}j?gR)@+5R4)WW8vsPtjaB zv>p)a_32oycXNY)S1pQ>3MpuX_dx;O5BBC;-&=dJwcV}AAJ(f67ourANP7|i- zf(lnckh)WWF;K`XaaQXV$s>QS{`%U)q2R2DUFfW1)?2d)gh7FNnlK-Rew#F-wL=VC z*G~AV1vNy$%d)R@Nl^ic`1HRY&h6Jfp1=O-;^)5^7Z<(atN#(j=3@kV<7eM^Yx9XO z$O(26PjT{2zJQ%>0=e{WIXlACScDtq(i45+YM`dItu zHrJM{=5sE2_N^Bnq5)qJg{_x2ybHrGb_F8Qxd@XCJFW8?`hs` z_q27gj)g|Vy^t!->r#IrvY{xnV>)+!?Ab1q8DR$Vl^UOI&g457_Cq>S&x_5R2JP9R zHb=cnLesTvL8M?+wM1Vw&d1#fqqyG}ru|ij8F!1icy%J}FLPt{Mf0YhAez+>5PQ>Z z8nI)#L!v^ox#TZV9PK~kN9mTp2!X3Qj&|#~6_x2IU^?`5*F=A48)7dGqkT@c)PLHe zjd+>Pr*YV|z!6(668D;SB7Q%viP7$+m6f!DztOqVj&SNA_nlop?0~2Z$z+_j#bLT7 zG$uE*{on;|_|X1lR`N=a3I9pwGqwz~A&l;-reW_KY=;5Lloh*nanvmOK2HdWqA)ccZUL>e1rdSeSuZQxR^NWtrC*Iv z7e^)@%fhs*OHF8&|mk+Xq*e)aBLk;p#P9TxQG$pC^teZNx+9#ik& zVkJlDb+O;`5x_0z<&CR_ftP(jdK7g2R!fm;^Zk+9MJNjbSwG6US&zvra#;Zh>;*Q3 zhN)V{rpo3?w}euyFxQQ}l~(v68>bgKaqPrxM9WV>_z>iObl7aPZpcl5!n$x%6h`80 zg*02Rc-Z!2$smHFs@1P17_p+f7c<~fTGF-(L*Go0L)uZaH}9Yfv%@lWyo9o*?dZ2P z+L||hmKEaAl;j_rta!?#nuiYZDcZ@{l>XhYxiG{92oBYPAiW&BS(o^?ual+{J)ixRb*W3ezcT&I|1xR>>7?`e8$&V?8g5 z#T{G`wy>C|o`qKM6-NF|$8sxIUtO5`yNZG zH3!~a8LGh{H&%8U#7`I2d5~R|RO1bQa7Wk$=eYT4U3BmDf4AGhlJ-efbhNjnmF|6K zOa6?15h>IqH%S+I^$4$huj&Qr_jUl=0=je~vDq;EdDd|M9MAUFE_eT%3=wiDNJb-4 z0m@$SNg52_XRbK~ORw}z z)PwlyblrP?cso8vP$i}5F*#hxj@$yOR4#dc=#iTG!e*Uq?-v;4_ePQOMLU2hBUpgp zYl6La6Gj3AQWFVy-@qCV)ST)5l5Ubb;-{qGaRQqxMjOG2ntdHi&4U{6>3mP;dph4k zo^LZC+b_*0>OWpeEhg~$!9kZ8OJAkXtYV1*#b9Kb&c%rs<+}4TbSO7d8zkU1D8TK1 zuzz)%Pnco;HX|$dB{c>1l$JtH*nqT3GR|FZJmlj`%p~Ja&uXj<;bpWT1W0 z&3o0&M{_%vq`W2>fd>4o0Fl>e)+=o>4GoGZhAhh(~E-OinTq;6>iE-H@g`7CGn#=lmq=^E{RuTQCX%!<~%N8N2#{NcXq4K4g zv7z2>L@94SPz&=e)#I^x{ZPcwT(N9@bMf)jU*Dd;X(?aR9X&Q7TNSLu{CzHeW=-X3 zibQQLLsKCs6NN*{P)u=-(l+tfUKNmzw3uIlnbh2%0IF+kg%r!BNs(@ID;N>D|56vQ zvFYvd7+of_wTS6z0d`%rtwn-3uz4+#QYllXlH;Pj7>Nm!5J2B6IvVoGF^((%11YI$ zVU&|BM^pKeLp2$Lp;d>Hayqep=gxO8AQy~%C(gMzSh7-9+5Tv2x5BN>l*s}Z=8@+K zRdG2DJQV8}#fwiV|Hmi!Gbw66Io%PLrf;2`Ucoj;T|*_1wHsF(^B z$vx}9QT9Hsqa2fNmK2O9N2a7~-IPnP#U@wQXQ{+cs{0?5Q3B6SfPJ7K00H6{&N!i(Z6kzBh#=MipXE5qwUIl5^R! zO3mxka*g{jAcg&O4w(_G*!hs0cAGY7z9EL3$?|pQZZv3_w`_Ib#W#>$KIeLl%JS2_ zkSN7zln_~cz85k}B0`TwR0g-~fxuc3qDN-!5WNuFd}{S5ZXTz9ce`(Fcq&Ra^C5%E zc2%78UdvbL+hC6iW~H&KgxR(=hVMZ+tHBB|V;gY1_7Z;-tSwfFD;ftTTgS}uA@rW>`%`W; z@eqqN2sHqJmz^t(a-(amNWIMe*bn`-%CyaoL#)UoZyHAZ_FF+#e*?cui_hdm)HBr$ z5o!Sa>;}?z-8Q6Gi5Bps{<`bTt#C2-vwDgefy{|JY~6u>hPQaaaZ+;FnMN*+@1=UT zm)1}Mgo)247ICaHFva2=9te1(TjAQ18`8g zX0N7yo1my-y?^)W-32xVmyVl71bG1pWdTma%47Usgky8QxrQ%M&7{m*;F^|G!_tdp&E?}9jJ+dqCUmlbWyk9`^($=oBNx0 zZ|%32Z?5h8%byk674@!ae@-$^Z*w+(SeC;G_nduX?W$7h8NN>`__q{P(>EVp-`~8t zd2{{t4sYP)YrEde_qW$S-TasF&UN)7HI7GSe?Frvt0&yUx$cq6z-f%$Q0MaQ?)tuQ zs<)SKf4;Ww?(q*AH$}u;V(d(vDL2jKUcY^%uvmE;a#S0r^_1GI#!1huR?wJ#(0>lE z@7P>sCr-FR-xRNj$`%LI;cPeGt`Xx=K^n7oL^MqM+c7liD?Wvz|k|fcnKce_12aeTMW( zAORZacJ<^W2oj(mYD4ph$Qd_(V>>iS$`6+)NswnPwifMm6Uj)yOWNpXnHE9c@V}gmZRlcqBp0%5i>i>o5i~91<-l>@2beRL1%~2eJ^s;mp(M{3NbyuFCNx; z&paRD;}3s&>HNDYB#nUzPpLxDNkh@>REiQ98tX%f68to+X;U2n6$9YGneSwXK3im# zjwTyp*Os1&M^DA0Q!XBVJz>)vZ{Lw)EI-k%q5TY`0|s2r!WyRU+;*b`&FglVwOtKj zu}AM98H1ZRO0xc~qs_fYH{RM>2Zb%QcZ#F>3oNw3gLL2b;|305r)p26phM#68NMz< z7Efu=qJY8BJ12|1G)N1ZE)k?es<=cO@PtXv)1b1)v*96LmF(M*Tr!uyX2dfv7bG()yRskM)q?E?U6n< zgi^o*m?uD?V$7)jrb-20`(v*gAOHG${dmb?8@xFnLU{h1H+hixF=-4>m5$1lof3b1 z_xE9celuSA?V;37`~|Y3Shg`cq3CP>Vy(6Fh%7(EOoQcroo6*K2cvaO17VNn^Z zfWCQ|wTV)wfGo-%OAf9B2QeCVv!hrsbWFmpkYR$QTcUIrbK@-oQ7~;$^TQ8=2^!$;{0V?-68M`0Bw03cx*(H(; z`HztFfHrf%`M$)+g_H@BU$M-|OeE8Rj=piWBoQKs0z4B<1;ol9q*>rUZ><%eH_&vq znb?eroaS?c(NjAk5U+@=!gcZ#?JRz-VN+;!23AymhQQnG1c6Pqk+{tVK-n{aT9pz=6a+1aRcDED;cAL4OtJ(*p>R6y;kWlg$kG(e z&v%E6ukPXDVUl-^2!jGN6AJ}w)F@d+kTCWu9p$Pqi216zfwrM=2BpN#_iXft!VJuP zVOA z8F|*D6XYl*xuP3CO#xRH^d&^JH2nKQ6cH7$&g*8(k5!Q933+qICyjzM@wnsE)>QL) z4PO2$cwdeg8J_zF9h3(I4}d9lNT9$fzCg`?DsVQ(F$z5_MzV;QdzcZNJiy|m`RTbH zN>`maG>R0M^)t^Ol$rzzvHHaUcya)&_F;R}7*`eciioDJDfBVasrTZk_u{Gd;#7Js zj-e5EXY5VkZeA{+<*=I#VaiWImF~-x909JD9q&BY4X^M?Cw#&8;>Dvpnf!#Tqw0Qt zC6?!P@Mm{-*N5+P7EcTu|6M%sJ_u2)l(e<8rf;mpMMLDa;9#aKc2E5-PW>)U{Vq=Z zE>8U}4&Cn}iYKL@fLmaaPnKSWj^SMvcQP5z;~7zT#z%>7NgM^fyL}#((k-m$J$pe9 z$IIo-1DkLvnkLSyP?5;^!Dg0+OqZp9ST!dQ2>hSF|JVQL-=f%JC>H}2k?;BJB&xSx%NEBdRt0C=cU#=-kPHta@eVk&-u{^DyP0M!7H2xdFAHtV)o^ z!XE+`b7XBn0*z6pzCgn$d*j5hAFf7BXTNox-V|&76%uiWtOMhnh*8U!oFfkz&_sU; zty^VQLs16D8c$IgV}6;wxiY|iXM&n6>EJiSr;lYa~)&V(pI&}7@_T$kS#$UM0GPlGwV!$$O0K&hh{%5 zwh4AU6!Ga{K;A`jM-O$j(6(~vyS@{MnjwR3SIh7^_?8(B8H9!`N>=NmE-@zEj98r| zcv_6AS8eI|fwW_|!BtmI2>2^$j9h=YwH8sfwpv?7>W6#RJ?Ai@n8P-YixMeL&}5iL zM$DrzBs7*O-aTaNu6;9q=ZGS9<_#SorK#(7^p@eieRqF-K>+~pzd5Pr_oAneULC7x zX%kGO@={qX{+?SMCb_`uW!W!e9A=RP>_TSwZvOrMwh|N|C+z@MlDY2kZ3VQPgA;NP zPQghyHAkV2Ei%Rm&G-t%q=d{49gC}QGVa1@xC~9Y4SC;`rQ*qdNkTgc?dIXwd5ToF zrcrjU=1mpH>P_|a850i`&tzb0#_FAW50j8%vg0ptgKGB%;$`X#BM>#a2U8DlukV$8 z_Zwf+sqm-|BnBP^`A;yL<@#Q_o!ya%qY_VZcEOZ^2=hmMKU? zW4ih;pGNmdcFT$%#_W+HLpQ_BX78GzL>|$wDVrFX;Ok6FjhCTH)Ilx0SG?FRXOl!i z!>8n;QIm^o<@+ZZLmoQaNiGSUM+IAvU{k?YLgc9EGhpO@X%ZVri$eLwM`{=u+L(R! zhLH>0R)1q9VL`8jF$?@)KIWk@f}g+O?+RcgXhYAyJYoq5+-Np<>pu} zCTLzoSmtHuxp6{Wqx+jUN;3AQT?xA4L{$F$@utByCW>43yXsB|5b4iATmu#q6KMbz z$zQ6((hc{2KAvno3Ace^eLR<0hBk3Vk)jlUfiabyIW-p>fE4P>OmN%ZIgzO<8d z!rDksV7XX#-$TnX5oH(*JFBaWwc7P{ozM;<$NQEm(xwCWUu09@L$TmcEO-LzOpT&* zR_bh!mE@sr##`T(%XD$p;bP&J<6J4l!11=i?R2<*O>`L-c^@xa;jzBfm z+s$ErQl`aV&$L`)x|E3+Qv<{t0#1K+C_d6WJrz~a z@l=vCMa04=nP|`NMm216pl`=4SJNCIBc`#~lj?9%9nAFS8%uRy>DMx@H*r;CEM-Ev z%x-^Mr=<&-k(Wa|Ag9L&s$8l$W>Hq_bk444olq~_?rS!rb*;6BQ`rppW zJB%ZJc%xoW@TFq($-Q83P5}x>#E#_TEQ%nErYg$U4?TRf0Yv8SwS$;7b)%NQ47!`$ zcbjb3cUmfg7}v9lmG(AVG4q#g507_mHMDWZ@5?1`fa~0p4RL<;qkx2%Nweg^!skJM zw6aRo!+P?wHQufwQV!+djm?{pc={#}GCvMb+3Q_7f{woUX*RdslRED*HgDk%H>NB* zLHprjqNVbTpUO0!4(0FD+;}A4NWI|k$}44jX%WrvTq|&@TPCIM6cSyZrjO=a zn!QrjV5L*XHDq*xsBb8x#%i`z5bg$lVe+jJ?*;M4vWtb3P*P6@>t+Cv`T7f)p8eU7 zXU%GCoBAqvmrs{h)C(mKtX&B4&`oHK+2lp}5hJD6PzhuA*~YwcR^zbId!XvwtC{8O zYLfJp%V}srtW)c#01>1mfU2iX@<^Z7zPq;Y`)@e`NfomeSP!taJ_OIoerkJL%xJ!=;`vZ{4v*GEI|R zoL}X~Xi=jmtxxG^ih)Ae&M{m>)fi^N~8Gm9Rl zwQy48SrNr0z(2DBKSa(72|={RPJ(A>75|STKnDdL=vWo&Dn70KfDxtW7)?!{6({U3 z$x+c^$%#P>tO!Iw!dA_HN6<5b81m_SVe$j4&4jQS=#n;tR+9{NyBFDww9Eb?pr- zdPRZo_}A);@4PQ|1>zHygL(W5zC^K;ts#_9Arw9Oj^#&I0ip?ikp>d>NG)d(kgQ0! z3*=%^%)p{~51yt1H4_ux&|AiO0$SjrIjM_6&%sx?;7EK86I6gFQ520}ORX?ld>4u_;(YI6)9S z;l-l_UL3KxX)q>#K`-c56>)ml(UeXH`|1eOaKu?yrncwq#<3OXe@L5hzZIgo<@l#xTj>u=$kq*yjTBC&l)Kl^cv z2`7>qxQEa{7dy9p0`L@AJ-p^*uVG}&3KnwGEq?Y%xXbf@mrK}{%m=(J_&7N$LEeJ{ zC2Ms`K@TJWDe%*omE&;(m^wjjlx`^8-x9}TKi`tua)*C8|FlRcM zVNkyaePL+x24P>H zLTPKzDEiblU=W%@lPln~fSC!D7PbN4&yH0+n|uv_W2g-L5~{q0^HQ+2T59Zp>Vf3Y zuVl}wJ}L6FBMV+>EWTntMqqLu<>`@I_!(_eJB#c>e>*h&l!m&1H=1ewvTZ7mWxueyU@@;@il|6uc_y{d@5IU z8KWkDNwq83ZP8T|wEb6epBr-cVboC&4D}F>{ph6VnmfYz#ego%?!A*UFjN~(fF=#$ z8fT+$)%ZI<<04R2V{n>=%=FKY$?2hoKk^@O62&OVwu}TW{*@T`DvbYditn+|6FS&K z(z)^D9Cz7VoJzxIaOP0L>ARW2*QC3I7*8D>p2<3odsI#|$g3>*=70aPMkF7oj#ju)g70!1 zg&xUw2kgq2q!9X$+DUfHIxDh>{)7B=W<}*6ZPH))e7--?0pE4S2a0!LMN%>p!uaeM z%OUPb>N)+7{OOXwC9%?InLR-wod^A;A?X<31IYVbqNGTq#fo`~LKj)llKz^1W_v~@ zIBeQXvF)I%q#W}Gy1TA*VQO9)F> z+Hal8hQQgPF<)FJ&koSo>F?1(qrJ6k?%^Z>run|niZjmj`Qeaz~I>;)v{L%k2V zj+Cua3tBzStt)WUr*LtXev*=Z=F0dFn(erGfD%kD)M2jq7;RcRRkXu&Ib~gKPE$1^0Q*Isz_(L^ly5J#ww_9|LfO>p z9nnKIr7Vd9lnp7IDNhh7a8j(;iWL@e$idP#Ds?IC|38MA=>GR0 zA4kg-(x;;OylR}sG52HCj%X-EA)7DiKf z|4M`=w4^vs1s+gJP-Y0(skK5ON(d}fg#QXHIHE>jsg``E+r$+H6Oql|f;&R{M1+{| zio)*rgyq}-ITY295KTM6gp~WLpeS(V+$!;d>c%h>t1Gmkz+-S?F>RfuKs(+RGtoJo zoYbO^j^*VE1V%r9F*c*PC!cB{p^!hnA7+U|A`C_91qC%q&_8lNK^|=boKeU)C#yfy zNUx}fDt<;^A^zlER3fZ(Z8$lMB4311@Pw?V>Km{?`1~eH@n7N>S@Z(1=G&*E zB?+GV7>#%T2Y--HB1ZyU&EV1NJ&{u2`<1~zCFA;Xkzx^l<7Rg#8^TH!f?+TAhq*H> zNPvMzmoJoEQ1`sZTi3rE`*G26QsGTTa#^y48Fy^N@{Tt6sNP|I*Ci-dqirIfeypMN zeZCnzp3W*V;2o?CKw8&#SyxJAZZ&WmgG`qat^+2}Zry5@3%MO4W$?fOn%NI?Bq$De z?;>Y!J#XNDsDwtb&)&*do?W6RdbSYIF`Q^3FhS~x{!cPu=jl{v|Z7IKh!4uaoafs$KY z44Mj}gBSG9+w@W__64$F&nj0)IX$JOM6D|mH8-Sx{Yje9Z;E207qdcV`AdL*uNO#? zjuAX|~F(`eb+ z4Db#?s}TIF`2p>J`noXLZs-SqLBcos1Q@MZDZwGjDv}!a*lAv*(sNiAufSIs^fRkO zs5i2Ibbk`}W=6#l{vWvuiM5Fmv_F57yrM(}=q3)$E%9U~LM1cJdk>E4_NDJy*D&QT z&)t2{t}Qu~kxV8Rw^t5Ro1$c(GPp*z4qn4fp1O9m)U~#`_H?RvlY~5|JVUiteLg-p zGJH!%adX+A^`dsSCThKCbx)JAUd%K~F$sBpRno5jyFX|)84F>C8$BdB0oV%Z8NUH5 zJGWh|mCe1{9Gq|RAoFd{-=HuhYH&kQ?>RM+AGV33B-4cchjdYxUP_Ig362b5K(e^j zp;I8@%wYf#&lD<}1wUOkZaN8-d6D6$^YQ`Cw!r()~cjja_eM2vZhuF4C3=o!AGQ^R=oM}`u^tC&714DcQ^0eUcR>9U*6u|+~Ysn z?{BYvy7?~^{hz6~){B(YSbN2nhOT;lcK&c~%Gs$bde20dQ5E%_rK#12{r2+BwS9m2 zv+1KT=}cx$!thr0EwVooV^AD@f(Gb>D}b7J`jiQdb3t({F7NKH?;BVA_VVq|*Y@2# z{(Dg4uOa;}Ebj8L=pOg=DXsnkF&n?HJP;MCIUwqLP&;_%qtxGHE;c zhfe;XlYi*sA3FJmPX3|8`-ez>eeIrDRWgGQ??zHns>Gk}enNYQ7*3nlOtP5)$6|+e|GeCc!pR4M8*rFBgp-43BnOY0oDg-bJWuzLnq(2( zGjhbU(?*LJQ)7lfjGf-JHB25GO9{7ekIDqp>0VI+WET^JgE5gTD5L^^vl#Y5F>UNn z*k<2CMtmOQokz~bo=*9=dDb1YdR&0<&$aVQWgN}IM><583E2)M`pknxpu(HcyGa@y zI|f{&T7tR4BDFKkr`XCwy0EXINSq#1^Km@l!p;{p+RZp`>Yk!RX;405W77YmXb3AB zq-l%NBacss<=8osg4sELX*z07QIXGdaEoS1*)w3A<52+gk_me3`Bdr5TW^e>Yp6wq zIui&wt$yh5R;`fcBwOCk5CJ0hQrNrH5yszQ>EgSsH#&VFW~*(qAnk^1V}%h@ zU_(gd7pD#o&%-e9KGqbr{I~uD#t|8%gRrmti#o42kL+vY`UKaTq=XYx9imXoIVkNj zV`)uNb-^P0((Mi=cjPS{9$;2osJYuu^Fb5F1d}63sgSz8xD}C*MkC z-=~msbztxz@!irzvQov<652LJ$GmJ+sf0JAf6LJ(&bD^S)^N_wmD)sPYg?tRN~VNQ zG8J!(%qp2B&lHw?oE{$4GDbr{TcQJ-lL<1_nQgY&w7O=0%0171xI~HFH) z=&JN}X}fz&5PBW|?&qDJe})qYjmbb$j_TP!*8>;^HC+vMg3>$~`ITkfCw@Sr+S0z& zkozFuPSJcSInVuUIuG#>jCgulWgNirkFd%O<2V#WhT$iWab$>8`h3v>&|c&;xc$XX zGZgN`JX4u}y_YWVH~_4TYFy_1el*CE4b_aHlk);HmLCdW?x^n4s9VBQa}--Pad*%| zF$z6sg@8AcT=#aYFrCr{A5>~giZ#nexCrm6Y^0zYkGD{1&@1_ujThoH$P#^889Tpc z;OKvUtbdJ)KEKe-B#d^0{V69BJw%f6DZSVTa&!fMilMR{D&U3&9mNKc%?)K|@|;t= zs`DR2_INlj(eBdKfvWNkox&va@a<+dwey+)PKe4w(ym73Rpc-o_cerh0Tz;U{86If z0Bu{9-+ox%Y=FeEs(l%4oK!t=4LD9}wp^&6biZ^JJ7mm+%5(P#522aoTHsi+Z~Tsf zXQ+OExSSWQXpuRw0-{NEs8r8WImQMxN)4KMPoRhq{=?MLY*wzG`%CqFPA>j^& zfHF9-vT;yyh7xyT=@FXJ4-;CQZU}>(<-}rt7$>=MiehNLGxCbwDUNZ9V~{vTArzHe z%sjS}iewDo;{P^+Bkf2=P%Ys&EP5P7s=`gIPYc8w{Di8UZj>Y_jzZ55S0I|^%^ zfPj8_zyiyII}}a!zLF?AFww&b;otv%>I6A5)UZlUZCjyi&rqe^tip+CZrR$&EH6Uz zUK81tf^Z{BrzF@n z8aqolDJE%A_V$rdN7&LvOEMULG##|YmR~NLT6O#FQavO;L7rrk^0^s4>?G4MEvHd? zTVH>PkqZ#8B5pE{|H~P|2cO~-4+=ME#Tzsz0ni4>@vvQ&hn}T`)SGQ%G@v1Ex*pZ^ zwKUf4eejHEMFY{SktlD{%|xE+v5Z7E2OUZ)HI^$hQ1@x0cZ37qrqO?YcvK~gm7_H% z7~~|xz>)ikhV34z>=ZfqD@ONMoO~9e`7Cs_w`Y-5R%^DukldjzX*aXd$V%5y9(ZNO z!PZV$O9&lZJHx}ySX-}o{*=e z5znP*#5itk$wUyPw2w-EJRKG_rx37psuB^}a6;P7^;7c=Q_VL_1})T(gr9eM)f6t` zDRt0v1WmEa=!w-wVfE*eM>s&2=~G&v!RB7N`8mg$j5rDe=me4x)%ajYf3RGy8&gjC zA)=;cQVPG-)2aRKL!8a98HjwZFm!W)WE4Ay91kV78-*GAl1(IkwXmTU6sbw~nAX>X z)GJCU$HKiZkZ;{LwYI>E11GdSCv!%`Ok~d~BM{IRFnS7Y{K{sdu7Wr1SWif? zo6#ag$s3m37?gj&V>Q`^zR+PxOQ7xAbR!MDeGJx_z>h4Yzj{*n!Wu zIsQqQS#tXCuql0mE0e_{e<_Mz@V7TueM@{N@c)VA-{P`_*NLt2tz?MAy`Im=e-cD3AVXK1y@sAe>l?xEN&-VXfm)2&X8^|qdWl!-h@zxNACSt9f}a?alKM#LIa zgpclC=0ST3J+GIt{MAd(eNv9p7@um(~ed;vdiFFL(a6o!IvxH+@-In7{XEymH<#$4B@mR>7P-D;bWB{JDpl zK&#(>9Z=b=En6M)=~EGx{`AR;7JtV)Z8?vQAAoCxW}ZO|+ahAqTIOM4f`|AQjo>ZI zzLs{kEH@B?u^|b{wk0IBYQTeKo&$D`?->tzh)gXK#Ju2!)?Y`fH`0;N4sqv3(9S$T zG{TYEi`)-9HOlVDShwX+KXOJAA+NZXHWU1R<3cD8L68oim(pNJvc-sU#(L|kgAj*V zRf)2F79VEsN>)=MQi}E2l#p*Ks5V^o<^XV^f8>7BScA=cdWE3Z@7Xv}k3O}iG z6Hw*uS$Z0x-WSSwGb@de>o1{**HA z2k{0^w1cwe)W@P~J53(Ht>{x=^%HaLiP(y+ zi$ZKt(Z4=4XD=;Yvaoq=VHFFT7YqCP6@RIC;%z^)u?&Dl#-JPLL52tV?RO4Vt{r01 zJz~=fj{(DfKmTt29T2ehTRh4#f+c=Gv%bUs0#%F1+rqd0wEq6z?`XXbYzw&(eT4QB z^{1D3l$K9n?XT7W{vVis@qdETFK+I?ck<3>0_d4Uo1PmJQbhb3A;#+XzQ2j1gaJcy z$w)P0;aWIx%z~z2eDz%n+vWr+-@U^o5ei+@Yku?B+=#i%?PjiPhrn`D#vsk_c9Ow4 zx{3%V3?rItmTDa2&fBR$58>}xz1AVBWizN8_*;DYercvr8C}_b96f@l)VV&8efDRh zbce1Yl(_yPK=;wkFlHBt#Z;iP##h%rU4D3dZ@>F+|Ng_hF%k)Wsuo=$ZC4D?smmh; zo!2mqIjVNvA9&EpXGfXR%A0%J9LXfHfTJ*Pr`4$t3a;mOWE8`~A;s1T*1zVZb2!OE z{gc0~1`&=k(33!aH{pA#QqTiYi!v~B-Fm0d3o>*MtDx9-GvvV01v*#hpr=L)b<6tU zi$cY-GL&Xu6qm||^P%yKoV47L@ z1{B3=DUG|;RdXAZts}3fzoRQ@&L%+keSbBKKW<<8*S(MUBSq33@mwCa93prEa$P$b}n7}_MqVF0k3&PE%_P!dtCKWNk*h!ZwqNE?6@VkV;hAS>*& z`+$G5sTbk`*mNAQHR}awC$y7sLF~yVCmk^9!r-HSFctn1QKk--J$##w$6)o8l)H+* z6Zgi{S*!o0J2ZPaL14F>)l=ZE!L1n6y!jeyS|6KJKU`RsK~RQ&3$L4nHhu;v!h4y) z)8f_+?eSE3bNI>|JQtOGAn|Tqm6^Py$ZO`W*Rt}{w0Mj6nsIW&_+>qOCb9vCz0iFD za*X4D2OR)C*P!S1*im~q&WZ~GR|QyCd$1eg#vM%a+gFi_cWkSuLAUbu?u^k~UJIJ8 zap=n^59O=HrSL|X*h6IZ3R=`5ZXTgW)X0!Uwjg*q1D-TP8+iz@PWZ{6ihi|}=}Wjt z*GbXLdRn6dQ3PrNNeQiFi@INYG#e)qpQe0&a45%rtoo6(?ivv!4@IM8=-66JMlrA{ zW%Q`$f><_v_-3-*NCcUU54_)tR4dR0CWS2-q!*@2BQoY{cx}i&3iq}Yz+-dz4&m9f8(;4;@xr|QRsbxyZB&# za2FY`$wYUS?Q#&fUH{Vks}0EA@B81p3%1jp)zIoe;y^kzXqg@0pQsUV+8qUujoH^w zn4BQ6BCMGtL{Um-7A;61c~a<$<7R*i?yg0(6ciZMQ`jcO$b5f#!Ke3v>$MCvavo&_ zlO-T8B%x{tb6*MuNI$aggqW>5s+b*r?I_L4W|Q39aq)&}zAjoSFm#jZw^5y@3yUU? zR$*K#cctdN&th$Pjq(phfMJ@ilOKtL@5LX3%{%rQUi#5Vn*Gx z+c0y!z(+q}a!_KE-_89nMD${RewvHU-C%L+tjwDIhod6&6Fc`17T4fv#2=VqOCoWePk_VDY1jDq~e zb9R`QhV~mCuZ)iD~24iFihg5@#xkuH5cIF({2{XDTbn=D_;SB)=Ac|iE z_-6s=LNm)J>QwRT1_r|rS`yRz2Q4MscLDU7{Iwk~WBi{?{%_FaSCL&qSn2#n$uxdr zKct}ul;aWLIQB0P5FJ7N-vzKbB$#6tJeXHZ6nw98uvASh?IkJl=`mgwCb5o z5RfMb$P+r^2_2CSBdkH^`@ji>yWPy#(1ktYoKPW6p+dfLGG{0{bp-}#6xnDw34X5K zMwyd`vD77ybi0~&^uE-fuhHRE*m;Csryce-?knn?LJwbaf5_v<)`XI0=(km)CYF{1 z*2zDKL2N4GWq#^^o=FtSvxMy2$MhuM6(IeZVhR9ZKrz@dP~-IW3kw!M9+y|Oz@u~0>VD_TtRJ9Ec5%P#jX91}mDCFm|ICwc#kG4X* z&5E`XPks>K6}=!j7>Nk(bTn;7)I1t^!I6P~-Flj+qpGi+?F#m{SGPm^ z6RM@uvxgIU;~?mb$Bg|qNN@7KyCK=+y?2~J$W|ql6vMoYLNp|C-#D70{8NS3i$}62 z*-vms1=Z}dMm%zgygSf67ad0Qtj?!+@AvoJRMvP8g~u4Am2c>Ip;jgrR!EP(3(?YDw@ejw)cQ zlInmUC~;J`kb+V-y$2b2!csk9sj6V9`d;Z6KO$LZ7)4bnpG;f0GA;t`VB@1Y2{0t$ALsHA+}D&sY^Xf%TlgdQNK5^H7Tv-_NN*^N49xr~WkG zc7Gawb+A)|(dMHCNUhU;nz~IZ3AxZ;(H9Du`{o6e4-O0X*@lq;>FuX?9~ZN*qXk z;H?G$Rvk>rf;QK96=e8=`87Veo{DMQ!7_RbqAI}s(%3Wdl(21Jk=tpc1Bz0UBSi@* z(tqXb{Cp;{i>-DcnFSEEc?_m96|3!Lp{eCXPa*Bs1(tI0OIT6Lsim0>B&_%c!d5N^ z<^*0_+d&z@K#!=Q8aT1$WBLw=y`GAHc@JdCH0sKTnayit_LTEP?|<>D<(d3#TmWA>rcP5cGoaK^b>J2a8FbDM!Q!jocucHXc^ zCK|vY3^+A4T7=xp0z~Zrk*Sd*WG!CEU}GtOc&HbG(3qZ9Nq=vvO!d~%is6G^N?7E# zq1|+<>SbRoKia{SlXZ*;HcmYk-vwp6@W3wkeews|%h|Z9kLdB?mtE=DSp3JPI*1(4 z_CuDBO|<`qo@0^FAbgQTd?X5giAxQ=z{@wAZ9x@`WXRD|Y}C?UNs`95@?}V<>*MVW z${ePk9)%v>^UF>)6MDU6=%EOCypAkCm=r}KWR=i;wh{~JT~e4kctjqQQ1a$yk3zr) z6^g7yUWW&zq?O*qs2)(Na5Q|tTA9aCWV2>!ia;x7qnnv!s>^i!bee8|9nsl4;hA)e z=v*5#jKJoqk6#7Uxb27R7tuk^b8Z*$hB|0fzFL+isC@TBSVQ+bkA@EeH&`&+B4O`g zRUz{>2ltG~d)6)W@x{#wDq41d0kCw^8lV_^USuKbth7)_c2_K1o!KE&jF)3}&%uTz zXL}PnMWK+nbZ}_nZeR_6&KfQ>WL>{5*%Wm$-{VQ08 z%fVqPKeg&C^cgKuU6yndWv8HS<4HW9{M1Rd_-9zDO0mxCH2O$?^Q!&IC3)o{95>6I zAlTAc*rG#q2g-c!h{8pyg>c}SeM)b-#byA#sH=>?NTuA5@(}eF!SER85e1} z7(viesQjj$%f6|SApphAe~;oiK}+lmIHAfuO;qMk1@wz^{=wFxsGsd;v{mwMwx2Lw z=&(OT&GVo1Y11++Ks;FET|LnQR#-_E*&Zt`>+F0WXH%Eo<(c@Jx|Rm6CMX20-JXZ^ zGPNmr&JLydf4kt!df+r2T6b$F z9;PK}6-`Spi}(rJ^wvuY`=emEOV4Xut!Z{qy?JN9xqN&1^YyL$=j*>tvYRS?ET|&F z&as?{4u=0Pa);>5T0I{-0X&UucuJgjClXjqV}fwPM)M6yR$2mv3_uj6v{%#-F{)&U z@PzLfFNNb?U0YxDe`a#CW4PTifUU0!`KsHhiKd&n8mDqo?+vfxq25)a6rI!iVH+vu zFjvLtckHll$4T?#J zHd~{6X%=CNF7^Q_a#{WO1=Z!ir(AxcsXqyLmqUwaG1Lvde*jR(Bzg)d>h-pE%Qr@~ z*3KiM_>ao~yrhGdyr~x|{%|gg?pS=gd70=2V+xC4J^YcL(pGfTYN&>dMJ{Z8kyzJMWbv(6 zrx8?XZATGT5heRBMy|gE*-~5!VCgy}S02=y#A#q!e{zZZv~hjJLrCQnMh?*)Wdy*tWC3b#SootT zn^h~FS)B@{z~KK;e&?*y>M6GfJf-zRiR?G8F9iPi@$SVRk7qCF z+1cb~;CW`n0;(Tig4(y{Ooo(?bog@A2dTCVEeZ9*Z!%x4qs7%RUbL>7%wS*DsBS$c z2FRBlp&q3fbHoGfNiEDVUu8#^`hxI>&yD5)e~jy3uHsT|JBv`8t{vZP5#?-$_hktd zjh`0);iS7{U7%QqhqU=4`X*`@t@bo&(?}?gOD0ft#Rx?Io8xd?isw46l4H!%ko5gX z>~?EFuE-E$#V(eR+jRlYyxK3dQ;B+H-*pjJAlM7{BCJ+MhJaH8wN zznZO^-m<0>ks|)900;Hm2`;z~On6~ke}9RQ3#rPE#c5x_#E5J-#fv0pyuuB($Y7R& zwdjOklFh6|p5gVo$cMH#@)HZ~y2@^fFsUMJk~n-46D=L<3#G5Fk@q7fkeeAp9sK_r zZ*4-Uz86vtxhxP$u?HkAlkpyZJr~F3fbq~{q6&}KVIoUH&vqZJnu;Wt@;lILf7!L6 zQUFJ^_GbJyLL{MTu=in&!a7XX^-z={$pgI>mNLYP;GL6#Q)*_?>C+;so~h#%tJ-aP zYO$imJ|IQ%03>;$1i3GIv>%N;dk=gkOO`lc3i=W9l(V3iIp#_UDN0DjA0IgVZ<&4o zp0k&0Q^;h%v3yHHC&Fe?fIJUXf7nwI6!~5W@}FHi$6ldi)}pFZIX~C0)#^J>!?j2| zg*nfp3~6UoU!eqv{x(WT@zKIb(V?o4qGS%!k5PK$EL@$sqaUwSZm6?JG4r|^?TD0Ale4G#)OO7tW&Q8a9bA=gze@JQoa0cLp ze{%c)D{4Y`!#zVlhx6^LW-~T(E2Yht^-y&%b#H38Z3A^Cs9|p^?K?_*Y`y*y(kO{7 zd4mOQ|Fz@9AjB^Ih0!zs+745{F6z3`!_5$773-AwOBAL_gVq~ha#4uzj_<$6xAh%X z1`s?I`*7o?*G+^&1G89Vf5{ax`ulpELFi1g8UaLw&_9RKQ&>@Zm$mUkgesA)3q?h< z2Fb@~nuJbJ*B~_pW>+7PKliNBtxh9SLCs{THO-_z@og$j5Dm6njR~6D)?o=kF4lkS zJhFWs>rvEH+8-43jnMm`OQ*oM##Zcm(D04)$t3j(Ljk;WG16MHe@7}$M!r^PN9R>= zGBqDEo~wyhLnMu~g^ezV-BH}EvMae0dNur%1&1-SqUxxjt|vuFQDv0o3-XEj3#5F; zv7VeQ9@@#QvWO)mGd-;%YygvQEKrSeg*?GbU*QrI_@~M0)>$9N7T8koVdC{p8;gYv zDAfSbS=)SUoweApe=!-oe^W*@@-D7bRFe^XE{L-J<*}@Jy?)xyDW(UnDo(if2yjV0-kSa#Zj92m?p`) zV)4v3F_u^DbOfR6CAE<4D6wI?x3uxJP0I9aH*wPSfx93PY<_)}plRkvM-Dp!e#C*O z)CY-SAgfXH8SDhRX>F)%QHQl5wNp$TyeA|+5!<|vKKFb4jo(`y!r$2VAu4M6@IAp- z9zP-5LIxqye_j?OL5PrtJfT!bR#8oMo{eV%ZjRt907f5>5(c$d(VUu z8W>#O)3Lj^H#R@jNb@u(wHw6-jD=>Ty-bxm@;?KXe-_zs3Ubv&U+lJOEYku~KJ~qW zJBMo#+wmkxH{fe1Z${d238`H&y>_}{DSGK_RpONb@)K8olTF!5kqejrb{5%Bj-RRY zdQz+q!_vqOSwJ*r9AU$_l&XNNt`oR<04b;*3Y@LtahrL&|E2p^8%Q$zUgDG)eUzj= ztkzITf1&mEVFXcWP>v{y1e&{t##QK& zQANp1l1=msQm2Z{B!busNp=U!kb>!t0-RX`@%SxfFYi8&1N5x=ahXXJdQZIVmsyrf ztVdYs_m$|3)D>m>&uC$6VLLUQTA;kGk%SWle{S$jlp9m{ON|G^yXVkLBj^}Y8OwC< zI?Fr1o37`5$}~OD&DbsPq2%K3{ykc#$Hn*VwoLwi&|@W ze@6zzJL@m<3<>ukv(7*?HCm6+DDZwd2xFM0&?)mQn)kmLy@9K`6TG$x118wgY!rzm zXZYIWt~8-#pED?*FH=FV4O91miveGbpxbr_*%^~m5&E+ohAk#4)>?f|r%Rc1Fnqaz z%zQgUPqwWW?RJAyE0Ftl#)Ehvq=G7jf3q9RszQK*CM`scdb82V1G9IpoQvslA*=Wg z5w+*J63H&+F;dCtmC@sSPJ??DWnJ2e0>X%pkP{Tcgcx)?HR^R~RM)JSa`9Yrueri; zf}1WR(D}P>#&VK)9pn$iWw$>xe=fQ}m!glG#OX|<+oi^7GM~K(UN2wtjkN}}e;Y;L z`*RtPMZ@tF5_@M zR`2^yP7>mkXbys$&q?(ptHcZRfB=kD^t+G^@9IWi3Rv0(l%xtRD9m*#V6W@1D`6X; zO}z92osi8vf)6;!_LZODO^tfne~}2rLA6TC?=gQMi0s^NwK{of#bZUHG;){_eWP3! zH{uRu>SGAB_3iual@kO)y?y%zc*VkD<$d{Q6r!Xmg_8fiaA)Ga0fgEU_kCG3V&C_D z;YP)M0|<93?jJyX_3Qv8_uJc8{mUOhaTlK?$dpLiJk{)qt+NTVC7O-Ce`F|3b(12J zD2wnTs@5Z0t-2bH{4(&JbmZpRNgihY2GN|BR@@e)_Aw7xcN!jSp33A71Kb4Nh7$&@e`L1`TQ+U}s27^-RP~e={63pZtLn>xz zU~2Fn7Hpsik<3mT+UKDVe~e8V=&~_yX{n|C)N7aYkwf~kS{n!Q-FJ%=C6A7&e%*U3 zjGZJSe}q;8cH)F99c$rzIT~K_ZDXthH-s0tn}y5jmuQ3DMxb(wb&KZ=Ckd%9F>2yF zVfL#Z1?Gmm&BMzeL5{b*{(^Pi)WCRGMJL+>OC*!HW=@_#8@U>;f1+8CWn+cHc*f;i zt23Dp^I!gacYl3rU%h+#)6LKJUoYRhwtu>Lef{?G&9yog6fJ^Yzq`78jfZ}9ZQotr z{)(r$yT81>|M1?vzj<^0?!&$E3{aw4whzjD{EFieof19)*T9w_JG$@0uhmo+>86}>*L7C&3L^+HSf930FBmWsK-jnvU z@0ug&6P9LCg7<=`p$sZH!uW%JfwG_ z6Jzn385%EF7YF#rf6U#_8a@$BL!}-Gp?)$3x+OP5XN2@8e?Q2Oy2^0xtc3StNMTrB znao)YsU2S4-Cf_?@A0#BbAR*ht$lm>_UCK+`t2+G{!+ui+c_$E9ks^&@$%}=`1yWq z-@Gz24jx2ZEa3HBzr80SMw6a;r$8~$8VXCj4|s^%>-*ck>J9YnosqS{5IXYz%@~%dPB(*-uJ!Y<_Czxv%7Y1h*0L zrUOBpHW0RKG8jp_C>&W|+-3o^0dh$*SRH!zyU7}$e`+URLCGmi@nq~$Ro)p=*+pFr z)EfsVaJLBLrQ;{dAbP4B_mZ1Sdq4piDESj+-tu#JTm-3IevAS?EI*haYwaW+6@?#V z6G1-Re>Fh4jLU*bfUE@2*9JEnoGS^z=S!%iX zLuSc#%}<^;>rU4z4% ze?oh1BES`OQa{)ha==>VS)QPo1;Gy=Bt}ENhb&DsZMB~}2 zMb8=Rg7wqarKjNLl@5DwIkTMVKi~amH$0FgCOd{64<1_NI$#m6;QPeeuni)|GfZ1| z_!LSZb;D#NmRZNj%o7Z-BQ~Xal{oQQe}mv3@lb^5pBn?2rx=Sio7enJ)ML3<;$WWK zDwt>@gqV&%aDw6}^+6|UY;*TdjX9Tk%>Qc6*Z9sV`v>r zqokF_X$*oF&^-n|Epqj#6IRZV+C3aWHT#9=H_1_NTYk)g&zH1h!hkrdN0SP=_4xctec;FTRves#jiw{0X-*p0A6p>r94aP=k<$dUkb%(+m#{oMSb(YLZ-GN@0d+DX3}G6Dl852*6%6*7aa-)&{n`<5RK#~^I|4N zE>=IZ`X|#7z*A!QxlFNoFfik`R6WTAH_nKl=)B9bIM43tbr={^do=uHN{lf$0~R@B zt@@uTc$PGC>jrgC(BhqPe`2YeKHjKha_?OpH;A3e#=Fr5^C+^-qzhls(Xb`{rZtvX znmq?AF(IVZq*`jmD>BX%8Rm|TJqW$j6>7%AF$$d|JTso(R^MTZH|8n|LkcxvWH?il z8TL#U!`-4Z5AB z1U^N{XZ#sjY}Y{cR80=}OF7;xjhD9ZLbYk8+Q?iNP=_ibzaT7g7Rbrepx$7Jmar-s zI`B~8-aVou@jXUIf9VTxzzDg{m?J~*a&UMa82eVFZQWsWm!yG(`DTF<0OY1IEZQvo z$qxd60bk_HB}$No|Gb10GTJNtDe${otwD#S#Mfyr(!k6^hfBoof#mrE2nIJsm*#?j0 z#{r@lskD8Ug~fi57WsD`BIw-6@nB;bpR&nR=X2|xWYsyJ@k+#IkK*iwAF^{p*(1D- zGE|%nvb-oHX{Q;bj+_IaHlQ-Sugt--(ujV^&q&rIboeHbd=DRTwvO`5av%rLMJXo} zHi6XtBK}4W$H)ZM0MWp90NoCEK_!2xeubmRl!+_UtQlu8mT)mboZ=l$@=R ztXP&|U;hdPQ$JqbU;Sd=-TZ&oYCxQgfxqL7aDL7ZK?0oOrv;0Es3AZ^VYAz-S#DWG z3~VATb}`EI{i`7T9lz7taq6{#=m*v>uqBmkm0Jo`f8_xQqi~lG?k-aH+ljapdOjqq z8=Ib0cP7bh2T>K+;A#E+Rz#rwWHpnA3l8%TbX(i=mrBhUm;iy#d}oz9i~shOBj1*N z&dKVq7~R8thG67M3HH-yletrgKC#_(TF^Vjer)(LBozMzeWD#!JEMM$KuAo^#5P~8 zFMTa4e-E+&Vv>5W9pIH}h;qk&`$6O}dStrFE(F2j1*BuY)M0Ozn*3m4|95Pk;!DmR z;+)$KiKnFPZL6XZg@xtD$!vjBI%A)b@&ovdYZn?;0BiX=MnJ=A>NeL9^c?+L$g|}X z-pId4jGVHw0UB@eT8cN8)88ZyjG5o)Er1%zf3N);b75jbc{IZo{|onM%kN$nQtyJb zxVC8gI=xlgA{Y6OoK@_I=dVhX>Nl(ksgk;JGRbyTtQQs-PoY5z=ga+FuO#$S8G0n& zU=f-`9%W7!8^LFNCdn|Y&xu(wVkc+mG1!65L}f>1O*)S1!f8^Jp-swnj4@lf3J09K zf3-Va-))=bRrqNJtpr|2tD?kCLCb6Rn~~Wk-kj$=Wrf!p6sj`?djEBF`%4wU+EqJ2 zHa*?#P$17eeIe4}w0Aii&jh=%Jtvar@Ak6qx%N7JC#CtA)qIk9=!)GZc`SIY-T;>v zYG~tUV={Qc&ckBZbLw(}pZ=w0EPVz^fA}^Ek+SP;_lxTY^mmVrnYCpUj|{tW*-r z^Aw?i#uFE+kr7p%U{0yB1_qN2vjPrR%hC^m3tFpilojyGk)#=`%`GWf8jBL$+xEuU{^C5Ma<;!9=X2c;PUhb6fBLNVr-b$KVuw}T zxWDb+LX5gUx5(SU@uvTMNt$p0__N zGf36aHti?QZu0}6Wq@3)JWhyqXXC|%-fk4E=a7Nl z{v%GHQAM^@jmwjef92XqZEl=gd9z0;o>Hv0!z))vFjtP(Hty6On+S^FuDls1^klQB z$KY_1(vvcN8TO(naO1$|W8IC(T@0zWOr%mpIi*B2E;$6R31xBhI<^3w7jT_OHF~zT z+&s;qjg{t$)+1dPLKE)?Nr^c-pO^2F%#5^h+E1+LDYVJ~e=L6!2dHY=l4|--8LHDa zAnTrwMC18Kdy%L1^aj0<5X%qC5gM$GQc3dRyOqr~pjRk3xXdzW^@K>Dqy(i=fHiw; zDMC96{KFk-U26PurQCI95U=J9ja}swH0@;(sy(a;TKOboGuQ(=Kvt;S>wBmqIFerk zHTNp1(&cT@e@aD?xkqEX$pgI09d$6w7vLGa!F|OJhkk_j=t8M6Pe79~aMowB`UGI}9 zi(H2PgdL?I3v(7Jv?R_pC|gIKmKhCMyB=MeUEx)xV?O!ytk5Wp9r(RatmRcV>F)q} zkHv{;~&rGFROo{Wu6zg>C3Y1Zu=|B)2ZdS0MZ9~M1g)v zy8cF_JvA7#kUy5rdt1{I3V^;3DcUu6=UDcif1Sh7tHfDQ06_}DxNjH}@I?X;3Ef~V zK-tDr^nqnnvsMU&X$evI=~KxQTW1q|`eZF3rwRY^)2IJlBG>)$?#=b5PXdd&3<#rT z{v!&uv%U49c#VyP#0l^!A+DF>Js|DG>2iuD$as&f6lKjMyuQ^WPMG?zKYsXPgEmou ze-%z_8DYh?)%Un}fU786`l~!4)(g$pgU-qDF)Lk1c>tK3U`Zisu?3UXqz^Uh$NMPFR*=C+T2&YE&4Sft);7w?&XJs3yia?lm*#jQ9aew$ zYW8IWIh%Mv7yONy&#eH@h>y+>-5~eSf5nB>6gBwYVj<~E5F~aQ`f-f1y}zM2h_-mn zs@;0LBBb+(#s6Hm4hgSbSj{zyd@*psRgU-X!uspwo7VztoUGCdfq|>Ivkj2F)>$)G z=KR9C2|eF+GRQ_P`q#sSE58H1>Z=Q3;lqvr02!)5v$@FJg%C+9PQ?bb-_u?L}oP5P9zf#FhOd=5i zStPn_x45>b8Urqi6K<=)3m*uywe^YpN9XqZ^z*E`BNe>%%xbiT;>?YYGOXIHBf4QE z$Ji?WuOJB@0quf8KSQ1g@(^#3f9C^N%&i}{C8+L9bb4~4B`~mKUBuf9^4W_|{Xp#V zt~2>GuccqVCAK#|5qdjJQ}0HDoc~jP2(u`b>GS4fSMZTfqEl`hK=wt+R){Yl)3aj6 z8lSyjK}a^==eq*Fw=5>XssJGJM&T-gg~7qaPMV3*TSCggWbH%VIX%$4_NZ#XeMfPb~|lK@Bw~kofgfsFN-+qbnDcrll>Rl=^k3$B88sZ z&U*KcPjqHe_fzutI@e;wOG89)vL(7otl+orxhVN%E7&&eWouU;y!<(sJq~$hs_*P9fO?pP znR+kB5yqfnw-+WMb!YIy}z5+{UeZbT^QHqteCxXY5%4Cj{RdHTfFwvPdlTGogLQ9EkA zq0QQFjxEJt7%%j$0*I`Y!?6mt`+Yif}PJF!w>HL;+S+qrzu)l|LD z1(840i%Qfke`&crsuINPE{O@BgY8wJ>5sTa6KofExZNjh*X^L$cYSO=ZMJ@&D3>Z! z25K^B!!(@KZouGw_(Oks+vg`IQM=7T?FhQfz9&RN^KoX;>4`mw|A+tLy(rRUv0+~% z%T|Uc&mu7oqq(C6D7Kw_-5$jpdEMHjB9&Kr1DPXqe^&v~X^uMpbyTA1(AJcR=IJY( z)csnw3e9_}^I&vW(Gwj!+O}yn7_CD$!=8Ra>|<$)J#4mj!yP0Efva4il4g)U>TERf zz1dzYemzBN9CaWMA)na!kXidoXWHZrlm`+i=^EspbN7Ji2d*IY24{gTr{ED>WiekS z|A<@Tf2f~q_q#iRqm(P68M-R-eAs7c-{*b=oGcP3;PY`~6m>4%Q*}mWVBS_tpM80y z^C}U6!QeH74W+3){rb@s{)OroP5ol=jY#ztWCO9lRBzsZ00@UDotJma@>%z)BmZy% z<;x3H7NmHVzij1?K&Cy|t|ZfHsR>RoK{?fjf2(GgRE`I4AVC_%nXRRR@FSmmu1f{O zmostS<>(4zPl$7pr^s!YAR4X}KU#eav(HO43|P?+yl?GDl=`Knm_GBxDoht zJoospA}-~@E}Pyv%6|_9l9O1O+Cz)Ue|(X;iN8RJQsy<3Z;n_A@!C%_1%uhyp&b&K3Iuzk70T3`kQGZ; zyNpCD{K;XN0)r=I7&t~QM~wY0ORa0L?h`vyY@9Fnl}hssBKuxopQXq2*|Qi$MbUQ^2=*ZJ-qB0!>WRf(DC_0I(wzl<5v-j95E!TC0aw04?IX z5_%Dcso868U4~lV_Gl4cLPjx}n49oZ2df8Xjwtx8xlLY38RrGw#{1?-a8|Hu*SGy{r5;qHQ~ zsW?J{r&AmwW!kKLu`4*X3T|)rb}Qc_z#t;vXsHjFJt@AO0FkqTYh0nHMv3)ioBksh z@8T47hy=g~Y7ZAq2BGL;CkUijU2QyIO7kLLF4ZCd$6*7M+2hw?mTZsNe-P+o9{~GF zn+UbiK;bpY@}Q96t!bLz;k``;^F>fKr0xG$3aw;Z0~q=headJ+z!0D&c>bt?HEySZ z0~Nr>2?B4}$T3F6eh;(0oe}?|9U@T`~g)H-cfE1!M1AQt(U$PWT5g`QKYRoF=mqS0W z4c3Z+Z8u0hX+-d;2HN`sYLr_p0?3d7LZ`TXKDKA_0MFP3Y0ex+7oo>qp%k8urYlpt3K|CoCgYRf0`D*COD+@H^cxX zqu>WOl0j^3?t0Ohq5*DAjulvmbP)h*01sDqX)M&v@>ei&6IfC3gl|dHMDau3xkY#% z!v>%4DkUPLGC(a&V|>ihZRpy5Xw!Qq5b+i(U&o`~gm1{0$AJa%it5!vLxLCthbZ@V zERcvWielR=8pqq{e_cEtBFAtj7gAPb1)X|Kuo;cZEDA}%OHOPXE@Sp*zK}v7&?z2~ z;+g)yG0(;uE&EJ=M?|=v3Czn{Bd_1FY!fivcJL8Mn!BL@8N&9bUBCb3`pxz2@I@Q+!6QvT{?&H zMl_5NdmU|%e+`~4C1o*E%fa+VRqHe*=3sHVUZ4cYNi#8r@g!SlV1 zvOAPrCkgBMQA@Asx(!yVPia{Sf+hUC=f0AD!+#6=PqS=GRJ2%3Nf#~Un0_bC)Ll#Z zSVk89BKqQ|qyekfXea|MQIkd+Mrin>K}cih{`P>hf9+0+(iEDBLH9`N!v*2g>?@>9 z1?j;{o8m&Z*LJ^4*nx@`ya8lqif%#hGw208S3K3f(*CmQIZh~zf=5JKsv+QR5ZdSq zxIfA!be+<=-3xcCOGZxHJXI}jA>y&29XKh&q-zuev==JrXKVS{&hOl2Z(un}Ae2vh z^5h^df0$?Sx4(5i?_?0VaaQy0{_uY&EiaqWiy=taXAYC#O?V$Yq2vyhtvJSi$A@~+ z678^jg_HZiI{WXiBI{qQ<`A9q{Oxc3jNIBC80frA$w@V`2wMm7KcM^W`y_%h{vWO5 z5O0I6ObLjEW-QBTHN$S}AF@I~5zuI&3QO<9f6mFy`+|Ss;r&e%EO~LwVrU&_%q{a% zXORxOTV@rpn=%jdS3e4foHwJ8u|L~!u^osz^h;MFz}gxdOXBb;x z3Mz(g8gFv%$hihL$B^--WDbd3$q8LRo(_MwThwLr4Q?69ShOsAfDU1+SVy8|-U8Eu zD}pH_#b}Ux+6q_F)w{Pp-TZ9-_43VY`=^`N*KaT1TpynaA&@eyir#j(N0-l>Gghl8 zK5wxvzbJQ#6a!3Js&}x6ELOn~fAVd>#ax&H?wimxKWsx-J)p(rFo#B5EI>DQeJJ40 z4~e@zvwX-%B7XO)G9hRYpeq=lKx+aRr!BVg0ktWO@O|(%*m{3*Lh#FT4znO&?L4Bg zHGP^d$Zr9}X1SL;LY*}m2M}*ivb7vYa4K#7C@n`3o3=4k7FpQ(L_Vg&fAKt@Iv%Xg zX!{f;p5-K~9QGi!V)!^@x+PJ*S~pOCEO=Ar0=)Yf{;c#iaT$=!{B&pPcFZn=kSCHC zB`d+1%YMR}IGuI3^+|T}P9Bo%^GFIE=mj7b5{t0lDGJ4J`) zw|svYtZmopj4V?XsDD6xf52-;c}!g!uhSxo(G6{?=P5?+aU5sQTEtFN$0lh$%ST(X z`~Ld&?gktBZ||p5v#ZGv5_F7L`zzIkyIc1J2Dz~ORS2aO*6*#eI7(9=(pthOMCT(F z@AAJt+ERoY7yckCJk+^FzZ_URP~Wq;f%DI;)hKQj-Nt16t18|Ye|FeH=h63EqxyM# z{!lN7)@2X*dg{I<2=yiza3NA%ZMfXSAmRrz-Y6CcFwGzS&^u4dZr7`UX9B-2180>A zcwOTpicyknwLGqVYS)Q7gEgj+bC{C&&LWBeWzQ&2&D8=|?$T_#3?hNpiYeuG3^ox* z(LHg=B)DW3wWym(e}rHs6k;-i9lM~*|Kd;$&=V=5M&`t zk;HW>OklW8(gX4wzQ+Q8qm$Mwx=;N+?FQ}grDHSYtW&j=6eC(M0NL6eKN)*`y_c1N zcTlxg(pla=e-dEVw32Yuju5{c%gFf2G4s!gk`$$^#%S?(hTVEg4WS(MpiK6$0YCZxzt zYrI(~On16Llv+=!QyQ}%PlRIUVKIJY9LnB)nlJNbf72(B1PA9isKGWYmAvmRBb(jB z>Rgw-m`b@0W2vY;gd*mGhdNT7kh>~-JZ|8LEAqH(wJ$@CbM;-VXBNNqiH&8L%|F^9 zA70x)O~KJW`9mv-ux+myZ3Fzqmn%wqpy{WO)-?qs;nx|rQ=z>Kq9=R> zw*gX#f4s6=WizHvqa?FGqiw1?tGdZ25WnERgQI(~6;)(aK_wt-9xev%PB+0NOJ_7{ zNr;`z8!INkpSIuaL!|9jp{PNEGNlC3-{gGk-984vVwwZX`>~uW!cMowzBY3CzJbjY z$y}7(!M%L)Z(twA5+`MMvXO6?egm5*nqH~0f0etrpx?lD3a7uS?q%`~ZDL~dfoUYO zej|^JE6`s^Whcu#+vmTH+^piBE!_XmSCP6wq~fK`W6#NuF~5dL5<{uggY|t3evXRX zM<>XUBtTKO)xTtw<_hi4OyK)XdOMxbA%74R=Y57YsU8HF2+y0V9IJ1RmY;@Y>OZqs zfBVpGRCAYJB$D(EI4RA$CPB^GIM0pgIpLyW(Fz_}I87%&n}zS%k5IY5NNc#@CNf>p zk$$BEDW+lZUA-C*x)XGnK8S`;)ti;bp0J3nz>>r4Y`G3`wy+cQ=rd_!h@&-fyxjrh zz$v;nNGGN(qkT3VHMHZQnh_$ql@fFXe^?t&HOT5ZBDJ!zwhnge0auA5ph8~l2-s7O z;e-wK-l>6os_X$o#pl`i`2ZE|!v`8pXEWH@nDG{$4oK&KL~Qt;&xw{=k7=ylgv={K3K6FY^R@F&e?OquanL8#by7so4tCCDK+)-?1tPUsJr!`87c6~rX+UnV+QJu#Qvy770B-}bpxs5^5##kHNWH8L1 znFvd_*bMjxU*<>OL*9%4X@pVTB@xe6bD1zijZ8=m zzyfjo<6s^WQJt=#2JWQ3j-mr{(`^r_0KS&Xd{)%{$}Nym`x+XZ*z7%OpLK@jt2ya3 zeC?)3U{$c)rq}8!@hpEyPwVoD~wvMIJ$<&t~OtZV9M81wzZzzcdqMrxQ zePs6f2YNG?H&N(kQBoVQqvS5vvp&l=YS2Wc-n|?9u;`6uzQPIZb@AL4ElyMLgIp_wFdB+7Nk;Z!dpe?C0`Cno>5 z20t9XZeB8ZLb7u41BQQ(4-gyAQEV?AKgbhwf0FGdwg+EfKZj@t{6+@u0k6VdN!>}U zIg$dmBhqaq%IX_G^f&qDWbK|>X6x-MWa`PlX zp<9)g+JV3EvuDz~lXYhvo;^d;jN1UFo6=9 zct2N+sI7KgTXmnt#|K@^*ZmV7Ty{0iAwZ8PIQ8Z}NiCyNON8eqAPjcz!N5qTdAv#- z4~+?3A17GpwU?pF+o5_D@o(P4v_FLgpO4*+?WSZ7e_XC%01I9w(WYl78)$KJf2{o` zXr5+Kf*+yz#>e~sdpyrGKj;xPWO#oQM+pOrigFgDQSUV?XI;@JKU*sdYVe&91xM;b zv6A9(kv1~i!MH-@L+m*q%?RvLdDQdy6#DNK)F^zNE4r%N*V9{d8>0)$Uxk?eE$jEz zSss24qo>f?AS{AC3mb2Z?V9*zf6#l26q*QdxvL9A_4(Wg{Kkgagzf~PXN+4h*%c(n z4?XmSX27MUIlB3tpDx4BWhk3AOz1w8Bu(j|h@&+1p`CY#m9%5nfe~H@&An5zULtG` zY#<^Ab;wU>K}(`X?ZcJfecgb-<3TiBC`Qg$mQ)l4c7oik8zAHJ9?W(bf2{eH$UPE8 zM?Lh7R^)t<_e6}P+3%?Mwa{U2&Rf3!b@?8clTq-E9QZeS*drgbt^#~I>S2yrv3`r1 zBgf()ZM!)ooS6{vaW)Ij=^xvcC1|=HQZt6r6|^e_!wKJ1t6&uTR~55qf(AGlCmq(M z^v(GnjzrBkx@8;GsV8hEe-A0lUg4SM1BV+uKgBDXO0Bd0Gor<^6gbUEGJol~IueV! zs}mMD+O!YmFMxHqQIvRo=wwlHICp^vA;-MQfs=<=dLMX)nN&>q{^{yF(`61f+QfN= zNHPpfk~<)eh!S(Go1G#z!TPQZSha`TX8}5lZLx_>mhDRRiss$if3WgbI9qgo{pP*> z>gM)N>y$<#=A)ug_n?A|8z3jlW4-V<)nkJLpP}xyar>{epNzkSfAajt>T{1idIFf? z7YnSW;tjEU5C3#$;d96ig~xNTwSCA1#)CK=LpWrFb%K`o$MgBi>R;Q5eJ^s;mjv`6 zbb|EvWnLO@s*mtJf4o-b-x-<7`6BRLy;7v+v|~B}VN%A77mBC^<&-TEN>Lx;A`@Y$SSSoe5Z{I_UH2!P9&e?=B8R((W*)8CS0W^oG2 z^ZQtD!~>-S=69n6D$1kKBij-Y!d5=kEis{U>t<<%5$)R8+&bSAogM!1Q)?OJp*OQ= zBDVDjjPJ&FGsf6IU;(E{g7C7u(evdgz8FlcBsK(YzmAs3-58?5q~=^EioJ>(v*_gX zx0WiUM;7h0f0J5jy~Hmhxt3awWs^0=c{6urH1c%Pk7bGDHoAc7ys#QK=Je1OU&S*0 zwx8d}d1oscrufWKCL8m$t+u1_*cMbszqvAxEq$KHeRK8NmkVCRF&>us;TX5tPScs* z7Nsh&OU$k5PkxX|XHnJ%m`dh!uq7IYDIU%llD!`&f1;ln3Isoh;w5kcIOjG^-AcCK zJqMZjp+nmmSpE2Ww6N3AiPLqIjha1N%sCzXqY)4O&uDRn>ElF%58jhrPg-i6yyyXn zpyn9hqaZ41^O zbTtQQe-MKNZK4ctbz^K+qc9^t1{x3st<`XY#?8YyHluOW*MyP8=p-bUMRgZN%ORe} zZY#_l_#wh{+ZsdcoRQp-%SS5AFP29Qs&S7MO=nR@0nfbdl0U{6#lSPeDq-oo$p_Uj zPfzyAJUUWs6MaE$PSD-szzI**(yrQhUGC3&f4n_+1*Om1ab<=jCdlh_Yn%a^svlDf zxX#hJgT1)p9q&Q8SvLcnU`)a?NyT%LheIaJjKshw7UW{Jnt;RbGZP2}ulO_CrX#~T z4u&SIj|bVsLI=UmZoHI4prH8AXxox2oVW7f8HktiLJlWmv~I`90!pZFo4#mbIeRb( zf64-5uv;%e_@fi#$c_`V^uLTL?aTw9^Rqcc_JiGzhks@9e{oTVe|0R6!uJF>$!ElyRtBamJonNE#YW(%Su=Zhtzn4=ej5zM-xw$8m8v z$2BtltdfXTzIaN1pVoV*{B(gw0p@6%Kv4KZ5OpSQNEg%p)rJeV%=um*PP7kD>&9hL#{jstK3=YGg0q8z+wI z`j}B#zekI|BSy3Nhl8B~N~7QrdC=Gp3nffrodh-3aa=A^P>HfZ?8O7^D>x7Hf3dyW zA41mQiD(yhY_eyH>fOPPfoW+!8{sm^txuwes&uEvu94z&+K?JQ^I#9ogrk6Jdr81& zkMaG6Zv*XrM%yXsMkGNTOsy#KSN?&Fnp;8!HrL(}A|`6qz%Bt4#rRtVU&Xugp0vVz z$DaLgtQ1G7pGC=*Al2EPlR1atf2RMRy?5>NltDbw-yW%MG-LwuDxouHb@gle&p#9R4Ml40(c$^ULpPO{;ju@3UeTQhVQz5$fEW31Bo(|-iC zu>7#JhYrjeULyOmQA2lO0Ng6S5;m>FE05JoV9J1o2Np)8Iz&r#=Nj%;kvnoAbVn}y z1%?s~SVnJ{dEKMYD=yMSW3)&eBUDQIQNWa1#E@xBvF<|B<2@*)%ASMeLi{$BE`yqA*yZEMed-$VVx*$bS#wVqpS8 zOnw#<2%f`X!_Nt98{OBW=HC=Qs>=2B-&QnrV3>nyLW68LwW%8kd;Yvv)d;U@_p}<eQOnzpB85^Sf165jEAuU7UJIW@Ro|No zR6=6lgQUcQ<;P$))8~*r8Ba zU#fssRa~-md0|sIcxw@EoLvqqC3NT5GB@JGU%R2~6$tXH#LP>gUQ1^G_8Dk*RfH}m zQFZH46HFT}UAAiCr4aEn9dCzt6m(vW=%i7u^yu&f33Z9j9;D$=J6vtX6aP5UNmD1> z`Pf;aniMbWfmB|#6@NWppE`ni;*sD9Nu({wLL$!j5zH=^${89ch;(6ptR}>|d=so0&u{bQBsZ= z*D`56YI@gW>@H@l-aOkkaF<#`B1KTkqygC|Ljv0%N#kt7gnz=bpUzf9oOGZfiEF@_ zwvlO|sK(aTeHBZdso9sDNFqVWmN~R6=*||%NZV`=O%|7QtwQ9Gt2qw4^g>pyCbA9v z8c7+J8}0I-UL?HdbLsQ}RUx>ey1Bl@q`AT!88>tnaa*D^isB162f?$5-ujZW!!J4O zi=+DDs6(&x$$vB9W@)-e&R)HG^wU{39!{e9tGuM+dp|1v^Oc_@8BSjP>;L}Y-wg8s zOLjw5GL##7_20d^bIz}BUthob-MPAXGrGHX-e0{RU0>adoV)v5-iYo{3LyO{lDrca zAdmjv(Zz@Rt9Lif<@vn`;@YIJCe9T}$GtE?%t)Td|~#dBBPMPJQszBXJ!_2kCB8>U9-H+N&@{Vg@j{22=JpDK>f+geZq)*cC|5rjZv{Nt+jzN8}>O=l*e3AOPc;u1P zGBze-RczGuXe$lJ(BY7i?t~Tf6api%lMVjMbbqJc4PD5m$LbR@9~sK>tQsL*c^YQO z&{XD?OWvaeL_nD)I9WQh*K$IBl!YmdHEZEj-w4RYEU#bMg2xZ15v^&GemFX5-u2Pp zO>p!oPHddc9?MaG=iDcxU(90xy}J+AWC){#SE8j9{63l9Vlw@4Ca|kVAP%wk;6)_Y zcYiB4K9Or9+Gmj;b{4rFJgO#$W-hoMaEgnm@u5CNSOy{($ZM&_Q{7hd6P<`ez0p_W z-nHgp<+~|3Xl(BAX4+n*Hm|DnNi5P@%C?!~vH6^B-3%q=G^3U>r%G@YG4qc(fDcL# zTAiNG%i%cdS`We;UEOXssOtqS(MNe1qko=*C2Sp7w?UN$C(*=lceOU~s_Q+KszV!c zX3B-weZ+RWuBFQ`34WLm6Or&v$dluC$Vev-pvpsUIT~jD=J`vg-1YzUvoMY*W2mTP zzC62e=!YEhyZ&VGRSh3>MJ(I}xhKj1yd&x@_7KCvIvjs>iK@Tpm(p{z(MebNT7M53 z@_d$+Fn80*j5Qmz17L?KR}n=~p0z-GwLx!Gax_k!gh?buzX91EN8*7UY?!2=z#L9x zxx*eY;(FTFlOTB5afvz5;QzX>$9{f~1-8XIUjNipysD?tp;a2`-11lGT>l|43{6w> zR1&AnCzhJLUe5Cs5JMA<@Oa5Nwtrl4=1E&kc;ze=Ng7r7ykN&5EO2BVD(~*G*Ou zAhv0rb(jT#I}WgubiM5${Qg%QV9)G>LpHO$- z8M-Su`TY9QB|ky(g+Ux=D3r0%DL@=b6}T0fzAAa&;E(G9C@AeJErpo8^#G-FJdfff z#ULDf{|K~q?DBz{)Eq39+?Xjt_VkPE1dhU#g zGo$ht`L;=)IUSuiFbKOrb-vpv7%4Wqfp=sbONo0?mM*f?7Etf#YL-BgY2MptkD_1P z1XH4W12CvHW3%P*6DR35I~JRm_o?Yb?8_y2asK3eu~gFJd~D#liGKmG^uph6^7QwN zrC-WS8mecWqo?&4D87cjLb{W>k6KE-h~4wm2X6fiw@bT*zVZJ2_Wp{tw7EHdJ96&N z-xztf*0_t^5E5omH`Z!sU{`j2cQ?9s))#kse)9&J5s@G8?{Dx@a51{M zRK-LSiLx?`gj?1k%zuTceQT;?QtO|arddlZ1J|$X_fTTYSB16on;!*~;g8}tij6Hr zxje`VB3p_!NIDKIoyRE7@r#u*`s7Y(@p!!VB|IEVly`$Dd_*vap(_WKl!KzvNjs+H z9geG~nQRW|HR;u0%Fo(mIHtW6#Vy`!olJcv^>cTF*S;)%dw&c(7r1Sdr8IjyBL9l_ zkTqWISWqdd)v?Gs{c6_4@-|CSw1}f8-@~YcC1|6#o>9x@&eOm9M24yp?s`KP(e(&j zKnKWzF(JyBh7D22mPFGXbT2ay%eJi{cAuW=)rIULL-&0tMN-D}nHAH*^^);-L09w5 z2z^tsS;IOV1Aipom!7xA+a@B(Tn{3-AzP4^5+( zalvH$S@L7buBKT?`v`qMb`$b5kCD;(bIG1$n-phjvS)-!v7)(QVdW9Az1dX0wRQ~2 zWY!9mjA6_tV3uHW{9J?A1hN{?6(jr`UfxQrz84p)w100=;Adpd)+rMrl%*;r{^^8h zbsDbnKda;-jhv*2aL{zl^7G^LfR}U>H0mgqaB7OUGs0h5NplF==ftO>6o8{4L%TU#>gc>LPtdvzzGonH> zaH^7bC4V-6WTc5+FTT{5>Kmz`=4b)1wT8xsZ}oR+lF0|H%wiZb!XkQd??sg@C|!qH za8a@yW5vEf^!QjeK9s-b<>;3WZ={ptw6fT8Sy1L`NuRQIP(_`6zSN%brHpfqgnEiX zg3-LKrHzSuW zHmohx!)s!j?Wr@sPEOhFd^5SOnYh~sltH{)>`*3yUDgj}R3_6*0fMCSOhP{!m|#*c z4oS*jR?Wg6Nb(eoqn0%@S>oUY2J{HH=L;L7Gi<)(`n5a8x>a9#Pct?5s`rfL5zoSv zj(?dZAVcmp1SyAh^bHMj;A;#Gi6YOEIcC}KZ1NbHScmo$&XXHtIzwk_>_ru(VSPF-&uuB)qcbpAAVyH&sx#dqORe zgh_#ZnBve&AiXTN3|YPfqVHWRb#aH?D1SG%mB?o^PReAb)Hz>`L{N?Wrg5Donltj- zAoW~AJPwTbVY0vzf9g+kC(cm6{;1-6*%arC<=A_l^Q#ODxHZpKj(>$x+@f(^(Y0y3Z&keGCA;d}(HAQ_g7 zcAW!;Q9OrCEbNpPYNp-4>39mA^r@}66tKje2U5smL1u`((WDNxKur*g!)3RAH-V1w z-=b$f2+)`YMEyr7J5M7tcRyn%#Lv0I;p7wr(KC*rul~dhf+TfUcx(#abLL^vraTEp zs2rx*BKjjfKI4Do0nYd^o*ORktI7;ofd%yOF70DI?KmZK-MeBu!q*RxdLhgOof0@< zKR=;00W>rdPYxmy#>o*bmGOl(B?z>*)V1&P} z>t2kFjdi5)QHPOS_+L#?m2)0i)Ie?909vSp2tVPN*sy=l&4&CU|BN?8=qf}>G{;0K zNN_?`0~{xUyU2GYry*N|?t#B7g21=FsL4Oe;k73H0H^)#VVqiS#luIrvgam~4c? zb_Bjgmt2Ji_x|S@$#fBs!-}YJpMv%v>?*w`1|s=O;Grl+8(V>(Ux1U-108_;h5X~9 z7=OPWRhUe0NRSnQ*jDRpT}n_c!vNxc6A1QzqI7=-uZV#&RBm9P%T;rw;hrcW`rF3=7j{Eg525R#_?e>SD*g8qoC zr-xuQXi%CKCRvP`O9OUwG_%Xdd@;rm+e+d(WdC*6Dh}5YTNN;CLaymk$jEeA=NsuK3wagpDm{SNIsFfl} zzAgFU?{m#{#kJut6yIz}G+{Q2D0V%6f~IaVW57gN=*cY)mjsz5(3+W1CA4;?u;P$h z)uh-3Jm_Arh0WVL_dK8FbOcN4tV2X8WfVjMb$$wdxhw`*e?X8s##Fof&Yymlmj)_c zACn;H#2@0}fU+NO6P_|R;ddeSfo#6pGE#MXv2?Uo8J}Wp0U323G0sobEJ4EN`6VUW0xeaMGIg6qDA=wY+S%k}Sb#an2bXtd* z(=5)JAh8e6iJ~!Iq)SxQYO_9IUu+ge8+*0k*4DRTUeq#7B?3fM>*-rE(X`=EXGa4K zmTu#PUxNO#kWI@MU%}Q&t>1!7o__alLbf_U_CB`O+uN;d<(L{6?b{kW6-jG{D9BGl zr7V%U;B8>aakUaKcR??e6Mbyq7=3(~XK@KM0eP34aS0v)=a;*23A6!(mvC|k+W{E2 zOmhhp0Ww?~fwOwTcll}-0K;F%T29|+_CZ+;>%?bXZd>QB;y+7hdR1ZUXgvhL$vBDv zy(7GKmy>h}Hv}z=p2L^UbP1mUnU`*L2^#^gmx^@>L=to7+`n_)p8x%qk@N2D)xGoX zm*8~?Dn<7C>iXKbx^xJL1N8p60sfcUcL^hZ=0^cdJsHJu z6gM(L<3mUhh)TQ*6;yeqH9v!!Fwyt~jgkSeS!1CkD#Y1HVxL+i7>!v+sukvz>a4q5 z4J*<(_#oNRSBgX=w{G-!Js9ToEp}>vOuWlQ#ZMOQvpIv2X|dnV4!RAfy4#zvn$wqnm4@ zIl?|=id9i!-oeP|EM0AXWZ_V@dneiL$DwI$<_ic~XPlh2*UrQENUSxey(5VlCh(7A z!zB>oMU?pIx>u=bk6Qx_uVHa!Zs-NrY>kqEB77slKT z-N(K6uaGiNc?HulMdYGzro=qirnY_wHT&?rX#58eR-C$hxpo{XCT}yiJ0F9ac#__6 za+oynCx-+j)4CZP+~osh_JaW3CL?>GdhTJRC|<(gZs3lsz^*p1yKB%Z4U@G8d?}Wc z&&?GCmLBA~^XT<|Gi&5rs|1Gk1eQCw@xm$ucT_jGM@iQlm)}#59@+Mc&7f1ZdwKKN z=~(xl(nO6cAtni{QGr2?n4pUec?kTuPpeTPls9|%-u2^Y5Iql2vcMC63d19pnW5xH_(u5ZfnED%JF z@;&}C!HcxC$$3EF^Ohr+f0Cea5KTTKW~Q@=$wY^ym3A~9Swcs9(o2NdThn2=S?MruJ$h1V33)n1zt8BTW^#iwq9x*x+<^S(5SSGP zprRz3Ovt6dNU!zv#rfkUX)Fpd) z41sVz$bF=9Tq8CiCLb+JcB13Pr3c5((sYrWy?XV3=%=%6JS1=7Rq-DEsQAxUev)K3 zdG)XV`^SInCovrLB!)u?*!RN$`uM+D{QvFw&H0-?_TR_;`>_I@9V>8X4gAHy8X9ur z#b;VJ+-mw!5w)I6%TDjhNJ^+A&|Czag zpDx>fp9@e$1RO_$*$6L_mMA;O*6;TrUl>82*#%K$1An439JXQ}s#J-@>nIC7XaPbu z22-zW^Rc;{39&Pf?`aiGH1>Q%#TG+E5SkPn!Tj({Fich#fz`jqd+>f}ioP+{5T}y#Em>{!GAFhMqMADCc zSmWVw#E%SNw#3ReaWa>hk-EAH_=x@w0O*$-@0pu2bW62-)lz3+bvgxtX+Wv^MmJH7(Vxfr&>ZsC2!C zieagSh%@)>Bzv|^r+z?`rM8FCLUiJPHQjlS7FbQNHj5KZN3Nr^MXNDElZx9$gwIg` z_l1aYHu(%K^p`Ea5*^=9o=N`;1zAUe-Mf#1FYm2B!A&MO^mtn5aZL`^EijRDP(K{7 z@Rt^z>H?3K!oe2}oNw}3Dd&q~*2DR-_`S5N>kzH0S9f}Kr&o8nqV9A-SP990;qb+j z6yIx0QVDwCG$7*mJMy1h%f`4fiL!R%D=$hQ8Mv{0iI~sZ<^P_Rp8n$-Qlo5R<}YE8*@~hnlO(-W#!&g+w^UC= zE(-jFP6LKQpj_Z1(DPX1lVW~xuKB^3;23(MjFl~?C+E>56cSK zE<^>)=ka4wceafW!vAtr0G$-X{&6j)A5PC$#|!#50PuO{Lx+o~_z~!zL)opUkS%RQ zsKQ$O@mEWKMH$x0g%21Pf7vaEbqbB<@S z0o(#P;?}O7^nNR8QQ8oHWB}}V2W!)NrzeDKU4NVc3WKfh2ez`vBYv%AhJ&=>vgWM~|a0jh7-K*=yE>sbm6w`;;mi`jgI5z& z1)WVzK|f=EL)N6Unb=}l^C}T-cGJl$zf~za@SuA{bx^b5K|3~R97oy8ueASJ{5pJz zt>cWN@bEMaggJ3Y#gs!32IRajF44cceZIRD!L|GLbYD;&(ItPuyAj<+ody#Z(so_X zp?f=QV45>=C$p|3kafIgn<=GgT|i47rEEdxXfVisC`eubpj7gsxp%2jp9N?>W3Ae! zbNKS#@KSGH5kY|S>fE9m(1uGJMjwAuo^nIAppbi0<5Zg15s1$6^| zy1n?Z8u2POANjBFP$%Nr7J?dCrS1LHJNF+Y4m* zCa*-zY13l6n7~bOk~(wpN9?+a}Wj4SSdN`P$0@L%~JHtyhSl|#of4VE^JvHO|WdCn7#le$vPde>-)>i>24gJg!fKCfdm+KnkA8?b10nBCSu z8Jox(&PwK8^+Dl&Kx%{CCR8PVS3|=Fm?mG{a-IDyh#s44@>uoUO99c{=PMpBP`2Nt zERlToj*cXF!6O1TA4@4By(Ud%(zR+g(r)^3G_T?rp^XfUXiAKP#VK z1%&gvyV1S#_WXWydv$(&^?%Oquio7_@2}5qZbp|9*q~|9Zs^qmX$e$3flmeF4wXsE(jx zbp8R-!N9G(?FwXh1lXkwvUf~6svJ>oc%>&d8TJ%sL~-waxf|X7cEr>c5l$IDDVMp0 z38DnO8~=fqUxo=Q0a2HWh6%y}*_Td-2|@u=3cgNJ!?4qb> zu8M9!l=^Q2WG;29fUbJWDrRHVL2ZPNl$1RF+q}AQ-rv4^b33}bQ@CAz#=VXEtz-24 z)k+`GYnvUuFx>deb)ZeZ2-LC5*6>nI%xa3fgy&YZ`i&;@U1LuFd<{<`Vs^vkM z=7S5{+jTFjumRyA&d@e+H|sk8rN(dDcuL)y{ZvXb-q+x#5Pd2^@oDX*%w4iuLvWKu z-Qh_o*gM42qSOrA@oRO>u;JU#XP&4KV8D6fGa+49X5j^G?#D zZDrv#g!#CH(NlCt+|ib@Ow`N=BuK0pa}W4b3*NZ7otatdA$6dFpN zqX|n4A;KIEWW+9$pb1^5bd)GrjT<3r5r}Z;jspS)g9o;T56*wHAoW)URgo$nv+p|k zOLwIs$Xs%UFJuwVpW_g^;Uem^9w1`&49iDd0a^?&o8cJCD;bk03)48C>y3W?Isfs8 zJNBpYtrbj%b93wLVS3Vy^oru^YMNRp`_l6#X)<6~U`i|e1fX%zoV`hkIrkBW5)?)F zPl{U#oGXL6gsguOz%ZqiKl0E)Ao@8sq-r92UVgmo+tegvd4?ySHCQQ#E%3s+^Ja`XyaF{v0<-j*<`ksbvW z!t=}TRba2VZzCdF&hw%oBxFKreF}cZQt)kA-iImUXqDGS9&gfcnmAwRDakyU#PIhU zXKPlZc7$81u%V`sR^^=DEjYVXQyyLle;#AP5wNqLO8))&T5GOk3TE|7#D`tqb81~) zpB=i_$((-&>2eVcs}?f=z6~VDKzLpb(Ss8-%ijIEN)<|jA}1i%ousAyyM1vkcj&xM zWvgbh9=WR9*3*sb^UTAN8hZ#kaz$<JU({ zR?kHqe``PIPQm$Mx0wv6ksGSuM&p=dfhYdd#~wOcEYIkYXP++F{a3X;`P4+vpyI~S z2|<5W-hPGtJx?c-gsm&_b8-mn@VUx65XaFgR#Tcme}IzBn2o94f~8J)uIIHbooe^& zmUOBHb3avUZOEyCwO#^kin1dKyPtdBR;w{BiAf$go-d-5FtlJPC891PoS-mD5g~Wv zhRY2oW-j@85M$R{BK*Zq(u0@CdeMD?n_+)PCYpPz11Cd4vl6TQ$70t{u!G|`iXCdI zJrTRD+#`qJine^=&)u`w+pAZT?BXSV1?I>xO~c$=sP$A#S$l3jtV+{XZfOCd6%Kx+p`6tPN>6Gu(-|8S_^H5{Vr&vG8UsF;`=%IcPIXQ(td{%WL4=(2(pQo7kkxKED5Bh^p&R76_|?N zvaV9MWw#WSN+^3RWxui5t+9H|Ybh7NqG3vyyBSPnI>S1o`ceX^6-ouyYYXZH6?46I z(Q6m`(JngeE3qMEI-z>hIwx6?D)`JMvA@{NSJjiu4#fGF?mTc7%XCIyowy2J{=lTN_Xy*Nw1&*PMS?UJP zvm1x%-ux2c=(~d;3oxbcX<&aCdngARF|f1Pm6*>bhp?Qp=FdGr6Y{$#43-cXDO${W ztW5wk8oQtXY{CI5Ezt;<$c-^_)0EC2k&ie*D4rgWn0M%R%yJfxm(AzP{KrM+#OAJf zB0~^8Cn#eP{mBF;@E07*Z(pFeVEjW#?om)Sh)2C)EfTcY;0rCzYvX@SssPQ6o1Dmx zcPTgwB@~AdN?BKtzl#dCRbF(^bmW=;i8-osncgCFq~Xb&B~yjhQ|7 z$?twtoD;_d$MX~DBk54{76_f;Gtq-jd6>Nvj7A`puSuOiEo`IyoH^NiRSa!+fv;Z& zl9QUgN;1;=2cyDP*f4)T4QoeIBamlI`Z~9^AXrOg9dl0-|7ut$Q@x3F)Dw%><$YC< zq5f!3WpiExLrW?Ure^$a*sZz_3~Ek3*f6S@H-ns~umL(`Q9HC70L(AIA&v>Lh^*Z+ z>23wP2Ua6{WzbBqr*kB=6vXtJtP?06fT<%tH0G(}9Z#3;f$V>K|B)sCQ3X>|QfJ@^ zb?d}hX23@cauGPt6uI;1gXvB2;lW=BtMjbB7YPKY`Fu}pu$vtbt;b~`K!Di=wi!a^ zZz%4=!{l1@I9j*k-(%ic2a`wi?^S#~r-n4gNY@GRvm}7cHr;5G7De#DrG97DV9`w{ zGiQ!dmzc0_i(P*_YPw|o0`R=e!4b8uIG8>k?PsMjg#fvTJexdpIbPB(O5n=(Q`%8C zj8cEPgdgN#&GCj0nw#P41%s*#q|Z2glBp^+y<FE!ivOmWVjCFkN+ByFH_d;_RrvjF7QS}q?lTOZyIkt#wegp3^w5(3C>h&ODCTWbe zuDe#wP$P~dvqJgW>{Rp7NhoZ5RbLNo^KFyTksBW7u^~)V2uygh4?1Opi-o$6LB*`n z&q#lfphg~xp=rzk4%_sfG=9Sz4gY7J?|kjqVtar-rp!pKGSh>2Nuu*J|3GjwC$u7y zBz%CHT8rL`-XT&Y!@2HR39>>uKN-q`Q!P;>Op3A}#LTTx9SIg8W{NRQcjfXJLvQX$ zNF_#@&4MWrC@d zNG$h>nA5hi42w~{Z8R_a3^U-Jwh>_U?0*rscAk?$c@aiAtphTdF0>zkXd=K zOfq~EyNlWXT;H+#rOi2DFs%<}DI7Ee_YX7p5FJEtunZYayyDcWi{EhZmW;kCy6qrGT3VG%1i#K|(zdLJIS3Y`g1;44v09d*GOAo3%x zsgw{xfHz+WdkkkaPE?ex(yTsc#?gBKHZJcKK%=;M@yYZF7wQB;o}{-tbesq0+e zvjP=I<({h=!Lyz?fD?A3jvqR^WGi(iXKb9o^sl-MK%117Hjl)++FnUlGAqDKM%Q z*5g|S)mzs@WECH$25k^DC9M=i(o=r8abBNaU4OV8k()Zddv^m@RnJdO6)`E#SdIoo z8W<|MJq1yCnTI2W!X6`oKBe$TYi~sN`AMo2vP<$SOZlK|vN7vzoKB>Fz^a+TmZcG4 zjQ9(lWVGc-GK;dnqq1e`)IF|-GNpOj@xNBh<8|H^|23#kb`U*ts{=F$@aw?JD^_$R zB-vQQkzm%UWS!Ef5#1C#{Rbrn^Xl;3Nh$}Pnb)D@5@@_Bm~hAdA+HZwXqPprM=Y}|Y;LrrQ? zi8h@5m4J*W7&PXbb%BvbSD-c?!4e? zT!156s~heS;zCm+>ZeH8m(odgj2kV@qH*I^Zl?qz?VNRy$px;1qY!CEq^KKEfh> zSA6z-g*~1ht{(<+X(K^K@g7LG$0MugPjHja#G6K?2|4M-cuPoR3+$PgOfVqSnZ!6K zme6QnY7Y-EkuCOrT_uBD)~r=2;Zef2a@<)I8J9^1F5TQ)n40H@lOQ8XL|!~yIzCiC z7ZB6>b}4GNH$c=NS&R2oiSQlwyY+!B8Ro2zELPWJm#8>r$bSr@7^_=FYIx*-S%gXP zx0}S}_U;PU)ba4BA+{yuL0DES?XFT}EjtS+7i<&L-@oFXI#w z9cxohR%o9rRT%J5HR+#wu6lxhnnP%UK4QmFt{DJ$AGGQdcvgmJ$J!3lmF?-Apwv#W zt)8k^H?QBBj7U~sg5pd%DF!5HI>#L)tS~`hFSjwey?u8pMK4vEgKAJpd0I|XT2jyf z-p-R7WXfZIyk$K%0`%Ryxw;uSqu)k1_ZnZXhg?O9aIGjl3ZxA%HI}aef~-?Tjv$Km zP5jqf4~<=wL>MFC10xKtsObdu1NV7IS~96v=u*PEK3I-r%Ez#Nn*BDzR@s&RU0Xeg zt1C&2au3uly4mCdIatnY23Z;mec4Ef5R(-r@b)2pDjg z_wHw$AQzPho;ucO1zZ9(@_vXGF!=>?=+=d~#Wc}L6qC;_qR@k4-nH|+y)fU9T(Lo@ zZ=>&?oV$hU0Wl^p=(z%`w$xX8VIGyEr)rfro+W2UbJDK`#aApnl-zszXJ}e=5vt8# zzB+z?IE@rx(8(031|jtcNvH07p@9XcX`}fFU<`8CVL9e4Xziw?rJ?ofYDlIB>4FWS z+)!MK%Qu$33(s}}1Lp(v;f{^flAIaE*g2c(W(XfxCfMoOi^*$hDu8Z~kz$sK(uE8Z z-GE7Zxf>?_KaBvMT%MHTqIZ~CE|6S6E^Y3Ahiv?7-gszeHMM~AMhfoVyVA=`yuW%s zx&~+Z#re$z{MVa9bf{ZN7B~zy{6V^!s~=x$&Sul3oEFql>~+Mk+q}ZsL~UDN!(gF? zp;w|?SE3I!t-DvN)zoV1TJ=5jLjsk0<|b&2afs$_{26Xlu2< z<`(}Qjq@&sm&Y{Jv^Uv$ldU(|UPvT_XR|Tc+gof0W3lC(RC|N%#TPF~D@eT^+1rr^ zYDX6H#QYdfV5|^M49(6d5qHkq4aqZqj-6uJ=NN5APs61&99VDM0XmHWBM@&(8Ums^t5z_vsTk*~NOz zPoD;0!cYCjjJ9zM>8HRG1<~38EeV4`H8n@x*mweSZ2dHW;j96k6XlJiR7TUCZHMb; zaB}+T6P*i*$yTuW`tVYlt{0_$wP`EQ#E`vQHn9PX2_|DqFyTR6TltLW1P>pF1DLWq zVWTQ#w*B-eCzPvvnIT)gIMFHkZj1>$_&YWuD8COsp_^cjVpe9OHT*f;pFX|M$%LHm zj-WV8hBxo-oxA(<+xyWaK_&qx#X~{|c!}H~iO?LHYvn_O!YKSc%;YYAbo7NBFm!`r z!*{Vyj0Q!~zj42~Mf#WVZq$66VvjRRD3Aw*}WUi9BriuHG++nh@^c zf_OZbSFA4E(rN{|)3y++mf1=sqrAx`Gc&11^fz4OCbr4=4r8%@J$I_i#W@rEzD)2U zHIvZoXB&t+w{yzwwL+N*CaOi?{|O^boptrT1Lt-K66!Aqg+o^8 zZ7ud5t{-0EY8~Up+?lw}?ve&ONrAwWKwe2vv>)#z6DSI^UR;j@?_y4#;&(yHQ~AH<_*v|OUb9A zgn6TZc5s}?c%tc|o{zoWYu;$ONrybvj9e=`))ruY^jtiT!Xf#;54E46$uOAP(cOo) zBj@(RjdT6(jq`SNcX$3~)VmLQ|N6`EudnqUP5-(n!KhVaLP(ZFX#~4GI^<}OS2xc4 z+jnmWOSq#9;qLzY{=?nq?nRL1?H*{6XeIC#{E(QYqaj^H~EOs$mlQzBXe=uw`3xkrKXG^k7MwHuT;di#BwY`sl|CssjF z{}R;Elf^royI&+&TxFHjUEY(*xVIFf?>R+>t5%r=YhEDSS{z5br7IN}X{6ezv>Viw z_>WK*4mBRww843k9ng|3B2n~~cAPL)H(C8cAO-pi`Hx`~WAj#u3wcyDJ5{0pBkv-A z(PY?P3Jh`}+LLf!fEcn7J2M@WIM74m0~lTmi&A-(Dr`d6W*2Zag|{oSipG9v)|pI$rXo`u&z?p%+kI0+3e(#?~kO5H$M4lp>-# zpUQLjs|w^C+YsD zjBTB^o`+8BB4V538925^LWv0%c7wq2S5&+Kf{Ndyv_#4)0Id&>Rz4+_liXeWI=cLD zU7yczD&0q}xDYNUZA}+h3(+x&qj05C?GY;_g7EZ$$r~pTzbj1>Q%qkw zhGRFdDsRUs9vH&g3Ao9Zoj7t8I93vVzDlMOe3fnt$=AaK+QVXjL!C^5r8^IFxRyJ` zj+f0BI$1zcQk^4XiTU7WLF!C@gXozM#xhV*p2@J&S3Dx^hR2igtrDG;%;d?%$(}p&$rRDoD@!rVzDNYAg-LP9+ zoj=*IY&T)NDG zd2?To$81}a}|urel208 zi;#s#lvT1d#8yE`0@{aUHxg)m*PxSSsrGH#LhvMuW9VpS!K+z8z4mJpE77K8UMG+Y z7V_MGHgf%HVda}DdU=q4(%83gG9&-F=b7>uGl_DdT+C#dheVTvq$N98TGnyWxQb;taCs$|Yw<&p*wk;kyqD*H7TqQ z){4?e{W;NT-5RG7|F~s=!(T_{Mbzj}3|P&$nz^RH-(8i6Io^$b7D^m>zBk$MU@0=7 zrrk{3M5imDmg=q}Pt9W^N`+tzN#tzdLHGVfgt8$DpZ%2fzvUTpClV3z#-!1y?x8$= zF~ogf>e!X%?0jsia`w|kS(-^2x}2x2*(7wO5MZNe=pD&E*YZMI%{`ZKU>;oNdGF!u zJ)FIVQ!{hVtjIurg0V`?>J_`g1RS!OQng!$DKTtel`f=(?} zAotm74f=BIOf9%#efS^!CmbS%H#Bn-P3Co^;y8T!Qrgu$@)81tM7QMJvoM4+ln33@z!~AW3Dj1<@K|q?bN%__TfU?ksEfFlufic z=p?#*J!G4%69AY%XTQCdyH}Ts1j$+|LEgRKY8OlhcHw`eu{*&YC)q^osnP0W(`?q0 zQWpUGIX?|_JQB}PQ^bo&KGqRpMy8Ka;|XG$a#oZgwtq}9e}<;lNKBW2sKJuj!10|- zE1-ww(Ja+4s|$VZ9jQ8grK}Onln<>zDitj#3g0jtQRhC9RiSmiq`Q8vy*q`i6fAe1 z6RVXPeRs?y6lWz_jxM*v7OT^5@?cHvvXF*o6ew#xoxJ5Na{W=^HYLAI1n;4j550V7 zOg>o3Z*DQEe_7LR)p0G_>@lyCXRXaMI@sX6=TJR|($iqgU#|E8nz9!=4$q#$^c<$= zFs*Z#Hlh_an2bmCq&+j4-VT)X`kfv4o3KM`t(pcBEld&m7M(1jB=HGXLr_O1U%y8`Eq$6WwmwBfNUI7W0*ry320TP$|rwKoQ ze^vi#?vvmBr~|A!O*xZQj9~rVHmvpHrXJRf-AwAYWKxkgAFV7Op&mbt4^1guU!c*qB-QtAqrdD1lpHqLpp{?N6uM*Q*K^qyhl<|!)BAq9>HBHh z6LWS1{)b-G*HiTc!m$B`oiBncYu(L%Ifq0gkCw95#Y*NR#*i@~{QJTJEUYj=%dySlfo}ajH`$~ne9E@2cquxqKhZ{(L7ZdaQ zXMcems3{hYXm2-p(N0EgT};8sYcQK@(I5z-RyYgX+$Gx};_h)TKF;>~f`jNWaTabm zbEc5gou9SULZt$~&8ch#3DCS{JK?m{?H9MY_>SK7zFx(24%l@tG>>$guH@oV)t0lY zZBjHq+!sHUz+1D{AO14I)QD(*yP*?&^`5t7&DSvb)h}*>M+M*^HrnOZ{4`)JWJtg?j9afw&+xAofrcA{WK@F$>%n744UoH>wGJ0h5=t zstGzP!5rcsdL&p6lWcB;?-49^9X(#;OEq>BBTTFGGyR2FeN#UOHcp~HO6hHv8mkE$ zASdNR&eo5e)`+8u4_ZZC+W{#*aqwb>$;)+v#tV%>x~6Y_y4tl)tc3iN|7}pm~<@p?3z`iQ~wnXWI_q zyum4rV-|DW^U3wmv=rS;hUjXF%4CRK^5K8^_TT>fKT@=aqbJ|P-T;yJBWDtYX&eP+&fR)e!*?j?77s;> zl*l3Ww4H?;yL0{cFP|-miNCyzfcSZhwx(Lci)B+RO{9^T9BEsY@T+etzTTEHr4d5o zd97HErGw+RP8qAm1QkX1afU68&a%>axgfF6{-PApbYOqRYm}wDgC1fN<~$pVh^1V$ zAFKq$EXJ;vpy#L%P|vZS;&Pfo76v#;K)@}@*C$a1IX#H1PLVW3_cK31ej*1#zCZHe zH&I3ad7j}Iqh}&LS0IEKL|lZ(<1Yh3enMF|@(VdfB`YGlqeImOsg9mEuVkGTKQWFcygC|2=Qbrf6L8pHrYXF zgOD7mXttT)|KimU1M7q*9*>2!X;Gxjx7X~8YxAiUdmh^q=a(w>H6Dcw3D_9$yASeS z6l5UYU0f`tN>eYeKEdFg6|c)upSPYUkDn;buG%VH+8kLpi?YCj&`iwO|6@$FB9@BH ze93x-NkXg0xV>W7be$^t13Db?xzP~GH`EL4H^ z{U=rEbgmm{T5}E5rxDWfL(1rqA6XNG^1)F4A(^UkD_18NDkol!&ZfTUkc?d`7) zAw8X2EAzYdeO2M=XT@t$!P?!$ucONk*CXTfK-OkY_u{$qqeun%mtPc5SeVR?g9Etx z(aqhv+y3U^=4q1b3%U365BKk!x99hx+pF{ItN+u#eYo}Q+-WPckXV>G>iTsvuxNje zC~<$Nnxng*WQefxAp}KylG1#Wg6vpsWc62J@YrAVMUoOaC0*jH2rvV|95P)TGDjVA z%B9(M<<&IwcYWpCR=%J;$g41_mNCe=8vE`fKm3D`w}Znc=gDm#UyT>Rj3zW6$_d>$ z?o?Vz7n=n)IVT!V2vNR>wp68Csu}BpPr36*pH+6yxhQaza99 zrh3idMuX7xk(l%ToYL#Eie!I=kUElSy~1my%-0AYDgNDjXR#{PtJ0`QIJaD?0MxTi zi=huiT^3^SAo_d;Xo}Ox3^BDCMdJkePSb*|4XxRvcNrCHA^xIlCytqE6t~zTiDJVk zp+UzRR>`g#&vT!H3-w2<(-QN8)UP=(&6(yuEJ0kw^l6ndIIO&_FiL;Q?%L<-X?r|z_P?xo(%R7(Z0}xri&5$$2eI; zAuVpkKKWd{^^{RX&*s|QOVkZ>mFNPrze!5Vwy7KrqwxDM3xaK~Fo3FVDA4vW`C0gg zpt>HpW}73I94*g{`y+oNtcY)dcDzxS>Nk>vS$?h*i- z%!U;tS*;0f;YHoz86iBS9E+*NVNNJ3xA#g6dz&9ho4@#|H-Kl$i{&`G43oP1JQo+ z!dJdNtvcT;avo4cH2iSF_}4?%I`ydp?b-}3S#RoBbkU=Y{RoMooJ64$kViE~_)U%F z8%+^*iD8_#04#sn`^j|NqqLZm)kw~V&*R7BOlH;9%9P5{NkOw8i_3gCJwx}iLY<}` zBBsLBCwg_w838G>Tf_f~Cl0uiJYIeW(kIMmdUdD)D(LMaAs#{_=$!UMgdfGr-14Ay z65MCijWK+v91~DCq^P9xH50N6F@naJnrKBS55w}z1*dug%i&AK>!)u$OK`i72I#WYXWFWV zwyvRj>N+61aabBZqDIB|3k;UdlkC=OIgneiaoH+FSxqjoq6Pa{(FL`<3o(WS94M=Y=Bs}WyGKe|&H59#`^tC_%BAldi`JUE zp&sBp=gG=I!qH4WguZevb1CDDYN&5F#j{>T`1Ydj){aR#3tm8gW&|db%%Ts%JU{#H z0q{W5whnNah_H4jk7ThqVSRadSxpSLLD~SYM*BO@l8vk6;EwF>&s}sn=A_)2vR*| zN$XV2{DHbehq`UF^dG6~7t}G|-Hq-`h0N#oSMP2#)+rxCJOv3YfimB8miKL256hoP!uDf4JDr?w2v;dx&5A7FUppCjlV1l^$IR-Kiq#@ zkM8aq@~3lkX{^+XPsImE%49iFa3t37comqWmZ(P(53Ynf8h`3fs6$q3-qsE$Hv{XB zXk1^|FGorL{q7g%=KSr*h?X`Ion$P&viDIpiHC7Pnm+3!*`nkw*mrNwN)J-u!n|Xk z3fxG|)mWC%hQHuRmhP19Ygb%W9n^oAdn2P>dkFgr*3kb$Ew473BAH;;Dk@9zS zh_>d%O`>q>o6z#*`J21@(XDgw?&kH?8|UxmZ?B!#SJxvcLxE#w77%|r8xR_uJi)Pt z6N9r}P*5_OgM0x$mkMiDjcJ4bX1O^ud1MjMbOxQJo@aiF1E0uJ=m58I#0q*9uA;i9+9MuT^F zx3Q32NGH*Jk)@a#VskenKZ=bQI$iBLdVIUFmR*>wwW=z5Z#9YFIEqZhRa{3CH#m<| zf9g)sM&ZoD!~%nA62yWv8N*rdr)^-X1w7yQEc@%$K1$fAEst*Lhj?#jeN(XwZP zyi8F#tX31(g`3VazV=7thqkXnoW7XTtU^zBb<%^()}H2ink#5-<^$C&jZ<%%CEAtr z?n$>NUE8D!9I@l{UuZEs_4m}jHJ&SJl=3DeZ=1tBW}aR;8e7Sk`Z(}(3RpC|PKXFi z)4~6s-#$alfoXsG5Y%=%ktjqeJHeIW+G*_I0MDDE9r2T4Q9IFl85}hZ=#OlmpcIo) z!GM>|7dofcM0m7F9q8M!Z>-a0WYNx<12qkzXD3OQfocw!L}S-e*_QWKMTrx|#mF#8 zwp4pd{QSYgku99>Q9{(4k!1j_=zba)`JgPi9%`bKdzpXLpaH&#pqCciwzWC_i>t?t z1Q|b^8q7zN0Ht=8!Zwni25oW3dBzuGwj>sW(7TnNCgGe28B& zzjUyyW@bqm%{SCc)y7b*9lK@Eg0RCy1@44G$+%cfBW-o7y^JYm&-18zmaf9mlfyV= zdu+HFF(QA=I<1Gl#iO4IUWe2ZJJa*v)$IvMWTyM>K?mU$^Bv1^RWL<&GQD!EIZcoH`e3tT5&gBivA=+t3)m^qv~dkQ zp5EVtAcC!T5t=6QB1+Q7cq?kY7bCf}P$`zCMlF9W2jQ$3+Lbq;Wrj5y4QoT^FpbXF z%m<@!Zk5urWBy{AJH zI^2J%t~ydWG_qXg%jBOyZ?^2qY}rMBZ?klj(aGG^9t@VZ%e()%?yZ&HS~)1J;pGg2N~DQQ zTlg>E{@cI*M@rX5i62fdnP`96p3hgHp_F|mP&}=&{24|=B5tq%3uDzS?Qo>( zT`d<-+NlFMg2GfjYPuZ07d`F2)Wv^B$wRHrV}-?9{IiR^f_j6f#MtiF_ z*5$bGelAVV@N3}GbX#9{Fi88|W58D--e+x8e&f{roJ(Q}W~0%suvx<1TzJnk292u&0p7$!}|> za&2z)5xzvgb$5DPgdX|ze{n}Z?UD-p?;0$E055H>-IhgST%4$BTAXdEEF*RcxhJc%4L5vc-Z1D z8wqOGDCy;wk-iBfe@{3ait!@G31QtXU<;(Si_R9yGrGpvr!5iwX;?c|%w zf|6O31s)2c6fu5~`b5|g8BRnm{R(0c@?bfvIofK$-4h7?Kec^Vr*nwXJ4B^%9Bo^C zyr6!AMBD5J8sk{YwtG|R0k~rUcLS_VtG3(S8V8c0n{7+=e>hIHVSOI{kqV3Q06GrK z*pdVNu;Kw<;-Pi09T>)^4)|F0*2F=y=+#fi(v*vb*2B1U1SyP8c^P<;D)UjCCqYG4 zw!pDsmY%duU2!EcA-Yq=v?EPJ!HTh9$6yeYEo*kS1$OK#+}NEPC$Q^ULETAB)^=TFMq^hr#lkG0olJocVDiFHysXB*8_E6B|C`rIRif zs_E?F9svWhTCD?qhL-eJdl>|+JVHrl+QHnUdERY9fB6ut>a0g}p=zE{c@6fUEJ`&u z>cQNthI?3}`fYQ0ixuvsfl<@Peh_cmZh40F6q^PTyHy<3hr@;yJnu3Ju*D=H%Pd&6 zR*6-tB#?YFnd5X8d4i&RnSsKNa5k<%>xnbn24dQ?XODVXuS_3>q7eB|i+r`)sx{kE zt#7Axf8ZTw^s0FaV0WfZ9@LvMYo^vhBelMXTK~qJgRY!6YoFFa>$JXY+L1pn-6Wj) z?o5gq6Z$v0uMWOZl-lohcn!!o&vDZ?J3QnzOP13e{?nz|N5S~TGFb>yE~j0C<(E?h`My~ zJPPkD@6+5%``Q?FY~}GC42`J4EeNK&K9rpZbA7#rUC8AlZ!t(W@(aUZV)U{f}ygX{(3VaixzRTz;U`n?l^kF3VSCo zPW;JDQ51OOS3VBY1i_lno(P%{vG6AHqGDiE8ZS{A(a)f~{UBR`K(&+=tn{=o@ZE;o1gqg&_V-OcN(H_qSB-(EYf zudYWo=Wjj{SAx**0!?*T^aAV&4^)g~AD+0gsm@!wDh*CznXW3AF)7m;S>E zyaC0RyTl1iAF^476-2!RreOzB$Hq47B*AxuYpAu#ec6n|7Oq|bmnX#uT7SW!faFTHz{hCwzmp=IC3 zgNi!%RXae{P%dfH4|cCHPKD+lwjN?rNf7d|J=j%G>L$#+h!jVKmN@ODI4S^TDaDaL zz{A9jQJ4yH2ziupO<sd>N-y?%k-bX+KGqLB|Od ze=m)<%5NdoJuabZJez=_YH!Q&apfX*r7iaeADVlG zw13qmf^}Zw=5hA=4iEC-RpL)cIjB>mEu)g3GbA(z8s-!wx9d@Hi`y*RJEtJHO(?rC zU=!8 z0X-l-N(CU^gXk}|9&V%7MDFkRf5l1Wm~~Zz$DQ$?N|fPu(1Tja!#g%Fs(hVs1FT{T zw-%hK7dtoAeTS-avS3%De{vf z!wGtx;Sj-rVds2u4J;gmC<+Ml2+E$xwbD<nKbmt*}VIH)hug?_Rbh)18m~$1KVc z#8#%CkRDV{OUq~(5^Vvoi2N{>5V)fH4kQ1xdM%xu*3AcVD1{!&Hm2+}#Uq6{c?qmi zG^x6Mj``MIEQq3{$TY(-O>m8M%4W{PWjj2zDP79$>&}NLugieCfASuco*=C+`)d6D z#Lp^?bV_LZ7t~7V%W)I_6Pa{Q5yK^)gs3E-@h54Z&)*;)LB4=1_-@x&d@gw z6YR;W+`4^5t=m@x?Y@ff6u!G~;j0Px#>cl=^8v7kx|DM4$=d&$5ECJXX!kE?A!XZ77E9Tr9f?Hij$Ol{;zM`z#Y5r6(_g9 zVU-_;KMa3>eRh6J7}GR@ll(Y9KahW5^Ks-Y;afk=e*Dk7DkzI5?DpuW+G==KApG=- zeCH=ZWGi}{`H!;zY9I++{sc5gXfdbFsv!iIUCRk90;<}Vi^~ZoF7YHaODH)Yi-%}l z9e1_4k`ZWG>IcaXhffAzk#GBP6j}r)jw2HnZIU+#qib=2-a#02$*b3iM#Vk28JPL5CoZGH#P%yA98&0j*>5qhVUUT$yY<$o^!`y$3fy-$#f7NB+~(7hL(EtY5WduN~izk(%h zLH7x{Pp%(;s6o$uI`c!aM9uZy;bvs`~euAO}4zV{t{uG4~`czQm zCq!&KViczAQ{Pqal2{l9$sZ~y)u>;Qxf4$&1` z?eKqJp1--fAKf~?zI!|RgmMK1`njMdm*@uUvgnybTjavSBiBQKA~+&foRm;^QlM(} zlLc9U;E)gk0c?F=r=pz%NPl0^#27<37qBWpSLg9#awgijbWZXDP73DrF&AJT2}c?r zB3m9FPNmj@|6QzN*o!!NA`8QR7BU^3>!ndZs_mVW_x5!#}ZxI$@8 zKC*kPsEpyfg3fZ@GejR2^kdS`zxZFV&?JZwLPpj2+Qt!z@%K5B;p0*4KlJjwO>WH%~cBmjrVi=N3_o|1?7?8ct(;&z3!APfca z*Tffd!pZA*6OO&fT~)>nT^H7%9n`{zV>?P~siKhh)Vf7U8WEDk7F>4qjaHP!lROvV`S*m83+jk^$N%H-vXh_WO+S z0%3PDLnT97u&tj&0X@kpmZgSbmwKT?&!>)aklREZEoYe#Mgu7EBbJ$#&)pzQMKbj) znPs#aXU<3n?0*T-PiS6Uwm`WUONb_kQh$z5B_=SeoDADO0yXmAb>Qg5V)+vQjYq|t zsZNt9?SVs((w^Q95`&AsY79nGnBHP?ba>O$3&mRVtsb-!g$|G;P@@4}xK4_%vI#BH zAFOAlf;S*)v@7v-QPli&(8^d-Wv`UDy?7hqPiorqhJP=FDdJ)zRo2#S}b#pkr$&KT)DVatn6_iptmi zi2P7fKQknQ!tVxVzx43BdS0$S+!=>N-qiW?>+`ltn`i0t{}CNQ&jOix#yqSP?o=TR zFPkq+x_|hKgEIrIV~eMBJJTR~c9L`%sHWmes58cVLDCP-znnb5StHR>>hWq4t1oiw z%MLh5~i7pXB|n`tm=?N&YVrZm3z9QzUlEs7Jf@4>i@T_2p5 zqXG}vK zEPq^6;jka9yo2KXz}Ze+goHE3)H4S$fOt-0AuxvtGp9V;5S)!kHeS0LX)K6*&r8Hx zQMV-X9FECS6Ih}s7$qQ}nV-;b!{skSZpM1P+#PjC7PZ?ds-@4kB;JlYjN@ zvqgZL%gAm!o%*f2{MCKJh1&5uc0b3QNn@Pz-8&7WX47M`{0Di}h~tKYueK#V)oofvT}m?uoFyFev4$;}GqKrkemD!Iw_0 zritcBG8IXmpeq+rHCJHSU*T;a$Y>jKGFs}gkaypgj%ihXSk?QiD5k}9=aLhELu8`n z6K$2T{}GK@vxp6ze8A0_>cvCHifKh}KxEuh-J34Yy2VL0$4AVwVtT-yXMeTBvuXy; zvpdKgS07W;=5)Iy7GW3O$+bg_=8wv7{tK9dMEg{U8rh@3*z4Q9rhnq{24OfduZTb5A>Uw0fA6r3cv%3!$7o)p7 zlil(qq_+ET^S7IKzu%Z_mwzv@BWHCe`C^7ApNSCt6}v$?1HC0U1Z{-@3c12An!pjL zbNiV-OJ_#UqOF)D{AbM(q!nzTZj*WPcw8l;wFR=V8zw#u)3%RWDhO`#yd^sHz2my# zn$XUb2l36Rk7HKT0EL>VKgojspS?F>ZrsSyMgK~UJKhb^L$mCj`+si4XzYF?t7Ka} zwcV0zPe+Xc1c{`WE)Za2k&4|>|NZ63On?9hUO~cw=N*fJrdn)Q%_{Z5nWvc)vGez&HC^3}p1D;j%0FZ^dF>ZZF>7Qmb`3<+)80bX$M`jBEWv zIk8T!P&v)Ie1C{P(k0_5SkTxk&uT;Bf1fRrIKN*utjhM%!m4N<8g0-8_@^klKHI%+ zqjLlq9srO4M~vmIuodKELf^nyN;Wkgu2ESw&%UA!RyKqm+7w_Cs_mxi9J3FqV}h8Z zNp-u#W6IllToNck6`5y1E+9q_Xx$i7ldx+MFEaEpJb$Ew2eZV&9#QGJ4(hYiKI>Yj z-xh1muzPq0q~<++&(!o3u~H6@ZE)~J6YTK$A>>eQP`R(cr2HrY=$SI^FGru)YnD7< zcG2KZY0gqE7db$lYSR`208gqJK46=Gl_d5&jC^Bh_6ZY=%v8jF-) z*x8*YgMXeQovmXnvxL_SRu1Ls$w7A9qOi|NT0vz#eaNiD)ixrf@99{9dG~MM9yq7G zd1uyJJFI_ZseBD-KB?E@Q#~g4%b@Sa?@KH=nCdDIDpst`3q4Wb)0n%4_Ua04FZED+ zEZ0gpiT!sOcr}WMX!-dnHAcJrVJ0E6>(v^-Ie(~*8(dXjZSC+us%3Rx71hpb5M$28 zB@Qn8+f^J9j!-p0@92}00*qD4l0c|UN>%s`edxBRQ(DKk3-W?{oK??ffM@x=Uj1F$ zsE+isj%D>J^DqxE!+-Fp`IRtg`sWZ#sbM$D572Pw6Ur#cc^Be)$P}0IP2c8hou2X5 zXMcRVNJso~_qdb&IEl6MArGl&ANe~CO9-YQ6nrw^M~>VkDUWXLuKwna8D8ni|5T9> zMOGmzE&bN~#qWl&rdW*^toqH3vF5-fezi(ER^C?tj8v;K4_M*XG@M~rV8Gaa(q(U! z#3$X6mzarhKh2yc{q5hpIA%mEbNH zJFJ}Qr;bH?fC4lTBzq}scjY_G>DLq|9OC{J$E{6Af>yOAx}ryZzSe| zU;gZm^_t~Dyq|m$s`LoW2Khn<_#KZQ=(Z`d*j=}1r*z!<3~A>VNJQR#uFCT+ZGWu| zF!S$SB=pbk-(7mwZ+?2~-Cq2B6m_>;qT~tqr!J+0+ERG80_X{Q)eN-`rdEhgNd}eO zJYQDHe~*=r>iEl^d*oPi93J3aPv&7ITiRi8Khwr8t8F!v2$bk789wJZH0*C6%dW_}ig*q0^g(IN+ip-J@hAMLgDgs+WM`YTRU+CvOncbx z7Kcao^+B8oVZi0CfJA%k6+PNdt!(+n`l8zCfi=5P@<5n+8P4q;zXMag_7;P`kqOmK z1eWX=$x&$APfq* zbQV&34YsDZ5+XoLSr%41x5EpQTXmm|9TD)fy7;fISm6`C`ozufzs55td9m4yo6JwZ zrmiL9Nwi%zoLoN$*oCS%PVEBxvcoGMf}&bu+%Zd7o1fR{zEwkLMt@K)X&hNnilm*; z5V&!(>Fq$PgjmLDW>27`l2Y;|guZR4*3`6N?cZ1~6G)mvEmK9xH7t|Gj8#tY&W39` zC@nELAnUiZkpfdafzB zEesn}-9AU;K8h2J(4WxRI!;ppH5gGG;gR7=NHoY^R>4ML)nMFhL-$Y{>6XerD>;!s zikywcJ;1D^fCE)UU z9Mz|8SSACcT)wI|s89;qk^~h>q3lSQ!tBaNSWP81>4*8n*M8!!EFAKQxsSG9&0_Cd zHYg>wqY_s?m4Eh|s}F7N@L)QmL+ie?Rgd{z0u@T|-*b{Ml$uSrGLS$S*g@KN0)vSY9U6 zxdf6Mt1so0n;clpucm2gzNzlJteG>bIDnl5!h6U|lt$4lquzSeeI}2CHa4Wy z^LjG7%dzV)k<&1;Jlw-A_sF@L#vVM0l}je5OF1r`&I36dw&9VaQ}kNb(Y0OTazU1U z>S^Z>DSr(U3n-QDZ14W0zlIl@p6b~~cCgRfFMltt-`0hOPvgY=%~NQ5ska~zNtZY{ zqT|+HcB!y%>=vQYot->r%KTl{*H0LVxY4*dX@ZjxOj_c?&?+<$J?_)hDv%T9{yNwv2cTa$(4k(Awo z*zZP}C01z%CnXs;M>>10j3w>)x8~Cw>FhOf54GoB&;QY$z7hfM?D&>VFMVsQi2>In z9LED-YaSyC{WD2?zXYv6yefD<1ciZBDfezm+WGIcu2W#yatPz;Bmqeyd9(qQNb1da zd4D=aZxe{*$?82>y@x$-hdMXhI$%d<&IG2cxY8~QK{H+@aq;za-@5g~T6m5-PlwPe zx;sqJM(ZGQ5-*RDcy*FBElc)mSFWp!!4U&<&tgQ63xeZ<_%g$fQXB=Sa%5P-1yxw+ z-%X5zfbEmeA^iTqDMd&%3Ter3d-t}d>3@L(WUxO<5HiNb=_$i04@XnOU|qhz9|W%? z;j@s3hU&bPU{xM|sYD)Gn-DHRRFyZmkL=*SGu*U+H06_EDF_;aKN~c)+IEvwUeqpf z{htFfRr@7Y@=IwtKCTxWq>oygMRLy!;|Ku=6PLFE@-yUz;TVAWsPIF7?g1JFP4FxFjLAEf_u5e1!dZ zMjo&=kXaSlMn_?+y?Uw-U=bDyD|_3TN!YT(Tp^uFv|T^b(xNZMiPOFWY+JVs#DmGR zC$M~Oo+hKHZGnOJ8n0$JxnPg}U4IY7UQH2UL!}j>Q6aXm5gJ9KQQ6fGIxmf`>^6KF z&2@X7rxWVPesJgb)S8)sy65WC9Iq|Rzto3kMde+&r85Z-5N|*FR1b^pS!gO-QY)Az zU1u@kH|V?tQJ1vBYiJ%W*22FepH)LOvIOk4rhk>ft=2RmWp~?-jI4_gw)0`Am;$X;3R${7Rh7AjDHVbA`z8-kzhKb z0L?aNO}m2j+E|K;^ga4cz$-=D^iwpY(l_y^WxH%d92$9oZkHH+#G4ew3&ehpjt2|Q z({vpIOR2~gqpi|`WZ?!;5FOv+`Rpdp^_9pMQjz`ry$A3jj0j z6n~b|-(hP;`_3N01u9|$O02x#8p$B2!Ft~0E4 z9ML6Z8IdqD)?2ppGYBv6F`T2b??$REpH^?x^gqzqpXn#ngMR?CPE&fw>6BLD!Xai2 zFtTP*_7A@Xf2bI*mx8B9=?Ry&>pQbva* zI+plI>1hD5*Zl#IJj-TxYcz5??&)(r?vh28PxQRYi!clVSu>T=ksn^`4RSm55Qaa= zc*FW6CwV^OtA6aVRC1~sTl?|i_VO3+_0{dg%ZuBKBY#nXycyVXUZGp|q!aD*a#E3+ zUWS@g{bckdlTjbN@?>&Fd(fp!uSpyI`4_EVwI4_sv-_8+Z<(C;BT~Ok&&ijljTs4N zedX+U6f!u^-78?HThj7clsyfha~*+-<9>6DwVE$alTpt2yqn{B(q&8!w#%k@kZ`Nl;OXagqoi2?hGT@Y`D6rvQ<5V3AIL?31ZEcTEJL;1b$_0sGYBwO{^B)HN}P_+w!ETs2#i}Z zD8uq7UE?`fkoh*w3t?Cc$p#SDWrhz+nT`{Hq@K1t6H`^kMH$9K^^5x(Cg*Tg*IAr9 zr07}Ff8QxI41k)iptC=jF>66a9-d|0b*gYty^nbFl(r{cKe-cC2*Ia2@I`dQV|RVo z>wgmd$vy1lgAU15@YXHzFx;YMQpHQPVLbp2hVu(%OAJqif7k(9(ESc14FUr%O{T1c?Ij zK!ThuRW*6*^fI4b=F`i3dYMlz^I^tbOMj6VaNu@1V@9*ljhziPIgF&=2Y;kY zXq+EcK@Sg#vf8NIx8BR^n|H4+{^s4>zTXx}wWCML%B_@prM%v?H%s$MH)7AEHh&l; z?sUAx738xp5A90e5uo&fl^GRlbZ!HEaF{J>7~*HeEEOJnECYP+d6&9b$HGW)IOT2d zOjSY#R*9xz>GglN+e>Jk&fTu6bweK*oAp!9#e-@rZ~J(eO-kb>>7OB|UDcNNww-^s znQKnH%0HH4zv>VMuSsCH+bSKW`+xme6XU?KN{G1+Mg9~ixw9m`fAx5s>v%3m@Uow9_a%DB-tNPjY11xcbg zuydP$F>;*zs~UdQTy$z$KL!|m=8mpG-rOT75$@HUey;RDm-pOEBXZNviNN*%)PUAIpfmyTM^I>yHAz~(1aCR|9Tb{Ethxtm}8fB#NtW0HZF5T7UF_XPf^X0B`??z7YQt*?3$fM@8Q)x;I1{MWV^7=q$eD zSgx_;sWV9^CM)LfX%s)&={mL@!e{?zTYqKwr+GH-l=vaR zR0o*bWI<&AkP>q@lO*XMFf;aw7z#;ziLE| z1dTOQZWIZS@{u$HmVY-rK)S<`r%K94qfWEb8HGAwSUw7@1d9gNTpxgf`K0;}}UWY`i6%?&= zCLz_tsRU#|-6=+N$WS2Xhv5c2#>q#Rqj-=~bVl3U09`3yqjNZR=!P&@@@nN+I!5eQ zQ?goz%38Sue}7Z`mLr%0x_N>44jIiw0Y30SOg^2B82o!mH-lH>6S^hK4eu2`rTc;t z;7d^!z_Z3-MM+f9x3cN--|V^uPU;d}a87dIi$M-H4^ORb0I%GilW;p-yf%cRJn*?$4c5?SGVY+sgp!humy@^>2F_-p+Zn z@(QPVY}z-NKdSkfm1R?Lk2vpG3B|%#Fo2i@m{Hh!*QOyUx}t3qoD=jBSmj|xP|0zI zaP&ZuID)qr9vRjt?W=eu1QSWUDqPxKKo;zA%0wqAf6%u-uDynIL~B2R9>Ph#CvOhS zk!(bsSbt)xZQf;vGZ_UNgsv}exCJl@05B30Z|<+DwuK(Mt?YT{Q^!&vF%=xb!+a5WIww+-(8(A z3tW0Py9ZgE@zLk8ex7@)<Df{PsHd?jjV_%m?vbO&^%(WsJmdd6l-zxG z=$^v^+9;TX?^JG5b606Wx>pb;-g8&z*$9FA4TIsrX!Dp;4q^V2v|#Hi7#_EDe=3(3 z{C`t=C&Ag4uKaXa1(EbTXwCDAJ}OSpJz~d+PIn9pbCE}!W^qC8scKDUkZ05&^Ep5# zM3w*oy_}F>#H^4Kf}MsQ!GN1-O>!QusOeRBc7?OGq?BZ)8TG z*>5AkUM~JpYqk=fqAc>b@L+6~g>cgTbGOcDLfGVzfd zgkVs&ddYOdk7nTRhd}_4KySYnyu>LK*hSq^|KZK9UMD5c&TADS-^iM_P4!{($#p** z)d_WSHhRM>-1RiIK9>195E(lqX$6mbiWGk)`X+|tBQ;y;ZzL$FBvt7o)(u7X)eV7; z%#OCa2dnhnGOeI`Gk zu?{f`smKmf?iX8cvSl0<{y?-OIPsJDaswHME5=|GAQ462`1L&RP{)4;o;r|n5QKmB z??L93PCJlzKlxP27z@JzY=Q)*;GtvgJiqYNp?i^l!mSFOe#?2XY;Kk(+L)D6S|TKR zh(FSK(oQ+U4y;e%v8=9$PVZH@PG?q5J`h|&{07mVbIeyhf0q5Y^w(<)WB~nmCuIt$ z++W~8pEXP>h#opZJtahitD*xNQRII}k!Vie>nLQIuVQCbK8Xavk4TuJCpiW72uSQ8 zen|d-1N}aDQ;kb9X_^>%@Dt+C;1(>CIKN+thyc$jIUDKs{D@J6c``HH=&dWAdG;AE z6*%;{x>BT4L4MYxZ$0~1Q-uzaV>0AofV9|>nwiOxAt?}DqrZ4XvXidUKa+oGH@ePG zAc>;QZXj?Bg(zilN^#h@GPCp_@V2mm{|h47#OiU)l8qAx(KZcMC&!%W@nhC1k>x8X+5IP<(XkRv!-XXr~#}A z75)C4mdq)-(~%!j9I07O74C0Hgj)07n{Tr;T)C`e_?d*)`b~*y7Be;&cMWI9D1#hK zs3>kfb?|Wfpu51vJzFf0H1W-19Q;cwTomQn8(x7t#mP5R(;*R++y8&rR-a;V4Z><| z)nKdS9GEa`s07e)A5XeT7*#tW23gi*uu zA2JKBW>0`uu9IAA7JD^ z_$1^W%ou^O>!)Zst>6z#rxWyR$^aMGWz&gEY<;ig7}BOe1cVAcYH3c;Z48UcbDgOL znr3vD%7BOnaVU9!1)hXQm9TVL0hOR;3H|-)fBq5ArYHbW>u2;x(EmJg>pKjKyys~a zd-T`NMpN)%EMtF`IpwQ*K3{Ln*$>aBKPUcr`4Th#0X-#Cjh(vP-I{2L6Oz#drz;ou z2`d7Az!8B0cQLG#N3VJ6HU6}Y)52MR(K{Y&D!x_?J|wfmPd024t2j8H@?h1uxG_^; zg3jsrI3p808E?@eFq*}|hQ+slt9h*6o+_%vKLb3=@5g`OYKdv1KI3QR|1w4l`FD)w zbQK8QoiSSYnIC?hPDh%{S-Cod_6e(c@$Q=LG~LWFWqAOij=4C3R3@+i;E6ggRG$e{ zAN;>#M3u48RIpF)o^uug3vh^8d`{F2u;V%{&Y7yu!mywl%c5u7+r+?7NG3Yd5e>gq zEtTzMD;xy5aPFyM zh#7coioX6Df|Yp$(Z;X8{$i0z3SE1tD1JQeqJmNjs6@*V&=l$MX} zZb&gaSnoODv)D3194oZToij<31-jVz@gfGa7jl1_LnQ8#7}^sJwBJ;@c|VUaz$!ja zeU6=bPk!akEPaNfUhyuP@2z33;}Xw5T67+-GcOf47ubOOm3z&)rWjJEYwWaSf4t&_ zoSX57zD1Ku8m!aVYJQVVA;p{8=wrBk5ZEIs>Z%_)s447EJIb$3`Tz&cbJNS_VS0jV z8xVi4?WyTNN~E{`m7wNLDBLRt)OT-HVb z>LwxSl4G;_Xm21KYR)gf4AOj-;^ct{)Hx8?6D#xqCt$z(+3KY>^#vwr=jwlJ z-N`%EnVYivb=Oljq{)S>CMXQcc%O(N2AKYyNIPKZ4b^VlZ=P-9p-rSjH@C|=myj;u zE6XF{w6EHvM`q{U9Dh^Sxopk%rZTh@9DmhrZ8NF!s2@T}T?kJHdO5e%+v)fzub(BG zo!k0VIvsZH7(AR7x~+H$ICo8n?*xCojcwV5C|?T50||0JWJErx=Gt4*MRm9NcFcd> z_3uK}*TX36SoPd}rg{&VR++6Vu5xBrVWlb(`9UA5+M=eQGu&_^*2A%Jkwt3hRx`)1 z?i9n?$X%kczDC+u;g%^8+WO$Q!+5@m;n6H3z#h)~#CdTly!>}~Ld51{YVN?1M z##1PP&nACoc-$bWQEzi}*vfw*L1uDK=%0AxVuCKVj3fRGI8Q{~B_qKk83R8T(C6io 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 z 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

PG0`n{Z6gLK4=m_9>h0EYT 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
05t!Xu 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%0AwtL}Op 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 z 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