From patchwork Tue Apr 28 21:36:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeremy Cline X-Patchwork-Id: 1278747 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49BZjP3PFmz9sSK for ; Wed, 29 Apr 2020 07:36:57 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UmFlH462; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UmFlH462; dkim-atps=neutral Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 49BZjP2qjTzDqvH for ; Wed, 29 Apr 2020 07:36:57 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=redhat.com (client-ip=207.211.31.81; helo=us-smtp-1.mimecast.com; envelope-from=jcline@redhat.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UmFlH462; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UmFlH462; dkim-atps=neutral Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 49BZjB6GddzDqrT for ; Wed, 29 Apr 2020 07:36:41 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1588109798; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7ycIaW+d5Du43fD88tuj+lzAkv/U2aEsIoEE4iiiGeg=; b=UmFlH4625loLJ3KwKXjuc4KXcK4awbabetv16wQnQ+UrmRFGdsf97qJb2MBL+Xb0MbTdyu heLPtwCk91K/hFF7jS1bXCH8pdS1iA7wn+pB7wn27yxrvmDIQnhSlzrKFUZdfqyJczUjVq +I3v6kAReBbOg+is0eB2tz754CWMsKQ= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1588109798; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7ycIaW+d5Du43fD88tuj+lzAkv/U2aEsIoEE4iiiGeg=; b=UmFlH4625loLJ3KwKXjuc4KXcK4awbabetv16wQnQ+UrmRFGdsf97qJb2MBL+Xb0MbTdyu heLPtwCk91K/hFF7jS1bXCH8pdS1iA7wn+pB7wn27yxrvmDIQnhSlzrKFUZdfqyJczUjVq +I3v6kAReBbOg+is0eB2tz754CWMsKQ= Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-19-M4G5CotFPTyCBx2tKpi8lw-1; Tue, 28 Apr 2020 17:36:32 -0400 X-MC-Unique: M4G5CotFPTyCBx2tKpi8lw-1 Received: by mail-qt1-f198.google.com with SMTP id v18so26105312qtq.22 for ; Tue, 28 Apr 2020 14:36:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=E5rAA49pwxv9e420pH2BiPtt4Bzai/2a4xAJxh4UZPw=; b=aZnl+x8lGSHXSpt/HoIkgSvB0UCWGb9BqSYbWsRzGFcHFOEhptD4hoZ+0NGhry/Yem I3R/S0782vSta3EZExLw65/I3YFUabzV71Hv7UJNdMdpOWAUXZs8FUEV31JiAbQMRCI7 Tl3xEySf9OMKU7vcpXdmTQrU758Yg6yvzfGNqaclU3/gL0i4c6eAgvW2x5rj6jd9A4ke NWB2tBbKblEM10i3KJQQtqkz1eC1Cda9PS85eqSE7b77PRrux/ZUifqz0LtTvP9yLb+c nWTbcourErFsSLUICxmkjt3hpGipPAR6RIC3GrgddWhBxDJgiVkGjRJfj9l9WGVGAri/ uqLQ== X-Gm-Message-State: AGi0PubGUi5XA3F7NBjCAigwNMkVx0c0r2LawBZAZX1yaUQRODjp6ptb WI0hks1WRbZxO/wHR18jrqLo9oFj01FCx/GFfiMjlCDYqIXRkY72Ehdygb2s3kupTSV08PRXKwZ XB47FvAZsJJQr7Bb7A3xGqg== X-Received: by 2002:a37:d287:: with SMTP id f129mr29465705qkj.52.1588109790471; Tue, 28 Apr 2020 14:36:30 -0700 (PDT) X-Google-Smtp-Source: APiQypJ/IAYZeIkAPiecWspo0Ht3IwxfgcbJ+XfbIv5feqhCMLg8NJBV8IFKocUwuwKHPmOXNw9cmA== X-Received: by 2002:a37:d287:: with SMTP id f129mr29465680qkj.52.1588109789928; Tue, 28 Apr 2020 14:36:29 -0700 (PDT) Received: from dev.jcline.org.com ([136.56.87.133]) by smtp.gmail.com with ESMTPSA id z26sm14569063qkg.39.2020.04.28.14.36.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Apr 2020 14:36:29 -0700 (PDT) From: Jeremy Cline To: patchwork@lists.ozlabs.org Subject: [RFC] Add a setup.py so Patchwork can be pip-installed Date: Tue, 28 Apr 2020 17:36:13 -0400 Message-Id: <20200428213613.280483-1-jcline@redhat.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" 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. Signed-off-by: Jeremy Cline --- 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", +)