diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 1a842c4ea7..80cae43a7f 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -14,8 +14,6 @@ jobs:
- typer-slim
- typer
- typer-cli
- env:
- dir: ${{ matrix.package == 'typer-slim' && './' || matrix.package == 'typer' && 'typer_package' || matrix.package == 'typer-cli' && 'typer_cli_package' }}
permissions:
id-token: write
steps:
@@ -34,9 +32,8 @@ jobs:
- name: Install build dependencies
run: pip install build
- name: Build distribution
- working-directory: ${{ env.dir }}
+ env:
+ TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }}
run: python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@v1.8.11
- with:
- packages-dir: ${{ env.dir }}/dist/
diff --git a/.github/workflows/test-redistribute.yml b/.github/workflows/test-redistribute.yml
index c16d19d7b4..d2a33d30e2 100644
--- a/.github/workflows/test-redistribute.yml
+++ b/.github/workflows/test-redistribute.yml
@@ -18,8 +18,6 @@ jobs:
- typer-slim
- typer
- typer-cli
- env:
- dir: ${{ matrix.package == 'typer-slim' && './' || matrix.package == 'typer' && 'typer_package' || matrix.package == 'typer-cli' && 'typer_cli_package' }}
steps:
- name: Dump GitHub context
env:
@@ -36,25 +34,24 @@ jobs:
- name: Install build dependencies
run: pip install build
- name: Build source distribution
- working-directory: ${{ env.dir }}
+ env:
+ TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }}
run: python -m build --sdist
- name: Decompress source distribution
- working-directory: ${{ env.dir }}
run: |
cd dist
tar xvf typer*.tar.gz
- name: Install test dependencies
- if: ${{ matrix.package == 'typer-slim' }}
+ if: ${{ matrix.package != 'typer-cli' }}
run: |
cd dist/typer*/
pip install -r requirements-tests.txt
- name: Run source distribution tests
- if: ${{ matrix.package == 'typer-slim' }}
+ if: ${{ matrix.package != 'typer-cli' }}
run: |
cd dist/typer*/
bash scripts/test.sh
- name: Build wheel distribution
- working-directory: ${{ env.dir }}
run: |
cd dist
pip wheel --no-deps typer*.tar.gz
diff --git a/README.md b/README.md
index 0d4d824aa1..6bb4983a9f 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ The key features are:
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
* **Start simple**: The simplest example adds only 2 lines of code to your app: **1 import, 1 function call**.
* **Grow large**: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.
-* **Run scripts**: Typer includes a `typer` command that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.
+* **Run scripts**: Typer includes a `typer` command/program that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.
## FastAPI of CLIs
@@ -355,13 +355,10 @@ By default it also comes with extra standard dependencies:
* shellingham
: to automatically detect the current shell when installing completion.
* With `shellingham` you can just use `--install-completion`.
* Without `shellingham`, you have to pass the name of the shell to install completion for, e.g. `--install-completion bash`.
-* `typer-cli`: adds the `typer` command to your shell:
- * Quickly run scripts (that don't have to use Typer) with shell completion.
- * Generate docs for your Typer applications.
### `typer-slim`
-If you don't want the extra dependencies, install `typer-slim` instead.
+If you don't want the extra standard optional dependencies, install `typer-slim` instead.
When you install with:
@@ -369,15 +366,15 @@ When you install with:
pip install typer
```
-...it's the equivalent of:
+...it includes the same code and dependencies as:
```bash
pip install "typer-slim[standard]"
```
-The `standard` extra dependencies are `rich`, `shellingham`, `typer-cli`.
+The `standard` extra dependencies are `rich` and `shellingham`.
-**Note**: even if you don't install `typer-cli` you can still use it's functionality by calling `typer` as a module, e.g. `python -m typer`.
+**Note**: The `typer` command is only included in the `typer` package.
## License
diff --git a/docs/index.md b/docs/index.md
index 0d4d824aa1..6bb4983a9f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -37,7 +37,7 @@ The key features are:
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
* **Start simple**: The simplest example adds only 2 lines of code to your app: **1 import, 1 function call**.
* **Grow large**: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.
-* **Run scripts**: Typer includes a `typer` command that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.
+* **Run scripts**: Typer includes a `typer` command/program that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.
## FastAPI of CLIs
@@ -355,13 +355,10 @@ By default it also comes with extra standard dependencies:
* shellingham
: to automatically detect the current shell when installing completion.
* With `shellingham` you can just use `--install-completion`.
* Without `shellingham`, you have to pass the name of the shell to install completion for, e.g. `--install-completion bash`.
-* `typer-cli`: adds the `typer` command to your shell:
- * Quickly run scripts (that don't have to use Typer) with shell completion.
- * Generate docs for your Typer applications.
### `typer-slim`
-If you don't want the extra dependencies, install `typer-slim` instead.
+If you don't want the extra standard optional dependencies, install `typer-slim` instead.
When you install with:
@@ -369,15 +366,15 @@ When you install with:
pip install typer
```
-...it's the equivalent of:
+...it includes the same code and dependencies as:
```bash
pip install "typer-slim[standard]"
```
-The `standard` extra dependencies are `rich`, `shellingham`, `typer-cli`.
+The `standard` extra dependencies are `rich` and `shellingham`.
-**Note**: even if you don't install `typer-cli` you can still use it's functionality by calling `typer` as a module, e.g. `python -m typer`.
+**Note**: The `typer` command is only included in the `typer` package.
## License
diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md
index 6fb8075c87..6cec65fe23 100644
--- a/docs/tutorial/index.md
+++ b/docs/tutorial/index.md
@@ -68,12 +68,12 @@ The first step is to install **Typer**:
```console
$ pip install typer
---> 100%
-Successfully installed typer click shellingham rich typer-cli
+Successfully installed typer click shellingham rich
```
-By default, `typer` comes with `rich`, `shellingham`, and `typer-cli`.
+By default, `typer` comes with `rich` and `shellingham`.
!!! note
If you are an advanced user and want to opt out of these default extra dependencies, you can instead install `typer-slim`.
@@ -82,7 +82,7 @@ By default, `typer` comes with `rich`, `shellingham`, and `typer-cli`.
pip install typer
```
- ...is the equivalent of:
+ ...includes the same optional dependencies as:
```bash
pip install "typer-slim[standard]"
diff --git a/pdm_build.py b/pdm_build.py
new file mode 100644
index 0000000000..4629801f0e
--- /dev/null
+++ b/pdm_build.py
@@ -0,0 +1,55 @@
+import os
+from typing import Any, Dict, List
+
+from pdm.backend.hooks import Context
+
+TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "typer")
+
+
+def pdm_build_initialize(context: Context):
+ metadata = context.config.metadata
+ # Get main version
+ version = metadata["version"]
+ # Get package names to keep in sync with the same main version
+ sync_dependencies: List[str] = context.config.data["tool"]["tiangolo"][
+ "_internal-slim-build"
+ ]["sync-dependencies"]
+ # Get custom config for the current package, from the env var
+ config: Dict[str, Any] = context.config.data["tool"]["tiangolo"][
+ "_internal-slim-build"
+ ]["packages"][TIANGOLO_BUILD_PACKAGE]
+ project_config: Dict[str, Any] = config["project"]
+ # Get main optional dependencies, extras
+ optional_dependencies: Dict[str, List[str]] = metadata.get(
+ "optional-dependencies", {}
+ )
+ # Get custom optional dependencies name to always include in this (non-slim) package
+ include_optional_dependencies: List[str] = config.get(
+ "include-optional-dependencies", []
+ )
+ # Override main [project] configs with custom configs for this package
+ for key, value in project_config.items():
+ metadata[key] = value
+ # Get custom build config for the current package
+ build_config: Dict[str, Any] = (
+ config.get("tool", {}).get("pdm", {}).get("build", {})
+ )
+ # Override PDM build config with custom build config for this package
+ for key, value in build_config.items():
+ context.config.build_config[key] = value
+ # Get main dependencies
+ dependencies: List[str] = metadata.get("dependencies", [])
+ # Add optional dependencies to the default dependencies for this (non-slim) package
+ for include_optional in include_optional_dependencies:
+ optional_dependencies_group = optional_dependencies.get(include_optional, [])
+ dependencies.extend(optional_dependencies_group)
+ # Sync versions in dependencies
+ new_dependencies = []
+ for dep in dependencies:
+ if dep in sync_dependencies:
+ new_dep = f"{dep}=={version}"
+ new_dependencies.append(new_dep)
+ else:
+ new_dependencies.append(dep)
+ if new_dependencies != dependencies:
+ metadata["dependencies"] = new_dependencies
diff --git a/pyproject.toml b/pyproject.toml
index f5abe95d3c..b648d38ad4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,15 +3,12 @@ requires = ["pdm-backend"]
build-backend = "pdm.backend"
[project]
-# pip install typer-slim: is only the Typer library, without extras
-# pip install typer: is typer-slim[standard], with extras and typer-cli
-name = "typer-slim"
+name = "typer"
dynamic = ["version"]
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
authors = [
{name = "Sebastián Ramírez", email = "tiangolo@gmail.com"},
]
-readme = "README.md"
requires-python = ">=3.7"
classifiers = [
"Intended Audience :: Information Technology",
@@ -38,16 +35,12 @@ dependencies = [
"click >= 8.0.0",
"typing-extensions >= 3.7.4.3",
]
-
+readme = "README.md"
[project.urls]
Documentation = "https://typer.tiangolo.com/"
homepage = "https://github.com/tiangolo/typer"
[project.optional-dependencies]
-all = [
- "shellingham >=1.3.0",
- "rich >=10.11.0",
-]
standard = [
"shellingham >=1.3.0",
"rich >=10.11.0",
@@ -65,6 +58,50 @@ source-includes = [
"scripts/",
]
+[tool.tiangolo._internal-slim-build]
+sync-dependencies = [
+ "typer-slim[standard]",
+ "typer-cli",
+ "typer"
+]
+
+[tool.tiangolo._internal-slim-build.packages.typer-slim.project]
+name = "typer-slim"
+
+[tool.tiangolo._internal-slim-build.packages.typer]
+include-optional-dependencies = ["standard"]
+
+[tool.tiangolo._internal-slim-build.packages.typer.project]
+optional-dependencies = {}
+
+[tool.tiangolo._internal-slim-build.packages.typer.project.scripts]
+typer = "typer.cli:main"
+
+[tool.tiangolo._internal-slim-build.packages.typer-cli.project]
+name = "typer-cli"
+readme = "typer-cli/README.md"
+dependencies = [
+ "typer",
+]
+optional-dependencies = {}
+
+[tool.tiangolo._internal-slim-build.packages.typer-cli.tool.pdm.build]
+# excludes needs to explicitly exclude the top level python packages,
+# otherwise PDM includes them by default
+# A "*" glob pattern can't be used here because in PDM internals, the patterns are put
+# in a set (unordered, order varies) and each excluded file is assigned one of the
+# glob patterns that matches, as the set is unordered, the matched pattern could be "*"
+# independent of the order here. And then the internal code would give it a lower score
+# than the one for a default included file.
+# By not using "*" and explicitly excluding the top level packages, they get a higher
+# score than the default inclusion
+excludes = ["typer", "tests", "pdm_build.py"]
+# source-includes needs to explicitly define some value because PDM will check the
+# truthy value of the list, and if empty, will include some defaults, including "tests",
+# an empty string doesn't match anything, but makes the list truthy, so that PDM
+# doesn't override it during the build.
+source-includes = [""]
+
[tool.isort]
profile = "black"
known_third_party = ["typer", "click"]
diff --git a/typer_cli_package/README.md b/typer-cli/README.md
similarity index 82%
rename from typer_cli_package/README.md
rename to typer-cli/README.md
index dba1a0dcf7..0ebe65102c 100644
--- a/typer_cli_package/README.md
+++ b/typer-cli/README.md
@@ -30,9 +30,13 @@ Typer is a library for building =3.7"
-classifiers = [
- "Intended Audience :: Information Technology",
- "Intended Audience :: System Administrators",
- "Operating System :: OS Independent",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python",
- "Topic :: Software Development :: Libraries :: Application Frameworks",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Topic :: Software Development :: Libraries",
- "Topic :: Software Development",
- "Typing :: Typed",
- "Development Status :: 4 - Beta",
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "License :: OSI Approved :: MIT License",
-]
-dependencies = [
- "typer-slim[standard]",
-]
-
-[project.urls]
-Documentation = "https://typer.tiangolo.com/"
-homepage = "https://github.com/tiangolo/typer"
-
-[project.optional-dependencies]
-# For backwards compatibility
-all = []
-
-[project.scripts]
-typer = "typer.cli:main"
-
-[tool.pdm]
-version = { source = "file", path = "../typer/__init__.py" }
-distribution = true
-
-[tool.pdm.build]
-excludes = ["*"]
diff --git a/typer_package/pdm_build.py b/typer_package/pdm_build.py
deleted file mode 100644
index b670aa9504..0000000000
--- a/typer_package/pdm_build.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from pathlib import Path
-from typing import List
-
-from pdm.backend.hooks import Context
-
-packages_to_sync = ["typer-slim", "typer-cli"]
-
-readme_name = "README.md"
-license_name = "LICENSE"
-readme_path = Path("..") / readme_name
-license_path = Path("..") / license_name
-
-
-def pdm_build_hook_enabled(context: Context):
- return context.target == "sdist"
-
-
-def pdm_build_initialize(context: Context):
- metadata = context.config.metadata
- # Get main version
- version = metadata["version"]
- # Update version in dependencies to sync them
- dependencies: List[str] = metadata["dependencies"]
- new_dependencies = []
- for dep in dependencies:
- if any(dep.startswith(name) for name in packages_to_sync):
- new_dep = f"{dep}=={version}"
- new_dependencies.append(new_dep)
- else:
- new_dependencies.append(dep)
- if new_dependencies != dependencies:
- metadata["dependencies"] = new_dependencies
- # README.md and LICENSE
- readme_content = readme_path.read_text()
- license_content = license_path.read_text()
- metadata["readme"] = readme_name
- context.ensure_build_dir()
- # Copy README.md and LICENSE to build directory
- # (context.build_dir / readme_name).write_text(readme_content)
- # (context.build_dir / license_name).write_text(license_content)
- # # Workaround, copy README.md and LICENSE to package_dir during build
- Path(readme_name).write_text(readme_content)
- Path(license_name).write_text(license_content)
-
-
-def pdm_build_finalize(context: Context, artifact: Path):
- # Workaround, remove README.md and LICENSE from package_dir after build
- Path(readme_name).unlink()
- Path(license_name).unlink()
diff --git a/typer_package/pyproject.toml b/typer_package/pyproject.toml
deleted file mode 100644
index c2f3f45bfa..0000000000
--- a/typer_package/pyproject.toml
+++ /dev/null
@@ -1,52 +0,0 @@
-[build-system]
-requires = ["pdm-backend"]
-build-backend = "pdm.backend"
-
-[project]
-name = "typer"
-dynamic = ["version"]
-description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
-authors = [
- {name = "Sebastián Ramírez", email = "tiangolo@gmail.com"},
-]
-requires-python = ">=3.7"
-classifiers = [
- "Intended Audience :: Information Technology",
- "Intended Audience :: System Administrators",
- "Operating System :: OS Independent",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python",
- "Topic :: Software Development :: Libraries :: Application Frameworks",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Topic :: Software Development :: Libraries",
- "Topic :: Software Development",
- "Typing :: Typed",
- "Development Status :: 4 - Beta",
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "License :: OSI Approved :: MIT License",
-]
-dependencies = [
- "typer-slim[standard]",
- "typer-cli",
-]
-
-[project.urls]
-Documentation = "https://typer.tiangolo.com/"
-homepage = "https://github.com/tiangolo/typer"
-
-[project.optional-dependencies]
-# For backwards compatibility
-all = []
-
-[tool.pdm]
-version = { source = "file", path = "../typer/__init__.py" }
-distribution = true
-
-[tool.pdm.build]
-excludes = ["*"]