diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 895ad48..b8ab3b2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,36 +1,91 @@ name: Unit tests on: - push: - branches: [ master ] pull_request: - branches: [ master ] + push: + branches: + - master + tags: + - "v*" jobs: - build: + test: + runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, pypy2, pypy3] + + name: Python ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v2 + - name: Get history and tags for SCM versioning to work + run: | + git fetch --prune --unshallow + git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Test with tox + run: tox -e py + + dist: runs-on: ubuntu-latest + needs: [test] + name: Build Python packages + steps: + - uses: actions/checkout@v2 + - name: Get history and tags for SCM versioning to work + run: | + git fetch --prune --unshallow + git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - uses: actions/setup-python@v2 + with: + python-version: "3.8" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade wheel setuptools build + - name: Build package + run: python -m build -s -w -o dist/ + - uses: actions/upload-artifact@v2 + with: + name: dist + path: dist + dist_check: + runs-on: ubuntu-latest + needs: [dist] + name: Twine check + steps: + - uses: actions/setup-python@v2 + with: + python-version: "3.8" + - name: Install dependencies + run: pip install twine + - uses: actions/download-artifact@v2 + with: + name: dist + path: dist + - run: twine check dist/* + + dist_upload: + runs-on: ubuntu-latest + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + needs: [dist_check] + name: PyPI upload steps: - - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v2 - - name: Set up Python - ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install tox -r requirements.txt; - - name: Test with pytest - env: - PYTHON_VERSION: ${{ matrix.python-version }} - run: | - # Remove . from python version - ENV_NAME="${PYTHON_VERSION/./}" - # Add "py" suffix for plain python version - [[ ${ENV_NAME} =~ ^[0-9]+$ ]] && ENV_NAME="py${ENV_NAME}" - tox -e "${ENV_NAME}" + - uses: actions/download-artifact@v2 + with: + name: dist + path: dist + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.gitignore b/.gitignore index 77a95a1..a57a25f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ venv* /.tox /.cache /.pytest_cache +# Generated by setuptools_scm +flask_compress/_version.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e3b00..89a2baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to `flask-compress` will be documented in this file. +## 1.10.0 (2021-06-15) + +- Automate the release process with GitHub Actions +- Use `setuptools_scm` to manage package versions +- The layout is now an actual package rather than a single module +- Clean up unused files + ## 1.9.0 (2021-02-12) - Add support for the `identity` value in *accept-encoding*, fixes [#19](https://github.com/colour-science/flask-compress/issues/19) diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index f5458f8..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include LICENSE.txt -include README.md -recursive-include tests * -recursive-exclude tests *.pyc diff --git a/README.md b/README.md index 59570fb..a671e21 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # Flask-Compress +[![Build](https://github.com/colour-science/flask-compress/actions/workflows/ci.yaml/badge.svg)](https://github.com/colour-science/flask-compress/actions/workflows/ci.yaml) [![Version](https://img.shields.io/pypi/v/flask-compress.svg)](https://pypi.python.org/pypi/Flask-Compress) -[![Build Status](https://travis-ci.org/libwilliam/flask-compress.png)](https://travis-ci.org/libwilliam/flask-compress) -[![Coverage](https://coveralls.io/repos/libwilliam/flask-compress/badge.svg)](https://coveralls.io/github/libwilliam/flask-compress) -[![License](https://img.shields.io/pypi/l/flask-compress.svg)](https://github.com/libwilliam/flask-compress/blob/master/LICENSE.txt) +[![Downloads](https://pypip.in/d/Flask-Compress/badge.png)](https://pypi.python.org/pypi/Flask-Compress) -Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. +Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. It originally started as a fork of [Flask-gzip](https://github.com/closeio/Flask-gzip). The preferred solution is to have a server (like [Nginx](http://wiki.nginx.org/Main)) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you. diff --git a/flask_compress/__init__.py b/flask_compress/__init__.py new file mode 100644 index 0000000..0a643ec --- /dev/null +++ b/flask_compress/__init__.py @@ -0,0 +1,9 @@ +from .flask_compress import Compress + +# _version.py is generated by setuptools_scm when building the package, it is not versioned. +# If missing, this means that the imported code was most likely the git repository, that was +# installed without the "editable" mode. +try: + from ._version import __version__ +except ImportError: + __version__ = "0" diff --git a/flask_compress.py b/flask_compress/flask_compress.py similarity index 100% rename from flask_compress.py rename to flask_compress/flask_compress.py diff --git a/index.html b/index.html deleted file mode 100644 index a8212cf..0000000 --- a/index.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - Flask-Compress by libwilliam - - - - - - - -
-
-

Flask-Compress

-

Compress responses in your Flask app with gzip.

- -

View the Project on GitHub libwilliam/flask-compress

- - - -
-
-

-Flask-Compress

- -

Version -Build Status -Coverage -License

- -

Flask-Compress allows you to easily compress your Flask application's responses with gzip.

- -

The preferred solution is to have a server (like Nginx) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you.

- -

-How it works

- -

Flask-Compress both adds the various headers required for a compressed response and gzips the response data. This makes serving gzip compressed static files extremely easy.

- -

Internally, every time a request is made the extension will check if it matches one of the compressible MIME types and will automatically attach the appropriate headers.

- -

-Installation

- -

If you use pip then installation is simply:

- -
$ pip install flask-compress
- -

or, if you want the latest github version:

- -
$ pip install git+git://github.com/libwilliam/flask-compress.git
- -

You can also install Flask-Compress via Easy Install:

- -
$ easy_install flask-compress
- -

-Using Flask-Compress

- -

Flask-Compress is incredibly simple to use. In order to start gzip'ing your Flask application's assets, the first thing to do is let Flask-Compress know about your flask.Flask application object.

- -
from flask import Flask
-from flask_compress import Compress
-
-app = Flask(__name__)
-Compress(app)
- -

In many cases, however, one cannot expect a Flask instance to be ready at import time, and a common pattern is to return a Flask instance from within a function only after other configuration details have been taken care of. In these cases, Flask-Compress provides a simple function, flask_compress.Compress.init_app, which takes your application as an argument.

- -
from flask import Flask
-from flask_compress import Compress
-
-compress = Compress()
-
-def start_app():
-    app = Flask(__name__)
-    compress.init_app(app)
-    return app
- -

In terms of automatically compressing your assets using gzip, passing your flask.Flask object to the flask_compress.Compress object is all that needs to be done.

- -

-Options

- -

Within your Flask application's settings you can provide the following settings to control the behavior of Flask-Compress. None of the settings are required.

- - - - - - - - - - - - - - - - - - - - - - - - - - -
OptionDescriptionDefault
COMPRESS_MIMETYPESSet the list of mimetypes to compress here. -[
'text/html',
'text/css',
'text/xml',
'application/json',
'application/javascript'
] -
COMPRESS_LEVELSpecifies the gzip compression level.6
COMPRESS_MIN_SIZESpecifies the minimum file size threshold for compressing files.500
-
- -
- - - - diff --git a/javascripts/scale.fix.js b/javascripts/scale.fix.js deleted file mode 100644 index 87a40ca..0000000 --- a/javascripts/scale.fix.js +++ /dev/null @@ -1,17 +0,0 @@ -var metas = document.getElementsByTagName('meta'); -var i; -if (navigator.userAgent.match(/iPhone/i)) { - for (i=0; i`'text/html',`
`'text/css',`
`'text/xml',`
`'application/json',`
`'application/javascript'`
`]` |\r\n| `COMPRESS_LEVEL` | Specifies the gzip compression level. | `6` |\r\n| `COMPRESS_MIN_SIZE` | Specifies the minimum file size threshold for compressing files. | `500` |\r\n", - "note": "Don't delete this file! It's used internally to help with page regeneration." -} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1c9f2ad --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[build-system] +requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +write_to = "flask_compress/_version.py" +write_to_template = "__version__ = \"{version}\"\n" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1893345..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -flask -brotli diff --git a/setup.py b/setup.py index 2e05c65..f40d50d 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ -import setuptools +from setuptools import setup, find_packages with open('README.md') as fl: LONG_DESCRIPTION = fl.read() -setuptools.setup( +setup( name='Flask-Compress', - version='1.9.0', + use_scm_version=True, url='https://github.com/colour-science/flask-compress', license='MIT', author='Thomas Mansencal', @@ -13,7 +13,7 @@ description='Compress responses in your Flask app with gzip, deflate or brotli.', long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', - py_modules=['flask_compress'], + packages=find_packages(exclude=['tests']), zip_safe=False, include_package_data=True, platforms='any', @@ -21,7 +21,6 @@ 'flask', 'brotli' ], - test_suite='tests', classifiers=[ 'Environment :: Web Environment', 'Intended Audience :: Developers', diff --git a/stylesheets/github-light.css b/stylesheets/github-light.css deleted file mode 100644 index 0c6b24d..0000000 --- a/stylesheets/github-light.css +++ /dev/null @@ -1,124 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2016 GitHub, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -.pl-c /* comment */ { - color: #969896; -} - -.pl-c1 /* constant, variable.other.constant, support, meta.property-name, support.constant, support.variable, meta.module-reference, markup.raw, meta.diff.header */, -.pl-s .pl-v /* string variable */ { - color: #0086b3; -} - -.pl-e /* entity */, -.pl-en /* entity.name */ { - color: #795da3; -} - -.pl-smi /* variable.parameter.function, storage.modifier.package, storage.modifier.import, storage.type.java, variable.other */, -.pl-s .pl-s1 /* string source */ { - color: #333; -} - -.pl-ent /* entity.name.tag */ { - color: #63a35c; -} - -.pl-k /* keyword, storage, storage.type */ { - color: #a71d5d; -} - -.pl-s /* string */, -.pl-pds /* punctuation.definition.string, string.regexp.character-class */, -.pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */, -.pl-sr /* string.regexp */, -.pl-sr .pl-cce /* string.regexp constant.character.escape */, -.pl-sr .pl-sre /* string.regexp source.ruby.embedded */, -.pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */ { - color: #183691; -} - -.pl-v /* variable */ { - color: #ed6a43; -} - -.pl-id /* invalid.deprecated */ { - color: #b52a1d; -} - -.pl-ii /* invalid.illegal */ { - color: #f8f8f8; - background-color: #b52a1d; -} - -.pl-sr .pl-cce /* string.regexp constant.character.escape */ { - font-weight: bold; - color: #63a35c; -} - -.pl-ml /* markup.list */ { - color: #693a17; -} - -.pl-mh /* markup.heading */, -.pl-mh .pl-en /* markup.heading entity.name */, -.pl-ms /* meta.separator */ { - font-weight: bold; - color: #1d3e81; -} - -.pl-mq /* markup.quote */ { - color: #008080; -} - -.pl-mi /* markup.italic */ { - font-style: italic; - color: #333; -} - -.pl-mb /* markup.bold */ { - font-weight: bold; - color: #333; -} - -.pl-md /* markup.deleted, meta.diff.header.from-file */ { - color: #bd2c00; - background-color: #ffecec; -} - -.pl-mi1 /* markup.inserted, meta.diff.header.to-file */ { - color: #55a532; - background-color: #eaffea; -} - -.pl-mdr /* meta.diff.range */ { - font-weight: bold; - color: #795da3; -} - -.pl-mo /* meta.output */ { - color: #1d3e81; -} - diff --git a/stylesheets/styles.css b/stylesheets/styles.css deleted file mode 100644 index 2e1768e..0000000 --- a/stylesheets/styles.css +++ /dev/null @@ -1,324 +0,0 @@ -@font-face { - font-family: 'Noto Sans'; - font-weight: 400; - font-style: normal; - src: url('../fonts/Noto-Sans-regular/Noto-Sans-regular.eot'); - src: url('../fonts/Noto-Sans-regular/Noto-Sans-regular.eot?#iefix') format('embedded-opentype'), - local('Noto Sans'), - local('Noto-Sans-regular'), - url('../fonts/Noto-Sans-regular/Noto-Sans-regular.woff2') format('woff2'), - url('../fonts/Noto-Sans-regular/Noto-Sans-regular.woff') format('woff'), - url('../fonts/Noto-Sans-regular/Noto-Sans-regular.ttf') format('truetype'), - url('../fonts/Noto-Sans-regular/Noto-Sans-regular.svg#NotoSans') format('svg'); -} - -@font-face { - font-family: 'Noto Sans'; - font-weight: 700; - font-style: normal; - src: url('../fonts/Noto-Sans-700/Noto-Sans-700.eot'); - src: url('../fonts/Noto-Sans-700/Noto-Sans-700.eot?#iefix') format('embedded-opentype'), - local('Noto Sans Bold'), - local('Noto-Sans-700'), - url('../fonts/Noto-Sans-700/Noto-Sans-700.woff2') format('woff2'), - url('../fonts/Noto-Sans-700/Noto-Sans-700.woff') format('woff'), - url('../fonts/Noto-Sans-700/Noto-Sans-700.ttf') format('truetype'), - url('../fonts/Noto-Sans-700/Noto-Sans-700.svg#NotoSans') format('svg'); -} - -@font-face { - font-family: 'Noto Sans'; - font-weight: 400; - font-style: italic; - src: url('../fonts/Noto-Sans-italic/Noto-Sans-italic.eot'); - src: url('../fonts/Noto-Sans-italic/Noto-Sans-italic.eot?#iefix') format('embedded-opentype'), - local('Noto Sans Italic'), - local('Noto-Sans-italic'), - url('../fonts/Noto-Sans-italic/Noto-Sans-italic.woff2') format('woff2'), - url('../fonts/Noto-Sans-italic/Noto-Sans-italic.woff') format('woff'), - url('../fonts/Noto-Sans-italic/Noto-Sans-italic.ttf') format('truetype'), - url('../fonts/Noto-Sans-italic/Noto-Sans-italic.svg#NotoSans') format('svg'); -} - -@font-face { - font-family: 'Noto Sans'; - font-weight: 700; - font-style: italic; - src: url('../fonts/Noto-Sans-700italic/Noto-Sans-700italic.eot'); - src: url('../fonts/Noto-Sans-700italic/Noto-Sans-700italic.eot?#iefix') format('embedded-opentype'), - local('Noto Sans Bold Italic'), - local('Noto-Sans-700italic'), - url('../fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff2') format('woff2'), - url('../fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff') format('woff'), - url('../fonts/Noto-Sans-700italic/Noto-Sans-700italic.ttf') format('truetype'), - url('../fonts/Noto-Sans-700italic/Noto-Sans-700italic.svg#NotoSans') format('svg'); -} - -body { - background-color: #fff; - padding:50px; - font: 14px/1.5 "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; - color:#727272; - font-weight:400; -} - -h1, h2, h3, h4, h5, h6 { - color:#222; - margin:0 0 20px; -} - -p, ul, ol, table, pre, dl { - margin:0 0 20px; -} - -h1, h2, h3 { - line-height:1.1; -} - -h1 { - font-size:28px; -} - -h2 { - color:#393939; -} - -h3, h4, h5, h6 { - color:#494949; -} - -a { - color:#39c; - text-decoration:none; -} - -a:hover { - color:#069; -} - -a small { - font-size:11px; - color:#777; - margin-top:-0.3em; - display:block; -} - -a:hover small { - color:#777; -} - -.wrapper { - width:860px; - margin:0 auto; -} - -blockquote { - border-left:1px solid #e5e5e5; - margin:0; - padding:0 0 0 20px; - font-style:italic; -} - -code, pre { - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal, Consolas, Liberation Mono, DejaVu Sans Mono, Courier New, monospace; - color:#333; - font-size:12px; -} - -pre { - padding:8px 15px; - background: #f8f8f8; - border-radius:5px; - border:1px solid #e5e5e5; - overflow-x: auto; -} - -table { - width:100%; - border-collapse:collapse; -} - -th, td { - text-align:left; - padding:5px 10px; - border-bottom:1px solid #e5e5e5; -} - -dt { - color:#444; - font-weight:700; -} - -th { - color:#444; -} - -img { - max-width:100%; -} - -header { - width:270px; - float:left; - position:fixed; - -webkit-font-smoothing:subpixel-antialiased; -} - -header ul { - list-style:none; - height:40px; - padding:0; - background: #f4f4f4; - border-radius:5px; - border:1px solid #e0e0e0; - width:270px; -} - -header li { - width:89px; - float:left; - border-right:1px solid #e0e0e0; - height:40px; -} - -header li:first-child a { - border-radius:5px 0 0 5px; -} - -header li:last-child a { - border-radius:0 5px 5px 0; -} - -header ul a { - line-height:1; - font-size:11px; - color:#999; - display:block; - text-align:center; - padding-top:6px; - height:34px; -} - -header ul a:hover { - color:#999; -} - -header ul a:active { - background-color:#f0f0f0; -} - -strong { - color:#222; - font-weight:700; -} - -header ul li + li + li { - border-right:none; - width:89px; -} - -header ul a strong { - font-size:14px; - display:block; - color:#222; -} - -section { - width:500px; - float:right; - padding-bottom:50px; -} - -small { - font-size:11px; -} - -hr { - border:0; - background:#e5e5e5; - height:1px; - margin:0 0 20px; -} - -footer { - width:270px; - float:left; - position:fixed; - bottom:50px; - -webkit-font-smoothing:subpixel-antialiased; -} - -@media print, screen and (max-width: 960px) { - - div.wrapper { - width:auto; - margin:0; - } - - header, section, footer { - float:none; - position:static; - width:auto; - } - - header { - padding-right:320px; - } - - section { - border:1px solid #e5e5e5; - border-width:1px 0; - padding:20px 0; - margin:0 0 20px; - } - - header a small { - display:inline; - } - - header ul { - position:absolute; - right:50px; - top:52px; - } -} - -@media print, screen and (max-width: 720px) { - body { - word-wrap:break-word; - } - - header { - padding:0; - } - - header ul, header p.view { - position:static; - } - - pre, code { - word-wrap:normal; - } -} - -@media print, screen and (max-width: 480px) { - body { - padding:15px; - } - - header ul { - width:99%; - } - - header li, header ul li + li + li { - width:33%; - } -} - -@media print { - body { - padding:0.4in; - font-size:12pt; - color:#444; - } -} diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tox.ini b/tox.ini index 57635a8..2fae25a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,5 @@ [tox] +isolated_build = True skip_missing_interpreters = true envlist = py27,py35,py36,py37,py38,py39,pypy2,pypy3