shipit-cli 0.4.0__tar.gz → 0.5.0__tar.gz
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.
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/PKG-INFO +1 -1
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/pyproject.toml +1 -1
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/cli.py +12 -6
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/python.py +72 -15
- shipit_cli-0.5.0/src/shipit/version.py +5 -0
- shipit_cli-0.4.0/src/shipit/version.py +0 -5
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/.gitignore +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/README.md +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/__init__.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/assets/php/php.ini +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/generator.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/base.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/gatsby.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/hugo.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/laravel.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/mkdocs.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/node_static.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/php.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/registry.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/src/shipit/providers/staticfile.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/tests/test_examples_build.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/tests/test_generate_shipit_examples.py +0 -0
- {shipit_cli-0.4.0 → shipit_cli-0.5.0}/tests/test_version.py +0 -0
|
@@ -499,12 +499,18 @@ class LocalBuilder:
|
|
|
499
499
|
ignore_matches = step.ignore if step.ignore else []
|
|
500
500
|
ignore_matches.append(".shipit")
|
|
501
501
|
ignore_matches.append("Shipit")
|
|
502
|
-
|
|
503
|
-
(
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
502
|
+
if (self.src_dir / step.source).is_dir():
|
|
503
|
+
copytree(
|
|
504
|
+
(self.src_dir / step.source),
|
|
505
|
+
(build_path / step.target),
|
|
506
|
+
dirs_exist_ok=True,
|
|
507
|
+
ignore=ignore_patterns(*ignore_matches),
|
|
508
|
+
)
|
|
509
|
+
else:
|
|
510
|
+
copy(
|
|
511
|
+
(self.src_dir / step.source),
|
|
512
|
+
(build_path / step.target),
|
|
513
|
+
)
|
|
508
514
|
elif isinstance(step, EnvStep):
|
|
509
515
|
print(f"Setting environment variables: {step}")
|
|
510
516
|
env.update(step.variables)
|
|
@@ -16,9 +16,11 @@ from .base import (
|
|
|
16
16
|
|
|
17
17
|
class PythonFramework(Enum):
|
|
18
18
|
Django = "django"
|
|
19
|
+
Streamlit = "streamlit"
|
|
19
20
|
FastAPI = "fastapi"
|
|
20
21
|
Flask = "flask"
|
|
21
22
|
FastHTML = "python-fasthtml"
|
|
23
|
+
MCP = "mcp"
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class PythonServer(Enum):
|
|
@@ -58,7 +60,9 @@ class PythonProvider:
|
|
|
58
60
|
"psycopg2-binary"}
|
|
59
61
|
mysql_deps = {"mysqlclient", "pymysql", "mysql-connector-python", "aiomysql"}
|
|
60
62
|
found_deps = self.check_deps(
|
|
63
|
+
"streamlit",
|
|
61
64
|
"django",
|
|
65
|
+
"mcp",
|
|
62
66
|
"fastapi",
|
|
63
67
|
"flask",
|
|
64
68
|
"python-fasthtml",
|
|
@@ -105,6 +109,11 @@ class PythonProvider:
|
|
|
105
109
|
# gunicorn can't run with Wasmer atm
|
|
106
110
|
self.extra_dependencies = {"uvicorn"}
|
|
107
111
|
self.server = PythonServer.Uvicorn
|
|
112
|
+
elif "streamlit" in found_deps:
|
|
113
|
+
framework = PythonFramework.Streamlit
|
|
114
|
+
elif "mcp" in found_deps:
|
|
115
|
+
framework = PythonFramework.MCP
|
|
116
|
+
self.extra_dependencies = {"mcp[cli]"}
|
|
108
117
|
elif "fastapi" in found_deps:
|
|
109
118
|
framework = PythonFramework.FastAPI
|
|
110
119
|
if not self.server:
|
|
@@ -112,10 +121,9 @@ class PythonProvider:
|
|
|
112
121
|
self.server = PythonServer.Uvicorn
|
|
113
122
|
elif "flask" in found_deps:
|
|
114
123
|
framework = PythonFramework.Flask
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
framework = PythonFramework.Flask
|
|
124
|
+
if not self.server:
|
|
125
|
+
self.extra_dependencies = {"uvicorn"}
|
|
126
|
+
self.server = PythonServer.Uvicorn
|
|
119
127
|
elif "python-fasthtml" in found_deps:
|
|
120
128
|
framework = PythonFramework.FastHTML
|
|
121
129
|
else:
|
|
@@ -200,6 +208,7 @@ class PythonProvider:
|
|
|
200
208
|
"workdir(app[\"build\"])"
|
|
201
209
|
]
|
|
202
210
|
|
|
211
|
+
extra_deps = ", ".join([f"{dep}" for dep in self.extra_dependencies])
|
|
203
212
|
if _exists(self.path, "pyproject.toml"):
|
|
204
213
|
input_files = ["pyproject.toml"]
|
|
205
214
|
extra_args = ""
|
|
@@ -207,22 +216,22 @@ class PythonProvider:
|
|
|
207
216
|
input_files.append("uv.lock")
|
|
208
217
|
extra_args = " --locked"
|
|
209
218
|
inputs = ", ".join([f"\"{input}\"" for input in input_files])
|
|
210
|
-
|
|
211
|
-
steps += list(filter(None, [
|
|
219
|
+
steps += [
|
|
212
220
|
"env(UV_PROJECT_ENVIRONMENT=local_venv[\"build\"] if cross_platform else venv[\"build\"])",
|
|
213
|
-
"run(f\"uv sync --compile --python python{python_version} --no-managed-python
|
|
214
|
-
|
|
215
|
-
"run(
|
|
221
|
+
f"run(f\"uv sync --compile --python python{{python_version}} --no-managed-python{extra_args}\", inputs=[{inputs}], group=\"install\")",
|
|
222
|
+
"copy(\"pyproject.toml\", \"pyproject.toml\")",
|
|
223
|
+
f"run(\"uv add {extra_deps}\", group=\"install\")" if extra_deps else None,
|
|
224
|
+
"run(f\"uv pip compile pyproject.toml --python-version={python_version} --universal --extra-index-url {python_extra_index_url} --index-url=https://pypi.org/simple --emit-index-url --only-binary :all: -o cross-requirements.txt\", outputs=[\"cross-requirements.txt\"]) if cross_platform else None",
|
|
216
225
|
f"run(f\"uvx pip install -r cross-requirements.txt {extra_deps} --target {{python_cross_packages_path}} --platform {{cross_platform}} --only-binary=:all: --python-version={{python_version}} --compile\") if cross_platform else None",
|
|
217
226
|
"run(\"rm cross-requirements.txt\") if cross_platform else None",
|
|
218
|
-
]
|
|
227
|
+
]
|
|
219
228
|
if _exists(self.path, "requirements.txt"):
|
|
220
229
|
steps += [
|
|
221
230
|
"env(UV_PROJECT_ENVIRONMENT=local_venv[\"build\"] if cross_platform else venv[\"build\"])",
|
|
222
231
|
"run(f\"uv init --no-managed-python --python python{python_version}\", inputs=[], outputs=[\"uv.lock\"], group=\"install\")",
|
|
223
|
-
"run(
|
|
232
|
+
f"run(\"uv add -r requirements.txt {extra_deps}\", inputs=[\"requirements.txt\"], group=\"install\")",
|
|
224
233
|
"run(f\"uv pip compile requirements.txt --python-version={python_version} --universal --extra-index-url {python_extra_index_url} --index-url=https://pypi.org/simple --emit-index-url --only-binary :all: -o cross-requirements.txt\", inputs=[\"requirements.txt\"], outputs=[\"cross-requirements.txt\"]) if cross_platform else None",
|
|
225
|
-
"run(f\"uvx pip install -r cross-requirements.txt --target {python_cross_packages_path} --platform {cross_platform} --only-binary=:all: --python-version={python_version} --compile\") if cross_platform else None",
|
|
234
|
+
f"run(f\"uvx pip install -r cross-requirements.txt {extra_deps} --target {{python_cross_packages_path}} --platform {{cross_platform}} --only-binary=:all: --python-version={{python_version}} --compile\") if cross_platform else None",
|
|
226
235
|
"run(\"rm cross-requirements.txt\") if cross_platform else None",
|
|
227
236
|
]
|
|
228
237
|
|
|
@@ -230,7 +239,12 @@ class PythonProvider:
|
|
|
230
239
|
"path((local_venv[\"build\"] if cross_platform else venv[\"build\"]) + \"/bin\")",
|
|
231
240
|
"copy(\".\", \".\", ignore=[\".venv\", \".git\", \"__pycache__\"])",
|
|
232
241
|
]
|
|
233
|
-
|
|
242
|
+
if self.framework == PythonFramework.MCP:
|
|
243
|
+
steps += [
|
|
244
|
+
"run(\"mkdir -p {}/bin\".format(venv[\"build\"])) if cross_platform else None",
|
|
245
|
+
"run(\"cp {}/bin/mcp {}/bin/mcp\".format(local_venv[\"build\"], venv[\"build\"])) if cross_platform else None",
|
|
246
|
+
]
|
|
247
|
+
return list(filter(None, steps))
|
|
234
248
|
|
|
235
249
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
236
250
|
return [
|
|
@@ -273,6 +287,42 @@ class PythonProvider:
|
|
|
273
287
|
else:
|
|
274
288
|
start_cmd = '"python -c \'print(\\\"No start command detected, please provide a start command manually\\\")\'"'
|
|
275
289
|
return {"start": start_cmd}
|
|
290
|
+
elif self.framework == PythonFramework.Streamlit:
|
|
291
|
+
if _exists(self.path, "main.py"):
|
|
292
|
+
path = "main.py"
|
|
293
|
+
elif _exists(self.path, "src/main.py"):
|
|
294
|
+
path = "src/main.py"
|
|
295
|
+
if _exists(self.path, "app.py"):
|
|
296
|
+
path = "app.py"
|
|
297
|
+
elif _exists(self.path, "src/app.py"):
|
|
298
|
+
path = "src/app.py"
|
|
299
|
+
elif _exists(self.path, "src/streamlit_app.py"):
|
|
300
|
+
path = "src/streamlit_app.py"
|
|
301
|
+
elif _exists(self.path, "streamlit_app.py"):
|
|
302
|
+
path = "streamlit_app.py"
|
|
303
|
+
elif _exists(self.path, "Home.py"):
|
|
304
|
+
path = "Home.py"
|
|
305
|
+
|
|
306
|
+
start_cmd = f'"python -m streamlit run {path} --server.port 8000 --server.address 0.0.0.0 --server.headless true"'
|
|
307
|
+
elif self.framework == PythonFramework.Flask:
|
|
308
|
+
if _exists(self.path, "main.py"):
|
|
309
|
+
path = "main:app"
|
|
310
|
+
if _exists(self.path, "app.py"):
|
|
311
|
+
path = "app:app"
|
|
312
|
+
elif _exists(self.path, "src/main.py"):
|
|
313
|
+
path = "src.main:app"
|
|
314
|
+
# start_cmd = f'"python -m flask --app {path} run --debug --host 0.0.0.0 --port 8000"'
|
|
315
|
+
start_cmd = f'"python -m uvicorn {path} --interface=wsgi --host 0.0.0.0 --port 8000"'
|
|
316
|
+
elif self.framework == PythonFramework.MCP:
|
|
317
|
+
if _exists(self.path, "main.py"):
|
|
318
|
+
path = "main.py"
|
|
319
|
+
else:
|
|
320
|
+
path = next(self.path.glob( "**/main.py"))
|
|
321
|
+
if path:
|
|
322
|
+
path = path.relative_to(self.path)
|
|
323
|
+
else:
|
|
324
|
+
path = "main.py"
|
|
325
|
+
start_cmd = f'"python {{}}/bin/mcp run {path} --transport=streamable-http".format(venv[\"serve\"])'
|
|
276
326
|
elif self.framework == PythonFramework.FastHTML:
|
|
277
327
|
if _exists(self.path, "main.py"):
|
|
278
328
|
path = "main:app"
|
|
@@ -300,9 +350,16 @@ class PythonProvider:
|
|
|
300
350
|
def env(self) -> Optional[Dict[str, str]]:
|
|
301
351
|
# For Django projects, generate an empty env dict to surface the field
|
|
302
352
|
# in the Shipit file. Other Python projects omit it by default.
|
|
303
|
-
|
|
304
|
-
"PYTHONPATH": "python_serve_path"
|
|
353
|
+
env_vars = {
|
|
354
|
+
"PYTHONPATH": "python_serve_path",
|
|
355
|
+
"HOME": "app[\"serve\"]"
|
|
305
356
|
}
|
|
357
|
+
if self.framework == PythonFramework.Streamlit:
|
|
358
|
+
env_vars["STREAMLIT_SERVER_HEADLESS"] = '"true"'
|
|
359
|
+
elif self.framework == PythonFramework.MCP:
|
|
360
|
+
env_vars["FASTMCP_HOST"] = "\"0.0.0.0\""
|
|
361
|
+
env_vars["FASTMCP_PORT"] = "\"8000\""
|
|
362
|
+
return env_vars
|
|
306
363
|
|
|
307
364
|
def format_app_import(asgi_application: str) -> str:
|
|
308
365
|
# Transform "mysite.asgi.application" to "mysite.asgi:application" using regex
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|