Remove dependencies on requirements files and generate when needed
This commit is contained in:
@@ -7,6 +7,7 @@ Running from Source
|
|||||||
.. _GitHub: https://github.com/vkbo/novelWriter/releases
|
.. _GitHub: https://github.com/vkbo/novelWriter/releases
|
||||||
.. _PyPi: https://pypi.org/project/novelWriter/
|
.. _PyPi: https://pypi.org/project/novelWriter/
|
||||||
.. _Sphinx Docs: https://www.sphinx-doc.org/
|
.. _Sphinx Docs: https://www.sphinx-doc.org/
|
||||||
|
.. _uv: https://docs.astral.sh/uv/
|
||||||
|
|
||||||
This chapter describes various ways of running novelWriter directly from the source code, and how
|
This chapter describes various ways of running novelWriter directly from the source code, and how
|
||||||
to build the various components like the translation files and documentation.
|
to build the various components like the translation files and documentation.
|
||||||
@@ -28,6 +29,7 @@ by running:
|
|||||||
|
|
||||||
.. _docs_technical_source_depend:
|
.. _docs_technical_source_depend:
|
||||||
|
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
============
|
============
|
||||||
|
|
||||||
@@ -43,13 +45,22 @@ The following Python packages are needed to run all features of novelWriter:
|
|||||||
If you want spell checking, you must install the ``PyEnchant`` package. The spell check library
|
If you want spell checking, you must install the ``PyEnchant`` package. The spell check library
|
||||||
must be at least 3.0 to work with Windows. On Linux, 2.0 also works fine.
|
must be at least 3.0 to work with Windows. On Linux, 2.0 also works fine.
|
||||||
|
|
||||||
If you install from PyPi, these dependencies should be installed automatically. If you install from
|
If you install novelWriter from PyPi, these dependencies should be installed automatically.
|
||||||
source, dependencies can still be installed from PyPi with:
|
|
||||||
|
If you run it from source, and want to install dependencies using ``pip``, you must first generate
|
||||||
|
the ``requirements.txt`` file:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python pkgutils.py gen-req
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
Otherwise you can run novelWriter with uv_:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
uv run novelwriter
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
On Linux distros, the Qt library is usually split up into multiple packages. In some cases,
|
On Linux distros, the Qt library is usually split up into multiple packages. In some cases,
|
||||||
@@ -136,12 +147,14 @@ running:
|
|||||||
Building the Documentation
|
Building the Documentation
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
A local copy of this documentation can be generated as HTML. This requires installing some Python
|
A local copy of this documentation can be generated as HTML.
|
||||||
packages from PyPi:
|
|
||||||
|
If you're using ``pip``, you must first generate the ``requirements.txt`` file:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
pip install -r docs/requirements.txt
|
python pkgutils.py gen-req docs
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
The documentation can then be built from the root folder in the source code by running:
|
The documentation can then be built from the root folder in the source code by running:
|
||||||
|
|
||||||
@@ -149,6 +162,12 @@ The documentation can then be built from the root folder in the source code by r
|
|||||||
|
|
||||||
make -C docs html
|
make -C docs html
|
||||||
|
|
||||||
|
Or you can run directly with uv_:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
uv run make -C docs html
|
||||||
|
|
||||||
If successful, the documentation should be available in the ``docs/build/html`` folder and you can
|
If successful, the documentation should be available in the ``docs/build/html`` folder and you can
|
||||||
open the ``index.html`` file in your browser.
|
open the ``index.html`` file in your browser.
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,12 @@
|
|||||||
Running Tests
|
Running Tests
|
||||||
*************
|
*************
|
||||||
|
|
||||||
|
.. _uv: https://docs.astral.sh/uv/
|
||||||
|
|
||||||
The novelWriter source code is well covered by tests. The test framework used for the development
|
The novelWriter source code is well covered by tests. The test framework used for the development
|
||||||
is ``pytest`` with the use of an extension for Qt.
|
is ``pytest`` with the use of an extension for Qt.
|
||||||
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
============
|
|
||||||
|
|
||||||
The dependencies for running the tests can be installed with:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install -r tests/requirements.txt
|
|
||||||
|
|
||||||
This will install a couple of extra packages for coverage and test management. The minimum
|
|
||||||
requirement is ``pytest`` and ``pytest-qt``.
|
|
||||||
|
|
||||||
|
|
||||||
Simple Test Run
|
Simple Test Run
|
||||||
===============
|
===============
|
||||||
|
|
||||||
@@ -28,19 +17,35 @@ To run the tests, you simply need to execute the following from the root of the
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
pytest
|
uv run pytest
|
||||||
|
|
||||||
|
This uses uv_. See below for manually installing dependencies using ``pip``.
|
||||||
|
|
||||||
Since several of the tests involve opening up the novelWriter GUI, you may want to disable the GUI
|
Since several of the tests involve opening up the novelWriter GUI, you may want to disable the GUI
|
||||||
for the duration of the test run. Moving your mouse while the tests are running may otherwise
|
for the duration of the test run. Moving your mouse while the tests are running may otherwise
|
||||||
interfere with the execution of some tests.
|
interfere with the execution of some tests.
|
||||||
|
|
||||||
You can disable the renderring of the GUI by setting the flag ``QT_QPA_PLATFORM=offscreen``:
|
You can disable the rendering of the GUI by setting the flag ``QT_QPA_PLATFORM=offscreen``:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
export QT_QPA_PLATFORM=offscreen pytest
|
export QT_QPA_PLATFORM=offscreen pytest
|
||||||
|
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
To run generate the requirements file and install using ``pip``, run:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python pkgutils.py gen-req app test
|
||||||
|
pip install -r tests/requirements.txt
|
||||||
|
|
||||||
|
This will install a couple of extra packages for coverage and test management. The minimum
|
||||||
|
requirement is ``pytest`` and ``pytest-qt``.
|
||||||
|
|
||||||
|
|
||||||
Advanced Options
|
Advanced Options
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|||||||
+30
-5
@@ -40,7 +40,10 @@ import utils.build_windows
|
|||||||
import utils.docs
|
import utils.docs
|
||||||
import utils.icon_themes
|
import utils.icon_themes
|
||||||
|
|
||||||
from utils.common import ROOT_DIR, SETUP_DIR, extractVersion, readFile, stripVersion, writeFile
|
from utils.common import (
|
||||||
|
ROOT_DIR, SETUP_DIR, extractReqs, extractVersion, readFile, stripVersion,
|
||||||
|
writeFile
|
||||||
|
)
|
||||||
|
|
||||||
OS_LINUX = sys.platform.startswith("linux")
|
OS_LINUX = sys.platform.startswith("linux")
|
||||||
OS_DARWIN = sys.platform.startswith("darwin")
|
OS_DARWIN = sys.platform.startswith("darwin")
|
||||||
@@ -61,7 +64,7 @@ def installPackages(args: argparse.Namespace) -> None:
|
|||||||
print("=======================")
|
print("=======================")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
installQueue = ["pip", "-r requirements.txt"]
|
installQueue = ["pip", *extractReqs(["app"])]
|
||||||
if args.mac:
|
if args.mac:
|
||||||
installQueue.append("pyobjc")
|
installQueue.append("pyobjc")
|
||||||
elif args.win:
|
elif args.win:
|
||||||
@@ -130,6 +133,15 @@ def genMacOSPlist(args: argparse.Namespace) -> None:
|
|||||||
writeFile(outDir / "Info.plist", plistXML)
|
writeFile(outDir / "Info.plist", plistXML)
|
||||||
|
|
||||||
|
|
||||||
|
def genReqFiles(args: argparse.Namespace) -> None:
|
||||||
|
"""Generate requirements.txt file from pyproject.toml."""
|
||||||
|
select = [s.strip().lower() for s in args.groups] if args.groups else ["app"]
|
||||||
|
(ROOT_DIR / "requirements.txt").write_text(
|
||||||
|
"\n".join(extractReqs(select)),
|
||||||
|
encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
"""Parse command line options and run the commands."""
|
"""Parse command line options and run the commands."""
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@@ -222,7 +234,7 @@ if __name__ == "__main__":
|
|||||||
cmdBuildHtmlDocs = parsers.add_parser(
|
cmdBuildHtmlDocs = parsers.add_parser(
|
||||||
"docs-html", help="Build the HTML docs."
|
"docs-html", help="Build the HTML docs."
|
||||||
)
|
)
|
||||||
cmdBuildHtmlDocs.add_argument("lang", nargs="+")
|
cmdBuildHtmlDocs.add_argument("lang", nargs="+", help="Language codes to generate docs for.")
|
||||||
cmdBuildHtmlDocs.set_defaults(func=utils.docs.buildHtmlDocs)
|
cmdBuildHtmlDocs.set_defaults(func=utils.docs.buildHtmlDocs)
|
||||||
|
|
||||||
# Build Sample
|
# Build Sample
|
||||||
@@ -295,10 +307,23 @@ if __name__ == "__main__":
|
|||||||
cmdBuildClean.set_defaults(func=cleanBuildDirs)
|
cmdBuildClean.set_defaults(func=cleanBuildDirs)
|
||||||
|
|
||||||
# Generate MacOS PList File
|
# Generate MacOS PList File
|
||||||
cmdBuildMacOSPlist = parsers.add_parser(
|
cmdGenMacOSPlist = parsers.add_parser(
|
||||||
"gen-plist", help="Generate an Info.plist for use in a MacOS Bundle."
|
"gen-plist", help="Generate an Info.plist for use in a MacOS Bundle."
|
||||||
)
|
)
|
||||||
cmdBuildMacOSPlist.set_defaults(func=genMacOSPlist)
|
cmdGenMacOSPlist.set_defaults(func=genMacOSPlist)
|
||||||
|
|
||||||
|
# Generate Requirement File
|
||||||
|
cmdGenReq = parsers.add_parser(
|
||||||
|
"gen-req", help="Generate a requirements.txt file for pip."
|
||||||
|
)
|
||||||
|
cmdGenReq.add_argument(
|
||||||
|
"groups", nargs="*", help=(
|
||||||
|
"Groups to generate for, or 'all' to generate for all groups. "
|
||||||
|
"Use 'app' to generate for just the core application. "
|
||||||
|
"Defaults to app dependencies."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cmdGenReq.set_defaults(func=genReqFiles)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
args.func(args)
|
args.func(args)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
|
if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
|
||||||
echo "Not enouch input arguments"
|
echo "Not enough input arguments"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -108,6 +108,7 @@ conda install -c conda-forge enchant hunspell-en --yes
|
|||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
echo "Installing Python dependencies ..."
|
echo "Installing Python dependencies ..."
|
||||||
|
python3 pkgutils.py gen-req
|
||||||
pip install -r "$SRC_DIR/requirements.txt"
|
pip install -r "$SRC_DIR/requirements.txt"
|
||||||
|
|
||||||
# Leave conda env
|
# Leave conda env
|
||||||
|
|||||||
+1
-21
@@ -1,24 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
ENVPATH=/tmp/nwBuild
|
|
||||||
|
|
||||||
if [ ! -f pkgutils.py ]; then
|
if [ ! -f pkgutils.py ]; then
|
||||||
echo "Must be called from the root folder of the source"
|
echo "Must be called from the root folder of the source"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo " Create Python Env"
|
|
||||||
echo "================================================================================"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [ ! -d $ENVPATH ]; then
|
|
||||||
python3 -m venv $ENVPATH
|
|
||||||
fi
|
|
||||||
source $ENVPATH/bin/activate
|
|
||||||
pip3 install -U build twine -r requirements.txt -r docs/requirements.txt
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " Building Dependencies"
|
echo " Building Dependencies"
|
||||||
echo "================================================================================"
|
echo "================================================================================"
|
||||||
@@ -30,7 +17,7 @@ echo ""
|
|||||||
echo " Building Packages"
|
echo " Building Packages"
|
||||||
echo "================================================================================"
|
echo "================================================================================"
|
||||||
echo ""
|
echo ""
|
||||||
python3 -m build
|
uv build
|
||||||
mkdir -pv dist_upload
|
mkdir -pv dist_upload
|
||||||
cp -v dist/novelwriter-*.whl dist_upload/
|
cp -v dist/novelwriter-*.whl dist_upload/
|
||||||
cd dist_upload
|
cd dist_upload
|
||||||
@@ -38,13 +25,6 @@ FILE=$(ls -t | head -1)
|
|||||||
shasum -a 256 $FILE | tee $FILE.sha256
|
shasum -a 256 $FILE | tee $FILE.sha256
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo " Checking Packages"
|
|
||||||
echo "================================================================================"
|
|
||||||
echo ""
|
|
||||||
twine check dist/*
|
|
||||||
deactivate
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " Done!"
|
echo " Done!"
|
||||||
echo "================================================================================"
|
echo "================================================================================"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import zipfile
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from utils.common import (
|
from utils.common import (
|
||||||
ROOT_DIR, SETUP_DIR, copySourceCode, extractVersion, readFile,
|
ROOT_DIR, SETUP_DIR, copySourceCode, extractReqs, extractVersion, readFile,
|
||||||
removeRedundantQt, systemCall, writeFile
|
removeRedundantQt, systemCall, writeFile
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,7 +45,6 @@ def prepareCode(outDir: Path) -> None:
|
|||||||
files = [
|
files = [
|
||||||
ROOT_DIR / "CREDITS.md",
|
ROOT_DIR / "CREDITS.md",
|
||||||
ROOT_DIR / "LICENSE.md",
|
ROOT_DIR / "LICENSE.md",
|
||||||
ROOT_DIR / "requirements.txt",
|
|
||||||
SETUP_DIR / "iss_license.txt",
|
SETUP_DIR / "iss_license.txt",
|
||||||
SETUP_DIR / "windows" / "novelWriter.ico",
|
SETUP_DIR / "windows" / "novelWriter.ico",
|
||||||
SETUP_DIR / "windows" / "novelWriter.exe",
|
SETUP_DIR / "windows" / "novelWriter.exe",
|
||||||
@@ -85,7 +84,7 @@ def installRequirements(libDir: Path) -> None:
|
|||||||
"""Install dependencies."""
|
"""Install dependencies."""
|
||||||
print("Install dependencies ...")
|
print("Install dependencies ...")
|
||||||
systemCall([
|
systemCall([
|
||||||
sys.executable, "-m", "pip", "install", "-r", "requirements.txt", "--target", libDir
|
sys.executable, "-m", "pip", "install", *extractReqs(["app"]), "--target", libDir
|
||||||
])
|
])
|
||||||
print("Done")
|
print("Done")
|
||||||
print("")
|
print("")
|
||||||
|
|||||||
@@ -26,10 +26,24 @@ import sys
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import tomllib
|
||||||
|
|
||||||
ROOT_DIR = Path(__file__).parent.parent
|
ROOT_DIR = Path(__file__).parent.parent
|
||||||
SETUP_DIR = ROOT_DIR / "setup"
|
SETUP_DIR = ROOT_DIR / "setup"
|
||||||
|
|
||||||
|
|
||||||
|
def extractReqs(groups: list[str]) -> list[str]:
|
||||||
|
"""Generate requirements.txt file from pyproject.toml."""
|
||||||
|
data = tomllib.loads((ROOT_DIR / "pyproject.toml").read_text(encoding="utf-8"))
|
||||||
|
reqs = []
|
||||||
|
if "app" in groups or "all" in groups:
|
||||||
|
reqs += data["project"]["dependencies"]
|
||||||
|
for group in data["dependency-groups"]:
|
||||||
|
if group in groups or "all" in groups:
|
||||||
|
reqs += [d for d in data["dependency-groups"][group] if isinstance(d, str)]
|
||||||
|
return reqs
|
||||||
|
|
||||||
|
|
||||||
def extractVersion(beQuiet: bool = False) -> tuple[str, str, str]:
|
def extractVersion(beQuiet: bool = False) -> tuple[str, str, str]:
|
||||||
"""Extract the novelWriter version number without having to import
|
"""Extract the novelWriter version number without having to import
|
||||||
anything else from the main package.
|
anything else from the main package.
|
||||||
|
|||||||
Reference in New Issue
Block a user