diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index a4a5b9d037..74601e87fa 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -85,6 +85,7 @@ jobs: id: test-docker run: | docker build . --target production --tag inventree-test -f contrib/container/Dockerfile + docker run --rm inventree-test invoke version docker run --rm inventree-test invoke --version docker run --rm inventree-test invoke --list docker run --rm inventree-test gunicorn --version @@ -100,6 +101,7 @@ jobs: - name: Update Docker Image run: | docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke install + docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke version docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke update docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke dev.setup-dev docker compose --project-directory . -f contrib/container/dev-docker-compose.yml up -d diff --git a/contrib/container/Dockerfile b/contrib/container/Dockerfile index 27a452f858..475b6f7604 100644 --- a/contrib/container/Dockerfile +++ b/contrib/container/Dockerfile @@ -171,4 +171,4 @@ WORKDIR ${INVENTREE_HOME} ENTRYPOINT ["/bin/ash", "./contrib/container/init.sh"] # Launch the development server -CMD ["invoke", "server", "-a", "${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}"] +CMD ["invoke", "dev.server", "-a", "${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}"] diff --git a/contrib/container/init.sh b/contrib/container/init.sh index 29a386e25d..a9dceaf6f0 100644 --- a/contrib/container/init.sh +++ b/contrib/container/init.sh @@ -40,14 +40,17 @@ if [[ -n "$INVENTREE_PY_ENV" ]]; then if test -d "$INVENTREE_PY_ENV"; then # venv already exists echo "Using Python virtual environment: ${INVENTREE_PY_ENV}" + source ${INVENTREE_PY_ENV}/bin/activate else - # Setup a virtual environment (within the "data/env" directory) + # Setup a virtual environment (within the provided directory) echo "Running first time setup for python environment" python3 -m venv ${INVENTREE_PY_ENV} --system-site-packages --upgrade-deps + + # Ensure invoke tool is installed locally + source ${INVENTREE_PY_ENV}/bin/activate + python3 -m pip install --ignore-installed --upgrade invoke fi - # Now activate the venv - source ${INVENTREE_PY_ENV}/bin/activate fi cd ${INVENTREE_HOME} diff --git a/docs/docs/develop/contributing.md b/docs/docs/develop/contributing.md index f7d0176716..bdb61808a3 100644 --- a/docs/docs/develop/contributing.md +++ b/docs/docs/develop/contributing.md @@ -34,7 +34,9 @@ A "bare metal" development setup can be installed as follows: ```bash git clone https://github.com/inventree/InvenTree.git && cd InvenTree python3 -m venv env && source env/bin/activate -pip install django invoke && invoke +pip install --upgrade --ignore-installed invoke +invoke install +invoke update invoke dev.setup-dev --tests ``` diff --git a/docs/docs/develop/devcontainer.md b/docs/docs/develop/devcontainer.md index bb86080ba2..90d6adb18f 100644 --- a/docs/docs/develop/devcontainer.md +++ b/docs/docs/develop/devcontainer.md @@ -111,7 +111,7 @@ Make sure you have `gnupg` and `pinentry-mac` installed and set up correctly. Re #### Where are the database, media files, ... stored? -Backups, Commandhistory, media/static files, venv, plugin.txt, secret_key.txt, ... are stored in the `dev` folder. If you want to start with a clean setup, you can remove that folder, but be aware that this will delete everything you already setup in InvenTree. +Backups, media/static files, venv, plugin.txt, secret_key.txt, ... are stored in the `dev` folder. If you want to start with a clean setup, you can remove that folder, but be aware that this will delete everything you already setup in InvenTree. ### Performance Improvements diff --git a/docs/docs/faq.md b/docs/docs/faq.md index 6f7b7bce3a..1cf0cfe710 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -26,7 +26,7 @@ Refer to the [invoke guide](./start/invoke.md#cant-find-any-collection-named-tas If the installed version of invoke is too old, users may see error messages during the installation procedure. Refer to the [invoke guide](./start/invoke.md#minimum-version) for more information. -### No module named 'django' +### No module named During the install or update process, you may be presented with an error like: @@ -34,9 +34,27 @@ During the install or update process, you may be presented with an error like: ModuleNotFoundError: No module named 'django' ``` -Most likely you are trying to run the InvenTree server from outside the context of the virtual environment where the required python libraries are installed. +Either the named modules are not installed, or the virtual environment is not correctly activated. -Always activate the virtual environment before running server commands! +**Check Virtual Environment** + +Ensure that the virtual environment is correctly activated before running any InvenTree commands. + +**Check Invoke Tool** + +Ensure that the invoke tool is correctly installed inside the virtual environment, with: + +```bash +pip install --upgrade --ignore-installed invoke +``` + +**Install Required Python Packages** + +Ensure that all required python packages are installed by running: + +```bash +invoke install +``` ### 'str' object has no attribute 'removeSuffix' diff --git a/docs/docs/start/install.md b/docs/docs/start/install.md index 23cb5aae00..93e728ee4c 100644 --- a/docs/docs/start/install.md +++ b/docs/docs/start/install.md @@ -107,7 +107,8 @@ source ./env/bin/activate The Python packages required by the InvenTree server must be installed into the virtual environment. ``` -pip install --require-hashes -U -r src/backend/requirements.txt +pip install --upgrade --ignore-installed invoke +invoke install ``` This installs all required Python packages using pip package manager. It also creates a (default) database configuration file which needs to be edited to meet user needs before proceeding (see next step below). diff --git a/docs/docs/start/intro.md b/docs/docs/start/intro.md index 3b984a5443..418af33536 100644 --- a/docs/docs/start/intro.md +++ b/docs/docs/start/intro.md @@ -82,6 +82,24 @@ Or, if that does not work, try: This will place the current shell session inside a virtual environment - the terminal should display the ``(env)`` prefix. +### Invoke in Virtual Environment + +If you are using a virtual environment (and you should be!) you will need to ensure that you have installed the `invoke` package inside the virtual environment! If the invoke commands are run from outside the virtual environment, they may not work correctly - and may be extremely difficult to debug! + +To install the `invoke` package inside the virtual environment, run the following command (after activating the virtual environment): + +``` +pip install --upgrade --ignore-installed invoke +``` + +To check that the `invoke` package is correctly installed, run the following command: + +``` +which invoke +``` + +This should return the path to the `invoke` binary inside the virtual environment. If the path is *not* inside the virtual environment, the `invoke` package is not correctly installed! + ## InvenTree Source Code InvenTree source code is distributed on [GitHub](https://github.com/inventree/inventree/), and the latest version can be downloaded (using Git) with the following command: diff --git a/tasks.py b/tasks.py index 1aa89a7436..d787e4b1fc 100644 --- a/tasks.py +++ b/tasks.py @@ -15,6 +15,29 @@ from invoke import Collection, task from invoke.exceptions import UnexpectedExit +def task_exception_handler(t, v, tb): + """Handle exceptions raised by tasks. + + The intent here is to provide more 'useful' error messages when tasks fail. + """ + sys.__excepthook__(t, v, tb) + + if t is ModuleNotFoundError: + mod_name = str(v).split(' ')[-1].strip("'") + + error(f'Error importing required module: {mod_name}') + warning('- Ensure the correct Python virtual environment is active') + warning( + '- Ensure that the invoke tool is installed in the active Python environment' + ) + warning( + "- Ensure all required packages are installed by running 'invoke install'" + ) + + +sys.excepthook = task_exception_handler + + def success(*args): """Print a success message to the console.""" msg = ' '.join(map(str, args))