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.
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ cooldown:
8
+ default-days: 7
9
+ groups:
10
+ actions:
11
+ patterns:
12
+ - "*"
@@ -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,6 @@
1
+ rules:
2
+ unpinned-uses:
3
+ config:
4
+ # Major-version tags kept current by Dependabot, rather than SHA pins.
5
+ policies:
6
+ "*": ref-pin
@@ -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
+ ![Installing pytailwindcss, then watching and building CSS with the tailwindcss command](https://raw.githubusercontent.com/timonweb/pytailwindcss/main/assets/get-started.gif)
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)