Skip to content

Refactor pip install#1109

Merged
Caozhou1995 merged 6 commits intoflagos-ai:mainfrom
aoyulong:main
Feb 10, 2026
Merged

Refactor pip install#1109
Caozhou1995 merged 6 commits intoflagos-ai:mainfrom
aoyulong:main

Conversation

@aoyulong
Copy link
Copy Markdown
Contributor

@aoyulong aoyulong commented Feb 6, 2026

PR Category

Tools

PR Types

Improvements

PR Description

Refactor the installation process for FlagScale to make it easier for users to install with pip.
FLAGSCALE_PLATFORM=cuda FLAGSCALE_TASK=train pip install --no-build-isolation . -vvv

dynamic = ["dependencies"]

[project.urls]
Homepage = "https://github.com/flagos-ai/FlagScale"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why we changed the url to FlagOpen.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xmhubj No. We should use flagos-ai.

setup.py Outdated
return result

# Version is defined in pyproject.toml - keep in sync
FLAGSCALE_VERSION = "1.0.0"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to get the version from pyproject.toml


setup(
name="flag_scale",
name="flagscale",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the FlagScale installation process to streamline pip-based installations and modernize the CLI framework. The changes enable users to install FlagScale with FLAGSCALE_PLATFORM=cuda FLAGSCALE_TASK=train pip install --no-build-isolation ., providing a more standard Python packaging experience.

Changes:

  • Renamed package from "flag_scale" to "flagscale" with simplified package structure
  • Migrated CLI framework from click to typer for better type safety and modern Python practices
  • Introduced --only-pip installation mode to skip apt packages and source builds
  • Refactored setup.py to conditionally run install.sh based on build isolation detection
  • Consolidated version management (now defined in pyproject.toml, setup.py, and flagscale/init.py)

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
version.py Removed - version now managed in pyproject.toml and flagscale/init.py
init.py Removed - no longer needed at repository root
.coveragerc Removed configuration file
pyproject.toml Updated package name to "flagscale", removed nonexistent pip version constraint, simplified configuration
setup.py Complete rewrite to support conditional installation based on build isolation, now only includes minimal dependencies
flagscale/init.py New file managing version with fallback mechanism using importlib.metadata
flagscale/cli.py Complete rewrite using typer instead of click, added new run command and improved command structure
flagscale/run.py New file extracting core logic from root run.py for modular imports
run.py Refactored as backward compatibility wrapper importing from flagscale.run
requirements/common.txt Added typer>=0.9.0 for CLI framework
tools/install/install.sh Added --only-pip flag with documentation and examples
tools/install/utils/pkg_utils.sh Implemented is_only_pip() and updated should_install_src() to respect --only-pip mode
tools/install/install_dev.sh Added only-pip mode check in install_src()
tools/install/cuda/install_base.sh Added only-pip mode check to skip apt packages
tools/install/cuda/install_train.sh Added only-pip mode check in install_src()
tools/install/cuda/install_serve.sh Added only-pip mode check in install_src()
flagscale/train/megatron/training/training.py Added eval_iters parameter to evaluate() function signature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

setup.py Outdated
Comment on lines +60 to +62
result = subprocess.run(cmd, check=False)
if result.returncode != 0:
raise RuntimeError(f"Installation failed with exit code {result.returncode}")
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subprocess.run() call uses check=False and then manually raises an exception if returncode != 0. This bypasses Python's standard error handling. Either use check=True to let CalledProcessError be raised automatically, or if you need custom error handling, consider capturing stdout/stderr for better error messages.

Suggested change
result = subprocess.run(cmd, check=False)
if result.returncode != 0:
raise RuntimeError(f"Installation failed with exit code {result.returncode}")
try:
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as exc:
raise RuntimeError(f"Installation failed with exit code {exc.returncode}") from exc

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +52
args = [
"run.py",
f"--config-path={config_path}",
f"--config-name={config_name}",
f"action={action}",
]
if extra_args:
args.extend(extra_args)
sys.argv = args
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The run_task function sets sys.argv[0] to "run.py" which doesn't match the actual command being invoked ("flagscale"). This could cause issues with error messages or help text that reference sys.argv[0]. Consider using a more accurate argv[0] value like "flagscale" or the actual task name.

Copilot uses AI. Check for mistakes.
Comment on lines +115 to 126
args = [
"flagscale",
f"--config-path={config_path}",
f"--config-name={config_name}",
f"action={action.value}",
]
if overrides:
args.extend(overrides)

typer.echo(f"Running: {' '.join(args)}")
sys.argv = args
run_main()
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "run" command uses sys.argv[0] = "flagscale" at line 116, which is inconsistent with the run_task helper function that uses "run.py". This inconsistency could lead to confusion. Standardize on one approach throughout the CLI implementation.

Copilot uses AI. Check for mistakes.
flagscale/cli.py Outdated
stop: bool = typer.Option(False, "--stop", help="Stop serving"),
test: bool = typer.Option(False, "--test", help="Test serving"),
tune: bool = typer.Option(False, "--tune", help="Auto-tune"),
port: int | None = typer.Option(None, "--port", "-p", help="Server port"),
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter name "port" conflicts with the typer.Option() name. In the serve() function, the parameter is named "port" but the option flag is also "-p" (short for --port), which could be confused with --config's "-c" flag. Consider using a different short flag like "-P" for port to avoid confusion, or remove the short flag entirely since --port is self-explanatory.

Suggested change
port: int | None = typer.Option(None, "--port", "-p", help="Server port"),
port: int | None = typer.Option(None, "--port", help="Server port"),

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +82
packages=["flagscale"],
package_dir={"flagscale": "flagscale"},
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setup function only declares a single package "flagscale", but this may not include all subpackages. Consider using setuptools.find_packages() or explicitly listing all subpackages (like flagscale.train, flagscale.serve, etc.) to ensure all modules are properly packaged. The current configuration relies on pyproject.toml's package-finding, but setup.py should be self-contained for backward compatibility.

Copilot uses AI. Check for mistakes.
verbose=False,
non_loss_data_func=None,
extra_valid_index=None,
eval_iters=None,
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The eval_iters parameter is added to the function signature but never used in the function body. This creates dead code and potential confusion. Either implement the logic to use eval_iters within the function, or remove the parameter if it's not needed.

Copilot uses AI. Check for mistakes.
pyproject.toml Outdated
include = ["flagscale*"]

[tool.setuptools.package-data]
"*" = ["*.yaml", "*.yml"]
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package_data configuration in pyproject.toml uses a wildcard "" to match all packages and include ".yaml" and ".yml" files. This is overly broad and will include YAML files from all packages, not just flagscale. Consider being more specific with the package selector, e.g., "flagscale" = [".yaml", "*.yml"] to only include YAML files from the flagscale package.

Suggested change
"*" = ["*.yaml", "*.yml"]
"flagscale" = ["*.yaml", "*.yml"]

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +10
from importlib.metadata import version as get_version

__version__ = get_version("flagscale")
except Exception:
pass # Use hardcoded version above
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bare except clause on line 9 catches all exceptions including SystemExit and KeyboardInterrupt, which is generally not recommended. This could mask important errors during import. Consider catching specific exceptions like PackageNotFoundError or ImportError instead, or at minimum use "except Exception:" to avoid catching system-level exceptions.

Suggested change
from importlib.metadata import version as get_version
__version__ = get_version("flagscale")
except Exception:
pass # Use hardcoded version above
from importlib.metadata import PackageNotFoundError, version as get_version
except ImportError:
# importlib.metadata not available; use hardcoded version above
pass
else:
try:
__version__ = get_version("flagscale")
except PackageNotFoundError:
# Package metadata not found; use hardcoded version above
pass

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +68
def get_action(stop: bool, dryrun: bool, test: bool, query: bool, tune: bool) -> str:
"""Determine action from flags (mutually exclusive)"""
if stop:
return "stop"
if dryrun:
return "dryrun"
if test:
return "test"
if query:
return "query"
if tune:
return "auto_tune"
return "run" # default
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_action() function doesn't validate that the boolean flags are mutually exclusive. If multiple flags are set (e.g., both --stop and --dryrun), the function will just return the first matching one based on the if-chain order. Consider adding validation to ensure only one action flag is set at a time, or document the priority order clearly.

Copilot uses AI. Check for mistakes.
setup.py Outdated
Comment on lines +6 to +7
# Version is defined in pyproject.toml - keep in sync
FLAGSCALE_VERSION = "1.0.0"
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version is hardcoded in three places (setup.py line 7, pyproject.toml line 10, and flagscale/init.py line 2), which creates a maintenance burden. Consider having setup.py and flagscale/init.py read the version from pyproject.toml to maintain a single source of truth. This could use importlib.metadata or parse pyproject.toml directly.

Copilot uses AI. Check for mistakes.
lxd-cumt
lxd-cumt previously approved these changes Feb 6, 2026
Copy link
Copy Markdown
Collaborator

@lxd-cumt lxd-cumt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for training.py

@tengqm
Copy link
Copy Markdown
Contributor

tengqm commented Feb 6, 2026

Instead of having users to customize an installation by specifying environment variables, we can leverage the builtin mechanism in pyproject.toml. Say, we have

[project]
dependencies = [
  "foo==1.2.3",
  "core==2.4.0",
]

[project.optional-dependencies]
inference = [
  "vllm==3.4.0",
  "blah==2.3",
]

serve = [
  "flag-scale[inference]",
  "flask==1.0.3"
]

train = [
  "megatron-lm-fl==0.1.0",
  "..."
]

You can easily install flag-scale for different scenarios using the following commands:

  • pip install flag-scale[inference]
  • pip install flag-scale[train]
  • pip install flag-scale[serve]

This is much simpler than writing our own Python code.

@tengqm
Copy link
Copy Markdown
Contributor

tengqm commented Feb 6, 2026

PR #1078 was proposed exactly for simplify the installation process using declared dependencies. It can serve as a starting point for further revisions such as a better grouping of dependencies based on usage scenarios; a clearer dependency on the various -FL plugins provided those projects have their own release tags ...

@aoyulong
Copy link
Copy Markdown
Contributor Author

aoyulong commented Feb 9, 2026

Instead of having users to customize an installation by specifying environment variables, we can leverage the builtin mechanism in pyproject.toml. Say, we have

[project]
dependencies = [
  "foo==1.2.3",
  "core==2.4.0",
]

[project.optional-dependencies]
inference = [
  "vllm==3.4.0",
  "blah==2.3",
]

serve = [
  "flag-scale[inference]",
  "flask==1.0.3"
]

train = [
  "megatron-lm-fl==0.1.0",
  "..."
]

You can easily install flag-scale for different scenarios using the following commands:

  • pip install flag-scale[inference]
  • pip install flag-scale[train]
  • pip install flag-scale[serve]

This is much simpler than writing our own Python code.

This is our ultimate goal.

@aoyulong aoyulong requested a review from Darryl233 February 10, 2026 02:06
@Caozhou1995 Caozhou1995 merged commit da4dc54 into flagos-ai:main Feb 10, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants