create-dagster 1.12.16__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- create_dagster/__init__.py +5 -0
- create_dagster/cli/__init__.py +33 -0
- create_dagster/cli/scaffold.py +301 -0
- create_dagster/py.typed +1 -0
- create_dagster/scaffold.py +254 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/.dg/telemetry.yaml.jinja +1 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/.gitignore +203 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/README.md.jinja +61 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/pyproject.toml.jinja +26 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/__init__.py +0 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/definitions.py.jinja +8 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/defs/.gitkeep +0 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/defs/__init__.py +0 -0
- create_dagster/templates/PROJECT_NAME_PLACEHOLDER/tests/__init__.py +0 -0
- create_dagster/templates/WORKSPACE_NAME_PLACEHOLDER/deployments/local/pyproject.toml.jinja +10 -0
- create_dagster/templates/WORKSPACE_NAME_PLACEHOLDER/dg.toml.jinja +3 -0
- create_dagster/templates/WORKSPACE_NAME_PLACEHOLDER/projects/.gitkeep +0 -0
- create_dagster/version.py +1 -0
- create_dagster/version_check.py +88 -0
- create_dagster-1.12.16.dist-info/METADATA +19 -0
- create_dagster-1.12.16.dist-info/RECORD +24 -0
- create_dagster-1.12.16.dist-info/WHEEL +5 -0
- create_dagster-1.12.16.dist-info/entry_points.txt +2 -0
- create_dagster-1.12.16.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from create_dagster.cli.scaffold import scaffold_project_command, scaffold_workspace_command
|
|
4
|
+
from create_dagster.version import __version__
|
|
5
|
+
|
|
6
|
+
CREATE_DAGSTER_CLI_MAX_OUTPUT_WIDTH = 120
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_create_dagster_cli():
|
|
10
|
+
@click.group(
|
|
11
|
+
name="create-dagster",
|
|
12
|
+
commands={
|
|
13
|
+
"project": scaffold_project_command,
|
|
14
|
+
"workspace": scaffold_workspace_command,
|
|
15
|
+
},
|
|
16
|
+
context_settings={
|
|
17
|
+
"max_content_width": CREATE_DAGSTER_CLI_MAX_OUTPUT_WIDTH,
|
|
18
|
+
"help_option_names": ["-h", "--help"],
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
@click.version_option(__version__, "--version", "-v")
|
|
22
|
+
def group():
|
|
23
|
+
"""CLI for creating a new Dagster project or workspace."""
|
|
24
|
+
|
|
25
|
+
return group
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
ENV_PREFIX = "CREATE_DAGSTER"
|
|
29
|
+
cli = get_create_dagster_cli()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
cli(auto_envvar_prefix=ENV_PREFIX)
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
from dagster_dg_core.config import discover_workspace_root, normalize_cli_config
|
|
6
|
+
from dagster_dg_core.context import DgContext
|
|
7
|
+
from dagster_dg_core.shared_options import dg_editable_dagster_options, dg_global_options
|
|
8
|
+
from dagster_dg_core.utils import (
|
|
9
|
+
DgClickCommand,
|
|
10
|
+
exit_with_error,
|
|
11
|
+
format_multiline_str,
|
|
12
|
+
get_shortest_path_repr,
|
|
13
|
+
get_venv_activation_cmd,
|
|
14
|
+
is_uv_installed,
|
|
15
|
+
pushd,
|
|
16
|
+
)
|
|
17
|
+
from dagster_dg_core.utils.telemetry import cli_telemetry_wrapper
|
|
18
|
+
|
|
19
|
+
from create_dagster.scaffold import scaffold_project, scaffold_workspace
|
|
20
|
+
from create_dagster.version_check import check_create_dagster_up_to_date
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _project_package_install_warning_message() -> str:
|
|
24
|
+
pip_install_cmd = "pip install --editable ."
|
|
25
|
+
uv_install_cmd = "uv sync"
|
|
26
|
+
return format_multiline_str(
|
|
27
|
+
f"""
|
|
28
|
+
The environment used for your project must include an installation of your project
|
|
29
|
+
package. Please run `{uv_install_cmd}` (for uv) or `{pip_install_cmd}` (for pip) before
|
|
30
|
+
running `dg` commands against your project.
|
|
31
|
+
"""
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _print_package_install_warning_message(install_msg_warning) -> None:
|
|
36
|
+
click.secho(
|
|
37
|
+
install_msg_warning,
|
|
38
|
+
fg="yellow",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _workspace_environment_install_warning_message() -> str:
|
|
43
|
+
pip_install_cmd = "pip install --editable ./deployments/local"
|
|
44
|
+
uv_install_cmd = "uv sync --directory ./deployments/local"
|
|
45
|
+
return format_multiline_str(
|
|
46
|
+
f"""
|
|
47
|
+
The Python environment used for your workspace must include an installation of the `dg`
|
|
48
|
+
CLI. Please run `{uv_install_cmd}` (for uv) or `{pip_install_cmd}` (for pip) before
|
|
49
|
+
running `dg` commands locally against your workspace.
|
|
50
|
+
"""
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _get_project_uv_sync_prompt_msg() -> str:
|
|
55
|
+
return format_multiline_str("""
|
|
56
|
+
A `uv` installation was detected. Run `uv sync`? This will create a uv.lock file and
|
|
57
|
+
the virtual environment you need to activate in order to work on this project.
|
|
58
|
+
If you wish to use a non-uv package manager, choose "n". (y/n)
|
|
59
|
+
""")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _get_workspace_environment_uv_sync_prompt_msg(local_environment_path: Path) -> str:
|
|
63
|
+
return format_multiline_str(f"""
|
|
64
|
+
A `uv` installation was detected. Run `uv sync --directory {local_environment_path}`?
|
|
65
|
+
This will create a uv.lock file and the virtual environment you need to activate in order to
|
|
66
|
+
use `dg` locally with this workspace. If you wish to use a non-uv package manager,
|
|
67
|
+
choose "n". (y/n)
|
|
68
|
+
""")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _should_run_uv_sync(
|
|
72
|
+
venv_path: Path,
|
|
73
|
+
uv_sync_flag: bool | None,
|
|
74
|
+
uv_sync_prompt_msg: str,
|
|
75
|
+
install_warning_msg: str,
|
|
76
|
+
) -> bool:
|
|
77
|
+
if uv_sync_flag is not None:
|
|
78
|
+
return uv_sync_flag
|
|
79
|
+
elif venv_path.exists():
|
|
80
|
+
_print_package_install_warning_message(install_warning_msg)
|
|
81
|
+
return False
|
|
82
|
+
elif is_uv_installed(): # uv_sync_flag is unset (None)
|
|
83
|
+
response = click.prompt(
|
|
84
|
+
uv_sync_prompt_msg,
|
|
85
|
+
default="y",
|
|
86
|
+
).lower()
|
|
87
|
+
if response not in ("y", "n"):
|
|
88
|
+
exit_with_error(f"Invalid response '{response}'. Please enter 'y' or 'n'.")
|
|
89
|
+
if response == "n":
|
|
90
|
+
_print_package_install_warning_message(install_warning_msg)
|
|
91
|
+
return response == "y"
|
|
92
|
+
else:
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# ########################
|
|
97
|
+
# ##### PROJECT
|
|
98
|
+
# ########################
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@click.command(
|
|
102
|
+
name="project",
|
|
103
|
+
cls=DgClickCommand,
|
|
104
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
105
|
+
)
|
|
106
|
+
@click.argument("path", type=Path)
|
|
107
|
+
@click.option(
|
|
108
|
+
"--uv-sync/--no-uv-sync",
|
|
109
|
+
is_flag=True,
|
|
110
|
+
default=None,
|
|
111
|
+
help="""
|
|
112
|
+
Preemptively answer the "Run uv sync?" prompt presented after project initialization.
|
|
113
|
+
""".strip(),
|
|
114
|
+
)
|
|
115
|
+
@dg_editable_dagster_options
|
|
116
|
+
@dg_global_options
|
|
117
|
+
@cli_telemetry_wrapper
|
|
118
|
+
def scaffold_project_command(
|
|
119
|
+
path: Path,
|
|
120
|
+
use_editable_dagster: bool,
|
|
121
|
+
uv_sync: bool | None,
|
|
122
|
+
**global_options: object,
|
|
123
|
+
) -> None:
|
|
124
|
+
"""Scaffold a new Dagster project at PATH. The name of the project will be the final component of PATH.
|
|
125
|
+
|
|
126
|
+
This command can be run inside or outside of a workspace directory. If run inside a workspace,
|
|
127
|
+
the project will be added to the workspace's list of project specs.
|
|
128
|
+
|
|
129
|
+
"." may be passed as PATH to create the new project inside the existing working directory.
|
|
130
|
+
|
|
131
|
+
Created projects will have the following structure::
|
|
132
|
+
|
|
133
|
+
├── src
|
|
134
|
+
│ └── PROJECT_NAME
|
|
135
|
+
│ ├── __init__.py
|
|
136
|
+
│ ├── definitions.py
|
|
137
|
+
│ ├── defs
|
|
138
|
+
│ │ └── __init__.py
|
|
139
|
+
│ └── components
|
|
140
|
+
│ └── __init__.py
|
|
141
|
+
├── tests
|
|
142
|
+
│ └── __init__.py
|
|
143
|
+
└── pyproject.toml
|
|
144
|
+
|
|
145
|
+
The `src.PROJECT_NAME.defs` directory holds Python objects that can be targeted by the
|
|
146
|
+
`dg scaffold` command or have dg-inspectable metadata. Custom component types in the project
|
|
147
|
+
live in `src.PROJECT_NAME.components`. These types can be created with `dg scaffold component`.
|
|
148
|
+
|
|
149
|
+
Examples::
|
|
150
|
+
|
|
151
|
+
create-dagster project PROJECT_NAME
|
|
152
|
+
Scaffold a new project in new directory PROJECT_NAME. Automatically creates directory
|
|
153
|
+
and parent directories.
|
|
154
|
+
create-dagster project .
|
|
155
|
+
Scaffold a new project in the CWD. The project name is taken from the last component of the CWD.
|
|
156
|
+
"""
|
|
157
|
+
cli_config = normalize_cli_config(global_options, click.get_current_context())
|
|
158
|
+
dg_context = DgContext.from_file_discovery_and_command_line_config(Path.cwd(), cli_config)
|
|
159
|
+
check_create_dagster_up_to_date(dg_context)
|
|
160
|
+
|
|
161
|
+
if uv_sync is True and not is_uv_installed():
|
|
162
|
+
exit_with_error("""
|
|
163
|
+
uv is not installed. Please install uv to use the `--uv-sync` option.
|
|
164
|
+
See https://docs.astral.sh/uv/getting-started/installation/.
|
|
165
|
+
""")
|
|
166
|
+
|
|
167
|
+
abs_path = path.resolve()
|
|
168
|
+
if dg_context.is_in_workspace and dg_context.has_project(
|
|
169
|
+
abs_path.relative_to(dg_context.workspace_root_path)
|
|
170
|
+
):
|
|
171
|
+
exit_with_error(f"The current workspace already specifies a project at {abs_path}.")
|
|
172
|
+
elif str(path) != "." and abs_path.exists():
|
|
173
|
+
exit_with_error(f"A file or directory already exists at {abs_path}.")
|
|
174
|
+
|
|
175
|
+
scaffold_project(
|
|
176
|
+
abs_path,
|
|
177
|
+
dg_context,
|
|
178
|
+
use_editable_dagster=use_editable_dagster,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
venv_path = path / ".venv"
|
|
182
|
+
|
|
183
|
+
if _should_run_uv_sync(
|
|
184
|
+
venv_path,
|
|
185
|
+
uv_sync,
|
|
186
|
+
uv_sync_prompt_msg=_get_project_uv_sync_prompt_msg(),
|
|
187
|
+
install_warning_msg=_project_package_install_warning_message(),
|
|
188
|
+
):
|
|
189
|
+
click.echo("Running `uv sync --group dev`...")
|
|
190
|
+
with pushd(path):
|
|
191
|
+
subprocess.run(["uv", "sync", "--group", "dev"], check=True)
|
|
192
|
+
|
|
193
|
+
click.echo("\nuv.lock and virtual environment created.")
|
|
194
|
+
display_venv_path = get_shortest_path_repr(venv_path)
|
|
195
|
+
click.echo(
|
|
196
|
+
f"""
|
|
197
|
+
Run `{get_venv_activation_cmd(display_venv_path)}` to activate your project's virtual environment.
|
|
198
|
+
""".strip()
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# ########################
|
|
203
|
+
# ##### WORKSPACE
|
|
204
|
+
# ########################
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@click.command(
|
|
208
|
+
name="workspace",
|
|
209
|
+
cls=DgClickCommand,
|
|
210
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
211
|
+
)
|
|
212
|
+
@click.argument("path", type=Path)
|
|
213
|
+
@click.option(
|
|
214
|
+
"--uv-sync/--no-uv-sync",
|
|
215
|
+
is_flag=True,
|
|
216
|
+
default=None,
|
|
217
|
+
help="""
|
|
218
|
+
Preemptively answer the "Run uv sync?" prompt presented after project initialization.
|
|
219
|
+
""".strip(),
|
|
220
|
+
)
|
|
221
|
+
@dg_editable_dagster_options
|
|
222
|
+
@dg_global_options
|
|
223
|
+
@cli_telemetry_wrapper
|
|
224
|
+
def scaffold_workspace_command(
|
|
225
|
+
path: Path,
|
|
226
|
+
use_editable_dagster: bool,
|
|
227
|
+
uv_sync: bool | None,
|
|
228
|
+
**global_options: object,
|
|
229
|
+
):
|
|
230
|
+
"""Initialize a new Dagster workspace.
|
|
231
|
+
|
|
232
|
+
The scaffolded workspace folder has the following structure::
|
|
233
|
+
|
|
234
|
+
├── projects
|
|
235
|
+
│ └── Dagster projects go here
|
|
236
|
+
├── deployments
|
|
237
|
+
│ └── local
|
|
238
|
+
│ ├── pyproject.toml
|
|
239
|
+
│ └── uv.lock
|
|
240
|
+
└── dg.toml
|
|
241
|
+
|
|
242
|
+
Examples::
|
|
243
|
+
|
|
244
|
+
create-dagster workspace WORKSPACE_NAME
|
|
245
|
+
Scaffold a new workspace in new directory WORKSPACE_NAME. Automatically creates directory
|
|
246
|
+
and parent directories.
|
|
247
|
+
create-dagster workspace .
|
|
248
|
+
Scaffold a new workspace in the CWD. The workspace name is the last component of the CWD.
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
cli_config = normalize_cli_config(global_options, click.get_current_context())
|
|
252
|
+
dg_context = DgContext.from_file_discovery_and_command_line_config(Path.cwd(), cli_config)
|
|
253
|
+
check_create_dagster_up_to_date(dg_context)
|
|
254
|
+
|
|
255
|
+
abs_path = path.resolve()
|
|
256
|
+
|
|
257
|
+
existing_workspace_path = discover_workspace_root(path)
|
|
258
|
+
if existing_workspace_path:
|
|
259
|
+
exit_with_error(
|
|
260
|
+
f"Workspace already exists at {existing_workspace_path}. Run `create-dagster project` to add a new project to that workspace."
|
|
261
|
+
)
|
|
262
|
+
elif str(path) != "." and path.exists():
|
|
263
|
+
exit_with_error(f"Folder already exists at {path}.")
|
|
264
|
+
|
|
265
|
+
scaffold_workspace(
|
|
266
|
+
abs_path,
|
|
267
|
+
use_editable_dagster=use_editable_dagster,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
local_environment_path = abs_path / "deployments" / "local"
|
|
271
|
+
local_venv_path = local_environment_path / ".venv"
|
|
272
|
+
|
|
273
|
+
click.echo(
|
|
274
|
+
f"Scaffolded files for Dagster workspace at {abs_path}.\nA local environment to run `dg` commands against this workspace was created at {local_environment_path}."
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
shortest_local_environment_path = get_shortest_path_repr(local_environment_path)
|
|
278
|
+
|
|
279
|
+
if _should_run_uv_sync(
|
|
280
|
+
local_venv_path,
|
|
281
|
+
uv_sync,
|
|
282
|
+
uv_sync_prompt_msg=_get_workspace_environment_uv_sync_prompt_msg(
|
|
283
|
+
shortest_local_environment_path
|
|
284
|
+
),
|
|
285
|
+
install_warning_msg=_workspace_environment_install_warning_message(),
|
|
286
|
+
):
|
|
287
|
+
click.echo(f"Running `uv sync --directory {shortest_local_environment_path}`...")
|
|
288
|
+
with pushd(path):
|
|
289
|
+
subprocess.run(
|
|
290
|
+
["uv", "sync"],
|
|
291
|
+
check=True,
|
|
292
|
+
cwd=local_environment_path,
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
click.echo("\nuv.lock and virtual environment created.")
|
|
296
|
+
display_venv_path = get_shortest_path_repr(local_venv_path)
|
|
297
|
+
click.echo(
|
|
298
|
+
f"""
|
|
299
|
+
Run `{get_venv_activation_cmd(display_venv_path)}` to activate your workspace's local virtual environment.
|
|
300
|
+
""".strip()
|
|
301
|
+
)
|
create_dagster/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
partial
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import uuid
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from dagster_dg_core.config import DgWorkspaceScaffoldProjectOptions, modify_dg_toml_config
|
|
8
|
+
from dagster_dg_core.context import DgContext
|
|
9
|
+
from dagster_dg_core.utils import exit_with_error, get_toml_node, has_toml_node, set_toml_node
|
|
10
|
+
from dagster_shared.libraries import parse_package_version
|
|
11
|
+
from dagster_shared.scaffold import scaffold_subtree
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def scaffold_workspace(
|
|
15
|
+
path: Path,
|
|
16
|
+
use_editable_dagster: bool,
|
|
17
|
+
) -> None:
|
|
18
|
+
scaffold_subtree(
|
|
19
|
+
path=path,
|
|
20
|
+
name_placeholder="WORKSPACE_NAME_PLACEHOLDER",
|
|
21
|
+
project_template_path=Path(
|
|
22
|
+
os.path.join(os.path.dirname(__file__), "templates", "WORKSPACE_NAME_PLACEHOLDER")
|
|
23
|
+
),
|
|
24
|
+
excludes=None,
|
|
25
|
+
**get_dependencies_template_params(
|
|
26
|
+
use_editable_dagster,
|
|
27
|
+
scaffold_project_options=None,
|
|
28
|
+
pypi_deps=_get_pypi_local_workspace_environment_deps(),
|
|
29
|
+
# add create-dagster to editable installs so you can scaffold projects in the
|
|
30
|
+
# workspace editable venv, since if you are installing editably you probably have
|
|
31
|
+
# create-dagster installed in your current venv editably
|
|
32
|
+
editable_deps=(
|
|
33
|
+
EDITABLE_DAGSTER_DEPENDENCIES
|
|
34
|
+
+ EDITABLE_DAGSTER_DEV_DEPENDENCIES
|
|
35
|
+
+ ["create-dagster"]
|
|
36
|
+
),
|
|
37
|
+
pypi_dev_deps=[], # no dev extra
|
|
38
|
+
editable_dev_deps=[],
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if use_editable_dagster:
|
|
43
|
+
with modify_dg_toml_config(path / "dg.toml") as toml:
|
|
44
|
+
set_toml_node(toml, ("workspace", "scaffold_project_options"), {})
|
|
45
|
+
set_toml_node(
|
|
46
|
+
toml,
|
|
47
|
+
("workspace", "scaffold_project_options", "use_editable_dagster"),
|
|
48
|
+
True if use_editable_dagster == "TRUE" else use_editable_dagster,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_dependencies_template_params(
|
|
53
|
+
use_editable_dagster: bool,
|
|
54
|
+
scaffold_project_options: DgWorkspaceScaffoldProjectOptions | None,
|
|
55
|
+
*,
|
|
56
|
+
editable_deps: list[str],
|
|
57
|
+
editable_dev_deps: list[str],
|
|
58
|
+
pypi_deps: list[str],
|
|
59
|
+
pypi_dev_deps: list[str],
|
|
60
|
+
) -> dict[str, str]:
|
|
61
|
+
cli_options = DgWorkspaceScaffoldProjectOptions.get_raw_from_cli(use_editable_dagster)
|
|
62
|
+
|
|
63
|
+
final_use_editable_dagster = cli_options.get(
|
|
64
|
+
"use_editable_dagster",
|
|
65
|
+
scaffold_project_options.use_editable_dagster if scaffold_project_options else None,
|
|
66
|
+
)
|
|
67
|
+
if final_use_editable_dagster:
|
|
68
|
+
deps = editable_deps
|
|
69
|
+
dev_deps = editable_dev_deps
|
|
70
|
+
sources = _gather_dagster_packages(Path(_get_editable_dagster_from_env()))
|
|
71
|
+
else:
|
|
72
|
+
dev_deps = pypi_dev_deps
|
|
73
|
+
deps = pypi_deps
|
|
74
|
+
sources = []
|
|
75
|
+
|
|
76
|
+
dependencies_str = _get_pyproject_toml_dependencies(deps)
|
|
77
|
+
dev_dependencies_str = _get_pyproject_toml_dev_dependencies(dev_deps)
|
|
78
|
+
uv_sources_str = _get_pyproject_toml_uv_sources(sources) if sources else ""
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
"dependencies": dependencies_str,
|
|
82
|
+
"dev_dependencies": dev_dependencies_str,
|
|
83
|
+
"uv_sources": uv_sources_str,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _get_pypi_project_deps() -> list[str]:
|
|
88
|
+
from create_dagster.version import __version__
|
|
89
|
+
|
|
90
|
+
create_dagster_version = parse_package_version(__version__)
|
|
91
|
+
if create_dagster_version.release[0] >= 1:
|
|
92
|
+
# Pin scaffolded libraries to match create-dagster version
|
|
93
|
+
return [f"dagster=={__version__}"]
|
|
94
|
+
else:
|
|
95
|
+
return ["dagster"]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _get_pypi_local_workspace_environment_deps() -> list[str]:
|
|
99
|
+
return _get_pypi_project_deps() + PYPI_DAGSTER_DEV_DEPENDENCIES
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def scaffold_project(
|
|
103
|
+
path: Path,
|
|
104
|
+
dg_context: DgContext,
|
|
105
|
+
use_editable_dagster: bool,
|
|
106
|
+
) -> None:
|
|
107
|
+
import tomlkit
|
|
108
|
+
import tomlkit.items
|
|
109
|
+
|
|
110
|
+
click.echo(f"Creating a Dagster project at {path}.")
|
|
111
|
+
|
|
112
|
+
scaffold_project_options = (
|
|
113
|
+
dg_context.config.workspace.scaffold_project_options
|
|
114
|
+
if dg_context.config.workspace
|
|
115
|
+
else None
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
project_excludes = None
|
|
119
|
+
if dg_context.is_in_workspace:
|
|
120
|
+
project_excludes = [
|
|
121
|
+
".gitignore",
|
|
122
|
+
"README.md.jinja",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
scaffold_subtree(
|
|
126
|
+
path=path,
|
|
127
|
+
name_placeholder="PROJECT_NAME_PLACEHOLDER",
|
|
128
|
+
project_template_path=Path(
|
|
129
|
+
os.path.join(os.path.dirname(__file__), "templates", "PROJECT_NAME_PLACEHOLDER")
|
|
130
|
+
),
|
|
131
|
+
excludes=project_excludes,
|
|
132
|
+
project_id=str(uuid.uuid4()),
|
|
133
|
+
**get_dependencies_template_params(
|
|
134
|
+
use_editable_dagster,
|
|
135
|
+
scaffold_project_options,
|
|
136
|
+
pypi_deps=_get_pypi_project_deps(),
|
|
137
|
+
pypi_dev_deps=PYPI_DAGSTER_DEV_DEPENDENCIES,
|
|
138
|
+
editable_deps=EDITABLE_DAGSTER_DEPENDENCIES,
|
|
139
|
+
editable_dev_deps=EDITABLE_DAGSTER_DEV_DEPENDENCIES,
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
click.echo(f"Scaffolded files for Dagster project at {path}.")
|
|
143
|
+
|
|
144
|
+
# Build the venv
|
|
145
|
+
cl_dg_context = dg_context.with_root_path(path)
|
|
146
|
+
|
|
147
|
+
# Update pyproject.toml
|
|
148
|
+
if cl_dg_context.is_in_workspace:
|
|
149
|
+
entry = {
|
|
150
|
+
"path": str(cl_dg_context.root_path.relative_to(cl_dg_context.workspace_root_path)),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
with modify_dg_toml_config(dg_context.config_file_path) as toml:
|
|
154
|
+
if not has_toml_node(toml, ("workspace", "projects")):
|
|
155
|
+
projects = tomlkit.aot()
|
|
156
|
+
set_toml_node(toml, ("workspace", "projects"), projects)
|
|
157
|
+
item = tomlkit.table()
|
|
158
|
+
else:
|
|
159
|
+
projects = get_toml_node(
|
|
160
|
+
toml,
|
|
161
|
+
("workspace", "projects"),
|
|
162
|
+
(tomlkit.items.AoT, tomlkit.items.Array),
|
|
163
|
+
)
|
|
164
|
+
if isinstance(projects, tomlkit.items.Array):
|
|
165
|
+
item = tomlkit.inline_table()
|
|
166
|
+
else:
|
|
167
|
+
item = tomlkit.table()
|
|
168
|
+
|
|
169
|
+
# item.trivia.indent is the preceding whitespace-- this ensures there is always a blank
|
|
170
|
+
# line before the new entry
|
|
171
|
+
item.trivia.indent = item.trivia.indent + "\n"
|
|
172
|
+
for key, value in entry.items():
|
|
173
|
+
item[key] = value
|
|
174
|
+
projects.append(item)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# Despite the fact that editable dependencies are resolved through tool.uv.sources, we need to set
|
|
178
|
+
# the dependencies themselves differently depending on whether we are using editable dagster or
|
|
179
|
+
# not. This is because `tool.uv.sources` only seems to apply to direct dependencies of the package,
|
|
180
|
+
# so any 2+-order Dagster dependency of our package needs to be listed as a direct dependency in the
|
|
181
|
+
# editable case. See: https://github.com/astral-sh/uv/issues/9446
|
|
182
|
+
EDITABLE_DAGSTER_DEPENDENCIES = [
|
|
183
|
+
"dagster",
|
|
184
|
+
"dagster-pipes",
|
|
185
|
+
"dagster-shared",
|
|
186
|
+
"dagster-test", # we include dagster-test for testing purposes
|
|
187
|
+
]
|
|
188
|
+
EDITABLE_DAGSTER_DEV_DEPENDENCIES = [
|
|
189
|
+
"dagster-webserver",
|
|
190
|
+
"dagster-graphql",
|
|
191
|
+
"dagster-dg-core",
|
|
192
|
+
"dagster-dg-cli",
|
|
193
|
+
"dagster-cloud-cli",
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
PYPI_DAGSTER_DEV_DEPENDENCIES = [
|
|
198
|
+
"dagster-webserver",
|
|
199
|
+
"dagster-dg-cli",
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _get_editable_dagster_from_env() -> str:
|
|
204
|
+
if not os.environ.get("DAGSTER_GIT_REPO_DIR"):
|
|
205
|
+
exit_with_error(
|
|
206
|
+
"The `--use-editable-dagster` option "
|
|
207
|
+
"requires the `DAGSTER_GIT_REPO_DIR` environment variable to be set."
|
|
208
|
+
)
|
|
209
|
+
return os.environ["DAGSTER_GIT_REPO_DIR"]
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _get_pyproject_toml_dependencies(deps: Sequence[str]) -> str:
|
|
213
|
+
return "\n".join(
|
|
214
|
+
[
|
|
215
|
+
"dependencies = [",
|
|
216
|
+
*[f' "{dep}",' for dep in deps],
|
|
217
|
+
"]",
|
|
218
|
+
]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _get_pyproject_toml_dev_dependencies(deps: Sequence[str]) -> str:
|
|
223
|
+
return "\n".join(
|
|
224
|
+
[
|
|
225
|
+
"dev = [",
|
|
226
|
+
*[f' "{dep}",' for dep in deps],
|
|
227
|
+
"]",
|
|
228
|
+
]
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _get_pyproject_toml_uv_sources(lib_paths: list[Path]) -> str:
|
|
233
|
+
lib_lines = [f"{path.name} = {{ path = '{path}', editable = true }}" for path in lib_paths]
|
|
234
|
+
return "\n".join(
|
|
235
|
+
[
|
|
236
|
+
"[tool.uv.sources]",
|
|
237
|
+
*lib_lines,
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _gather_dagster_packages(editable_dagster_root: Path) -> list[Path]:
|
|
243
|
+
package_dirs = set()
|
|
244
|
+
for pattern in [
|
|
245
|
+
"python_modules/dagster*/setup.py",
|
|
246
|
+
"python_modules/dagster*/pyproject.toml",
|
|
247
|
+
"python_modules/libraries/dagster*/setup.py",
|
|
248
|
+
"python_modules/libraries/dagster*/pyproject.toml",
|
|
249
|
+
"python_modules/libraries/create-dagster/setup.py",
|
|
250
|
+
"python_modules/libraries/create-dagster/pyproject.toml",
|
|
251
|
+
]:
|
|
252
|
+
for p in editable_dagster_root.glob(pattern):
|
|
253
|
+
package_dirs.add(p.parent)
|
|
254
|
+
return sorted(package_dirs)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
project_id: {{ project_id }}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
#poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
#pdm.lock
|
|
116
|
+
#pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
#pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# SageMath parsed files
|
|
135
|
+
*.sage.py
|
|
136
|
+
|
|
137
|
+
# Environments
|
|
138
|
+
.env
|
|
139
|
+
.envrc
|
|
140
|
+
.venv
|
|
141
|
+
env/
|
|
142
|
+
venv/
|
|
143
|
+
ENV/
|
|
144
|
+
env.bak/
|
|
145
|
+
venv.bak/
|
|
146
|
+
|
|
147
|
+
# Spyder project settings
|
|
148
|
+
.spyderproject
|
|
149
|
+
.spyproject
|
|
150
|
+
|
|
151
|
+
# Rope project settings
|
|
152
|
+
.ropeproject
|
|
153
|
+
|
|
154
|
+
# mkdocs documentation
|
|
155
|
+
/site
|
|
156
|
+
|
|
157
|
+
# mypy
|
|
158
|
+
.mypy_cache/
|
|
159
|
+
.dmypy.json
|
|
160
|
+
dmypy.json
|
|
161
|
+
|
|
162
|
+
# Pyre type checker
|
|
163
|
+
.pyre/
|
|
164
|
+
|
|
165
|
+
# pytype static type analyzer
|
|
166
|
+
.pytype/
|
|
167
|
+
|
|
168
|
+
# Cython debug symbols
|
|
169
|
+
cython_debug/
|
|
170
|
+
|
|
171
|
+
# PyCharm
|
|
172
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
173
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
174
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
175
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
176
|
+
#.idea/
|
|
177
|
+
|
|
178
|
+
# Abstra
|
|
179
|
+
# Abstra is an AI-powered process automation framework.
|
|
180
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
181
|
+
# Learn more at https://abstra.io/docs
|
|
182
|
+
.abstra/
|
|
183
|
+
|
|
184
|
+
# Visual Studio Code
|
|
185
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
186
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
188
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
189
|
+
# .vscode/
|
|
190
|
+
|
|
191
|
+
# Ruff stuff:
|
|
192
|
+
.ruff_cache/
|
|
193
|
+
|
|
194
|
+
# PyPI configuration file
|
|
195
|
+
.pypirc
|
|
196
|
+
|
|
197
|
+
# Marimo
|
|
198
|
+
marimo/_static/
|
|
199
|
+
marimo/_lsp/
|
|
200
|
+
__marimo__/
|
|
201
|
+
|
|
202
|
+
# Streamlit
|
|
203
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# {{ project_name }}
|
|
2
|
+
|
|
3
|
+
## Getting started
|
|
4
|
+
|
|
5
|
+
### Installing dependencies
|
|
6
|
+
|
|
7
|
+
**Option 1: uv**
|
|
8
|
+
|
|
9
|
+
Ensure [`uv`](https://docs.astral.sh/uv/) is installed following their [official documentation](https://docs.astral.sh/uv/getting-started/installation/).
|
|
10
|
+
|
|
11
|
+
Create a virtual environment, and install the required dependencies using _sync_:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv sync
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then, activate the virtual environment:
|
|
18
|
+
|
|
19
|
+
| OS | Command |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| MacOS | ```source .venv/bin/activate``` |
|
|
22
|
+
| Windows | ```.venv\Scripts\activate``` |
|
|
23
|
+
|
|
24
|
+
**Option 2: pip**
|
|
25
|
+
|
|
26
|
+
Install the python dependencies with [pip](https://pypi.org/project/pip/):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python3 -m venv .venv
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then activate the virtual environment:
|
|
33
|
+
|
|
34
|
+
| OS | Command |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| MacOS | ```source .venv/bin/activate``` |
|
|
37
|
+
| Windows | ```.venv\Scripts\activate``` |
|
|
38
|
+
|
|
39
|
+
Install the required dependencies:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e ".[dev]"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Running Dagster
|
|
46
|
+
|
|
47
|
+
Start the Dagster UI web server:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
dg dev
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Open http://localhost:3000 in your browser to see the project.
|
|
54
|
+
|
|
55
|
+
## Learn more
|
|
56
|
+
|
|
57
|
+
To learn more about this template and Dagster in general:
|
|
58
|
+
|
|
59
|
+
- [Dagster Documentation](https://docs.dagster.io/)
|
|
60
|
+
- [Dagster University](https://courses.dagster.io/)
|
|
61
|
+
- [Dagster Slack Community](https://dagster.io/slack)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{ project_name }}"
|
|
3
|
+
requires-python = ">=3.10,<3.15"
|
|
4
|
+
version = "0.1.0"
|
|
5
|
+
{{ dependencies }}
|
|
6
|
+
|
|
7
|
+
[dependency-groups]
|
|
8
|
+
{{ dev_dependencies }}
|
|
9
|
+
|
|
10
|
+
[build-system]
|
|
11
|
+
requires = ["hatchling"]
|
|
12
|
+
build-backend = "hatchling.build"
|
|
13
|
+
|
|
14
|
+
[tool.hatch.build.targets.wheel]
|
|
15
|
+
force-include = { "pyproject.toml" = "pyproject.toml" }
|
|
16
|
+
|
|
17
|
+
[tool.dg]
|
|
18
|
+
directory_type = "project"
|
|
19
|
+
|
|
20
|
+
[tool.dg.project]
|
|
21
|
+
root_module = "{{ project_name }}"
|
|
22
|
+
registry_modules = [
|
|
23
|
+
"{{ project_name }}.components.*",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
{{ uv_sources }}
|
|
File without changes
|
|
File without changes
|
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/defs/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.12.16"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import os
|
|
3
|
+
from functools import cached_property
|
|
4
|
+
|
|
5
|
+
from dagster_dg_core.context import DgContext
|
|
6
|
+
from dagster_dg_core.utils.warnings import emit_warning
|
|
7
|
+
from dagster_shared.libraries import DagsterPyPiAccessError, get_published_pypi_versions
|
|
8
|
+
from dagster_shared.record import record
|
|
9
|
+
from packaging.version import Version
|
|
10
|
+
|
|
11
|
+
from create_dagster.version import __version__
|
|
12
|
+
|
|
13
|
+
CREATE_DAGSTER_UPDATE_CHECK_ENABLED_ENV_VAR = "DAGSTER_DG_UPDATE_CHECK_ENABLED"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@record
|
|
17
|
+
class _PyPiVersionInfo:
|
|
18
|
+
timestamp: float
|
|
19
|
+
raw_versions: list[str]
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def datetime(self) -> datetime.datetime:
|
|
23
|
+
return datetime.datetime.fromtimestamp(self.timestamp)
|
|
24
|
+
|
|
25
|
+
@cached_property
|
|
26
|
+
def versions(self) -> list[Version]:
|
|
27
|
+
return sorted(Version(v) for v in self.raw_versions)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def check_create_dagster_up_to_date(context: DgContext) -> None:
|
|
31
|
+
if not _create_dagster_update_check_enabled(context):
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
version_info = _get_create_dagster_pypi_version_info(context)
|
|
35
|
+
if version_info is None: # Nothing cached and network error occurred
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
current_version = Version(__version__)
|
|
39
|
+
latest_version = version_info.versions[-1]
|
|
40
|
+
if current_version < latest_version:
|
|
41
|
+
emit_warning(
|
|
42
|
+
"create_dagster_outdated",
|
|
43
|
+
f"""
|
|
44
|
+
There is a new version of `create-dagster` available:
|
|
45
|
+
|
|
46
|
+
Latest version: {latest_version}
|
|
47
|
+
Current version: {current_version}
|
|
48
|
+
|
|
49
|
+
Update your create-dagster installation to keep up to date:
|
|
50
|
+
|
|
51
|
+
[uv tool run] $ uvx -U create-dagster
|
|
52
|
+
[uv tool install] $ uv tool upgrade create-dagster
|
|
53
|
+
[uv local] $ uv sync --upgrade create-dagster
|
|
54
|
+
[pip] $ pip install --upgrade create-dagster
|
|
55
|
+
""",
|
|
56
|
+
suppress_warnings=[],
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _create_dagster_update_check_enabled(context: DgContext) -> bool:
|
|
61
|
+
return (
|
|
62
|
+
bool(int(os.getenv(CREATE_DAGSTER_UPDATE_CHECK_ENABLED_ENV_VAR, "1")))
|
|
63
|
+
and "create_dagster_outdated" not in context.config.cli.suppress_warnings
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _get_create_dagster_pypi_version_info(context: DgContext) -> _PyPiVersionInfo | None:
|
|
68
|
+
if context.config.cli.verbose:
|
|
69
|
+
context.log.info("Checking for the latest version of `create-dagster` on PyPI.")
|
|
70
|
+
try:
|
|
71
|
+
published_versions = get_published_pypi_versions("create-dagster")
|
|
72
|
+
version_info = _PyPiVersionInfo(
|
|
73
|
+
raw_versions=[str(v) for v in published_versions],
|
|
74
|
+
timestamp=datetime.datetime.now().timestamp(),
|
|
75
|
+
)
|
|
76
|
+
except DagsterPyPiAccessError as e:
|
|
77
|
+
emit_warning(
|
|
78
|
+
"create_dagster_outdated",
|
|
79
|
+
f"""
|
|
80
|
+
There was an error checking for the latest version of `create-dagster` on PyPI. Please check your
|
|
81
|
+
internet connection and try again.
|
|
82
|
+
|
|
83
|
+
Error: {e}
|
|
84
|
+
""",
|
|
85
|
+
suppress_warnings=[],
|
|
86
|
+
)
|
|
87
|
+
version_info = None
|
|
88
|
+
return version_info
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: create-dagster
|
|
3
|
+
Version: 1.12.16
|
|
4
|
+
Summary: CLI for creating a new dg project or workspace.
|
|
5
|
+
Project-URL: Homepage, https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/create-dagster
|
|
6
|
+
Author-email: Dagster Labs <hello@dagsterlabs.com>
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: dagster-dg-core==1.12.16
|
|
16
|
+
Provides-Extra: test
|
|
17
|
+
Requires-Dist: flaky; extra == 'test'
|
|
18
|
+
Requires-Dist: psutil; extra == 'test'
|
|
19
|
+
Requires-Dist: pytest; extra == 'test'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
create_dagster/__init__.py,sha256=KNn9tdZHJR5WooJM4qGlsCsXb06zWVP_bJilfsfngjM,187
|
|
2
|
+
create_dagster/py.typed,sha256=mDShSrm8qg9qjacQc2F-rI8ATllqP6EdgHuEYxuCXZ0,7
|
|
3
|
+
create_dagster/scaffold.py,sha256=26z5ZBT9QNya8oiAqQ0tx4b9C6CdgdqMWuvDuHHWOZk,8584
|
|
4
|
+
create_dagster/version.py,sha256=fFgL2l_aO8HuiIYIT4ROy3I4MuBkR-FzMsPtNDtQisU,24
|
|
5
|
+
create_dagster/version_check.py,sha256=kEXXI5IudCmM4xGsHS8OQf1yFczVZJRTlKO1iAn4FtU,3063
|
|
6
|
+
create_dagster/cli/__init__.py,sha256=uhenH_pf5mkC6wIcbZZvhJdOxt-kUmnyJl7FpzcR1xw,851
|
|
7
|
+
create_dagster/cli/scaffold.py,sha256=9m7IQapvpm-G2CQYTgTH4BH-kc55aoRkoWm7riREivk,10490
|
|
8
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/.gitignore,sha256=a16PgPDtZU51UDiRgETFY8T9bIWmEB2YjouecJvi0Tw,4439
|
|
9
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/README.md.jinja,sha256=AzruT8J4OYsBHEzwTS2KtmOc3xpgrKisDS4SQII62Ig,1241
|
|
10
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/pyproject.toml.jinja,sha256=O3WOBq208rMgOPcrRIiKkPZdFszaLb0XgbjA9U8Otok,489
|
|
11
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/.dg/telemetry.yaml.jinja,sha256=fEYE0pB3Yu-xZ2JwyueQ0Y1C4CmbZZWmyY0ATZrjFCA,29
|
|
12
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/definitions.py.jinja,sha256=NyggUpOD0lkJS1E1pjgXFGaDCzQc335ZfU-eo6CAQF8,184
|
|
14
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/defs/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/src/PROJECT_NAME_PLACEHOLDER/defs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
create_dagster/templates/PROJECT_NAME_PLACEHOLDER/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
create_dagster/templates/WORKSPACE_NAME_PLACEHOLDER/dg.toml.jinja,sha256=P9vtkxp0XUYKhsa6UhPMzHkAADKJejQ0mxi2ciGnK0w,42
|
|
18
|
+
create_dagster/templates/WORKSPACE_NAME_PLACEHOLDER/deployments/local/pyproject.toml.jinja,sha256=d6uDPmDssBX9nDiQt_BnwRXqkKqFOMMpBVEYsUsDip8,173
|
|
19
|
+
create_dagster/templates/WORKSPACE_NAME_PLACEHOLDER/projects/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
create_dagster-1.12.16.dist-info/METADATA,sha256=Em5D6JO6bRlkrrCGcedv9QkQxBHGw2hNuBjcbUqLJGQ,813
|
|
21
|
+
create_dagster-1.12.16.dist-info/WHEEL,sha256=e22IIVjxDyt0lABi4WpktFIGsmO_ebSDXLnPUbPK0E0,105
|
|
22
|
+
create_dagster-1.12.16.dist-info/entry_points.txt,sha256=Z63NCOZRLoCLiDynvq0VU7mjblrZAlFgYmBVbvFcOCc,59
|
|
23
|
+
create_dagster-1.12.16.dist-info/licenses/LICENSE,sha256=lY5yc1KHX4HoXjlWnIPGcCAsnNney2rb8M8ccT6NzRQ,11347
|
|
24
|
+
create_dagster-1.12.16.dist-info/RECORD,,
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2023 Dagster Labs, Inc.
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|