From 6244b0a6d4bdd05c1a16e0d9e0111ac503f7b1d5 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Fri, 4 Dec 2020 14:16:53 +0900 Subject: [PATCH 1/6] Add setup.py to support pip installation --- app/MANIFEST.in | 7 ++++++ app/doccano/__init__.py | 0 app/doccano/doccano.py | 44 +++++++++++++++++++++++++++++++++ app/setup.py | 55 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 app/MANIFEST.in create mode 100644 app/doccano/__init__.py create mode 100644 app/doccano/doccano.py create mode 100644 app/setup.py diff --git a/app/MANIFEST.in b/app/MANIFEST.in new file mode 100644 index 00000000..e9e17c0c --- /dev/null +++ b/app/MANIFEST.in @@ -0,0 +1,7 @@ +include manage.py +include requirements.txt +include README.md +graft staticfiles +graft client +graft doccano +global-exclude *.pyc diff --git a/app/doccano/__init__.py b/app/doccano/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/doccano/doccano.py b/app/doccano/doccano.py new file mode 100644 index 00000000..16f255d6 --- /dev/null +++ b/app/doccano/doccano.py @@ -0,0 +1,44 @@ +import argparse +import os +import subprocess + + +def main(): + parser = argparse.ArgumentParser(prog='gfg', description='GfG article demo package.') + parser.add_argument('--username', type=str, default='admin') + parser.add_argument('--password', type=str, default='password') + parser.add_argument('--email', type=str, default='example@example.com') + parser.add_argument('--port', type=int, default=8000) + parser.add_argument('--workers', type=int, default=1) + args = parser.parse_args() + + print('Create staticfiles.') + # subprocess.call(['python', 'manage.py', 'collectstatic', '--noinput'], shell=False) + + print('Setup databse.') + base = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + #base = os.path.abspath(os.path.dirname(__file__)) + # manage_path = os.path.join(base, 'app/manage.py') + manage_path = os.path.join(base, 'manage.py') + print(manage_path) + subprocess.call(['python', manage_path, 'wait_for_db'], shell=False) + subprocess.call(['python', manage_path, 'migrate'], shell=False) + subprocess.call(['python', manage_path, 'create_roles'], shell=False) + + print('Create admin user.') + subprocess.call(['python', manage_path, 'create_admin', + '--username', args.username, + '--password', args.password, + '--email', args.email, + '--noinput'], shell=False) + + print(f'Starting server with port {args.port}.') + subprocess.call(['gunicorn', + '--bind', f'0.0.0.0:{args.port}', + '--workers', str(args.workers), + 'app.wsgi', + '--timeout', '300'], shell=False) + + +if __name__ == '__main__': + main() diff --git a/app/setup.py b/app/setup.py new file mode 100644 index 00000000..cc17f416 --- /dev/null +++ b/app/setup.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import io +import os +import sys + +from setuptools import find_packages, setup + +NAME = 'doccano' +DESCRIPTION = 'doccano' +URL = 'https://github.com/doccano/doccano' +EMAIL = 'hiroki.nakayama.py@gmail.com' +AUTHOR = 'Hironsan' +LICENSE = 'MIT' + +here = os.path.abspath(os.path.dirname(__file__)) +with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = '\n' + f.read() + +if sys.argv[-1] == 'publish': + os.system('python setup.py sdist bdist_wheel upload') + sys.exit() + +# required = ['requests', 'boto3', 'pydantic', 'jinja2'] +required = [line.rstrip() for line in io.open(os.path.join(here, 'requirements.txt')) if not line.startswith('psy')] + +setup( + name=NAME, + use_scm_version={'root': '..'}, + setup_requires=['setuptools_scm'], + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=EMAIL, + url=URL, + packages=find_packages(exclude=('*.tests',)), + entry_points={ + 'console_scripts': [ + 'doccano = doccano.doccano:main' + ] + }, + install_requires=required, + include_package_data=True, + license=LICENSE, + classifiers=[ + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy' + ], +) From 8ba409e792cdd1fd7212cfbc86bdebd59487edb8 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Fri, 4 Dec 2020 15:06:56 +0900 Subject: [PATCH 2/6] Add a workflow to support pip installation --- .github/workflows/pypi-publish.yml | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/pypi-publish.yml diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml new file mode 100644 index 00000000..85e8ec02 --- /dev/null +++ b/.github/workflows/pypi-publish.yml @@ -0,0 +1,47 @@ +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Preparation + run: | + mkdir app/client + cp README.md app/README.md + - name: Use Node.js + uses: actions/setup-node@v1 + with: + node-version: '12.x' + - name: Build with Node.js + run: | + yarn install + yarn build + cp -r dist ../app/client/ + working-directory: ./frontend + - name: Setup Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel + pip install -r requirements.txt + - name: collectstatic + run: | + python manage.py collectstatic --noinput + working-directory: ./app + - name: Build a binary wheel and a source tarball + run: | + python setup.py sdist bdist_wheel + - name: Publish a Python distribution to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + user: ${{ secrets.PYPI_USERNAME }} + password: ${{ secrets.PYPI_PASSWORD }} From e38d9d1f8719f0a9393ddad5496dd4a09fd59121 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Mon, 7 Dec 2020 13:21:27 +0900 Subject: [PATCH 3/6] Update setup.py --- .github/workflows/pypi-publish.yml | 5 +++-- MANIFEST.in | 7 +++++++ app/MANIFEST.in | 7 ------- app/doccano/doccano.py | 15 +++------------ app/setup.py => setup.py | 11 +++-------- 5 files changed, 16 insertions(+), 29 deletions(-) create mode 100644 MANIFEST.in delete mode 100644 app/MANIFEST.in rename app/setup.py => setup.py (84%) diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index 85e8ec02..8fbdc214 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -7,13 +7,12 @@ on: jobs: deploy: runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v2 - name: Preparation run: | mkdir app/client - cp README.md app/README.md - name: Use Node.js uses: actions/setup-node@v1 with: @@ -24,6 +23,8 @@ jobs: yarn build cp -r dist ../app/client/ working-directory: ./frontend + env: + PUBLIC_PATH: "/static/_nuxt/" - name: Setup Python 3.8 uses: actions/setup-python@v2 with: diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..33a7af5b --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +include app/manage.py +include app/requirements.txt +include README.md +graft app/staticfiles +graft app/client +graft app/doccano +global-exclude *.pyc diff --git a/app/MANIFEST.in b/app/MANIFEST.in deleted file mode 100644 index e9e17c0c..00000000 --- a/app/MANIFEST.in +++ /dev/null @@ -1,7 +0,0 @@ -include manage.py -include requirements.txt -include README.md -graft staticfiles -graft client -graft doccano -global-exclude *.pyc diff --git a/app/doccano/doccano.py b/app/doccano/doccano.py index 16f255d6..91052e1c 100644 --- a/app/doccano/doccano.py +++ b/app/doccano/doccano.py @@ -12,15 +12,9 @@ def main(): parser.add_argument('--workers', type=int, default=1) args = parser.parse_args() - print('Create staticfiles.') - # subprocess.call(['python', 'manage.py', 'collectstatic', '--noinput'], shell=False) - - print('Setup databse.') + print('Setup Database.') base = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) - #base = os.path.abspath(os.path.dirname(__file__)) - # manage_path = os.path.join(base, 'app/manage.py') manage_path = os.path.join(base, 'manage.py') - print(manage_path) subprocess.call(['python', manage_path, 'wait_for_db'], shell=False) subprocess.call(['python', manage_path, 'migrate'], shell=False) subprocess.call(['python', manage_path, 'create_roles'], shell=False) @@ -33,11 +27,8 @@ def main(): '--noinput'], shell=False) print(f'Starting server with port {args.port}.') - subprocess.call(['gunicorn', - '--bind', f'0.0.0.0:{args.port}', - '--workers', str(args.workers), - 'app.wsgi', - '--timeout', '300'], shell=False) + os.environ['DEBUG'] = 'False' + subprocess.call(['python', manage_path, 'runserver', f'0.0.0.0:{args.port}']) if __name__ == '__main__': diff --git a/app/setup.py b/setup.py similarity index 84% rename from app/setup.py rename to setup.py index cc17f416..57538e8b 100644 --- a/app/setup.py +++ b/setup.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- import io import os -import sys from setuptools import find_packages, setup @@ -17,16 +16,12 @@ here = os.path.abspath(os.path.dirname(__file__)) with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: long_description = '\n' + f.read() -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist bdist_wheel upload') - sys.exit() - # required = ['requests', 'boto3', 'pydantic', 'jinja2'] -required = [line.rstrip() for line in io.open(os.path.join(here, 'requirements.txt')) if not line.startswith('psy')] +required = [line.rstrip() for line in io.open(os.path.join(here, 'app/requirements.txt')) if not line.startswith('psy')] setup( name=NAME, - use_scm_version={'root': '..'}, + use_scm_version=True, setup_requires=['setuptools_scm'], description=DESCRIPTION, long_description=long_description, @@ -37,7 +32,7 @@ setup( packages=find_packages(exclude=('*.tests',)), entry_points={ 'console_scripts': [ - 'doccano = doccano.doccano:main' + 'doccano = app.doccano.doccano:main' ] }, install_requires=required, From 700ef2bcfd6ae213055e6b76888c558696165052 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Mon, 7 Dec 2020 14:25:25 +0900 Subject: [PATCH 4/6] Update MANIFEST.in --- MANIFEST.in | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MANIFEST.in b/MANIFEST.in index 33a7af5b..635f3eca 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,19 @@ include app/manage.py include app/requirements.txt include README.md +exclude *.yml +exclude *.yaml + graft app/staticfiles graft app/client graft app/doccano + +prune app/staticfiles/bundle +prune app/staticfiles/assets +prune app/staticfiles/components +prune app/server/static +prune frontend +prune docs +prune nginx +prune tools global-exclude *.pyc From f3fc214170258c94249e34d2fbf9c3bfcb475ee1 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Mon, 7 Dec 2020 14:50:10 +0900 Subject: [PATCH 5/6] Allow user to specify database url --- app/doccano/doccano.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/doccano/doccano.py b/app/doccano/doccano.py index 91052e1c..4186cf9c 100644 --- a/app/doccano/doccano.py +++ b/app/doccano/doccano.py @@ -4,14 +4,18 @@ import subprocess def main(): - parser = argparse.ArgumentParser(prog='gfg', description='GfG article demo package.') - parser.add_argument('--username', type=str, default='admin') - parser.add_argument('--password', type=str, default='password') - parser.add_argument('--email', type=str, default='example@example.com') - parser.add_argument('--port', type=int, default=8000) - parser.add_argument('--workers', type=int, default=1) + parser = argparse.ArgumentParser(description='doccano.') + 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') args = parser.parse_args() + os.environ.setdefault('DEBUG', 'False') + os.environ.setdefault('DATABASE_URL', args.database_url) + print('Setup Database.') base = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) manage_path = os.path.join(base, 'manage.py') @@ -27,7 +31,6 @@ def main(): '--noinput'], shell=False) print(f'Starting server with port {args.port}.') - os.environ['DEBUG'] = 'False' subprocess.call(['python', manage_path, 'runserver', f'0.0.0.0:{args.port}']) From 1ddb8b77ba4de7838f1ebb11648508c3a0da8707 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Mon, 7 Dec 2020 14:58:28 +0900 Subject: [PATCH 6/6] Update README.md --- README.md | 95 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 8cc6c0d0..3b5d1320 100644 --- a/README.md +++ b/README.md @@ -26,28 +26,67 @@ You can try the [annotation demo](http://doccano.herokuapp.com). ## Usage -Two options to run doccano: +Three options to run doccano: -- production, -- development. +- pip(experimental) +- Docker +- Docker Compose + - production + - development -To use doccano, please follow: +For docker and docker compose, you need to install dependencies: -### Install dependencies +- [Git](https://git-scm.com) +- [Docker](https://www.docker.com) +- [Docker Compose](https://docs.docker.com/compose) -You need to install dependencies: +### pip installation -- [Git](https://git-scm.com), -- [Docker](https://www.docker.com), -- [Docker Compose](https://docs.docker.com/compose). +To install doccano, simply run: -### Get the code +```bash +pip install doccano +``` + +After installation, simply run the following command: + +```bash +doccano +``` + +Go to . + +### Docker + +As a one-time setup, create a Docker container as follows: + +```bash +docker pull doccano/doccano +docker container create --name doccano \ + -e "ADMIN_USERNAME=admin" \ + -e "ADMIN_EMAIL=admin@example.com" \ + -e "ADMIN_PASSWORD=password" \ + -p 8000:8000 doccano/doccano +``` + +Next, start doccano by running the container: + +```bash +docker container start doccano +``` + +To stop the container, run `docker container stop doccano -t 5`. +All data created in the container will persist across restarts. + +Go to . + +### Docker Compose You need to clone the repository: ```bash -$ git clone https://github.com/doccano/doccano.git -$ cd doccano +git clone https://github.com/doccano/doccano.git +cd doccano ``` _Note for Windows developers:_ Be sure to configure git to correctly handle line endings or you may encounter `status code 127` errors while running the services in future steps. Running with the git config options below will ensure your git directory correctly handles line endings. @@ -56,7 +95,7 @@ _Note for Windows developers:_ Be sure to configure git to correctly handle line git clone https://github.com/doccano/doccano.git --config core.autocrlf=input ``` -### Production +#### Production Set the superuser account credentials in the `docker-compose.prod.yml` file: @@ -79,35 +118,7 @@ $ docker-compose -f docker-compose.prod.yml up Go to . - - -### Development +#### Development Set the superuser account credentials in the `docker-compose.dev.yml` file: