mirror of
https://github.com/modelscope/modelscope.git
synced 2026-08-29 01:58:59 +02:00
Delegate CLI script ownership to modelscope-hub (#1780)
This commit is contained in:
@@ -1,11 +1,17 @@
|
|||||||
# Copyright (c) Alibaba, Inc. and its affiliates.
|
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||||
"""ModelScope CLI — delegates to the modelscope_hub CLI engine.
|
"""ModelScope CLI — delegates to the modelscope_hub CLI engine.
|
||||||
|
|
||||||
The legacy ``modelscope`` / ``ms`` console-script entry points historically
|
The ``modelscope`` / ``ms`` console scripts historically lived here as a
|
||||||
lived here as a hand-rolled argparse tree. The hub CLI in ``modelscope_hub``
|
hand-rolled argparse tree. ``modelscope_hub`` now owns command registration,
|
||||||
now owns command registration, plugin discovery, and error translation;
|
plugin discovery, error translation *and* the console-script declarations for
|
||||||
this module exists solely to preserve the import path used by the
|
all four aliases (``modelscope``, ``ms``, ``modelscope-hub``, ``ms-hub``), so
|
||||||
``[project.scripts]`` entries in ``pyproject.toml``.
|
that a single distribution writes those files and neither package can strand
|
||||||
|
the other's CLI on upgrade.
|
||||||
|
|
||||||
|
This module stays as the ``python -m modelscope.cli.cli`` entry point and as a
|
||||||
|
stable import path for callers that reference it directly. The commands this
|
||||||
|
package adds on top of the hub CLI are contributed through the
|
||||||
|
``modelscope_hub.cli_plugins`` entry-point group declared in ``pyproject.toml``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -18,14 +18,21 @@ classifiers = [
|
|||||||
'Programming Language :: Python :: 3.9',
|
'Programming Language :: Python :: 3.9',
|
||||||
'Programming Language :: Python :: 3.10',
|
'Programming Language :: Python :: 3.10',
|
||||||
'Programming Language :: Python :: 3.11',
|
'Programming Language :: Python :: 3.11',
|
||||||
|
'Programming Language :: Python :: 3.12',
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://github.com/modelscope/modelscope"
|
Homepage = "https://github.com/modelscope/modelscope"
|
||||||
|
|
||||||
[project.scripts]
|
# No [project.scripts] here on purpose: the `modelscope`, `ms`, `modelscope-hub`
|
||||||
modelscope = "modelscope.cli.cli:run_cmd"
|
# and `ms-hub` console scripts are all owned by the `modelscope-hub`
|
||||||
ms = "modelscope.cli.cli:run_cmd"
|
# distribution that this package depends on. When two distributions declare the
|
||||||
|
# same script name, upgrading or removing either one can overwrite or delete the
|
||||||
|
# other's file and leave the user with no CLI at all; OS packagers such as
|
||||||
|
# FreeBSD pkg reject two ports owning one path outright. This package
|
||||||
|
# contributes its own commands through the plugin group below instead.
|
||||||
|
#
|
||||||
|
# `python -m modelscope.cli.cli` remains available as a direct entry point.
|
||||||
|
|
||||||
[project.entry-points."modelscope_hub.cli_plugins"]
|
[project.entry-points."modelscope_hub.cli_plugins"]
|
||||||
pipeline = "modelscope.cli.pipeline:PipelineCMD"
|
pipeline = "modelscope.cli.pipeline:PipelineCMD"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
filelock
|
filelock
|
||||||
modelscope-hub>=0.2.0
|
modelscope-hub>=0.3.0
|
||||||
packaging
|
packaging
|
||||||
requests>=2.25
|
requests>=2.25
|
||||||
setuptools
|
setuptools
|
||||||
|
|||||||
76
tests/cli/test_cli_entry_points.py
Normal file
76
tests/cli/test_cli_entry_points.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||||
|
"""Guards for CLI console-script ownership.
|
||||||
|
|
||||||
|
Every ModelScope console script (``modelscope``, ``ms``, ``modelscope-hub``,
|
||||||
|
``ms-hub``) is installed by the ``modelscope-hub`` distribution. If this package
|
||||||
|
declared any of them again, the two distributions would fight over the same
|
||||||
|
file: upgrading or uninstalling either one could delete the other's script and
|
||||||
|
leave the user with no CLI, and OS packagers such as FreeBSD pkg refuse to let
|
||||||
|
two ports own one path. These tests keep that arrangement from regressing
|
||||||
|
silently.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PLUGIN_GROUP = 'modelscope_hub.cli_plugins'
|
||||||
|
HUB_DIST = 'modelscope-hub'
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def _pyproject():
|
||||||
|
"""Parse the project metadata, or skip where tomllib is unavailable."""
|
||||||
|
if sys.version_info < (3, 11):
|
||||||
|
# tomllib is stdlib from 3.11; the declaration it reads is not
|
||||||
|
# interpreter-specific, so checking on newer runtimes is enough.
|
||||||
|
raise unittest.SkipTest('stdlib tomllib requires Python 3.11+')
|
||||||
|
import tomllib
|
||||||
|
return tomllib.loads(
|
||||||
|
(REPO_ROOT / 'pyproject.toml').read_text(encoding='utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
class TestConsoleScriptOwnership(unittest.TestCase):
|
||||||
|
"""This package must not declare console scripts of its own."""
|
||||||
|
|
||||||
|
def test_declares_no_console_scripts(self):
|
||||||
|
scripts = _pyproject()['project'].get('scripts', {})
|
||||||
|
self.assertEqual(
|
||||||
|
scripts, {},
|
||||||
|
'Console scripts belong to the modelscope-hub distribution. '
|
||||||
|
'Declaring them here lets either package delete the other side.')
|
||||||
|
|
||||||
|
def test_contributes_commands_as_plugins(self):
|
||||||
|
"""Giving up the scripts only works if the plugin group survives."""
|
||||||
|
entry_points = _pyproject()['project']['entry-points']
|
||||||
|
self.assertIn(PLUGIN_GROUP, entry_points)
|
||||||
|
self.assertTrue(entry_points[PLUGIN_GROUP])
|
||||||
|
|
||||||
|
def test_depends_on_the_script_owner(self):
|
||||||
|
"""The CLI now comes from modelscope-hub, so it cannot be optional."""
|
||||||
|
requirements = (REPO_ROOT / 'requirements'
|
||||||
|
/ 'hub.txt').read_text(encoding='utf-8')
|
||||||
|
self.assertIn(HUB_DIST, requirements)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCliShim(unittest.TestCase):
|
||||||
|
"""``python -m modelscope.cli.cli`` must survive the handover."""
|
||||||
|
|
||||||
|
def test_delegates_to_the_hub_engine(self):
|
||||||
|
from modelscope_hub.cli.main import run_cmd as hub_run_cmd
|
||||||
|
|
||||||
|
from modelscope.cli import cli
|
||||||
|
self.assertIs(cli._run_cmd, hub_run_cmd)
|
||||||
|
|
||||||
|
def test_module_entry_point_still_runs(self):
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, '-m', 'modelscope.cli.cli', '--version'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True)
|
||||||
|
self.assertEqual(result.returncode, 0)
|
||||||
|
self.assertIn('modelscope', result.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user