From be54ee09ff131df88583a4feccda900095056c10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:11:17 +0000 Subject: [PATCH 01/16] chore(deps): bump django-cors-headers in /requirements Bumps [django-cors-headers](https://github.com/adamchainz/django-cors-headers) from 4.3.0 to 4.3.1. - [Changelog](https://github.com/adamchainz/django-cors-headers/blob/main/CHANGELOG.rst) - [Commits](https://github.com/adamchainz/django-cors-headers/compare/4.3.0...4.3.1) --- updated-dependencies: - dependency-name: django-cors-headers dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements/core.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/core.txt b/requirements/core.txt index 488ee6e2..b8daf8aa 100644 --- a/requirements/core.txt +++ b/requirements/core.txt @@ -2,7 +2,7 @@ django==4.2.7 # https://www.djangoproject.com/ django-environ==0.11.2 # https://github.com/joke2k/django-environ django-celery-beat==2.5.0 # https://github.com/celery/django-celery-beat drf-spectacular==0.26.5 # https://github.com/tfranzel/drf-spectacular -django-cors-headers==4.3.0 # https://github.com/adamchainz/django-cors-headers +django-cors-headers==4.3.1 # https://github.com/adamchainz/django-cors-headers djangorestframework-api-key==3.0.0 psycopg2-binary==2.9.9 # https://github.com/psycopg/psycopg2 From 132de4a057098d3673f79cb5b8fac5dada4e8b03 Mon Sep 17 00:00:00 2001 From: Xenepix Date: Sat, 2 Dec 2023 17:36:53 +0100 Subject: [PATCH 02/16] docs(reference): add pydantic style in reference documentation --- .github/workflows/mkdocs.yml | 1 + docs/plugins/griffe_doclinks.py | 90 +++++++++++++++++++++ docs/theme/assets/stylesheets/docstring.css | 83 +++++++++++++++++++ mkdocs.yml | 33 +++++--- requirements/development.txt | 1 + 5 files changed, 199 insertions(+), 9 deletions(-) create mode 100644 docs/plugins/griffe_doclinks.py create mode 100644 docs/theme/assets/stylesheets/docstring.css diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index 8de396c7..67d49d71 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - dev permissions: contents: write diff --git a/docs/plugins/griffe_doclinks.py b/docs/plugins/griffe_doclinks.py new file mode 100644 index 00000000..012461b8 --- /dev/null +++ b/docs/plugins/griffe_doclinks.py @@ -0,0 +1,90 @@ +import ast +import re +from functools import partial +from pathlib import Path +from typing import Tuple + +from griffe.dataclasses import Object as GriffeObject +from griffe.extensions import VisitorExtension +from pymdownx.slugs import slugify + +DOCS_PATH = Path(__file__).parent.parent +slugifier = slugify(case='lower') + + +def find_heading(content: str, slug: str, file_path: Path) -> Tuple[str, int]: + for m in re.finditer('^#+ (.+)', content, flags=re.M): + heading = m.group(1) + h_slug = slugifier(heading, '-') + if h_slug == slug: + return heading, m.end() + raise ValueError(f'heading with slug {slug!r} not found in {file_path}') + + +def insert_at_top(path: str, api_link: str) -> str: + rel_file = path.rstrip('/') + '.md' + file_path = DOCS_PATH / rel_file + content = file_path.read_text() + second_heading = re.search('^#+ ', content, flags=re.M) + assert second_heading, 'unable to find second heading in file' + first_section = content[: second_heading.start()] + + if f'[{api_link}]' not in first_section: + print(f'inserting API link "{api_link}" at the top of {file_path.relative_to(DOCS_PATH)}') + file_path.write_text('??? api "API Documentation"\n' f' [`{api_link}`][{api_link}]
\n\n' f'{content}') + + heading = file_path.stem.replace('_', ' ').title() + return f'!!! abstract "Usage Documentation"\n [{heading}](../{rel_file})\n' + + +def replace_links(m: re.Match, *, api_link: str) -> str: + path_group = m.group(1) + if '#' not in path_group: + # no heading id, put the content at the top of the page + return insert_at_top(path_group, api_link) + + usage_path, slug = path_group.split('#', 1) + rel_file = usage_path.rstrip('/') + '.md' + file_path = DOCS_PATH / rel_file + content = file_path.read_text() + heading, heading_end = find_heading(content, slug, file_path) + + next_heading = re.search('^#+ ', content[heading_end:], flags=re.M) + if next_heading: + next_section = content[heading_end : heading_end + next_heading.start()] + else: + next_section = content[heading_end:] + + if f'[{api_link}]' not in next_section: + print(f'inserting API link "{api_link}" into {file_path.relative_to(DOCS_PATH)}') + file_path.write_text( + f'{content[:heading_end]}\n\n' + '??? api "API Documentation"\n' + f' [`{api_link}`][{api_link}]
' + f'{content[heading_end:]}' + ) + + return f'!!! abstract "Usage Documentation"\n [{heading}](../{rel_file}#{slug})\n' + + +def update_docstring(obj: GriffeObject) -> str: + return re.sub( + r'usage[\- ]docs: ?https://docs\.pydantic\.dev/.+?/(\S+)', + partial(replace_links, api_link=obj.path), + obj.docstring.value, + flags=re.I, + ) + + +def update_docstrings_recursively(obj: GriffeObject) -> None: + if obj.docstring: + obj.docstring.value = update_docstring(obj) + for member in obj.members.values(): + if not member.is_alias: + update_docstrings_recursively(member) + + +class Extension(VisitorExtension): + def visit_module(self, node: ast.AST) -> None: + module = self.visitor.current.module + update_docstrings_recursively(module) diff --git a/docs/theme/assets/stylesheets/docstring.css b/docs/theme/assets/stylesheets/docstring.css new file mode 100644 index 00000000..eb51d691 --- /dev/null +++ b/docs/theme/assets/stylesheets/docstring.css @@ -0,0 +1,83 @@ +.tile { +display: flex; +text-align: center; +width: 120px; +height: 120px; +display: inline-block; +margin: 10px; +padding: 5px; +border-radius: .5rem; +} + +.tile img { +width: 100px; +} + +.md-typeset__table > table { +max-height: 60vh; +} + +.md-typeset__table > table thead { +position: sticky; +top: 0; +background-color: var(--md-default-bg-color); +} + +.md-typeset__table > table th { +border-bottom: .05rem solid var(--md-typeset-table-color); +} + +.md-typeset__table > table tr:first-child td { +border-top: none; +} + +/* API documentation link admonition */ +:root { +--md-admonition-icon--api: url('data:image/svg+xml;charset=utf-8,') +} +.md-typeset .admonition.api, .md-typeset details.api { +border-color: #448aff; +} +.md-typeset .api > .admonition-title, .md-typeset .api > summary { +background-color: #448aff1a; +} +.md-typeset .api > .admonition-title::before, .md-typeset .api > summary::before { +background-color: #448aff; +-webkit-mask-image: var(--md-admonition-icon--api); + mask-image: var(--md-admonition-icon--api); +} + +/* Revert hue value to that of pre mkdocs-material v9.4.0 */ +[data-md-color-scheme="slate"] { +--md-hue: 230; +--md-default-bg-color: hsla(230, 15%, 21%, 1); +} + + + /* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); +} + +/* Mark external links as such. */ +a.external::after, +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + mask-image: url('data:image/svg+xml,'); + -webkit-mask-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + vertical-align: middle; + position: relative; + + height: 1em; + width: 1em; + background-color: var(--md-typeset-a-color); +} + +a.external:hover::after, +a.autorefs-external:hover::after { + background-color: var(--md-accent-fg-color); +} diff --git a/mkdocs.yml b/mkdocs.yml index a3ff48c9..cdcb0ef9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,8 +7,10 @@ copyright: MIT Licence docs_dir: "docs/" extra_css: - - theme/assets/stylesheets/extra.css - - theme/assets/stylesheets/api.css + - assets/stylesheets/extra.css + - assets/stylesheets/api.css + - assets/stylesheets/docstring.css + extra: social: @@ -67,6 +69,12 @@ theme: - navigation.top - content.code.copy - search.suggest + - content.tabs.link + - content.code.annotate + +watch: + - django_napse + - docs plugins: - search @@ -83,16 +91,21 @@ plugins: python: paths: [.] options: + members_order: source + separate_signature: true + filters: ["!^_"] + docstring_options: + ignore_init_summary: true + merge_init_into_class: true + heading_level: 3 + extensions: + - docs/plugins/griffe_doclinks.py show_source: false allow_inspection: false show_bases: false show_root_heading: false docstring_style: google - docstring_section_style: list - docstring_options: - ignore_init_summary: false - trim_doctest_flags: true - heading_level: 3 + # docstring_section_style: list # Contributors - neoteroi.contribs: contributors: @@ -102,7 +115,7 @@ plugins: markdown_extensions: - toc: - permalink: "#" + permalink: true - pymdownx.snippets: - pymdownx.magiclink: - attr_list: @@ -122,8 +135,10 @@ markdown_extensions: alternate_style: true - pymdownx.highlight: anchor_linenums: true + pygments_lang_class: true # line_spans: __span - # pygments_lang_class: true + + nav: - Home: diff --git a/requirements/development.txt b/requirements/development.txt index f71a6b79..8e4a2ad3 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -19,4 +19,5 @@ neoteroi-mkdocs==1.0.4 # https://github.com/Neoteroi/mkdocs-plugins drf-spectacular==0.26.5 # https://github.com/tfranzel/drf-spectacular mkdocstrings==0.24.0 # https://github.com/mkdocstrings/mkdocstrings mkdocstrings-python==1.7.5 # https://github.com/mkdocstrings/python +watchfiles==0.21.0 # https://github.com/samuelcolvin/watchfiles From 3a99a7a5c2b3625f02e05126d14bd84af4a1b689 Mon Sep 17 00:00:00 2001 From: Xenepix Date: Sat, 2 Dec 2023 17:38:19 +0100 Subject: [PATCH 03/16] docs(ruff): compliance --- docs/plugins/griffe_doclinks.py | 43 +++++++++++++++------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/docs/plugins/griffe_doclinks.py b/docs/plugins/griffe_doclinks.py index 012461b8..00dca481 100644 --- a/docs/plugins/griffe_doclinks.py +++ b/docs/plugins/griffe_doclinks.py @@ -9,59 +9,54 @@ from pymdownx.slugs import slugify DOCS_PATH = Path(__file__).parent.parent -slugifier = slugify(case='lower') +slugifier = slugify(case="lower") def find_heading(content: str, slug: str, file_path: Path) -> Tuple[str, int]: - for m in re.finditer('^#+ (.+)', content, flags=re.M): + for m in re.finditer("^#+ (.+)", content, flags=re.M): heading = m.group(1) - h_slug = slugifier(heading, '-') + h_slug = slugifier(heading, "-") if h_slug == slug: return heading, m.end() - raise ValueError(f'heading with slug {slug!r} not found in {file_path}') + msg = f"heading with slug {slug!r} not found in {file_path}" + raise ValueError(msg) def insert_at_top(path: str, api_link: str) -> str: - rel_file = path.rstrip('/') + '.md' + rel_file = path.rstrip("/") + ".md" file_path = DOCS_PATH / rel_file content = file_path.read_text() - second_heading = re.search('^#+ ', content, flags=re.M) - assert second_heading, 'unable to find second heading in file' + second_heading = re.search("^#+ ", content, flags=re.M) + assert second_heading, "unable to find second heading in file" # noqa: S101 first_section = content[: second_heading.start()] - if f'[{api_link}]' not in first_section: + if f"[{api_link}]" not in first_section: print(f'inserting API link "{api_link}" at the top of {file_path.relative_to(DOCS_PATH)}') - file_path.write_text('??? api "API Documentation"\n' f' [`{api_link}`][{api_link}]
\n\n' f'{content}') + file_path.write_text('??? api "API Documentation"\n' f" [`{api_link}`][{api_link}]
\n\n{content}") # noqa: ISC001 - heading = file_path.stem.replace('_', ' ').title() + heading = file_path.stem.replace("_", " ").title() return f'!!! abstract "Usage Documentation"\n [{heading}](../{rel_file})\n' def replace_links(m: re.Match, *, api_link: str) -> str: path_group = m.group(1) - if '#' not in path_group: + if "#" not in path_group: # no heading id, put the content at the top of the page return insert_at_top(path_group, api_link) - usage_path, slug = path_group.split('#', 1) - rel_file = usage_path.rstrip('/') + '.md' + usage_path, slug = path_group.split("#", 1) + rel_file = usage_path.rstrip("/") + ".md" file_path = DOCS_PATH / rel_file content = file_path.read_text() heading, heading_end = find_heading(content, slug, file_path) - next_heading = re.search('^#+ ', content[heading_end:], flags=re.M) - if next_heading: - next_section = content[heading_end : heading_end + next_heading.start()] - else: - next_section = content[heading_end:] + next_heading = re.search("^#+ ", content[heading_end:], flags=re.M) + next_section = content[heading_end : heading_end + next_heading.start()] if next_heading else content[heading_end:] - if f'[{api_link}]' not in next_section: + if f"[{api_link}]" not in next_section: print(f'inserting API link "{api_link}" into {file_path.relative_to(DOCS_PATH)}') file_path.write_text( - f'{content[:heading_end]}\n\n' - '??? api "API Documentation"\n' - f' [`{api_link}`][{api_link}]
' - f'{content[heading_end:]}' + f"{content[:heading_end]}\n\n" '??? api "API Documentation"\n' f" [`{api_link}`][{api_link}]
" f"{content[heading_end:]}", # noqa: ISC001 ) return f'!!! abstract "Usage Documentation"\n [{heading}](../{rel_file}#{slug})\n' @@ -69,7 +64,7 @@ def replace_links(m: re.Match, *, api_link: str) -> str: def update_docstring(obj: GriffeObject) -> str: return re.sub( - r'usage[\- ]docs: ?https://docs\.pydantic\.dev/.+?/(\S+)', + r"usage[\- ]docs: ?https://docs\.pydantic\.dev/.+?/(\S+)", partial(replace_links, api_link=obj.path), obj.docstring.value, flags=re.I, From 6bb5ca5de1d8b961d052a16a686992b955b2a04a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:24:31 +0000 Subject: [PATCH 04/16] chore(deps-dev): bump ruff from 0.1.5 to 0.1.8 in /requirements Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.5 to 0.1.8. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/v0.1.5...v0.1.8) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements/development.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/development.txt b/requirements/development.txt index 8e4a2ad3..ecabce0b 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -7,7 +7,7 @@ watchfiles==0.21.0 # https://github.com/samuelcolvin/watchfiles Werkzeug==3.0.1 # https://github.com/pallets/werkzeug django-extensions==3.2.3 # https://github.com/django-extensions/django-extensions django-debug-toolbar==4.2.0 # https://github.com/jazzband/django-debug-toolbar -ruff==0.1.5 # https://github.com/astral-sh/ruff +ruff==0.1.8 # https://github.com/astral-sh/ruff platformdirs==3.11.0 # https://github.com/platformdirs/platformdirs # Documentation From e9b99d30438870ba66f10f73fb955f676aec503e Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 14:47:19 +0100 Subject: [PATCH 05/16] tmp --- .github/workflows/mkdocs.yml | 2 ++ mkdocs.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index 67d49d71..cc8e1bca 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -5,6 +5,7 @@ on: branches: - main - dev + - feature/mkdocstring permissions: contents: write @@ -53,4 +54,5 @@ jobs: mkdocs-material- - run: | pip install -r requirements/development.txt + make coverage mkdocs gh-deploy --force diff --git a/mkdocs.yml b/mkdocs.yml index cdcb0ef9..b1c98dad 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -109,7 +109,7 @@ plugins: # Contributors - neoteroi.contribs: contributors: - - email: firenix.nex@gmail.com + - email: Firenix.nex@gmail.com image: https://avatars.githubusercontent.com/u/11559668?s=400&u=6564188698fbd519f21b7f400e522659e41a158e&v=4 From b207724036db6de3be6aee22f6807822ab97b12f Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 14:50:10 +0100 Subject: [PATCH 06/16] tmp --- .github/workflows/mkdocs.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index cc8e1bca..511d0bcf 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: 3.x + python-version: 3.11 - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - uses: actions/cache@v3 with: @@ -54,5 +54,7 @@ jobs: mkdocs-material- - run: | pip install -r requirements/development.txt - make coverage + coverage run tests/test_app/manage.py test -v2 --keepdb + coverage html + coverage report mkdocs gh-deploy --force From ecd4990b2ce8ed60ad46c7b6b5825e5d365621ed Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 14:54:51 +0100 Subject: [PATCH 07/16] tmp --- .github/workflows/mkdocs.yml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index 511d0bcf..6175d1a6 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -52,9 +52,21 @@ jobs: path: .cache restore-keys: | mkdocs-material- - - run: | - pip install -r requirements/development.txt - coverage run tests/test_app/manage.py test -v2 --keepdb - coverage html - coverage report + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pip-tools + pip-compile ./requirements/development.txt --output-file ./full-requirements.txt --resolver=backtracking + pip install -r ./full-requirements.txt + - name: Tests with coverage + run: | + export PYTHONPATH="$PYTHONPATH:./django-napse/" + export NAPSE_IS_IN_PIPELINE=True + cd tests/test_app + bash setup_secrets.sh + cd ../.. + python3 tests/test_app/manage.py makemigrations && python3 tests/test_app/manage.py migrate + coverage run ./tests/test_app/manage.py test -v2 --keepdb && coverage html + - name: Deploy documentation + run: | mkdocs gh-deploy --force From e86c3be2dce2c3817756ecbc0cd6ea2016213da8 Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 15:00:13 +0100 Subject: [PATCH 08/16] tmp --- .github/workflows/mkdocs.yml | 70 ++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index 6175d1a6..faaf6345 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -11,33 +11,33 @@ permissions: contents: write jobs: - api-schema: - name: API schema - runs-on: ubuntu-latest + start-runner: + name: Start self-hosted EC2 runner + runs-on: ubuntu-latest + outputs: + label: ${{ steps.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} steps: - - uses: actions/checkout@v4 - with: - python-version: 3.11 - - - name: Set up python - uses: actions/setup-python@v4 - with: - python-version: "3.11" - architecture: "x64" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pip-tools - pip-compile ./requirements/development.txt --output-file ./full-requirements.txt --resolver=backtracking - pip install -r ./full-requirements.txt - - - name: Write open-api schema - run: python tests/test_app/manage.py spectacular --file docs/schema.yml + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Start EC2 runner + id: start-ec2-runner + uses: machulav/ec2-github-runner@v2 + with: + mode: start + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + ec2-image-id: ${{ secrets.AWS_EC2_IMAGE_ID }} + ec2-instance-type: t3.micro + subnet-id: ${{ secrets.AWS_SUBNET_ID }} + deploy: - needs: api-schema + needs: start-runner name: Deploy documentation runs-on: ubuntu-latest steps: @@ -67,6 +67,30 @@ jobs: cd ../.. python3 tests/test_app/manage.py makemigrations && python3 tests/test_app/manage.py migrate coverage run ./tests/test_app/manage.py test -v2 --keepdb && coverage html + - name: Write open-api schema + run: python tests/test_app/manage.py spectacular --file docs/schema.yml - name: Deploy documentation run: | mkdocs gh-deploy --force + + stop-runner: + name: Stop self-hosted EC2 runner + needs: + - start-runner # required to get output from the start-runner job + - deploy # required to wait when the main job is done + runs-on: ubuntu-latest + if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Stop EC2 runner + uses: machulav/ec2-github-runner@v2 + with: + mode: stop + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + label: ${{ needs.start-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-runner.outputs.ec2-instance-id }} \ No newline at end of file From b8c0f8913f879c6e57e7081d631a028c7e6f794a Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 15:02:36 +0100 Subject: [PATCH 09/16] tmp --- .github/workflows/mkdocs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index faaf6345..65b27e24 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -34,6 +34,8 @@ jobs: ec2-image-id: ${{ secrets.AWS_EC2_IMAGE_ID }} ec2-instance-type: t3.micro subnet-id: ${{ secrets.AWS_SUBNET_ID }} + security-group-id: ${{ secrets.AWS_SECURITY_GROUP_ID }} + deploy: From a60888cc7306bcbe23e3b1157b986a55e1aa91d6 Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 15:13:45 +0100 Subject: [PATCH 10/16] tmp --- .github/workflows/django.yml | 4 ++-- .github/workflows/mkdocs.yml | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index f4c1c65c..fc100236 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -95,8 +95,8 @@ jobs: label: Coverage message: ${{ env.COVERAGE }} % valColorRange: ${{ env.COVERAGE }} - minColorRange: 50 - maxColorRange: 95 + minColorRange: 70 + maxColorRange: 100 stop-runner: name: Stop self-hosted EC2 runner diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index 65b27e24..98441f00 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -41,9 +41,12 @@ jobs: deploy: needs: start-runner name: Deploy documentation - runs-on: ubuntu-latest + runs-on: ${{ needs.start-runner.outputs.label }} + timeout-minutes: 10 steps: - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} - uses: actions/setup-python@v4 with: python-version: 3.11 From a900525b36e19f40cf0019ed35540b673a3727ae Mon Sep 17 00:00:00 2001 From: Xenepix Date: Mon, 18 Dec 2023 15:49:47 +0100 Subject: [PATCH 11/16] fix(docs): finish mkdocs setup --- .github/workflows/mkdocs.yml | 3 +-- docs/sources/reference/spaces.md | 2 ++ mkdocs.yml | 13 ++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index 98441f00..a283fb59 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -4,8 +4,6 @@ on: push: branches: - main - - dev - - feature/mkdocstring permissions: contents: write @@ -43,6 +41,7 @@ jobs: name: Deploy documentation runs-on: ${{ needs.start-runner.outputs.label }} timeout-minutes: 10 + environment: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} steps: - uses: actions/checkout@v4 with: diff --git a/docs/sources/reference/spaces.md b/docs/sources/reference/spaces.md index 97e99d40..725e8635 100644 --- a/docs/sources/reference/spaces.md +++ b/docs/sources/reference/spaces.md @@ -1,6 +1,8 @@ # Space ## Space's Model ::: django_napse.core.models.NapseSpace + options: + --- ## Space's manager diff --git a/mkdocs.yml b/mkdocs.yml index b1c98dad..c719f9cb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -98,14 +98,21 @@ plugins: ignore_init_summary: true merge_init_into_class: true heading_level: 3 - extensions: - - docs/plugins/griffe_doclinks.py + # extensions: + # - docs/plugins/griffe_doclinks.py show_source: false allow_inspection: false show_bases: false show_root_heading: false - docstring_style: google + docstring_style: google # docstring_section_style: list + + # Signature + show_signature: true + separate_signature: true + show_signature_annotations: true + annotations_path: full + line_length: 80 # Contributors - neoteroi.contribs: contributors: From 2a4627289b33b537b9c045296cca33090e30d45a Mon Sep 17 00:00:00 2001 From: Xenepix Date: Thu, 21 Dec 2023 16:21:51 +0100 Subject: [PATCH 12/16] fix(space): remove possible_exchange_account --- django_napse/api/spaces/views/space_view.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/django_napse/api/spaces/views/space_view.py b/django_napse/api/spaces/views/space_view.py index 4a7da171..c34250cd 100644 --- a/django_napse/api/spaces/views/space_view.py +++ b/django_napse/api/spaces/views/space_view.py @@ -1,13 +1,11 @@ from rest_framework import status -from rest_framework.decorators import action from rest_framework.response import Response from rest_framework_api_key.permissions import HasAPIKey from django_napse.api.custom_permissions import HasFullAccessPermission, HasMasterKey, HasReadPermission from django_napse.api.custom_viewset import CustomViewSet -from django_napse.api.exchanges.serializers.exchange_account_serializer import ExchangeAccountSerializer from django_napse.api.spaces.serializers import SpaceDetailSerializer, SpaceSerializer -from django_napse.core.models import ExchangeAccount, NapseSpace +from django_napse.core.models import NapseSpace from django_napse.utils.errors import SpaceError @@ -38,7 +36,7 @@ def get_permissions(self): return [HasReadPermission()] case "list": return [HasAPIKey()] - case "possible_exchange_accounts" | "create": + case "create": return [HasMasterKey()] case _: @@ -82,11 +80,3 @@ def delete(self, request, *args, **kwargs): except SpaceError.DeleteError: return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) return Response(status=status.HTTP_204_NO_CONTENT) - - @action(detail=False, methods=["GET"]) - def possible_exchange_accounts(self, request): - serialized_exchange_account = ExchangeAccountSerializer(ExchangeAccount.objects.all(), many=True) - return Response( - serialized_exchange_account.data, - status=status.HTTP_200_OK, - ) From 039479fb0cd5b1cc15a7ada83cce5b0eb522c73b Mon Sep 17 00:00:00 2001 From: Xenepix Date: Thu, 21 Dec 2023 16:43:45 +0100 Subject: [PATCH 13/16] fix(fleet): improve list endpoint --- .../api/fleets/serializers/__init__.py | 1 + .../fleets/serializers/cluster_serialisers.py | 17 +++++++++++++++ .../fleets/serializers/fleet_serializers.py | 8 +++++-- django_napse/api/fleets/views/fleet_view.py | 15 +++++++++++-- django_napse/core/models/fleets/cluster.py | 12 +++++++++-- django_napse/core/models/fleets/fleet.py | 21 +++++++++++++++---- 6 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 django_napse/api/fleets/serializers/cluster_serialisers.py diff --git a/django_napse/api/fleets/serializers/__init__.py b/django_napse/api/fleets/serializers/__init__.py index b18113f7..deafb8a4 100644 --- a/django_napse/api/fleets/serializers/__init__.py +++ b/django_napse/api/fleets/serializers/__init__.py @@ -1 +1,2 @@ +from .cluster_serialisers import ClusterSerializer from .fleet_serializers import FleetDetailSerializer, FleetSerializer diff --git a/django_napse/api/fleets/serializers/cluster_serialisers.py b/django_napse/api/fleets/serializers/cluster_serialisers.py new file mode 100644 index 00000000..2508c7c1 --- /dev/null +++ b/django_napse/api/fleets/serializers/cluster_serialisers.py @@ -0,0 +1,17 @@ +from rest_framework import serializers + +from django_napse.api.bots.serializers import BotSerializer +from django_napse.core.models import Cluster + + +class ClusterSerializer(serializers.ModelSerializer): + template_bot = BotSerializer() + + class Meta: + model = Cluster + fields = [ + "template_bot", + "share", + "breakpoint", + "autoscale", + ] diff --git a/django_napse/api/fleets/serializers/fleet_serializers.py b/django_napse/api/fleets/serializers/fleet_serializers.py index a2138c8d..d8fa5831 100644 --- a/django_napse/api/fleets/serializers/fleet_serializers.py +++ b/django_napse/api/fleets/serializers/fleet_serializers.py @@ -2,12 +2,18 @@ from rest_framework.fields import empty from django_napse.api.bots.serializers import BotSerializer +from django_napse.api.fleets.serializers.cluster_serialisers import ClusterSerializer from django_napse.core.models import ConnectionWallet, Fleet class FleetSerializer(serializers.ModelSerializer): value = serializers.SerializerMethodField(read_only=True) bot_count = serializers.SerializerMethodField(read_only=True) + clusters = ClusterSerializer( + write_only=True, + many=True, + required=True, + ) class Meta: model = Fleet @@ -20,8 +26,6 @@ class Meta: ] read_only_fields = [ "uuid", - "value", - "bot_count", ] def __init__(self, instance=None, data=empty, space=None, **kwargs): diff --git a/django_napse/api/fleets/views/fleet_view.py b/django_napse/api/fleets/views/fleet_view.py index 72831927..15afa269 100644 --- a/django_napse/api/fleets/views/fleet_view.py +++ b/django_napse/api/fleets/views/fleet_view.py @@ -5,7 +5,7 @@ from django_napse.api.custom_permissions import HasSpace from django_napse.api.custom_viewset import CustomViewSet from django_napse.api.fleets.serializers import FleetDetailSerializer, FleetSerializer -from django_napse.core.models import NapseSpace +from django_napse.core.models import Fleet, NapseSpace class FleetView(CustomViewSet): @@ -13,7 +13,10 @@ class FleetView(CustomViewSet): serializer_class = FleetSerializer def get_queryset(self): - self.space = NapseSpace.objects.get(uuid=self.request.query_params["space"]) + space_uuid = self.request.query_params.get("space", None) + if space_uuid is None: + return Fleet.objects.all() + self.space = NapseSpace.objects.get(uuid=space_uuid) return self.space.fleets def get_serialiser_class(self, *args, **kwargs): @@ -25,6 +28,13 @@ def get_serialiser_class(self, *args, **kwargs): result = actions.get(self.action) return result if result else super().get_serializer_class() + def get_permissions(self): + match self.action: + case "list" | "create": + return [HasAPIKey()] + case _: + return super().get_permissions() + def list(self, request): serializer = self.serializer_class(self.get_queryset(), many=True, space=self.space) return Response(serializer.data, status=status.HTTP_200_OK) @@ -34,6 +44,7 @@ def retrieve(self, request, pk=None): def create(self, request, *args, **kwargs): return Response(status=status.HTTP_501_NOT_IMPLEMENTED) + # serializer = self.serializer_class(data=request.data, space=self.space) def delete(self): return Response(status=status.HTTP_501_NOT_IMPLEMENTED) diff --git a/django_napse/core/models/fleets/cluster.py b/django_napse/core/models/fleets/cluster.py index fbfb026a..b75c17e4 100644 --- a/django_napse/core/models/fleets/cluster.py +++ b/django_napse/core/models/fleets/cluster.py @@ -8,8 +8,16 @@ class Cluster(models.Model): - fleet = models.ForeignKey("Fleet", on_delete=models.CASCADE, related_name="clusters") - template_bot = models.OneToOneField("Bot", on_delete=models.CASCADE, related_name="cluster") + fleet = models.ForeignKey( + "Fleet", + on_delete=models.CASCADE, + related_name="clusters", + ) + template_bot = models.OneToOneField( + "Bot", + on_delete=models.CASCADE, + related_name="cluster", + ) share = models.FloatField() breakpoint = models.FloatField() autoscale = models.BooleanField() diff --git a/django_napse/core/models/fleets/fleet.py b/django_napse/core/models/fleets/fleet.py index 2def824e..c603847d 100644 --- a/django_napse/core/models/fleets/fleet.py +++ b/django_napse/core/models/fleets/fleet.py @@ -11,12 +11,25 @@ class Fleet(models.Model): - uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - name = models.CharField(max_length=100, default="Fleet") - exchange_account = models.ForeignKey("ExchangeAccount", on_delete=models.CASCADE) + uuid = models.UUIDField( + default=uuid.uuid4, + editable=False, + unique=True, + ) + name = models.CharField( + max_length=100, + default="Fleet", + ) + exchange_account = models.ForeignKey( + "ExchangeAccount", + on_delete=models.CASCADE, + ) running = models.BooleanField(default=False) setup_finished = models.BooleanField(default=False) - created_at = models.DateTimeField(auto_now_add=True, blank=True) + created_at = models.DateTimeField( + auto_now_add=True, + blank=True, + ) objects = FleetManager() From 14b8a5376b7ad4346bb18569b0bef66cb295c137 Mon Sep 17 00:00:00 2001 From: Xenepix Date: Thu, 21 Dec 2023 17:02:17 +0100 Subject: [PATCH 14/16] docs(fixes): fix docs errors & warnings --- django_napse/utils/api_test_case.py | 26 +++++++++++++------------- docs/sources/reference/spaces.md | 2 -- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/django_napse/utils/api_test_case.py b/django_napse/utils/api_test_case.py index ffd8db89..5db965b8 100644 --- a/django_napse/utils/api_test_case.py +++ b/django_napse/utils/api_test_case.py @@ -96,42 +96,42 @@ def run_tests(self, mode): self.check_auth(name="No permissions", mode=mode, error_list=error_list, divider=100, expected=2) else: if HasSpace in permissions: - self.check_auth(name="HasSpace \w no key", mode=mode, error_list=error_list, expected=400) + self.check_auth(name="HasSpace with no key", mode=mode, error_list=error_list, expected=400) self.build_url(kwargs={"space": str("random uuid"), **self.kwargs}) - self.check_auth(name="HasSpace \w no key", mode=mode, error_list=error_list, expected=400) + self.check_auth(name="HasSpace with no key", mode=mode, error_list=error_list, expected=400) self.build_url(kwargs={"space": str("7aafc68d-f619-4874-aaf5-c123a176e303"), **self.kwargs}) - self.check_auth(name="HasSpace \w no key", mode=mode, error_list=error_list, expected=400) + self.check_auth(name="HasSpace with no key", mode=mode, error_list=error_list, expected=400) self.build_url(kwargs={"space": str(self.space.uuid), **self.kwargs}) if HasAPIKey in permissions: - self.check_auth(name="HasAPIKey \w no key", mode=mode, error_list=error_list) + self.check_auth(name="HasAPIKey with no key", mode=mode, error_list=error_list) if HasReadPermission in permissions: - self.check_auth(name="HasReadPermission \w no key", mode=mode, error_list=error_list) + self.check_auth(name="HasReadPermission with no key", mode=mode, error_list=error_list) self.build_key([]) self.authenticate() - self.check_auth(name="HasReadPermission \w no permissions", mode=mode, error_list=error_list) + self.check_auth(name="HasReadPermission with no permissions", mode=mode, error_list=error_list) if HasFullAccessPermission in permissions: - self.check_auth(name="HasFullAccessPermission \w no key", mode=mode, error_list=error_list) + self.check_auth(name="HasFullAccessPermission with no key", mode=mode, error_list=error_list) self.build_key([]) self.authenticate() - self.check_auth(name="HasFullAccessPermission \w no permissions", mode=mode, error_list=error_list) + self.check_auth(name="HasFullAccessPermission with no permissions", mode=mode, error_list=error_list) self.build_key([HasReadPermission]) self.authenticate() - self.check_auth(name="HasFullAccessPermission \w read permissions", mode=mode, error_list=error_list) + self.check_auth(name="HasFullAccessPermission with read permissions", mode=mode, error_list=error_list) if HasAdminPermission in permissions: - self.check_auth(name="HasAdminPermission \w no key", mode=mode, error_list=error_list) + self.check_auth(name="HasAdminPermission with no key", mode=mode, error_list=error_list) self.build_key([]) self.authenticate() - self.check_auth(name="HasAdminPermission \w no permissions", mode=mode, error_list=error_list) + self.check_auth(name="HasAdminPermission with no permissions", mode=mode, error_list=error_list) self.build_key([HasReadPermission]) self.authenticate() - self.check_auth(name="HasAdminPermission \w read permissions", mode=mode, error_list=error_list) + self.check_auth(name="HasAdminPermission with read permissions", mode=mode, error_list=error_list) self.build_key([HasReadPermission, HasFullAccessPermission]) self.authenticate() - self.check_auth(name="HasAdminPermission \w read and full access permissions", mode=mode, error_list=error_list) + self.check_auth(name="HasAdminPermission with read and full access permissions", mode=mode, error_list=error_list) self.build_key(permissions) self.authenticate() diff --git a/docs/sources/reference/spaces.md b/docs/sources/reference/spaces.md index 725e8635..97e99d40 100644 --- a/docs/sources/reference/spaces.md +++ b/docs/sources/reference/spaces.md @@ -1,8 +1,6 @@ # Space ## Space's Model ::: django_napse.core.models.NapseSpace - options: - --- ## Space's manager From 5b2f910bf47ac106d48a9b9c2a57d51c3b880910 Mon Sep 17 00:00:00 2001 From: Xenepix Date: Thu, 21 Dec 2023 17:13:00 +0100 Subject: [PATCH 15/16] docs(setup): put all setup scripts into a folder --- Makefile | 6 +- README.md | 11 ++- docs/contributing.md | 10 ++- docs/{ => sources}/api.md | 0 docs/theme/assets/stylesheets/docstring.css | 83 -------------------- docs/theme/partials/header.html | 63 --------------- mkdocs.yml | 4 +- setup-osx.sh => setup/setup-osx.sh | 0 setup-unix.sh => setup/setup-unix.sh | 0 setup-windows.ps1 => setup/setup-windows.ps1 | 0 10 files changed, 23 insertions(+), 154 deletions(-) rename docs/{ => sources}/api.md (100%) delete mode 100644 docs/theme/assets/stylesheets/docstring.css delete mode 100644 docs/theme/partials/header.html rename setup-osx.sh => setup/setup-osx.sh (100%) rename setup-unix.sh => setup/setup-unix.sh (100%) rename setup-windows.ps1 => setup/setup-windows.ps1 (100%) diff --git a/Makefile b/Makefile index 277af169..44d25284 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,11 @@ all: setup-testing-environment makemigrations migrate runserver setup: ifeq ($(OS),Darwin) # Mac OS X - ./setup-osx.sh + ./setup/setup-osx.sh else ifeq ($(OS),Linux) - ./setup-unix.sh + ./setup/setup-unix.sh else - ./setup-windows.sh + ./setup/setup-windows.sh endif setup-testing-environment: diff --git a/README.md b/README.md index eb2abb2e..2cf4e18a 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,16 @@
## django-napse -.... + +Django napse is a portfolio management module using trading bots. + +This directory can be used as a django module, which you can install as follows: + +```bash +pip install django-napse +``` + +Or you can use it as a local backend for the [Napse desktop application](https://github.com/napse-invest/Napse), by cloning the repo (possibly after forking it). ## Useful commands Unless otherwise specified, all commands are to be run at the root folder of the project. diff --git a/docs/contributing.md b/docs/contributing.md index f270ac66..c0517c74 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -64,13 +64,19 @@ You can commit the code from your fork through a pull request on the official re === "Linux" ```bash - source setup-unix.sh + source setup/setup-unix.sh + ``` + +=== "MacOS" + + ```bash + source setup/setup-osx.sh ``` === "Windows" ```powershell - .\setup-windows.ps1 + .\setup\setup-windows.ps1 ``` #### Setup initial exchange accounts diff --git a/docs/api.md b/docs/sources/api.md similarity index 100% rename from docs/api.md rename to docs/sources/api.md diff --git a/docs/theme/assets/stylesheets/docstring.css b/docs/theme/assets/stylesheets/docstring.css deleted file mode 100644 index eb51d691..00000000 --- a/docs/theme/assets/stylesheets/docstring.css +++ /dev/null @@ -1,83 +0,0 @@ -.tile { -display: flex; -text-align: center; -width: 120px; -height: 120px; -display: inline-block; -margin: 10px; -padding: 5px; -border-radius: .5rem; -} - -.tile img { -width: 100px; -} - -.md-typeset__table > table { -max-height: 60vh; -} - -.md-typeset__table > table thead { -position: sticky; -top: 0; -background-color: var(--md-default-bg-color); -} - -.md-typeset__table > table th { -border-bottom: .05rem solid var(--md-typeset-table-color); -} - -.md-typeset__table > table tr:first-child td { -border-top: none; -} - -/* API documentation link admonition */ -:root { ---md-admonition-icon--api: url('data:image/svg+xml;charset=utf-8,') -} -.md-typeset .admonition.api, .md-typeset details.api { -border-color: #448aff; -} -.md-typeset .api > .admonition-title, .md-typeset .api > summary { -background-color: #448aff1a; -} -.md-typeset .api > .admonition-title::before, .md-typeset .api > summary::before { -background-color: #448aff; --webkit-mask-image: var(--md-admonition-icon--api); - mask-image: var(--md-admonition-icon--api); -} - -/* Revert hue value to that of pre mkdocs-material v9.4.0 */ -[data-md-color-scheme="slate"] { ---md-hue: 230; ---md-default-bg-color: hsla(230, 15%, 21%, 1); -} - - - /* Indentation. */ -div.doc-contents:not(.first) { - padding-left: 25px; - border-left: .05rem solid var(--md-typeset-table-color); -} - -/* Mark external links as such. */ -a.external::after, -a.autorefs-external::after { - /* https://primer.style/octicons/arrow-up-right-24 */ - mask-image: url('data:image/svg+xml,'); - -webkit-mask-image: url('data:image/svg+xml,'); - content: ' '; - - display: inline-block; - vertical-align: middle; - position: relative; - - height: 1em; - width: 1em; - background-color: var(--md-typeset-a-color); -} - -a.external:hover::after, -a.autorefs-external:hover::after { - background-color: var(--md-accent-fg-color); -} diff --git a/docs/theme/partials/header.html b/docs/theme/partials/header.html deleted file mode 100644 index d301d733..00000000 --- a/docs/theme/partials/header.html +++ /dev/null @@ -1,63 +0,0 @@ -{#- - This file was automatically generated - do not edit - -#} - {% set class = "md-header" %} - {% if "navigation.tabs.sticky" in features %} - {% set class = class ~ " md-header--shadow md-header--lifted" %} - {% elif "navigation.tabs" not in features %} - {% set class = class ~ " md-header--shadow" %} - {% endif %} -
- - {% if "navigation.tabs.sticky" in features %} - {% if "navigation.tabs" in features %} - {% include "partials/tabs.html" %} - {% endif %} - {% endif %} -
\ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index c719f9cb..b5fc1435 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -167,8 +167,8 @@ nav: - "sources/reference/spaces.md" - "sources/reference/transactions.md" - "sources/reference/wallets.md" - - API: "api.md" + - API: "sources/api.md" - Development: - Contributing: "contributing.md" - Security: "SECURITY.md" - - Coverage: coverage.md \ No newline at end of file + - Coverage: coverage.md diff --git a/setup-osx.sh b/setup/setup-osx.sh similarity index 100% rename from setup-osx.sh rename to setup/setup-osx.sh diff --git a/setup-unix.sh b/setup/setup-unix.sh similarity index 100% rename from setup-unix.sh rename to setup/setup-unix.sh diff --git a/setup-windows.ps1 b/setup/setup-windows.ps1 similarity index 100% rename from setup-windows.ps1 rename to setup/setup-windows.ps1 From af6929afa431988d0f5428e56051ef198e2adb9a Mon Sep 17 00:00:00 2001 From: Xenepix Date: Thu, 21 Dec 2023 17:39:37 +0100 Subject: [PATCH 16/16] docs(readme): improve readme & docs' homepage --- README.md | 41 +++++++---------------------------------- docs/contributing.md | 4 +++- docs/index.md | 32 ++++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 2cf4e18a..61cc3e3b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@

Django Napse ยท - Usefull commands . + Documentation . How to contribute


@@ -30,48 +30,21 @@ ## django-napse Django napse is a portfolio management module using trading bots. - This directory can be used as a django module, which you can install as follows: ```bash pip install django-napse ``` -Or you can use it as a local backend for the [Napse desktop application](https://github.com/napse-invest/Napse), by cloning the repo (possibly after forking it). - -## Useful commands -Unless otherwise specified, all commands are to be run at the root folder of the project. - -### Create a new project -- Unix \ -```source setup-unix.sh``` +Or you can use it as a local backend for the [Napse desktop application](https://github.com/napse-invest/Napse), by cloning the repository. -- Windows \ -```.\setup-windows.ps1``` +Find more details for installation in the [documentation](https://napse-invest.github.io/django-napse/#installation). -### Run a test version of the project +### Documentation -- Build migrations \ -```make makemigrations``` -- Apply migrations \ -```make migrate``` -- Run server \ -```make runserver``` +You can find the documentation [here](https://napse-invest.github.io/django-napse/). -### Run coverage tests -- Run tests \ -```test-napse``` -- Run tests with coverage \ -```coverage``` -- Run tests with coverage and open coverage report \ -```coverage-open``` +## How to contribute -## Documentation - -[Docs](https://napse-invest.github.io/django-napse/) - -Run mkdocs server: -``` -make mkdocs -``` \ No newline at end of file +If you want to contribute to the project, please read the [contributing guidelines](https://napse-invest.github.io/django-napse/contributing/) first. You will find the setup instructions and our standards. \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md index c0517c74..5c67726c 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -95,9 +95,11 @@ At `tests/test_app/`, build a `secret.json` file (or run the `./setup_secrets.sh } } } - ``` +!!! note + We **strongly recommend** to add the `secret.json` file to your `.gitignore` file to avoid sharing your API keys. + #### Run ```bash diff --git a/docs/index.md b/docs/index.md index 5de2077f..c3f8c100 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,13 +22,19 @@ # Welcome to django-napse's documentation! +Django napse is a portfolio management module using trading bots. + ## Installation +--- + +This project can be used as a django module, which you can install as follows: -To install the latest version of django-napse: ```bash pip install django-napse ``` +Or you can use it as a local backend for the [Napse desktop application](https://github.com/napse-invest/Napse), by cloning the repo (possibly after forking it). + ### Setup initial exchange accounts To make full use of the project, we recommend that you fill in the API keys of at least one exchange (among the django-napse [compabile exchanges](#compatible-exchanges)). @@ -38,7 +44,7 @@ At the root of your project, build a `secret.json` file. Here is an exemple with { "Exchange Accounts": { "Binance EA_NAME": { - "exchange": "BINANCE", # Name of your exchange (BINANCE, DYDX, ...) + "exchange": "BINANCE", # Name of your exchange "testing": true, "public_key": "YOUR_PUBLIC_KEY", "private_key": "YOUR_PRIVATE_KEY" @@ -46,10 +52,27 @@ At the root of your project, build a `secret.json` file. Here is an exemple with } } ``` -We **strongly** recommand you to add the `secret.json` file to your `.gitignore`. - +??? note "Note for developers" + We **strongly recommend** to add the `secret.json` file to your `.gitignore` file to avoid sharing your API keys. ## Use django-napse +--- + +### Local backend + +If you want to use django-napse as a local backend for the Napse desktop application, clone the repository and setup the project: +```bash +make setup +``` + +Then, you can run the server: +```bash +make up +``` + +Please check the documentation for more information about [endpoints](https://napse-invest.github.io/django-napse/api/). + +### Django module After the installation step, in a `.py` file you can use django-napse after importing it: ```python @@ -59,6 +82,7 @@ exchange_account_query = ExchangeAccount.objects.all() ``` ## Miscellaneous +--- ### Compatible exchanges