Merge pull request #1433 from SchrodingersGat/coverage-workflow

Add workflow for code coverage
This commit is contained in:
Oliver 2021-03-31 22:08:08 +11:00 committed by GitHub
commit 16433f49c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 242 additions and 616 deletions

46
.github/workflows/coverage.yaml vendored Normal file
View File

@ -0,0 +1,46 @@
# Perform CI checks, and calculate code coverage
name: SQLite
on: ["push", "pull_request"]
jobs:
# Run tests on SQLite database
# These tests are used for code coverage analysis
coverage:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_NAME: './test_db.sqlite'
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
INVENTREE_DEBUG: info
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get update
pip3 install invoke
invoke install
- name: Coverage Tests
run: |
invoke coverage
- name: Data Import Export
run: |
invoke migrate
invoke import-fixtures
invoke export-records -f data.json
rm test_db.sqlite
invoke migrate
invoke import-records -f data.json
- name: Check Migration Files
run: python3 ci/check_migration_files.py
- name: Upload Coverage Report
run: coveralls

46
.github/workflows/mariadb.yaml vendored Normal file
View File

@ -0,0 +1,46 @@
name: MariaDB
on: ["push", "pull_request"]
jobs:
test:
runs-on: ubuntu-latest
env:
# Database backend configuration
INVENTREE_DB_ENGINE: django.db.backends.mysql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_USER: root
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 3306
INVENTREE_DEBUG: info
services:
mariadb:
image: mariadb:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: inventree
MYSQL_USER: inventree
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
ports:
- 3306:3306
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get install mysql-server libmysqlclient-dev
pip3 install invoke
pip3 install mysqlclient
invoke install
- name: Run Tests
run: invoke test

49
.github/workflows/mysql.yaml vendored Normal file
View File

@ -0,0 +1,49 @@
# MySQL Unit Testing
name: MySQL
on: ["push", "pull_request"]
jobs:
test:
runs-on: ubuntu-latest
env:
# Database backend configuration
INVENTREE_DB_ENGINE: django.db.backends.mysql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_USER: root
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 3306
INVENTREE_DEBUG: info
services:
mysql:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: inventree
MYSQL_USER: inventree
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
ports:
- 3306:3306
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get install mysql-server libmysqlclient-dev
pip3 install invoke
pip3 install mysqlclient
invoke install
- name: Run Tests
run: invoke test

45
.github/workflows/postgresql.yaml vendored Normal file
View File

@ -0,0 +1,45 @@
# PostgreSQL Unit Testing
name: PostgreSQL
on: ["push", "pull_request"]
jobs:
test:
runs-on: ubuntu-latest
env:
# Database backend configuration
INVENTREE_DB_ENGINE: django.db.backends.postgresql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_USER: inventree
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: info
services:
postgres:
image: postgres
env:
POSTGRES_USER: inventree
POSTGRES_PASSWORD: password
ports:
- 5432:5432
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get install libpq-dev
pip3 install invoke
pip3 install psycopg2
invoke install
- name: Run Tests
run: invoke test

View File

@ -1,10 +1,6 @@
name: Style Checks
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
on: ["push", "pull_request"]
jobs:
style:
@ -26,4 +22,6 @@ jobs:
run: |
pip install flake8==3.8.3
pip install pep8-naming==0.11.1
- name: flake8
run: |
flake8 InvenTree

View File

@ -1,53 +0,0 @@
dist: xenial
services:
- mysql
- postgresql
language: python
python:
- 3.6
- 3.7
addons:
apt-packages:
- sqlite3
before_install:
- sudo apt-get update
- sudo apt-get install gettext
- sudo apt-get install mysql-server libmysqlclient-dev
- sudo apt-get install libpq-dev
- pip3 install invoke
- pip3 install mysqlclient
- pip3 install psycopg2
- invoke install
- invoke migrate
- cd InvenTree && python3 manage.py createsuperuser --username InvenTreeAdmin --email admin@inventree.com --noinput && cd ..
- psql -c 'create database inventree_test_db;' -U postgres
- mysql -e 'CREATE DATABASE inventree_test_db;'
script:
- cd InvenTree && python3 manage.py makemigrations && cd ..
- python3 ci/check_migration_files.py
# Run unit testing / code coverage tests
- invoke coverage
# Run unit test for SQL database backend
- cd InvenTree && python3 manage.py test --settings=InvenTree.ci_mysql && cd ..
# Run unit test for PostgreSQL database backend
- cd InvenTree && python3 manage.py test --settings=InvenTree.ci_postgresql && cd ..
- invoke translate
- invoke style
# Create an empty database and fill it with test data
- rm inventree_default_db.sqlite3
- invoke migrate
- invoke import-fixtures
# Export database records
- invoke export-records -f data.json
# Create a new empty database and import the saved data
- rm inventree_default_db.sqlite3
- invoke migrate
- invoke import-records -f data.json
after_success:
- coveralls

