diff --git a/.github/workflows/test_linux.yml b/.github/workflows/test_linux.yml index 83db7924..4c967dba 100644 --- a/.github/workflows/test_linux.yml +++ b/.github/workflows/test_linux.yml @@ -14,7 +14,7 @@ jobs: testLinux: strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] fail-fast: false runs-on: ubuntu-latest steps: diff --git a/README.md b/README.md index 5e690554..3ac3c385 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ documentation. ## Implementation -novelWriter is written with Python 3 (3.9+) using Qt5 and PyQt5 (5.15 only), and is released on +novelWriter is written with Python 3 (3.10+) using Qt5 and PyQt5 (5.15 only), and is released on Linux, Windows and macOS. It can in principle run on any Operating System that also supports Qt, PyQt and Python. diff --git a/novelwriter/__init__.py b/novelwriter/__init__.py index 3eaf6cdd..7e9f74f1 100644 --- a/novelwriter/__init__.py +++ b/novelwriter/__init__.py @@ -201,9 +201,9 @@ def main(sysArgs: list | None = None) -> GuiMain | None: # Check Packages and Versions errorData = [] errorCode = 0 - if sys.hexversion < 0x030900f0: + if sys.hexversion < 0x030a00f0: errorData.append( - "At least Python 3.9 is required, found %s" % CONFIG.verPyString + "At least Python 3.10 is required, found %s" % CONFIG.verPyString ) errorCode |= 0x04 if CONFIG.verQtValue < 0x050f00: diff --git a/novelwriter/common.py b/novelwriter/common.py index 317aced5..17a465ee 100644 --- a/novelwriter/common.py +++ b/novelwriter/common.py @@ -33,7 +33,7 @@ from collections.abc import Callable from configparser import ConfigParser from datetime import datetime from pathlib import Path -from typing import TYPE_CHECKING, Any, Literal, TypeVar +from typing import Any, Literal, TypeGuard, TypeVar from urllib.parse import urljoin from urllib.request import pathname2url @@ -44,9 +44,6 @@ from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType from novelwriter.error import logException -if TYPE_CHECKING: # pragma: no cover - from typing import TypeGuard # Requires Python 3.10 - logger = logging.getLogger(__name__) _Type = TypeVar("_Type") diff --git a/novelwriter/core/itemmodel.py b/novelwriter/core/itemmodel.py index 9cd82c39..8910e2b4 100644 --- a/novelwriter/core/itemmodel.py +++ b/novelwriter/core/itemmodel.py @@ -60,9 +60,7 @@ NODE_FLAGS = Qt.ItemFlag.ItemIsEnabled NODE_FLAGS |= Qt.ItemFlag.ItemIsSelectable NODE_FLAGS |= Qt.ItemFlag.ItemIsDropEnabled -if TYPE_CHECKING: # pragma: no cover - # Requires Python 3.10 - T_NodeData = str | QIcon | QFont | Qt.AlignmentFlag | None +T_NodeData = str | QIcon | QFont | Qt.AlignmentFlag | None class ProjectNode: diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py index e568e1cc..50bf4a94 100644 --- a/novelwriter/core/project.py +++ b/novelwriter/core/project.py @@ -30,7 +30,6 @@ from enum import Enum from functools import partial from pathlib import Path from time import time -from typing import TYPE_CHECKING from PyQt5.QtCore import QCoreApplication @@ -45,15 +44,12 @@ from novelwriter.core.options import OptionState from novelwriter.core.projectdata import NWProjectData from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState from novelwriter.core.sessions import NWSessionLog +from novelwriter.core.status import T_StatusKind, T_UpdateEntry from novelwriter.core.storage import NWStorage, NWStorageOpen from novelwriter.core.tree import NWTree from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType from novelwriter.error import logException -if TYPE_CHECKING: # pragma: no cover - # Requires Python 3.10 - from novelwriter.core.status import T_StatusKind, T_UpdateEntry - logger = logging.getLogger(__name__) diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py index f8569532..24b57aa6 100644 --- a/novelwriter/core/status.py +++ b/novelwriter/core/status.py @@ -29,7 +29,7 @@ import logging import random from collections.abc import Iterable -from typing import TYPE_CHECKING, Literal +from typing import Literal, TypeGuard from PyQt5.QtCore import QPointF, Qt from PyQt5.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygonF @@ -39,9 +39,6 @@ from novelwriter.common import simplified from novelwriter.enum import nwStatusShape from novelwriter.types import QtPaintAntiAlias, QtTransparent -if TYPE_CHECKING: # pragma: no cover - from typing import TypeGuard # Requires Python 3.10 - logger = logging.getLogger(__name__) @@ -65,10 +62,8 @@ class StatusEntry: NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0) -if TYPE_CHECKING: # pragma: no cover - # Requires Python 3.10 - T_UpdateEntry = list[tuple[str | None, StatusEntry]] - T_StatusKind = Literal["s", "i"] +T_UpdateEntry = list[tuple[str | None, StatusEntry]] +T_StatusKind = Literal["s", "i"] class NWStatus: diff --git a/pyproject.toml b/pyproject.toml index 08f4d999..79ecd45b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,6 @@ readme = {file = "setup/description_pypi.md", content-type = "text/markdown"} license = {text = "GNU General Public License v3"} classifiers = [ "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -25,7 +24,7 @@ classifiers = [ "Natural Language :: English", "Topic :: Text Editors", ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "pyqt5>=5.15", "pyenchant>=3.0.0", diff --git a/setup/debian/control b/setup/debian/control index 6e5504a2..9f9e5756 100644 --- a/setup/debian/control +++ b/setup/debian/control @@ -2,14 +2,14 @@ Source: novelwriter Maintainer: Veronica Berglyd Olsen Section: text Priority: optional -Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 9), python3 (>=3.9), python3-pyqt5 (>= 5.15), python3-enchant (>= 2.0) +Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 9), python3 (>=3.10), python3-pyqt5 (>= 5.15), python3-enchant (>= 2.0) Standards-Version: 4.5.1 Homepage: https://novelwriter.io -X-Python3-Version: >= 3.9 +X-Python3-Version: >= 3.10 Package: novelwriter Architecture: all -Depends: ${misc:Depends}, ${python3:Depends}, python3 (>=3.9), python3-pyqt5 (>= 5.15), python3-enchant (>= 2.0) +Depends: ${misc:Depends}, ${python3:Depends}, python3 (>=3.10), python3-pyqt5 (>= 5.15), python3-enchant (>= 2.0) Description: A markdown-like text editor for planning and writing novels novelWriter is a plain text editor designed for writing novels assembled from many smaller text documents. It uses a minimal formatting syntax inspired by diff --git a/setup/description_pypi.md b/setup/description_pypi.md index a774e10b..336a2e1c 100644 --- a/setup/description_pypi.md +++ b/setup/description_pypi.md @@ -10,7 +10,7 @@ synchronisation tools. All text is saved as plain text files with a meta data he project structure is stored in a single project XML file, and other meta data is primarily saved as JSON files. -The application is written with Python 3 (3.9+) using Qt5 and PyQt5 (5.10+). It is developed on +The application is written with Python 3 (3.10+) using Qt5 and PyQt5 (5.10+). It is developed on Linux, but should in principle work fine on other operating systems as well as long as dependencies are met. It is regularly tested on Debian and Ubuntu Linux, Windows, and MacOS. diff --git a/setup/launchpad_setup.cfg b/setup/launchpad_setup.cfg index e2dcb12c..74b3360d 100644 --- a/setup/launchpad_setup.cfg +++ b/setup/launchpad_setup.cfg @@ -11,7 +11,6 @@ license_files = LICENSE.md license = GNU General Public License v3 classifiers = Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 @@ -30,7 +29,7 @@ project_urls = [options] zip_safe = False -python_requires = >=3.9 +python_requires = >=3.10 include_package_data = True packages = find_namespace: install_requires =