Repository: doccano/doccano

Issue:
Error: pg_config executable not found on pip installation
How to reproduce the behaviour
---------

If we install doccano by pip without PostgresQL, the installation failed:

```bash
    ERROR: Command errored out with exit status 1:
     command: /usr/local/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-ah3c9rb8/psycopg2_417f887249d841b688fd71f98d0c1c9d/setup.py'"'"'; __file__='"'"'/tmp/pip-install-ah3c9rb8/psycopg2_417f887249d841b688fd71f98d0c1c9d/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-rx5i396x
         cwd: /tmp/pip-install-ah3c9rb8/psycopg2_417f887249d841b688fd71f98d0c1c9d/
    Complete output (23 lines):
    running egg_info
    creating /tmp/pip-pip-egg-info-rx5i396x/psycopg2.egg-info
    writing /tmp/pip-pip-egg-info-rx5i396x/psycopg2.egg-info/PKG-INFO
    writing dependency_links to /tmp/pip-pip-egg-info-rx5i396x/psycopg2.egg-info/dependency_links.txt
    writing top-level names to /tmp/pip-pip-egg-info-rx5i396x/psycopg2.egg-info/top_level.txt
    writing manifest file '/tmp/pip-pip-egg-info-rx5i396x/psycopg2.egg-info/SOURCES.txt'
    
    Error: pg_config executable not found.
    
    pg_config is required to build psycopg2 from source.  Please add the directory
    containing pg_config to the $PATH or specify the full executable path with the
    option:
    
        python setup.py build_ext --pg-config /path/to/pg_config build ...
    
    or with the pg_config option in 'setup.cfg'.
    
    If you prefer to avoid building psycopg2 from source, please install the PyPI
    'psycopg2-binary' package instead.
    
    For further information please check the 'doc/src/install.rst' file (also at
    <https://www.psycopg.org/docs/install.html>).
    
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
```

Your Environment
---------
<!-- Include details of your environment.-->
*   Operating System: Debian Buster
*   Python Version Used: 3.8.6
*   When you install doccano: Now
*   How did you install doccano (Heroku button etc): pip



Discussion:
This is due to `django-heroku`:

```bash
django-heroku==0.3.1
  - dj-database-url [required: >=0.5.0, installed: 0.5.0]
  - django [required: Any, installed: 3.1.4]
    - asgiref [required: >=3.2.10,<4, installed: 3.3.1]
    - pytz [required: Any, installed: 2020.4]
    - sqlparse [required: >=0.2.2, installed: 0.4.1]
  - psycopg2 [required: Any, installed: 2.8.6]
  - whitenoise [required: Any, installed: 5.2.0]
```

Resolving patch:
diff --git a/app/app/settings.py b/app/app/settings.py
--- a/app/app/settings.py
+++ b/app/app/settings.py
@@ -10,9 +10,10 @@
 Any setting that is configured via an environment variable may
 also be set in a `.env` file in the project base directory.
 """
+import importlib.util
+import sys
 from os import path
 
-import django_heroku
 import dj_database_url
 from environs import Env
 from furl import furl
@@ -53,13 +54,13 @@
     'django.contrib.staticfiles',
     'server.apps.ServerConfig',
     'api.apps.ApiConfig',
-    'widget_tweaks',
+    # 'widget_tweaks',
     'rest_framework',
     'rest_framework.authtoken',
     'django_filters',
     'social_django',
     'polymorphic',
-    'webpack_loader',
+    # 'webpack_loader',
     'corsheaders',
     'drf_yasg'
 ]
@@ -83,7 +84,7 @@
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'social_django.middleware.SocialAuthExceptionMiddleware',
-    'applicationinsights.django.ApplicationInsightsMiddleware',
+    # 'applicationinsights.django.ApplicationInsightsMiddleware',
     'corsheaders.middleware.CorsMiddleware',
 ]
 
@@ -277,7 +278,13 @@
 LOGIN_REDIRECT_URL = '/projects/'
 LOGOUT_REDIRECT_URL = '/'
 
-django_heroku.settings(locals(), test_runner=False)
+# dynamic import to avoid installing psycopg2 on pip installation.
+name = 'django_heroku'
+if (spec := importlib.util.find_spec(name)) is not None:
+    module = importlib.util.module_from_spec(spec)
+    sys.modules[name] = module
+    spec.loader.exec_module(module)
+    module.settings(locals(), test_runner=False)
 
 # Change 'default' database configuration with $DATABASE_URL.
 DATABASES['default'].update(dj_database_url.config(
@@ -309,7 +316,7 @@
 CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', [])
 
 # Allow all host headers
-# ALLOWED_HOSTS = ['*']
+ALLOWED_HOSTS = ['*']
 
 # Size of the batch for creating documents
 # on the import phase
diff --git a/app/doccano/doccano.py b/app/doccano/doccano.py
--- a/app/doccano/doccano.py
+++ b/app/doccano/doccano.py
@@ -4,13 +4,13 @@
 
 
 def main():
-    parser = argparse.ArgumentParser(description='doccano.')
+    parser = argparse.ArgumentParser(description='doccano, text annotation for machine learning practitioners.')
     parser.add_argument('--username', type=str, default='admin', help='admin username')
     parser.add_argument('--password', type=str, default='password', help='admin password')
     parser.add_argument('--email', type=str, default='example@example.com', help='admin email')
-    parser.add_argument('--port', type=int, default=8000, help='port')
-    parser.add_argument('--workers', type=int, default=1, help='workers')
-    parser.add_argument('--database_url', type=str, default='sqlite:///doccano.db', help='data store')
+    parser.add_argument('--port', type=int, default=8000, help='port number')
+    # parser.add_argument('--workers', type=int, default=1, help='the number of workers')
+    parser.add_argument('--database_url', type=str, default='sqlite:///doccano.db', help='the database URL')
     args = parser.parse_args()
 
     os.environ.setdefault('DEBUG', 'False')
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
 from setuptools import find_packages, setup
 
 NAME = 'doccano'
-DESCRIPTION = 'doccano'
+DESCRIPTION = 'doccano, text annotation tool for machine learning practitioners'
 URL = 'https://github.com/doccano/doccano'
 EMAIL = 'hiroki.nakayama.py@gmail.com'
 AUTHOR = 'Hironsan'
@@ -16,8 +16,9 @@
 with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
     long_description = '\n' + f.read()
 
-# required = ['requests', 'boto3', 'pydantic', 'jinja2']
-required = [line.rstrip() for line in io.open(os.path.join(here, 'app/requirements.txt')) if not line.startswith('psy')]
+# Todo: make a cleaned requirements.txt
+required = [line.rstrip() for line in io.open(os.path.join(here, 'app/requirements.txt'))
+            if not line.startswith(('psycopg2', 'django-heroku', 'django-mssql-backend'))]
 
 setup(
     name=NAME,
@@ -36,6 +37,10 @@
         ]
     },
     install_requires=required,
+    extras_require={
+        'postgresql': ['psycopg2-binary>=2.8.6'],
+        'mssql': ['django-mssql-backend>=2.8.1'],
+    },
     include_package_data=True,
     license=LICENSE,
     classifiers=[


Test patch: