[RFC] Add a setup.py so Patchwork can be pip-installed

Stephen Finucane stephen at that.guru
Thu May 7 23:29:30 AEST 2020


On Tue, 2020-04-28 at 17:36 -0400, Jeremy Cline wrote:
> Recently I needed to deploy Patchwork and I noticed it was missing a
> setup.py. This is a first draft at adding one and making Patchwork easy
> to install with pip.
> 
> To do this, static files and templates are moved within the Python
> package. "htdocs" is renamed to "static" which is the default location
> Django searches for static files. The two templates directories have
> been merged - I'm not sure why there are two so this perhaps breaks
> something I'm not aware of.
> 
> With this change you should be able to do something like:
> 
> $ python3 setup.py sdist
> $ python3 -m venv ~/.virtualenvs/pw
> $ source ~/.virtualenvs/pw/bin/activate
> $ pip install dist/patchwork-3.0.0a1.tar.gz
> $ DJANGO_SETTINGS_MODULE=patchwork.settings.dev PW_TEST_DB_TYPE=sqlite \
>     django-admin migrate
> $ DJANGO_SETTINGS_MODULE=patchwork.settings.dev PW_TEST_DB_TYPE=sqlite \
>     django-admin runserver
> 
> I poked around the web UI and everything seems to work as expected, but
> it's quite likely I've missed something. This change would obviously
> also require updating the installation documentation, but before I go
> any further I'd love some feedback on this. Is this something people are
> interested in?
> 
> My motivation for this is that I've got a little Django app that runs
> alongside Patchwork and would prefer it to be a simple "pip install" to
> get everything set up.

Sorry for the delay getting to this /o\ I've considered doing this
myself for some time and the main reason I hadn't was because Patchwork
isn't really packaged as a library or something reusable - it's an
application (in the packaging sense of the word [1]). As such, I'm not
sure how much sense there would be in publishing Patchwork to PyPI and,
for me at least, a setup.py file only real makes sense in that context
[2].

With that said, you've suggested that this is beneficial for you at
least. Could you go into a little more on this? I'd have suspected an
Ansible playbook or production Docker container to be far more useful
because they'd include things like nginx/Apache setup, etc. Is that not
the case?

Cheers,
Stephen

[1] https://caremad.io/posts/2013/07/setup-vs-requirement/
[2] Yes, you have distutils commands, but there are almost always
alternatives you can use for this.

