shipit-cli 0.4.1__py3-none-any.whl → 0.5.1__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.
shipit/cli.py CHANGED
@@ -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
- copytree(
503
- (self.src_dir / step.source),
504
- (build_path / step.target),
505
- dirs_exist_ok=True,
506
- ignore=ignore_patterns(*ignore_matches),
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
- elif "fastapi" in found_deps:
116
- framework = PythonFramework.FastAPI
117
- elif "flask" in found_deps:
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,23 +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
- extra_deps = ", ".join([f"{dep}" for dep in self.extra_dependencies])
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" + extra_args + "\", inputs=[" + inputs + "], group=\"install\")",
221
+ f"run(f\"uv sync --compile --python python{{python_version}} --no-managed-python{extra_args}\", inputs=[{inputs}], group=\"install\")",
214
222
  "copy(\"pyproject.toml\", \"pyproject.toml\")",
215
223
  f"run(\"uv add {extra_deps}\", group=\"install\")" if extra_deps else None,
216
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",
217
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",
218
226
  "run(\"rm cross-requirements.txt\") if cross_platform else None",
219
- ]))
227
+ ]
220
228
  if _exists(self.path, "requirements.txt"):
221
229
  steps += [
222
230
  "env(UV_PROJECT_ENVIRONMENT=local_venv[\"build\"] if cross_platform else venv[\"build\"])",
223
- "run(f\"uv init --no-managed-python --python python{python_version}\", inputs=[], outputs=[\"uv.lock\"], group=\"install\")",
224
- "run(f\"uv add -r requirements.txt\", inputs=[\"requirements.txt\"], group=\"install\")",
231
+ "run(f\"uv init --no-workspace --no-managed-python --python python{python_version}\", inputs=[], outputs=[\"uv.lock\"], group=\"install\")",
232
+ f"run(\"uv add -r requirements.txt {extra_deps}\", inputs=[\"requirements.txt\"], group=\"install\")",
225
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",
226
- "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",
227
235
  "run(\"rm cross-requirements.txt\") if cross_platform else None",
228
236
  ]
229
237
 
@@ -231,7 +239,12 @@ class PythonProvider:
231
239
  "path((local_venv[\"build\"] if cross_platform else venv[\"build\"]) + \"/bin\")",
232
240
  "copy(\".\", \".\", ignore=[\".venv\", \".git\", \"__pycache__\"])",
233
241
  ]
234
- return steps
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))
235
248
 
236
249
  def prepare_steps(self) -> Optional[list[str]]:
237
250
  return [
@@ -274,6 +287,42 @@ class PythonProvider:
274
287
  else:
275
288
  start_cmd = '"python -c \'print(\\\"No start command detected, please provide a start command manually\\\")\'"'
276
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\"])'
277
326
  elif self.framework == PythonFramework.FastHTML:
278
327
  if _exists(self.path, "main.py"):
279
328
  path = "main:app"
@@ -301,9 +350,16 @@ class PythonProvider:
301
350
  def env(self) -> Optional[Dict[str, str]]:
302
351
  # For Django projects, generate an empty env dict to surface the field
303
352
  # in the Shipit file. Other Python projects omit it by default.
304
- return {
305
- "PYTHONPATH": "python_serve_path"
353
+ env_vars = {
354
+ "PYTHONPATH": "python_serve_path",
355
+ "HOME": "app[\"serve\"]"
306
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
307
363
 
308
364
  def format_app_import(asgi_application: str) -> str:
309
365
  # Transform "mysite.asgi.application" to "mysite.asgi:application" using regex
shipit/version.py CHANGED
@@ -1,5 +1,5 @@
1
1
  __all__ = ["version", "version_info"]
2
2
 
3
3
 
4
- version = "0.4.1"
5
- version_info = (0, 4, 1, "final", 0)
4
+ version = "0.5.1"
5
+ version_info = (0, 5, 1, "final", 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shipit-cli
3
- Version: 0.4.1
3
+ Version: 0.5.1
4
4
  Summary: Add your description here
5
5
  Project-URL: homepage, https://wasmer.io
6
6
  Project-URL: repository, https://github.com/wasmerio/shipit
@@ -1,7 +1,7 @@
1
1
  shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- shipit/cli.py,sha256=5b5e1H-SscXBraZXxJ5cVs_IJSNqjWUt2IjcZtOdALE,49615
2
+ shipit/cli.py,sha256=BdkuFvLD3MCTs0nXw3DDOIMkJ4p4eohH3v2jfgFRXeg,49849
3
3
  shipit/generator.py,sha256=4pezEo4OzpDFSFqiFpGCpdwo72VkItS490R_f2rIz2k,5755
4
- shipit/version.py,sha256=snMorrRb7vcsXgkcL5T056NoRLUWbc6L5Mope2nDAbU,95
4
+ shipit/version.py,sha256=hST8ZDPXWcVn83WCgIB61TSxClfCr1MtDM7hisBESS8,95
5
5
  shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
6
6
  shipit/providers/base.py,sha256=a_5VA1tV4_QbH83yjPCTHsNR23EJT2CiKUpWA_pu_lo,2373
7
7
  shipit/providers/gatsby.py,sha256=uwNjIJloS9JwKXqkbhihgdTTpJL4iL4bLCZ5kuzqqNs,2138
@@ -10,10 +10,10 @@ shipit/providers/laravel.py,sha256=rDpfx7RyF4sK0xxDAWefX0IiguU2xdgEXP2jJp1Jdzo,2
10
10
  shipit/providers/mkdocs.py,sha256=QJFNt7QWMvYbWeo7WjOgFVKGVcdUnUmUNfFbe4c8ThM,2812
11
11
  shipit/providers/node_static.py,sha256=K55BXkNz4QXSXR2wdg5diP6HLpmksC70ph16zox7v6Y,2309
12
12
  shipit/providers/php.py,sha256=Hmtv47K5qtYbQ3v9SSk-_KTNlhXedStg2MxhTTOK9ac,2594
13
- shipit/providers/python.py,sha256=nupUuxNV4n-F-vaDbJLZd_O7cChs2ZNZhdAYR611VCg,13436
13
+ shipit/providers/python.py,sha256=HFH9cFoPvSuJbkVzU0VspFYhOB3X1_IBoi-LodxSHOg,16159
14
14
  shipit/providers/registry.py,sha256=UisII1dr24ZxmDD8GnpTsyNwPN9W8MnAHQ1Px1iJ-OQ,661
15
15
  shipit/providers/staticfile.py,sha256=Y4oqw6dNDU2crzcWQ5SEgnXHoDy0CXRntABwlgdf1mo,1827
16
- shipit_cli-0.4.1.dist-info/METADATA,sha256=tSa032WmxWchuT6sbwTZPH3xeO5mH5ZWZgReEj780eE,462
17
- shipit_cli-0.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- shipit_cli-0.4.1.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
19
- shipit_cli-0.4.1.dist-info/RECORD,,
16
+ shipit_cli-0.5.1.dist-info/METADATA,sha256=CCYO1muggGxpLHIW_oS_dod1zGJO89CXCTG0lO3vOrE,462
17
+ shipit_cli-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ shipit_cli-0.5.1.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
19
+ shipit_cli-0.5.1.dist-info/RECORD,,