pytailwindcss 0.4.1__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.
- pytailwindcss-0.4.1/.github/dependabot.yml +12 -0
- pytailwindcss-0.4.1/.github/workflows/ci.yml +83 -0
- pytailwindcss-0.4.1/.github/zizmor.yml +6 -0
- pytailwindcss-0.4.1/.gitignore +147 -0
- pytailwindcss-0.4.1/.pre-commit-config.yaml +42 -0
- pytailwindcss-0.4.1/CHANGELOG.md +36 -0
- pytailwindcss-0.4.1/LICENSE +21 -0
- pytailwindcss-0.4.1/PKG-INFO +193 -0
- pytailwindcss-0.4.1/README.md +166 -0
- pytailwindcss-0.4.1/pyproject.toml +89 -0
- pytailwindcss-0.4.1/src/pytailwindcss/__init__.py +68 -0
- pytailwindcss-0.4.1/src/pytailwindcss/__main__.py +36 -0
- pytailwindcss-0.4.1/src/pytailwindcss/exceptions.py +14 -0
- pytailwindcss-0.4.1/src/pytailwindcss/installation.py +167 -0
- pytailwindcss-0.4.1/src/pytailwindcss/py.typed +0 -0
- pytailwindcss-0.4.1/src/pytailwindcss/utils.py +63 -0
- pytailwindcss-0.4.1/tests/__init__.py +0 -0
- pytailwindcss-0.4.1/tests/conftest.py +26 -0
- pytailwindcss-0.4.1/tests/fakes.py +41 -0
- pytailwindcss-0.4.1/tests/test_core.py +83 -0
- pytailwindcss-0.4.1/tests/test_installation.py +234 -0
- pytailwindcss-0.4.1/tests/test_main.py +96 -0
- pytailwindcss-0.4.1/tests/test_utils.py +92 -0
- pytailwindcss-0.4.1/uv.lock +743 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
pre-commit:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
with:
|
|
21
|
+
persist-credentials: false
|
|
22
|
+
- uses: astral-sh/setup-uv@v10.3.0
|
|
23
|
+
with:
|
|
24
|
+
python-version: '3.14'
|
|
25
|
+
- run: uvx pre-commit run --all-files --show-diff-on-failure
|
|
26
|
+
|
|
27
|
+
tests:
|
|
28
|
+
needs: [ pre-commit ]
|
|
29
|
+
runs-on: ${{ matrix.os }}
|
|
30
|
+
strategy:
|
|
31
|
+
fail-fast: false
|
|
32
|
+
matrix:
|
|
33
|
+
os: [ ubuntu-latest ]
|
|
34
|
+
python-version: [ "3.11", "3.12", "3.13", "3.14" ]
|
|
35
|
+
include:
|
|
36
|
+
# Binary selection is OS-specific, so the newest Python also runs on macOS and Windows.
|
|
37
|
+
- os: macos-latest
|
|
38
|
+
python-version: "3.14"
|
|
39
|
+
- os: windows-latest
|
|
40
|
+
python-version: "3.14"
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v7
|
|
43
|
+
with:
|
|
44
|
+
persist-credentials: false
|
|
45
|
+
- uses: astral-sh/setup-uv@v10.3.0
|
|
46
|
+
with:
|
|
47
|
+
python-version: ${{ matrix.python-version }}
|
|
48
|
+
- run: uv sync --locked
|
|
49
|
+
- run: uv run pytest --cov --cov-report=term
|
|
50
|
+
|
|
51
|
+
tests-alpine:
|
|
52
|
+
needs: [ pre-commit ]
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v7
|
|
56
|
+
with:
|
|
57
|
+
persist-credentials: false
|
|
58
|
+
# JavaScript actions can't run inside Alpine containers (the runner's Node is glibc-only),
|
|
59
|
+
# so the musl test run happens through a plain `docker run`. Tailwind's musl builds link
|
|
60
|
+
# against libstdc++ and libgcc, which Alpine doesn't ship by default.
|
|
61
|
+
- run: >-
|
|
62
|
+
docker run --rm -v "$PWD:/src" -w /src -e UV_PYTHON_DOWNLOADS=never python:3.14-alpine
|
|
63
|
+
sh -c "apk add --no-cache libstdc++ libgcc && pip install --root-user-action=ignore uv && uv sync --locked && uv run pytest"
|
|
64
|
+
|
|
65
|
+
release:
|
|
66
|
+
needs: [ tests, tests-alpine ]
|
|
67
|
+
if: success() && startsWith(github.ref, 'refs/tags/')
|
|
68
|
+
runs-on: ubuntu-24.04
|
|
69
|
+
environment: release
|
|
70
|
+
permissions:
|
|
71
|
+
contents: read
|
|
72
|
+
id-token: write
|
|
73
|
+
steps:
|
|
74
|
+
- uses: actions/checkout@v7
|
|
75
|
+
with:
|
|
76
|
+
persist-credentials: false
|
|
77
|
+
- uses: astral-sh/setup-uv@v10.3.0
|
|
78
|
+
with:
|
|
79
|
+
python-version: '3.14'
|
|
80
|
+
- name: Check tag matches project version
|
|
81
|
+
run: test "${GITHUB_REF_NAME#v}" = "$(uv version --short)"
|
|
82
|
+
- run: uv build
|
|
83
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
98
|
+
__pypackages__/
|
|
99
|
+
|
|
100
|
+
# Celery stuff
|
|
101
|
+
celerybeat-schedule
|
|
102
|
+
celerybeat.pid
|
|
103
|
+
|
|
104
|
+
# SageMath parsed files
|
|
105
|
+
*.sage.py
|
|
106
|
+
|
|
107
|
+
# Environments
|
|
108
|
+
.env
|
|
109
|
+
.venv
|
|
110
|
+
env/
|
|
111
|
+
venv/
|
|
112
|
+
ENV/
|
|
113
|
+
env.bak/
|
|
114
|
+
venv.bak/
|
|
115
|
+
|
|
116
|
+
# Spyder project settings
|
|
117
|
+
.spyderproject
|
|
118
|
+
.spyproject
|
|
119
|
+
|
|
120
|
+
# Rope project settings
|
|
121
|
+
.ropeproject
|
|
122
|
+
|
|
123
|
+
# mkdocs documentation
|
|
124
|
+
/site
|
|
125
|
+
|
|
126
|
+
# mypy
|
|
127
|
+
.mypy_cache/
|
|
128
|
+
.dmypy.json
|
|
129
|
+
dmypy.json
|
|
130
|
+
|
|
131
|
+
# Pyre type checker
|
|
132
|
+
.pyre/
|
|
133
|
+
|
|
134
|
+
# pytype static type analyzer
|
|
135
|
+
.pytype/
|
|
136
|
+
|
|
137
|
+
# Cython debug symbols
|
|
138
|
+
cython_debug/
|
|
139
|
+
|
|
140
|
+
.DS_Store
|
|
141
|
+
.idea
|
|
142
|
+
src/pytailwindcss/bin
|
|
143
|
+
.claude
|
|
144
|
+
.history
|
|
145
|
+
|
|
146
|
+
_devcontext/
|
|
147
|
+
*.tape
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v6.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: check-added-large-files
|
|
6
|
+
exclude: ^assets/.*\.gif$ # README demo, deliberately committed
|
|
7
|
+
- id: check-ast
|
|
8
|
+
- id: check-case-conflict
|
|
9
|
+
- id: check-json
|
|
10
|
+
- id: check-merge-conflict
|
|
11
|
+
- id: check-symlinks
|
|
12
|
+
- id: check-toml
|
|
13
|
+
- id: check-yaml
|
|
14
|
+
- id: debug-statements
|
|
15
|
+
- id: detect-private-key
|
|
16
|
+
- id: end-of-file-fixer
|
|
17
|
+
- id: trailing-whitespace
|
|
18
|
+
- id: mixed-line-ending
|
|
19
|
+
- repo: https://github.com/crate-ci/typos
|
|
20
|
+
rev: v1.51.1
|
|
21
|
+
hooks:
|
|
22
|
+
- id: typos
|
|
23
|
+
- repo: https://github.com/tox-dev/pyproject-fmt
|
|
24
|
+
rev: v2.30.3
|
|
25
|
+
hooks:
|
|
26
|
+
- id: pyproject-fmt
|
|
27
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
28
|
+
rev: v0.17.0
|
|
29
|
+
hooks:
|
|
30
|
+
- id: ruff-check
|
|
31
|
+
args: [ --fix, --show-fixes ]
|
|
32
|
+
- id: ruff-format
|
|
33
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
34
|
+
rev: v2.4.0
|
|
35
|
+
hooks:
|
|
36
|
+
- id: mypy
|
|
37
|
+
additional_dependencies:
|
|
38
|
+
- pytest>=9.0.3
|
|
39
|
+
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
|
40
|
+
rev: v1.30.1
|
|
41
|
+
hooks:
|
|
42
|
+
- id: zizmor
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.1 (2026-10-13)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Pressing Ctrl+C in `tailwindcss` (e.g. to stop `--watch`) or `tailwindcss_install` no longer prints a Python `KeyboardInterrupt` traceback; the command exits with status 130.
|
|
8
|
+
|
|
9
|
+
## 0.4.0 (2026-10-13)
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Downloads are verified against the release's `sha256sums.txt`; a mismatch raises `PyTailwindCssChecksumMismatch` and nothing is installed. Releases without checksums (before v4) install with a warning.
|
|
14
|
+
- Alpine and other musl-based Linux systems get the `-musl` Tailwind CSS binary (it needs `apk add libstdc++ libgcc`).
|
|
15
|
+
- `TAILWINDCSS_BIN_DIR` environment variable to choose where binaries are stored.
|
|
16
|
+
- Type hints and a `py.typed` marker.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Installation is atomic: the binary is downloaded next to its destination and swapped in only after it's verified, so a failed download keeps the previous binary.
|
|
21
|
+
- Installed binaries are mode `0755`, so a binary installed as root (e.g. at Docker build time) runs for any user.
|
|
22
|
+
- Download progress is printed to stderr instead of stdout, so it no longer mixes with `tailwindcss` output.
|
|
23
|
+
- Network failures, HTTP errors other than 404, unsupported platforms, and unwritable binary directories raise `PyTailwindCssException` with a readable message; the CLI commands print it instead of a traceback.
|
|
24
|
+
- Downloads time out after 60 seconds without data.
|
|
25
|
+
- `run()` raises `PyTailwindCssBinaryNotFound` only when the binary is actually missing; a missing `cwd` now surfaces as the original `FileNotFoundError`.
|
|
26
|
+
- README updated for Tailwind CSS v4.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Windows: the binary is saved as `tailwindcss.exe`, so it can be executed.
|
|
31
|
+
- `run(bin_path="...", auto_install=True)` no longer crashes when `bin_path` is a string.
|
|
32
|
+
- Temporary download directories are no longer leaked.
|
|
33
|
+
|
|
34
|
+
## Earlier releases
|
|
35
|
+
|
|
36
|
+
See the [git tags](https://github.com/timonweb/pytailwindcss/tags).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Tim Kamanin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pytailwindcss
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Standalone Tailwind CSS CLI, installable via pip. Use Tailwind CSS without Node.js.
|
|
5
|
+
Project-URL: Changelog, https://github.com/timonweb/pytailwindcss/blob/main/CHANGELOG.md
|
|
6
|
+
Project-URL: Homepage, https://github.com/timonweb/pytailwindcss
|
|
7
|
+
Project-URL: Issues, https://github.com/timonweb/pytailwindcss/issues
|
|
8
|
+
Project-URL: Source, https://github.com/timonweb/pytailwindcss
|
|
9
|
+
Author-email: Tim Kamanin <tim@timonweb.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,css,tailwind
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Standalone Tailwind CSS CLI, installable via pip
|
|
29
|
+
|
|
30
|
+
Use *Tailwind CSS* without *Node.js* — install it via pip.
|
|
31
|
+
|
|
32
|
+
## Why
|
|
33
|
+
|
|
34
|
+
*Tailwind CSS* is notoriously dependent on *Node.js*. If you're a *Python* developer, this dependency may not be welcome
|
|
35
|
+
in your team, your Docker container, or your inner circle.
|
|
36
|
+
|
|
37
|
+
The *Tailwind CSS* team ships a standalone CLI build that gives you the full power of *Tailwind CLI* in a
|
|
38
|
+
self-contained executable — no *Node.js* or `npm` required.
|
|
39
|
+
|
|
40
|
+
However, installing the standalone CLI isn't as easy as running `npm install`.
|
|
41
|
+
|
|
42
|
+
That's why I created this package to make it as simple as running the `pip install` command. Now you can install the standalone *Tailwind CLI* via `pip` by running:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install pytailwindcss
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Now you can run `tailwindcss` in your terminal:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
tailwindcss -i input.css -o output.css --minify
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Voilà!
|
|
55
|
+
|
|
56
|
+
## Get started
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
1. Install `pytailwindcss` via `pip` (or `uv add pytailwindcss`):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install pytailwindcss
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
2. **[Recommended]** Preinstall the `tailwindcss` binary:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
tailwindcss_install
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If you skip this step, the binary will be downloaded automatically on the first run of the `tailwindcss` command.
|
|
73
|
+
|
|
74
|
+
3. Create an `input.css` file that imports Tailwind CSS:
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
@import "tailwindcss";
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Tailwind CSS v4 is configured right in your CSS — there's no `tailwind.config.js` and no `tailwindcss init` anymore. See the [official documentation](https://tailwindcss.com/docs) for theming and customization.
|
|
81
|
+
|
|
82
|
+
4. Start a watcher to compile CSS automatically during development:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
tailwindcss -i input.css -o output.css --watch
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
5. Compile and minify your CSS for production:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
tailwindcss -i input.css -o output.css --minify
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
That's it! Run `tailwindcss --help` to see all the CLI options.
|
|
95
|
+
|
|
96
|
+
## Pinning a Tailwind CSS version
|
|
97
|
+
|
|
98
|
+
By default, the latest binary version is downloaded. To pin to a specific Tailwind CSS version, set the `TAILWINDCSS_VERSION` environment variable. It's used by both `tailwindcss_install` and `tailwindcss`:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# On Linux/macOS
|
|
102
|
+
export TAILWINDCSS_VERSION=v4.3.3
|
|
103
|
+
tailwindcss_install
|
|
104
|
+
|
|
105
|
+
# On Windows (cmd)
|
|
106
|
+
set TAILWINDCSS_VERSION=v4.3.3
|
|
107
|
+
tailwindcss_install
|
|
108
|
+
|
|
109
|
+
# On Windows (PowerShell)
|
|
110
|
+
$env:TAILWINDCSS_VERSION="v4.3.3"
|
|
111
|
+
tailwindcss_install
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
To see a list of available Tailwind CSS releases, visit: https://github.com/tailwindlabs/tailwindcss/releases
|
|
115
|
+
|
|
116
|
+
Every download is checked against the SHA-256 checksums published with the release, and a binary that doesn't match is never installed. Releases before v4 don't publish checksums; for those, `pytailwindcss` logs a warning and installs the binary unverified.
|
|
117
|
+
|
|
118
|
+
## Where the binary lives
|
|
119
|
+
|
|
120
|
+
Binaries are stored per version inside the installed package, so every virtualenv gets its own copy and projects don't affect each other.
|
|
121
|
+
|
|
122
|
+
If that directory isn't writable (for example, a virtualenv owned by another user), point `TAILWINDCSS_BIN_DIR` at a directory you can write to (relative paths and `~` are resolved):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
export TAILWINDCSS_BIN_DIR=~/.cache/pytailwindcss
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Binaries then go to `$TAILWINDCSS_BIN_DIR/<version>/tailwindcss`.
|
|
129
|
+
|
|
130
|
+
## Docker
|
|
131
|
+
|
|
132
|
+
Install the binary while building the image, so containers start without downloading anything:
|
|
133
|
+
|
|
134
|
+
```dockerfile
|
|
135
|
+
ENV TAILWINDCSS_VERSION=v4.3.3
|
|
136
|
+
RUN pip install pytailwindcss && tailwindcss_install
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The binary is readable and executable by every user, so it's fine to install it as root and run your app as an unprivileged user.
|
|
140
|
+
|
|
141
|
+
On Alpine (musl) images, `pytailwindcss` downloads the matching `-musl` build of Tailwind CSS v4. That build needs the C++ runtime libraries, which Alpine doesn't include by default:
|
|
142
|
+
|
|
143
|
+
```dockerfile
|
|
144
|
+
RUN apk add --no-cache libstdc++ libgcc
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Using it from Python
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
import pytailwindcss
|
|
151
|
+
|
|
152
|
+
# Download the binary (optional, see auto_install below).
|
|
153
|
+
pytailwindcss.install(version="v4.3.3")
|
|
154
|
+
|
|
155
|
+
# Run the CLI and get its output as a string.
|
|
156
|
+
pytailwindcss.run("-i input.css -o output.css --minify", version="v4.3.3")
|
|
157
|
+
|
|
158
|
+
# Arguments can be a list too; auto_install downloads the binary if it's missing.
|
|
159
|
+
pytailwindcss.run(["-i", "input.css", "-o", "output.css"], auto_install=True)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`run()` raises `subprocess.CalledProcessError` when Tailwind CSS exits with an error. Pass `live_output=True` to stream Tailwind's output to the terminal instead; you then get the `subprocess.CompletedProcess` back. Download and installation problems raise subclasses of `pytailwindcss.exceptions.PyTailwindCssException`.
|
|
163
|
+
|
|
164
|
+
## Caveats
|
|
165
|
+
|
|
166
|
+
Without *Node.js*, you can't install third-party plugins from npm. The standalone build bundles the official plugins, though — `@tailwindcss/forms`, `@tailwindcss/typography`, and `@tailwindcss/aspect-ratio` — so you can enable them in your CSS:
|
|
167
|
+
|
|
168
|
+
```css
|
|
169
|
+
@import "tailwindcss";
|
|
170
|
+
@plugin "@tailwindcss/typography";
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This covers the vast majority of typical *Tailwind CSS* setups.
|
|
174
|
+
|
|
175
|
+
Here's what the *Tailwind CSS* team says about the standalone build:
|
|
176
|
+
> If you're working on a project where you don't otherwise need *Node.js* or `npm`, the standalone build can be a great choice. If Tailwind was the only reason you had a package.json file, this is probably going to feel like a nicer solution.
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
uv sync # create the virtualenv with dev dependencies
|
|
182
|
+
uv run pytest # run all tests (some download real binaries)
|
|
183
|
+
uv run pytest -m "not network" # skip the tests that need network access
|
|
184
|
+
uvx pre-commit install # run linters, formatters, and mypy on every commit
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Bugs and Suggestions
|
|
188
|
+
|
|
189
|
+
Found a bug or have a suggestion? Please use the issue tracker on GitHub:
|
|
190
|
+
|
|
191
|
+
[https://github.com/timonweb/pytailwindcss/issues](https://github.com/timonweb/pytailwindcss/issues)
|
|
192
|
+
|
|
193
|
+
2021 - 2026 (c) Tim Kamanin — [A Full-Stack Django and Wagtail Developer](https://timonweb.com)
|