> Signed-off-by: Jeremy Cline <jcline at redhat.com>
> ---
>  MANIFEST.in                                   |   7 ++
>  htdocs/js/jquery-1.10.1.min.js                |   1 -
>  htdocs/js/jquery.checkboxes-1.0.6.min.js      |   1 -
>  htdocs/js/jquery.stickytableheaders.min.js    |   1 -
>  htdocs/js/jquery.tablednd.js                  |   1 -
>  patchwork/settings/base.py                    |   4 +-
>  {htdocs => patchwork/static}/README.rst       |   0
>  .../static}/css/bootstrap.min.css             |   0
>  .../static}/css/selectize.bootstrap3.css      |   0
>  {htdocs => patchwork/static}/css/style.css    |   0
>  .../fonts/glyphicons-halflings-regular.eot    | Bin
>  .../fonts/glyphicons-halflings-regular.svg    |   0
>  .../fonts/glyphicons-halflings-regular.ttf    | Bin
>  .../fonts/glyphicons-halflings-regular.woff   | Bin
>  .../static}/js/bootstrap.min.js               |   0
>  {htdocs => patchwork/static}/js/bundle.js     |   0
>  .../static}/js/clipboard.min.js               |   0
>  patchwork/static/js/jquery-1.10.1.min.js      |   1 +
>  .../static/js/jquery.checkboxes-1.0.6.min.js  |   1 +
>  .../js/jquery.stickytableheaders.min.js       |   1 +
>  patchwork/static/js/jquery.tablednd.js        |   1 +
>  .../static}/js/selectize.min.js               |   0
>  {templates => patchwork/templates}/404.html   |   0
>  {templates => patchwork/templates}/base.html  |   0
>  .../registration/password_change_done.html    |   0
>  .../registration/password_change_form.html    |   0
>  .../registration/password_reset_complete.html |   0
>  .../registration/password_reset_confirm.html  |   0
>  .../registration/password_reset_done.html     |   0
>  .../registration/password_reset_email.html    |   0
>  .../registration/password_reset_form.html     |   0
>  requirements-test.txt                         |   2 +-
>  setup.py                                      |  69 ++++++++++++++++++
>  33 files changed, 83 insertions(+), 7 deletions(-)
>  create mode 100644 MANIFEST.in
>  delete mode 120000 htdocs/js/jquery-1.10.1.min.js
>  delete mode 120000 htdocs/js/jquery.checkboxes-1.0.6.min.js
>  delete mode 120000 htdocs/js/jquery.stickytableheaders.min.js
>  delete mode 120000 htdocs/js/jquery.tablednd.js
>  rename {htdocs => patchwork/static}/README.rst (100%)
>  rename {htdocs => patchwork/static}/css/bootstrap.min.css (100%)
>  rename {htdocs => patchwork/static}/css/selectize.bootstrap3.css (100%)
>  rename {htdocs => patchwork/static}/css/style.css (100%)
>  rename {htdocs => patchwork/static}/fonts/glyphicons-halflings-regular.eot (100%)
>  rename {htdocs => patchwork/static}/fonts/glyphicons-halflings-regular.svg (100%)
>  rename {htdocs => patchwork/static}/fonts/glyphicons-halflings-regular.ttf (100%)
>  rename {htdocs => patchwork/static}/fonts/glyphicons-halflings-regular.woff (100%)
>  rename {htdocs => patchwork/static}/js/bootstrap.min.js (100%)
>  rename {htdocs => patchwork/static}/js/bundle.js (100%)
>  rename {htdocs => patchwork/static}/js/clipboard.min.js (100%)
>  create mode 120000 patchwork/static/js/jquery-1.10.1.min.js
>  create mode 120000 patchwork/static/js/jquery.checkboxes-1.0.6.min.js
>  create mode 120000 patchwork/static/js/jquery.stickytableheaders.min.js
>  create mode 120000 patchwork/static/js/jquery.tablednd.js
>  rename {htdocs => patchwork/static}/js/selectize.min.js (100%)
>  rename {templates => patchwork/templates}/404.html (100%)
>  rename {templates => patchwork/templates}/base.html (100%)
>  rename {templates => patchwork/templates}/registration/password_change_done.html (100%)
>  rename {templates => patchwork/templates}/registration/password_change_form.html (100%)
>  rename {templates => patchwork/templates}/registration/password_reset_complete.html (100%)
>  rename {templates => patchwork/templates}/registration/password_reset_confirm.html (100%)
>  rename {templates => patchwork/templates}/registration/password_reset_done.html (100%)
>  rename {templates => patchwork/templates}/registration/password_reset_email.html (100%)
>  rename {templates => patchwork/templates}/registration/password_reset_form.html (100%)
>  create mode 100755 setup.py
> 
> diff --git a/MANIFEST.in b/MANIFEST.in
> new file mode 100644
> index 0000000..8d20fbf
> --- /dev/null
> +++ b/MANIFEST.in
> @@ -0,0 +1,7 @@
> +include COPYING CONTRIBUTING.rst README.rst
> +include requirements-prod.txt requirements-test.txt
> +recursive-include patchwork/static *.js *.css *.png *.ico *.eot *.svg *.ttf *.woff *.woff2
> +recursive-include patchwork/templates *.html *.txt
> +recursive-include patchwork/fixtures *.xml
> +graft docs
> +prune docs/_build
> diff --git a/htdocs/js/jquery-1.10.1.min.js b/htdocs/js/jquery-1.10.1.min.js
> deleted file mode 120000
> index d48d893..0000000
> --- a/htdocs/js/jquery-1.10.1.min.js
> +++ /dev/null
> @@ -1 +0,0 @@
> -../../lib/packages/jquery/jquery-1.10.1.min.js
> \ No newline at end of file
> diff --git a/htdocs/js/jquery.checkboxes-1.0.6.min.js b/htdocs/js/jquery.checkboxes-1.0.6.min.js
> deleted file mode 120000
> index dfef5d4..0000000
> --- a/htdocs/js/jquery.checkboxes-1.0.6.min.js
> +++ /dev/null
> @@ -1 +0,0 @@
> -../../lib/packages/jquery/jquery.checkboxes-1.0.6.min.js
> \ No newline at end of file
> diff --git a/htdocs/js/jquery.stickytableheaders.min.js b/htdocs/js/jquery.stickytableheaders.min.js
> deleted file mode 120000
> index 0c22fa9..0000000
> --- a/htdocs/js/jquery.stickytableheaders.min.js
> +++ /dev/null
> @@ -1 +0,0 @@
> -../../lib/packages/jquery/jquery.stickytableheaders.min.js
> \ No newline at end of file
> diff --git a/htdocs/js/jquery.tablednd.js b/htdocs/js/jquery.tablednd.js
> deleted file mode 120000
> index ed51ba1..0000000
> --- a/htdocs/js/jquery.tablednd.js
> +++ /dev/null
> @@ -1 +0,0 @@
> -../../lib/packages/jquery/jquery.tablednd.js
> \ No newline at end of file
> diff --git a/patchwork/settings/base.py b/patchwork/settings/base.py
> index 001878a..e72d809 100644
> --- a/patchwork/settings/base.py
> +++ b/patchwork/settings/base.py
> @@ -5,7 +5,7 @@ Base settings for patchwork project.
>  import os
>  
>  ROOT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
> -                        os.pardir, os.pardir)
> +                        os.pardir)
>  
>  #
>  # Core settings
> @@ -97,7 +97,7 @@ SITE_ID = 1
>  STATIC_URL = '/static/'
>  
>  STATICFILES_DIRS = [
> -    os.path.join(ROOT_DIR, 'htdocs'),
> +    os.path.join(ROOT_DIR, 'static'),
>  ]
>  
>  #
> diff --git a/htdocs/README.rst b/patchwork/static/README.rst
> similarity index 100%
> rename from htdocs/README.rst
> rename to patchwork/static/README.rst
> diff --git a/htdocs/css/bootstrap.min.css b/patchwork/static/css/bootstrap.min.css
> similarity index 100%
> rename from htdocs/css/bootstrap.min.css
> rename to patchwork/static/css/bootstrap.min.css
> diff --git a/htdocs/css/selectize.bootstrap3.css b/patchwork/static/css/selectize.bootstrap3.css
> similarity index 100%
> rename from htdocs/css/selectize.bootstrap3.css
> rename to patchwork/static/css/selectize.bootstrap3.css
> diff --git a/htdocs/css/style.css b/patchwork/static/css/style.css
> similarity index 100%
> rename from htdocs/css/style.css
> rename to patchwork/static/css/style.css
> diff --git a/htdocs/fonts/glyphicons-halflings-regular.eot b/patchwork/static/fonts/glyphicons-halflings-regular.eot
> similarity index 100%
> rename from htdocs/fonts/glyphicons-halflings-regular.eot
> rename to patchwork/static/fonts/glyphicons-halflings-regular.eot
> diff --git a/htdocs/fonts/glyphicons-halflings-regular.svg b/patchwork/static/fonts/glyphicons-halflings-regular.svg
> similarity index 100%
> rename from htdocs/fonts/glyphicons-halflings-regular.svg
> rename to patchwork/static/fonts/glyphicons-halflings-regular.svg
> diff --git a/htdocs/fonts/glyphicons-halflings-regular.ttf b/patchwork/static/fonts/glyphicons-halflings-regular.ttf
> similarity index 100%
> rename from htdocs/fonts/glyphicons-halflings-regular.ttf
> rename to patchwork/static/fonts/glyphicons-halflings-regular.ttf
> diff --git a/htdocs/fonts/glyphicons-halflings-regular.woff b/patchwork/static/fonts/glyphicons-halflings-regular.woff
> similarity index 100%
> rename from htdocs/fonts/glyphicons-halflings-regular.woff
> rename to patchwork/static/fonts/glyphicons-halflings-regular.woff
> diff --git a/htdocs/js/bootstrap.min.js b/patchwork/static/js/bootstrap.min.js
> similarity index 100%
> rename from htdocs/js/bootstrap.min.js
> rename to patchwork/static/js/bootstrap.min.js
> diff --git a/htdocs/js/bundle.js b/patchwork/static/js/bundle.js
> similarity index 100%
> rename from htdocs/js/bundle.js
> rename to patchwork/static/js/bundle.js
> diff --git a/htdocs/js/clipboard.min.js b/patchwork/static/js/clipboard.min.js
> similarity index 100%
> rename from htdocs/js/clipboard.min.js
> rename to patchwork/static/js/clipboard.min.js
> diff --git a/patchwork/static/js/jquery-1.10.1.min.js b/patchwork/static/js/jquery-1.10.1.min.js
> new file mode 120000
> index 0000000..659cd57
> --- /dev/null
> +++ b/patchwork/static/js/jquery-1.10.1.min.js
> @@ -0,0 +1 @@
> +../../../lib/packages/jquery/jquery-1.10.1.min.js
> \ No newline at end of file
> diff --git a/patchwork/static/js/jquery.checkboxes-1.0.6.min.js b/patchwork/static/js/jquery.checkboxes-1.0.6.min.js
> new file mode 120000
> index 0000000..8b3452b
> --- /dev/null
> +++ b/patchwork/static/js/jquery.checkboxes-1.0.6.min.js
> @@ -0,0 +1 @@
> +../../../lib/packages/jquery/jquery.checkboxes-1.0.6.min.js
> \ No newline at end of file
> diff --git a/patchwork/static/js/jquery.stickytableheaders.min.js b/patchwork/static/js/jquery.stickytableheaders.min.js
> new file mode 120000
> index 0000000..7031ac1
> --- /dev/null
> +++ b/patchwork/static/js/jquery.stickytableheaders.min.js
> @@ -0,0 +1 @@
> +../../../lib/packages/jquery/jquery.stickytableheaders.min.js
> \ No newline at end of file
> diff --git a/patchwork/static/js/jquery.tablednd.js b/patchwork/static/js/jquery.tablednd.js
> new file mode 120000
> index 0000000..80574c4
> --- /dev/null
> +++ b/patchwork/static/js/jquery.tablednd.js
> @@ -0,0 +1 @@
> +../../../lib/packages/jquery/jquery.tablednd.js
> \ No newline at end of file
> diff --git a/htdocs/js/selectize.min.js b/patchwork/static/js/selectize.min.js
> similarity index 100%
> rename from htdocs/js/selectize.min.js
> rename to patchwork/static/js/selectize.min.js
> diff --git a/templates/404.html b/patchwork/templates/404.html
> similarity index 100%
> rename from templates/404.html
> rename to patchwork/templates/404.html
> diff --git a/templates/base.html b/patchwork/templates/base.html
> similarity index 100%
> rename from templates/base.html
> rename to patchwork/templates/base.html
> diff --git a/templates/registration/password_change_done.html b/patchwork/templates/registration/password_change_done.html
> similarity index 100%
> rename from templates/registration/password_change_done.html
> rename to patchwork/templates/registration/password_change_done.html
> diff --git a/templates/registration/password_change_form.html b/patchwork/templates/registration/password_change_form.html
> similarity index 100%
> rename from templates/registration/password_change_form.html
> rename to patchwork/templates/registration/password_change_form.html
> diff --git a/templates/registration/password_reset_complete.html b/patchwork/templates/registration/password_reset_complete.html
> similarity index 100%
> rename from templates/registration/password_reset_complete.html
> rename to patchwork/templates/registration/password_reset_complete.html
> diff --git a/templates/registration/password_reset_confirm.html b/patchwork/templates/registration/password_reset_confirm.html
> similarity index 100%
> rename from templates/registration/password_reset_confirm.html
> rename to patchwork/templates/registration/password_reset_confirm.html
> diff --git a/templates/registration/password_reset_done.html b/patchwork/templates/registration/password_reset_done.html
> similarity index 100%
> rename from templates/registration/password_reset_done.html
> rename to patchwork/templates/registration/password_reset_done.html
> diff --git a/templates/registration/password_reset_email.html b/patchwork/templates/registration/password_reset_email.html
> similarity index 100%
> rename from templates/registration/password_reset_email.html
> rename to patchwork/templates/registration/password_reset_email.html
> diff --git a/templates/registration/password_reset_form.html b/patchwork/templates/registration/password_reset_form.html
> similarity index 100%
> rename from templates/registration/password_reset_form.html
> rename to patchwork/templates/registration/password_reset_form.html
> diff --git a/requirements-test.txt b/requirements-test.txt
> index 5afe243..43af5ea 100644
> --- a/requirements-test.txt
> +++ b/requirements-test.txt
> @@ -2,4 +2,4 @@ mysqlclient~=1.4.4
>  psycopg2-binary~=2.8.0
>  sqlparse~=0.3.0
>  python-dateutil~=2.8.0
> -https://github.com/p1c2u/openapi-core/archive/97ec8c796746f72ef3298fe92078b5f80e1f66f7.tar.gz
> +git+https://github.com/p1c2u/openapi-core.git@97ec8c796746f72ef3298fe92078b5f80e1f66f7  # openapi-core
> diff --git a/setup.py b/setup.py
> new file mode 100755
> index 0000000..0ea5fe4
> --- /dev/null
> +++ b/setup.py
> @@ -0,0 +1,69 @@
> +#!/usr/bin/env python
> +
> +import os
> +
> +from setuptools import setup, find_packages
> +
> +
> +here = os.path.abspath(os.path.dirname(__file__))
> +with open(os.path.join(here, "README.rst")) as fd:
> +    README = fd.read()
> +
> +
> +def get_requirements(requirements_file="requirements-prod.txt"):
> +    """Get the contents of a file listing the requirements.
> +
> +    Args:
> +        requirements_file (str): The path to the requirements file, relative
> +                                 to this file.
> +
> +    Returns:
> +        list: the list of requirements, or an empty list if
> +              ``requirements_file`` could not be opened or read.
> +    """
> +    with open(requirements_file) as fd:
> +        lines = fd.readlines()
> +    dependencies = []
> +    for line in lines:
> +        maybe_dep = line.strip()
> +        if maybe_dep.startswith("#"):
> +            # Skip pure comment lines
> +            continue
> +        if maybe_dep.startswith("git+"):
> +            # VCS reference for dev purposes, expect a trailing comment
> +            # with the normal requirement
> +            __, __, maybe_dep = maybe_dep.rpartition("#")
> +        else:
> +            # Ignore any trailing comment
> +            maybe_dep, __, __ = maybe_dep.partition("#")
> +        # Remove any whitespace and assume non-empty results are dependencies
> +        maybe_dep = maybe_dep.strip()
> +        if maybe_dep:
> +            dependencies.append(maybe_dep)
> +    return dependencies
> +
> +
> +setup(
> +    name="patchwork",
> +    version="3.0.0a1",
> +    description="A patch tracking system for community-based projects.",
> +    long_description=README,
> +    url="https://github.com/getpatchwork/patchwork/",
> +    # Possible options are at https://pypi.python.org/pypi?%3Aaction=list_classifiers
> +    classifiers=[
> +        "Development Status :: 5 - Production/Stable",
> +        "Framework :: Django",
> +        "License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
> +        "Programming Language :: Python :: 3",
> +        "Programming Language :: Python :: 3.6",
> +        "Programming Language :: Python :: 3.7",
> +        "Programming Language :: Python :: 3.8",
> +    ],
> +    license="GPLv2",
> +    packages=find_packages(),
> +    include_package_data=True,
> +    zip_safe=False,
> +    install_requires=get_requirements(),
> +    tests_require=get_requirements(requirements_file="requirements-test.txt"),
> +    test_suite="patchwork.tests",
> +)



More information about the Patchwork mailing list