View File

@ -1,18 +0,0 @@
"""
Configuration file for running tests against a MySQL database.
"""
from InvenTree.settings import *
# Override the 'test' database
if 'test' in sys.argv:
print('InvenTree: Running tests - Using MySQL test database')
DATABASES['default'] = {
# Ensure mysql backend is being used
'ENGINE': 'django.db.backends.mysql',
'NAME': 'inventree_test_db',
'USER': 'travis',
'PASSWORD': '',
'HOST': '127.0.0.1'
}

View File

@ -1,17 +0,0 @@
"""
Configuration file for running tests against a MySQL database.
"""
from InvenTree.settings import *
# Override the 'test' database
if 'test' in sys.argv:
print('InvenTree: Running tests - Using PostGreSQL test database')
DATABASES['default'] = {
# Ensure postgresql backend is being used
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'inventree_test_db',
'USER': 'postgres',
'PASSWORD': '',
}

View File

@ -319,83 +319,68 @@ MARKDOWNIFY_BLEACH = False
DATABASES = {}
"""
When running unit tests, enforce usage of sqlite3 database,
so that the tests can be run in RAM without any setup requirements
Configure the database backend based on the user-specified values.
- Primarily this configuration happens in the config.yaml file
- However there may be reason to configure the DB via environmental variables
- The following code lets the user "mix and match" database configuration
"""
if 'test' in sys.argv:
logger.info('InvenTree: Running tests - Using sqlite3 memory database')
DATABASES['default'] = {
# Ensure sqlite3 backend is being used
'ENGINE': 'django.db.backends.sqlite3',
# Doesn't matter what the database is called, it is executed in RAM
'NAME': 'ram_test_db.sqlite3',
}
# Database backend selection
else:
"""
Configure the database backend based on the user-specified values.
- Primarily this configuration happens in the config.yaml file
- However there may be reason to configure the DB via environmental variables
- The following code lets the user "mix and match" database configuration
"""
logger.info("Configuring database backend:")
logger.info("Configuring database backend:")
# Extract database configuration from the config.yaml file
db_config = CONFIG.get('database', {})
# Extract database configuration from the config.yaml file
db_config = CONFIG.get('database', {})
# Environment variables take preference over config file!
# If a particular database option is not specified in the config file,
# look for it in the environmental variables
# e.g. INVENTREE_DB_NAME / INVENTREE_DB_USER / etc
db_keys = ['ENGINE', 'NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']
db_keys = ['ENGINE', 'NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']
for key in db_keys:
# First, check the environment variables
env_key = f"INVENTREE_DB_{key}"
env_var = os.environ.get(env_key, None)
for key in db_keys:
if key not in db_config:
logger.debug(f" - Missing {key} value: Looking for environment variable INVENTREE_DB_{key}")
env_key = f'INVENTREE_DB_{key}'
env_var = os.environ.get(env_key, None)
if env_var:
logger.info(f"{env_key}={env_var}")
# Override configuration value
db_config[key] = env_var
if env_var is not None:
logger.info(f'Using environment variable INVENTREE_DB_{key}')
db_config[key] = env_var
else:
logger.debug(f' INVENTREE_DB_{key} not found in environment variables')
# Check that required database configuration options are specified
reqiured_keys = ['ENGINE', 'NAME']
# Check that required database configuration options are specified
reqiured_keys = ['ENGINE', 'NAME']
for key in reqiured_keys:
if key not in db_config:
error_msg = f'Missing required database configuration value {key} in config.yaml'
logger.error(error_msg)
for key in reqiured_keys:
if key not in db_config:
error_msg = f'Missing required database configuration value {key} in config.yaml'
logger.error(error_msg)
print('Error: ' + error_msg)
sys.exit(-1)
print('Error: ' + error_msg)
sys.exit(-1)
"""
Special considerations for the database 'ENGINE' setting.
It can be specified in config.yaml (or envvar) as either (for example):
- sqlite3
- django.db.backends.sqlite3
- django.db.backends.postgresql
"""
"""
Special considerations for the database 'ENGINE' setting.
It can be specified in config.yaml (or envvar) as either (for example):
- sqlite3
- django.db.backends.sqlite3
- django.db.backends.postgresql
"""
db_engine = db_config['ENGINE']
db_engine = db_config['ENGINE']
if db_engine.lower() in ['sqlite3', 'postgresql', 'mysql']:
# Prepend the required python module string
db_engine = f'django.db.backends.{db_engine.lower()}'
db_config['ENGINE'] = db_engine
if db_engine.lower() in ['sqlite3', 'postgresql', 'mysql']:
# Prepend the required python module string
db_engine = f'django.db.backends.{db_engine.lower()}'
db_config['ENGINE'] = db_engine
db_name = db_config['NAME']
db_host = db_config.get('HOST', "''")
db_name = db_config['NAME']
print("InvenTree Database Configuration")
print("================================")
print(f"ENGINE: {db_engine}")
print(f"NAME: {db_name}")
print(f"HOST: {db_host}")
logger.info(f"Database ENGINE: '{db_engine}'")
logger.info(f"Database NAME: '{db_name}'")
DATABASES['default'] = db_config
DATABASES['default'] = db_config
CACHES = {
'default': {

View File

@ -1,4 +1,10 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://travis-ci.org/inventree/InvenTree.svg?branch=master)](https://travis-ci.org/inventree/InvenTree) [![Coverage Status](https://coveralls.io/repos/github/inventree/InvenTree/badge.svg)](https://coveralls.io/github/inventree/InvenTree)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Coverage Status](https://coveralls.io/repos/github/inventree/InvenTree/badge.svg)](https://coveralls.io/github/inventree/InvenTree)
![PEP](https://github.com/github/docs/actions/workflows/style.yaml/badge.svg)
![SQLite](https://github.com/github/docs/actions/workflows/coverage.yaml/badge.svg)
![MySQL](https://github.com/github/docs/actions/workflows/mysql.yaml/badge.svg)
![MariaDB](https://github.com/github/docs/actions/workflows/mariadb.yaml/badge.svg)
![PostgreSQL](https://github.com/github/docs/actions/workflows/postgresql.yaml/badge.svg)
<img src="images/logo/inventree.png" alt="InvenTree" width="128"/>

View File

@ -1,19 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

View File

@ -1,100 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../'))
sys.path.append(os.path.abspath('../InvenTree'))
# -- Project information -----------------------------------------------------
project = 'InvenTree'
copyright = '2019, InvenTree'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'autoapi.extension',
]
napoleon_google_docstring = True
napoleon_numpy_docstring = False
autoapi_dirs = [
'../InvenTree',
]
autoapi_options = [
'members',
'private-members',
'special-members',
]
autoapi_type = 'python'
autoapi_ignore = [
'*migrations*',
'**/test*.py',
'**/manage.py',
'**/apps.py',
'**/admin.py',
'**/middleware.py',
'**/utils.py',
'**/wsgi.py',
'**/templates/',
]
# Add any paths that contain templates here, relative to this directory.
autoapi_template_dir = 'templates'
autoapi_root = 'docs'
autoapi_add_toctree_entry = False
templates_path = ['templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = [
'_build',
'Thumbs.db',
'.DS_Store',
'manage.rst', # Ignore django management file
'**/*.migrations*.rst', # Ignore migration files
]
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Table of contents in sidebar
html_sidebars = {'**': [
'globaltoc.html',
'relations.html',
'sourcelink.html',
'searchbox.html'
]}

View File

@ -1,57 +0,0 @@
InvenTree Modal Forms
=====================
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: Modal Forms
:hidden:
The InvenTree web interface uses modal forms for user input. InvenTree defines a wrapper layer around the Django form classes to provide a mechanism for retrieving and rendering forms via jQuery and AJAX.
.. image:: _static/img/modal_form.png
Forms are rendered to a Bootstrap modal window, allowing in-page data input and live page updating.
Crispy Forms
------------
Django provides native form rendering tools which are very powerful, allowing form rendering, input validation, and display of error messages for each field.
InvenTree makes use of the `django-crispy-forms <https://github.com/django-crispy-forms/django-crispy-forms>`_ extension to reduce the amount of boilerplate required to convert a Django model to a HTML form.
Form Rendering
--------------
The InvenTree front-end web interface is implemented using jQuery and Bootstrap. Forms are rendered using Django `class-based forms <https://docs.djangoproject.com/en/2.2/topics/class-based-views/generic-editing/>`_ using standard Django methods.
The main point of difference is that instead of rendering a HTTP response (and displaying a static form page) form data are requested via AJAX, and the form contents are injected into the modal window.
A set of javascript/jQuery functions handle the client/server interactions, and manage GET and POST requests.
Sequence of Events
------------------
#. User presses a button or other element which initiates form loading
#. jQuery function sends AJAX GET request to InvenTree server, requesting form at a specified URL
#. Django renders form (according to specific model/view rules)
#. Django returns rendered form as a JSON object
#. Client displays the modal window and injects the form contents into the modal
#. User fills in form data, presses the 'Submit' button
#. Client sends the completed form to server via POST
#. Django backend handles POST request, specifically determines if the form is valid
#. Return a JSON object containing status of form validity
* If the form is valid, return (at minimum) ``{form_valid: true}``. Client will close the modal.
* If the form is invalid, re-render the form and send back to the client. Process repeats
At the end of this process (i.e. after successful processing of the form) the client closes the modal and runs any optional post-processes (depending on the implementation).
Further Reading
---------------
For a better understanding of the modal form architecture, refer to the relevant source files:
**Server Side:** Refer to ``./InvenTree/InvenTree/views.py`` for AJAXified Django Views
**Client Side:** Refer to ``./InvenTree/static/script/inventree/modals.js`` for client-side javascript

View File

@ -1,38 +0,0 @@
InvenTree Source Documentation
================================
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: Index
:hidden:
Translations<translate>
Modal Forms<forms>
Tables<tables>
REST API<rest>
InvenTree Modules <modules>
Module Reference<reference>
The documentation found here is provided to be useful for developers working on the InvenTree codebase. User documentation can be found on the `InvenTree website <https://inventree.github.io>`_.
Documentation for the Python modules is auto-generated from the `InvenTree codebase <https://github.com/InvenTree/InvenTree>`_.
Code Structure
--------------
**Backend**
InvenTree is developed using the `django web framework <https://www.djangoproject.com/>`_, a powerful toolkit for making web applications in Python.
The database management code and business logic is written in Python 3. Core functionality is separated into individual modules (or *apps* using the django nomenclature).
Each *app* is located in a separate directory under InvenTree. Each *app* contains python modules named according to the standard django configuration.
**Frontend**
The web frontend rendered using a mixture of technologies.
Base HTML code is rendered using the `django templating language <https://docs.djangoproject.com/en/2.2/topics/templates/>`_ which provides low-level access to the underlying database models.
jQuery is also used to implement front-end logic, and desponse to user input. A REST API is provided to facilitate client-server communication.

View File

@ -1,35 +0,0 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd

View File

@ -1,26 +0,0 @@
InvenTree Modules
=================
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: App Modules
:hidden:
docs/InvenTree/index
docs/build/index
docs/common/index
docs/company/index
docs/part/index
docs/order/index
docs/stock/index
The InvenTree Django ecosystem provides the following 'apps' for core functionality:
* `InvenTree <docs/InvenTree/index.html>`_ - High level management functions
* `Build <docs/build/index.html>`_ - Part build projects
* `Common <docs/common/index.html>`_ - Common modules used by various apps
* `Company <docs/company/index.html>`_ - Company management (suppliers / customers)
* `Part <docs/part/index.html>`_ - Part management
* `Order <docs/order/index.html>`_ - Order management
* `Stock <docs/stock/index.html>`_ - Stock management

View File

@ -1,14 +0,0 @@
Module Reference
===================
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: Module Reference
:hidden:
The complete reference indexes are found below:
* :ref:`modindex`
* :ref:`genindex`

View File

@ -1,3 +0,0 @@
Sphinx>=2.0.1
sphinx-autoapi==1.0.0
sphinx-rtd-theme==0.4.3

View File

@ -1,42 +0,0 @@
REST API
========
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: REST API
:hidden:
InvenTree provides a REST API which serves data to the web client and also provides data access to third-party applications. The REST API is implemented using the `Django REST framework (DRF) <https://www.django-rest-framework.org/>`_ which provides the following features out of the box:
* AJAX REST API
* Web-browseable REST
* User authentication
* Database model serialization and validation
API Access
----------
The API is accessible from the root URL ``/api/``. It requires user authentication.
* Requesting data via AJAX query will return regular JSON objects.
* Directing a browser to the API endpoints provides a web-browsable interface
.. image:: _static/img/api_http.png
API Documentation
-----------------
API documentation is provided by DRF autodoc tools, and is available for browsing at ``/api-doc/``
.. image:: _static/img/api_doc.png
API Code
--------
Javascript/jQuery code for interacting with the server via the REST API can be found under ``InvenTree/static/script/InvenTree``.
Python interface
----------------
A Python library for interacting with the InvenTree API is provided on `GitHub <https://github.com/inventree/inventree-python>`_

View File

@ -1,14 +0,0 @@
Table Management
================
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: Tables
:hidden:
InvenTree uses `Bootstrap Table <https://bootstrap-table.com/>`_ to manage tabulated data in the web front-end. The ability to tabulate data from read via an AJAX request allows tables to be updated on-the-fly (without a full page reload).
Bootstrap Table also provides integrated tools for table searching, filtering, and advanced rendering.
Frontend code for table functionality can be found at ``InvenTree/static/script/inventree/tables.js``.

View File

@ -1,97 +0,0 @@
{% if not obj.display %}
:orphan:
{% endif %}
:mod:`{{ obj.name }}`
======={{ "=" * obj.name|length }}
.. py:module:: {{ obj.name }}
{% if obj.docstring %}
.. autoapi-nested-parse::
{{ obj.docstring|prepare_docstring|indent(3) }}
{% endif %}
{% block subpackages %}
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
{% if visible_subpackages %}
Subpackages
-----------
.. toctree::
:titlesonly:
:maxdepth: 3
{% for subpackage in visible_subpackages %}
{{ subpackage.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block submodules %}
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
{% if visible_submodules %}
Submodules
----------
The {{ obj.name }} module contains the following submodules
.. toctree::
:titlesonly:
:maxdepth: 1
{% for submodule in visible_submodules %}
{{ submodule.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% if visible_children %}
{{ obj.type|title }} Contents
{{ "-" * obj.type|length }}---------
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
{% if include_summaries and (visible_classes or visible_functions) %}
{% block classes %}
{% if visible_classes %}
Classes
~~~~~~~
.. autoapisummary::
{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block functions %}
{% if visible_functions %}
Functions
~~~~~~~~~
.. autoapisummary::
{% for function in visible_functions %}
{{ function.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% endif %}
{% for obj_item in visible_children %}
{% if obj.all is none or obj_item.short_name in obj.all %}
{{ obj_item.rendered|indent(0) }}
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}

View File

@ -1,16 +0,0 @@
Translations
============
.. toctree::
:titlesonly:
:maxdepth: 2
:caption: Language Translation
:hidden:
InvenTree supports multi-language translation using the `Django Translation Framework <https://docs.djangoproject.com/en/2.2/topics/i18n/translation/>`_
Translation strings are located in the `InvenTree/locales/` directory, and translation files can be easily added here.
To set the default language, change the `language` setting in the `config.yaml` settings file.
To recompile the translation files (after adding new translation strings), run the command ``make translate`` from the root directory.