diff --git a/.github/workflows/test_linux.yml b/.github/workflows/test_linux.yml index 346b8db5c..30b50db20 100644 --- a/.github/workflows/test_linux.yml +++ b/.github/workflows/test_linux.yml @@ -14,7 +14,7 @@ jobs: testLinux: strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: ubuntu-latest steps: - name: Python Setup diff --git a/CREDITS.md b/CREDITS.md index 489495dd9..d792ce6f9 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -40,7 +40,6 @@ The following libraries are dependencies of novelWriter: * [Qt5](https://www.qt.io) by Qt Company * [PyQt5](https://www.riverbankcomputing.com/software/pyqt) by Riverbank Computing -* [lxml](https://lxml.de) by Martijn Faassen * [Enchant](https://abiword.github.io/enchant) by Dom Lachowicz * [PyEnchant](https://pyenchant.github.io/pyenchant) by Dimitri Merejkowsky diff --git a/docs/source/int_source.rst b/docs/source/int_source.rst index 3ae3bfafe..3630b537d 100644 --- a/docs/source/int_source.rst +++ b/docs/source/int_source.rst @@ -46,13 +46,10 @@ format of the main project file. Everything else is handled with standard Python The following Python packages are needed to run novelWriter: * ``PyQt5`` – needed for connecting with the Qt5 libraries. -* ``lxml`` – needed for full XML support. * ``PyEnchant`` – needed for spell checking (optional). PyQt/Qt should be at least 5.10, but ideally 5.13 or higher for all features to work. For instance, -searching using regular expressions with full Unicode support requires 5.13. There is no known -minimum version requirement for package ``lxml``, but the code was originally written with 4.2, -which is therefore set as the minimum. It may work on lower versions. You have to test it. +searching using regular expressions with full Unicode support requires 5.13. 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. diff --git a/novelwriter/__init__.py b/novelwriter/__init__.py index 8597a55cf..c85d949b1 100644 --- a/novelwriter/__init__.py +++ b/novelwriter/__init__.py @@ -155,13 +155,14 @@ def main(sysArgs=None): elif inOpt == "--testmode": testMode = True - # Set Logging - cHandle = logging.StreamHandler() - cHandle.setFormatter(logging.Formatter(fmt=logFormat, style="{")) - + # Setup Logging pkgLogger = logging.getLogger(__package__) - pkgLogger.addHandler(cHandle) pkgLogger.setLevel(logLevel) + if len(pkgLogger.handlers) == 0: + # Make sure we only create one logger (mostly an issue with tests) + cHandle = logging.StreamHandler() + cHandle.setFormatter(logging.Formatter(fmt=logFormat, style="{")) + pkgLogger.addHandler(cHandle) logger.info("Starting novelWriter %s (%s) %s", __version__, __hexversion__, __date__) @@ -184,12 +185,6 @@ def main(sysArgs=None): ) errorCode |= 0x10 - try: - import lxml # noqa: F401 - except ImportError: - errorData.append("Python module 'lxml' is missing") - errorCode |= 0x20 - if errorData: errApp = QApplication([]) errDlg = QErrorMessage() diff --git a/novelwriter/assets/text/credits_en.htm b/novelwriter/assets/text/credits_en.htm index 807903785..525ffca9f 100644 --- a/novelwriter/assets/text/credits_en.htm +++ b/novelwriter/assets/text/credits_en.htm @@ -47,7 +47,6 @@
Qt5 by Qt Company
PyQt5 by Riverbank Computing
- lxml by Martijn Faassen
Enchant by Dom Lachowicz
PyEnchant by Dimitri Merejkowsky
Section: text
Priority: optional
-Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 9), python3 (>=3.7), python3-pyqt5 (>= 5.10), python3-lxml (>= 4.0), python3-enchant (>= 2.0)
+Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 9), python3 (>=3.7), python3-pyqt5 (>= 5.10), python3-enchant (>= 2.0)
Standards-Version: 4.5.1
Homepage: https://novelwriter.io
X-Python3-Version: >= 3.7
Package: novelwriter
Architecture: all
-Depends: ${misc:Depends}, ${python3:Depends}, python3 (>=3.7), python3-pyqt5 (>= 5.10), python3-lxml (>= 4.0), python3-enchant (>= 2.0)
+Depends: ${misc:Depends}, ${python3:Depends}, python3 (>=3.7), python3-pyqt5 (>= 5.10), 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/windows_install.bat b/setup/windows_install.bat
index 474c88612..4b2c80d63 100644
--- a/setup/windows_install.bat
+++ b/setup/windows_install.bat
@@ -19,7 +19,7 @@ if exist setup.py (
)
echo.
-:: Install the PyQt5, lxml and pyenchant dependencies
+:: Install the PyQt5 and pyenchant dependencies
pip install --user pywin32 -r requirements.txt
:: Create the desktop and start menu icons
diff --git a/setup/windows_uninstall.bat b/setup/windows_uninstall.bat
index 7522f4bd0..18523176a 100644
--- a/setup/windows_uninstall.bat
+++ b/setup/windows_uninstall.bat
@@ -29,7 +29,7 @@ goto afterUninst
:: Remove the desktop and start menu icons
python setup.py win-uninstall
-:: Remove the PyQt5, lxml and pyenchant dependencies
+:: Remove the PyQt5 and pyenchant dependencies
pip uninstall --yes -r requirements.txt
:afterUninst
diff --git a/tests/files/nwProject-1.5.nwx b/tests/files/nwProject-1.5.nwx
index 8bee81e41..8952b63bf 100644
--- a/tests/files/nwProject-1.5.nwx
+++ b/tests/files/nwProject-1.5.nwx
@@ -25,7 +25,7 @@
Chapter %chw%: %title%
%title%
Scene %ch%.%sc%: %title%
-
+
New
@@ -45,111 +45,111 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Page
-
-
+
Part One
-
-
+
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
-
+
Interlude
-
-
+
A Note on Structure
-
-
+
Chapter Two
-
-
+
We Found John!
-
-
+
Sequel
-
-
+
Title Page
-
-
+
Chapter One
-
-
+
Characters
-
-
+
Main Characters
-
-
+
John Smith
-
-
+
Jane Smith
-
-
+
Locations
-
-
+
Earth
-
-
+
Space
-
-
+
Mars
-
-
+
Archive
-
-
+
Scenes
-
-
+
Old File
-
-
+
Trash
-
-
+
Delete Me!
diff --git a/tests/lipsum/nwProject.nwx b/tests/lipsum/nwProject.nwx
index 086183c61..0a4a69e56 100644
--- a/tests/lipsum/nwProject.nwx
+++ b/tests/lipsum/nwProject.nwx
@@ -1,6 +1,6 @@
-
-
+
+
Lorem Ipsum
Lorem Ipsum
lipsum.com
@@ -24,7 +24,7 @@
Chapter %ch%: %title%
%title%
* * *
-
+
New
@@ -41,88 +41,88 @@
-
-
+
Novel
-
-
+
Lorem Ipsum
-
-
+
Front Matter
-
-
+
Prologue
-
-
+
Act One
-
-
+
Chapter One
-
-
+
Chapter One
-
-
+
Scene One
-
-
+
Scene Two
-
-
+
Interlude
-
-
+
Chapter Two
-
-
+
Chapter Two
-
-
+
Scene Three
-
-
+
Scene Four
-
-
+
Scene Five
-
-
+
Characters
-
-
+
Mr. Nobody
-
-
+
Plot
-
-
+
Main
-
-
+
World
-
-
+
Ancient Europe
-
+
\ No newline at end of file
diff --git a/tests/reference/coreProject_NewFileFolder_nwProject.nwx b/tests/reference/coreProject_NewFileFolder_nwProject.nwx
index 5000c7d9b..c80520fac 100644
--- a/tests/reference/coreProject_NewFileFolder_nwProject.nwx
+++ b/tests/reference/coreProject_NewFileFolder_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -15,13 +15,13 @@
None
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,47 +38,47 @@
-
-
+
Novel
-
-
+
Plot
-
-
+
Characters
-
-
+
World
-
-
+
Title Page
-
-
+
New Chapter
-
-
+
New Chapter
-
-
+
New Scene
-
-
+
Stuff
-
-
+
Hello
-
-
+
Jane
diff --git a/tests/reference/coreProject_NewRoot_nwProject.nwx b/tests/reference/coreProject_NewRoot_nwProject.nwx
index 06a0ca07d..c94ce28e1 100644
--- a/tests/reference/coreProject_NewRoot_nwProject.nwx
+++ b/tests/reference/coreProject_NewRoot_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -15,13 +15,13 @@
None
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,67 +38,67 @@
-
-
+
Novel
-
-
+
Plot
-
-
+
Characters
-
-
+
World
-
-
+
Title Page
-
-
+
New Chapter
-
-
+
New Chapter
-
-
+
New Scene
-
-
+
Novel
-
-
+
Plot
-
-
+
Characters
-
-
+
Locations
-
-
+
Timeline
-
-
+
Objects
-
-
+
Custom
-
-
+
Custom
diff --git a/tests/reference/coreToOdt_SaveFlat_document.fodt b/tests/reference/coreToOdt_SaveFlat_document.fodt
index 6e879a5c0..0c2b658ed 100644
--- a/tests/reference/coreToOdt_SaveFlat_document.fodt
+++ b/tests/reference/coreToOdt_SaveFlat_document.fodt
@@ -1,72 +1,72 @@
-
+
- 2023-02-12T15:10:11
- novelWriter/2.0.4
+ 2023-05-29T22:10:15
+ novelWriter/2.0.7
Jane Smith
1234
P42DT12H34M56S
Test Project
- 2023-02-12T15:10:11
+ 2023-05-29T22:10:15
Jane Smith
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
@@ -75,7 +75,7 @@
Test Project / Jane Smith / 2
-
+
diff --git a/tests/reference/coreToOdt_SaveFull_content.xml b/tests/reference/coreToOdt_SaveFull_content.xml
index 4e191f7c2..0654b0f3f 100644
--- a/tests/reference/coreToOdt_SaveFull_content.xml
+++ b/tests/reference/coreToOdt_SaveFull_content.xml
@@ -1,11 +1,11 @@
-
+
-
+
-
+
diff --git a/tests/reference/coreToOdt_SaveFull_manifest.xml b/tests/reference/coreToOdt_SaveFull_manifest.xml
index f939a7b3d..858f5ff8d 100644
--- a/tests/reference/coreToOdt_SaveFull_manifest.xml
+++ b/tests/reference/coreToOdt_SaveFull_manifest.xml
@@ -1,8 +1,8 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/tests/reference/coreToOdt_SaveFull_meta.xml b/tests/reference/coreToOdt_SaveFull_meta.xml
index 79930faab..8791d9d71 100644
--- a/tests/reference/coreToOdt_SaveFull_meta.xml
+++ b/tests/reference/coreToOdt_SaveFull_meta.xml
@@ -1,13 +1,13 @@
-
+
- 2023-02-12T15:09:03
- novelWriter/2.0.4
+ 2023-05-29T19:48:33
+ novelWriter/2.0.7
Jane Smith
1234
P42DT12H34M56S
Test Project
- 2023-02-12T15:09:03
+ 2023-05-29T19:48:33
Jane Smith
diff --git a/tests/reference/coreToOdt_SaveFull_settings.xml b/tests/reference/coreToOdt_SaveFull_settings.xml
index 7b5218f25..53e43d1f2 100644
--- a/tests/reference/coreToOdt_SaveFull_settings.xml
+++ b/tests/reference/coreToOdt_SaveFull_settings.xml
@@ -1,2 +1,2 @@
-
+
diff --git a/tests/reference/coreToOdt_SaveFull_styles.xml b/tests/reference/coreToOdt_SaveFull_styles.xml
index 5319adf27..6c5f9bd26 100644
--- a/tests/reference/coreToOdt_SaveFull_styles.xml
+++ b/tests/reference/coreToOdt_SaveFull_styles.xml
@@ -1,68 +1,69 @@
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
- Test Project / Jane Smith / 2
+ Test Project / Jane Smith / 2
+
-
+
diff --git a/tests/reference/coreTools_NewCustomA_nwProject.nwx b/tests/reference/coreTools_NewCustomA_nwProject.nwx
index ffa4f38a7..844196755 100644
--- a/tests/reference/coreTools_NewCustomA_nwProject.nwx
+++ b/tests/reference/coreTools_NewCustomA_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Test Custom
Test Novel
@@ -15,13 +15,13 @@
None
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,91 +38,91 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Chapter 1
-
-
+
Scene 1.1
-
-
+
Scene 1.2
-
-
+
Scene 1.3
-
-
+
Chapter 2
-
-
+
Scene 2.1
-
-
+
Scene 2.2
-
-
+
Scene 2.3
-
-
+
Chapter 3
-
-
+
Scene 3.1
-
-
+
Scene 3.2
-
-
+
Scene 3.3
-
-
+
Plot
-
-
+
Main Plot
-
-
+
Characters
-
-
+
Protagonist
-
-
+
Locations
-
-
+
Main Location
-
-
+
Archive
-
-
+
Trash
diff --git a/tests/reference/coreTools_NewCustomB_nwProject.nwx b/tests/reference/coreTools_NewCustomB_nwProject.nwx
index 38084419f..53e23cd81 100644
--- a/tests/reference/coreTools_NewCustomB_nwProject.nwx
+++ b/tests/reference/coreTools_NewCustomB_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Test Custom
Test Novel
@@ -15,13 +15,13 @@
None
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,67 +38,67 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Scene 1
-
-
+
Scene 2
-
-
+
Scene 3
-
-
+
Scene 4
-
-
+
Scene 5
-
-
+
Scene 6
-
-
+
Plot
-
-
+
Main Plot
-
-
+
Characters
-
-
+
Protagonist
-
-
+
Locations
-
-
+
Main Location
-
-
+
Archive
-
-
+
Trash
diff --git a/tests/reference/coreTools_NewMinimal_nwProject.nwx b/tests/reference/coreTools_NewMinimal_nwProject.nwx
index dc3f2d434..04ad571ca 100644
--- a/tests/reference/coreTools_NewMinimal_nwProject.nwx
+++ b/tests/reference/coreTools_NewMinimal_nwProject.nwx
@@ -1,9 +1,9 @@
-
+
New Project
New Project
-
+
yes
@@ -15,13 +15,13 @@
None
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,35 +38,35 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
New Chapter
-
-
+
New Scene
-
-
+
Plot
-
-
+
Characters
-
-
+
Locations
-
-
+
Archive
diff --git a/tests/reference/guiBuild_Tool_Step1_Lorem_Ipsum.fodt b/tests/reference/guiBuild_Tool_Step1_Lorem_Ipsum.fodt
index d327ee5bf..4bd71182b 100644
--- a/tests/reference/guiBuild_Tool_Step1_Lorem_Ipsum.fodt
+++ b/tests/reference/guiBuild_Tool_Step1_Lorem_Ipsum.fodt
@@ -1,84 +1,84 @@
-
+
- 2023-02-12T14:52:03
- novelWriter/2.0.4
+ 2023-05-29T22:10:29
+ novelWriter/2.0.7
lipsum.com
- 38
- P0DT0H31M40S
+ 40
+ P0DT0H31M45S
Lorem Ipsum
- 2023-02-12T14:52:03
+ 2023-05-29T22:10:29
lipsum.com
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -87,7 +87,7 @@
Lorem Ipsum / lipsum.com / 2
-
+
diff --git a/tests/reference/guiBuild_Tool_Step2_Lorem_Ipsum.fodt b/tests/reference/guiBuild_Tool_Step2_Lorem_Ipsum.fodt
index d179c99de..cf329eb66 100644
--- a/tests/reference/guiBuild_Tool_Step2_Lorem_Ipsum.fodt
+++ b/tests/reference/guiBuild_Tool_Step2_Lorem_Ipsum.fodt
@@ -1,96 +1,96 @@
-
+
- 2023-02-12T15:00:22
- novelWriter/2.0.4
+ 2023-05-29T22:11:22
+ novelWriter/2.0.7
lipsum.com
- 38
- P0DT0H31M40S
+ 40
+ P0DT0H31M45S
Lorem Ipsum
- 2023-02-12T15:00:22
+ 2023-05-29T22:11:22
lipsum.com
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -99,7 +99,7 @@
Lorem Ipsum / lipsum.com / 2
-
+
@@ -147,9 +147,9 @@
Ut et consequat enim, quis ornare nibh. In lectus neque, mollis et suscipit et, vestibulum vitae augue. Praesent id ante sit amet odio venenatis placerat a at erat. Sed sed metus sed nisi dictum varius. Integer tincidunt fermentum purus ac porta. Fusce porttitor non risus eget tristique. Donec augue nunc, maximus at fermentum vel, varius et neque. Ut sed consectetur mauris. Quisque ipsum enim, porttitor vitae imperdiet sit amet, tempor et mauris. Aliquam malesuada tincidunt lectus quis blandit. Sed commodo orci felis, quis ultrices tellus facilisis sed. Nunc vel varius est. Duis ullamcorper eu metus in pulvinar. Morbi at sapien dictum, rutrum mauris eget, interdum tellus.
Why do we use it?
Comment: Exctracted from the lipsum.com website.
- It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
- The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
- Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
+ It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
+ The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
+ Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
Chapter Two: Chapter Two
Point of View: Bod
Plot: Main
diff --git a/tests/reference/guiBuild_Tool_Step3_Lorem_Ipsum.fodt b/tests/reference/guiBuild_Tool_Step3_Lorem_Ipsum.fodt
index ca391d276..d58917216 100644
--- a/tests/reference/guiBuild_Tool_Step3_Lorem_Ipsum.fodt
+++ b/tests/reference/guiBuild_Tool_Step3_Lorem_Ipsum.fodt
@@ -1,96 +1,96 @@
-
+
- 2023-02-12T15:01:25
- novelWriter/2.0.4
+ 2023-05-29T22:11:58
+ novelWriter/2.0.7
lipsum.com
- 38
- P0DT0H31M40S
+ 40
+ P0DT0H31M45S
Lorem Ipsum
- 2023-02-12T15:01:25
+ 2023-05-29T22:11:58
lipsum.com
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -99,7 +99,7 @@
Lorem Ipsum / lipsum.com / 2
-
+
@@ -147,9 +147,9 @@
Ut et consequat enim, quis ornare nibh. In lectus neque, mollis et suscipit et, vestibulum vitae augue. Praesent id ante sit amet odio venenatis placerat a at erat. Sed sed metus sed nisi dictum varius. Integer tincidunt fermentum purus ac porta. Fusce porttitor non risus eget tristique. Donec augue nunc, maximus at fermentum vel, varius et neque. Ut sed consectetur mauris. Quisque ipsum enim, porttitor vitae imperdiet sit amet, tempor et mauris. Aliquam malesuada tincidunt lectus quis blandit. Sed commodo orci felis, quis ultrices tellus facilisis sed. Nunc vel varius est. Duis ullamcorper eu metus in pulvinar. Morbi at sapien dictum, rutrum mauris eget, interdum tellus.
Why do we use it?
Comment: Exctracted from the lipsum.com website.
- It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
- The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
- Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
+ It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
+ The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
+ Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
Chapter Two: Chapter Two
Point of View: Bod
Plot: Main
diff --git a/tests/reference/guiEditor_Main_Final_nwProject.nwx b/tests/reference/guiEditor_Main_Final_nwProject.nwx
index dc0456a7a..c5c3b367c 100644
--- a/tests/reference/guiEditor_Main_Final_nwProject.nwx
+++ b/tests/reference/guiEditor_Main_Final_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -15,13 +15,13 @@
0000000000008
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,47 +38,47 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
New Chapter
-
-
+
New Chapter
-
-
+
New Scene
-
-
+
Plot
-
-
+
New Note
-
-
+
Characters
-
-
+
New Note
-
-
+
World
-
-
+
New Note
diff --git a/tests/reference/guiEditor_Main_Initial_nwProject.nwx b/tests/reference/guiEditor_Main_Initial_nwProject.nwx
index 977f03c13..4d758791d 100644
--- a/tests/reference/guiEditor_Main_Initial_nwProject.nwx
+++ b/tests/reference/guiEditor_Main_Initial_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -15,13 +15,13 @@
None
None
-
+
%title%
%title%
%title%
* * *
-
+
New
@@ -38,35 +38,35 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
New Chapter
-
-
+
New Chapter
-
-
+
New Scene
-
-
+
Plot
-
-
+
Characters
-
-
+
World
diff --git a/tests/reference/projectXML_ReadLegacy10.nwx b/tests/reference/projectXML_ReadLegacy10.nwx
index 5b189c1ed..edcab5b47 100644
--- a/tests/reference/projectXML_ReadLegacy10.nwx
+++ b/tests/reference/projectXML_ReadLegacy10.nwx
@@ -25,7 +25,7 @@
Chapter %ch%: %title%
%title%
Scene %ch%.%sc%: %title%
-
+
New
@@ -45,91 +45,91 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Page
-
-
+
Part One
-
-
+
A Folder
-
-
+
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
-
+
Interlude
-
-
+
A Note on Structure
-
-
+
Chapter Two
-
-
+
We Found John!
-
-
+
Characters
-
-
+
Main Characters
-
-
+
John Smith
-
-
+
Jane Smith
-
-
+
Locations
-
-
+
Earth
-
-
+
Space
-
-
+
Mars
-
-
+
Trash
-
-
+
Delete Me!
diff --git a/tests/reference/projectXML_ReadLegacy11.nwx b/tests/reference/projectXML_ReadLegacy11.nwx
index afc87cefb..fcc987efa 100644
--- a/tests/reference/projectXML_ReadLegacy11.nwx
+++ b/tests/reference/projectXML_ReadLegacy11.nwx
@@ -25,7 +25,7 @@
Chapter %ch%: %title%
%title%
Scene %ch%.%sc%: %title%
-
+
New
@@ -45,91 +45,91 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Page
-
-
+
Part One
-
-
+
A Folder
-
-
+
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
-
+
Interlude
-
-
+
A Note on Structure
-
-
+
Chapter Two
-
-
+
We Found John!
-
-
+
Characters
-
-
+
Main Characters
-
-
+
John Smith
-
-
+
Jane Smith
-
-
+
Locations
-
-
+
Earth
-
-
+
Space
-
-
+
Mars
-
-
+
Trash
-
-
+
Delete Me!
diff --git a/tests/reference/projectXML_ReadLegacy12.nwx b/tests/reference/projectXML_ReadLegacy12.nwx
index e31f035ae..b44e9acf4 100644
--- a/tests/reference/projectXML_ReadLegacy12.nwx
+++ b/tests/reference/projectXML_ReadLegacy12.nwx
@@ -25,7 +25,7 @@
Chapter %chw%: %title%
%title%
Scene %ch%.%sc%: %title%
-
+
New
@@ -45,103 +45,103 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Page
-
-
+
Part One
-
-
+
A Folder
-
-
+
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
-
+
Interlude
-
-
+
A Note on Structure
-
-
+
Chapter Two
-
-
+
We Found John!
-
-
+
Characters
-
-
+
Main Characters
-
-
+
John Smith
-
-
+
Jane Smith
-
-
+
Locations
-
-
+
Earth
-
-
+
Space
-
-
+
Mars
-
-
+
Outtakes
-
-
+
Scenes
-
-
+
Old File
-
-
+
Trash
-
-
+
Delete Me!
diff --git a/tests/reference/projectXML_ReadLegacy13.nwx b/tests/reference/projectXML_ReadLegacy13.nwx
index d629079d1..06fc31459 100644
--- a/tests/reference/projectXML_ReadLegacy13.nwx
+++ b/tests/reference/projectXML_ReadLegacy13.nwx
@@ -25,7 +25,7 @@
Chapter %chw%: %title%
%title%
Scene %ch%.%sc%: %title%
-
+
New
@@ -45,103 +45,103 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Page
-
-
+
Part One
-
-
+
A Folder
-
-
+
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
-
+
Interlude
-
-
+
A Note on Structure
-
-
+
Chapter Two
-
-
+
We Found John!
-
-
+
Characters
-
-
+
Main Characters
-
-
+
John Smith
-
-
+
Jane Smith
-
-
+
Locations
-
-
+
Earth
-
-
+
Space
-
-
+
Mars
-
-
+
Archive
-
-
+
Scenes
-
-
+
Old File
-
-
+
Trash
-
-
+
Delete Me!
diff --git a/tests/reference/projectXML_ReadLegacy14.nwx b/tests/reference/projectXML_ReadLegacy14.nwx
index 6bc7154c3..e40e3a077 100644
--- a/tests/reference/projectXML_ReadLegacy14.nwx
+++ b/tests/reference/projectXML_ReadLegacy14.nwx
@@ -25,7 +25,7 @@
Chapter %chw%: %title%
%title%
Scene %ch%.%sc%: %title%
-
+
New
@@ -45,111 +45,111 @@
-
-
+
Novel
-
-
+
Title Page
-
-
+
Page
-
-
+
Part One
-
-
+
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
-
+
Interlude
-
-
+
A Note on Structure
-
-
+
Chapter Two
-
-
+
We Found John!
-
-
+
Sequel
-
-
+
Title Page
-
-
+
Chapter One
-
-
+
Characters
-
-
+
Main Characters
-
-
+
John Smith
-
-
+
Jane Smith
-
-
+
Locations
-
-
+
Earth
-
-
+
Space
-
-
+
Mars
-
-
+
Archive
-
-
+
Scenes
-
-
+
Old File
-
-
+
Trash
-
-
+
Delete Me!
diff --git a/tests/test_base/test_base_init.py b/tests/test_base/test_base_init.py
index 71056fb76..a932dcfa4 100644
--- a/tests/test_base/test_base_init.py
+++ b/tests/test_base/test_base_init.py
@@ -154,7 +154,6 @@ def testBaseInit_Imports(caplog, monkeypatch, fncPath):
monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.__init__", lambda *a: None)
monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.resize", lambda *a: None)
monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.showMessage", lambda *a: None)
- monkeypatch.setitem(sys.modules, "lxml", None)
monkeypatch.setattr("sys.hexversion", 0x0)
monkeypatch.setattr("novelwriter.CONFIG.verQtValue", 0x050000)
monkeypatch.setattr("novelwriter.CONFIG.verPyQtValue", 0x050000)
@@ -167,11 +166,9 @@ def testBaseInit_Imports(caplog, monkeypatch, fncPath):
assert ex.value.code & 4 == 4 # Python version not satisfied
assert ex.value.code & 8 == 8 # Qt version not satisfied
assert ex.value.code & 16 == 16 # PyQt version not satisfied
- assert ex.value.code & 32 == 32 # lxml package missing
assert "At least Python" in caplog.messages[0]
assert "At least Qt5" in caplog.messages[1]
assert "At least PyQt5" in caplog.messages[2]
- assert "lxml" in caplog.messages[3]
# END Test testBaseInit_Imports
diff --git a/tests/test_core/test_core_projectxml.py b/tests/test_core/test_core_projectxml.py
index 4d0996326..35132107c 100644
--- a/tests/test_core/test_core_projectxml.py
+++ b/tests/test_core/test_core_projectxml.py
@@ -226,7 +226,7 @@ def testCoreProjectXML_ReadCurrent(monkeypatch, tstPaths, fncPath):
# Fail saving
with monkeypatch.context() as mp:
- mp.setattr("pathlib.Path.write_bytes", causeOSError)
+ mp.setattr("xml.etree.ElementTree.ElementTree.write", causeOSError)
assert xmlWriter.write(data, packedContent, timeStamp, 1000) is False
assert str(xmlWriter.error) == "Mock OSError"
diff --git a/tests/test_core/test_core_toodt.py b/tests/test_core/test_core_toodt.py
index 6e3ea4466..55c6d7856 100644
--- a/tests/test_core/test_core_toodt.py
+++ b/tests/test_core/test_core_toodt.py
@@ -21,12 +21,13 @@
import pytest
import zipfile
+import xml.etree.ElementTree as ET
-from lxml import etree
from shutil import copyfile
from tools import ODT_IGNORE, cmpFiles
+from novelwriter.common import xmlIndent
from novelwriter.core.toodt import ToOdt, ODTParagraphStyle, ODTTextStyle, XMLParagraph, _mkTag
from novelwriter.core.project import NWProject
@@ -44,7 +45,7 @@
def xmlToText(xElem):
"""Get the text content of an XML element.
"""
- rTxt = etree.tostring(xElem, encoding="utf-8", xml_declaration=False).decode()
+ rTxt = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode()
for nSpace in XML_NS:
rTxt = rTxt.replace(nSpace, "")
return rTxt
@@ -63,21 +64,21 @@ def testCoreToOdt_Init(mockGUI):
theDoc.initDocument()
# Document XML
- assert theDoc._dFlat is not None
- assert theDoc._dCont is None
- assert theDoc._dMeta is None
- assert theDoc._dStyl is None
+ assert theDoc._dFlat.tag == _mkTag("office", "document")
+ assert theDoc._dCont.tag == ""
+ assert theDoc._dMeta.tag == ""
+ assert theDoc._dStyl.tag == ""
# Content XML
- assert theDoc._xMeta is not None
- assert theDoc._xFont is not None
- assert theDoc._xFnt2 is None
- assert theDoc._xStyl is not None
- assert theDoc._xAuto is not None
- assert theDoc._xAut2 is None
- assert theDoc._xMast is not None
- assert theDoc._xBody is not None
- assert theDoc._xText is not None
+ assert theDoc._xMeta.tag == _mkTag("office", "meta")
+ assert theDoc._xFont.tag == _mkTag("office", "font-face-decls")
+ assert theDoc._xFnt2.tag == ""
+ assert theDoc._xStyl.tag == _mkTag("office", "styles")
+ assert theDoc._xAuto.tag == _mkTag("office", "automatic-styles")
+ assert theDoc._xAut2.tag == ""
+ assert theDoc._xMast.tag == _mkTag("office", "master-styles")
+ assert theDoc._xBody.tag == _mkTag("office", "body")
+ assert theDoc._xText.tag == _mkTag("office", "text")
# ODT Doc
# =======
@@ -86,21 +87,22 @@ def testCoreToOdt_Init(mockGUI):
theDoc.initDocument()
# Document XML
- assert theDoc._dFlat is None
- assert theDoc._dCont is not None
- assert theDoc._dMeta is not None
- assert theDoc._dStyl is not None
+ assert theDoc._dFlat.tag == ""
+ assert theDoc._dCont.tag == _mkTag("office", "document-content")
+ assert theDoc._dMeta.tag == _mkTag("office", "document-meta")
+ assert theDoc._dStyl.tag == _mkTag("office", "document-styles")
# Content XML
- assert theDoc._xMeta is not None
- assert theDoc._xFont is not None
- assert theDoc._xFnt2 is not None
- assert theDoc._xStyl is not None
- assert theDoc._xAuto is not None
- assert theDoc._xAut2 is not None
- assert theDoc._xMast is not None
- assert theDoc._xBody is not None
- assert theDoc._xText is not None
+ assert theDoc._xMeta.tag == _mkTag("office", "meta")
+ assert theDoc._xFont.tag == _mkTag("office", "font-face-decls")
+ assert theDoc._xFnt2.tag == _mkTag("office", "font-face-decls")
+ assert theDoc._xStyl.tag == _mkTag("office", "styles")
+ assert theDoc._xAuto.tag == _mkTag("office", "automatic-styles")
+ assert theDoc._xAut2.tag == _mkTag("office", "automatic-styles")
+ assert theDoc._xMast.tag == _mkTag("office", "master-styles")
+ assert theDoc._xBody.tag == _mkTag("office", "body")
+ assert theDoc._xText.tag == _mkTag("office", "text")
+
# END Test testCoreToOdt_Init
@@ -113,7 +115,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
theDoc = ToOdt(theProject, isFlat=True)
theDoc.initDocument()
- assert xmlToText(theDoc._xText) == " "
+ assert xmlToText(theDoc._xText) == " "
# Paragraph Style
# ===============
@@ -147,7 +149,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
theDoc._addTextPar("Standard", oStyle, "")
assert xmlToText(theDoc._xText) == (
""
- " "
+ " "
" "
)
@@ -217,7 +219,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
assert theDoc.getErrors() == []
assert xmlToText(theDoc._xText) == (
""
- "Hello World "
+ "Hello World "
" "
)
@@ -366,7 +368,7 @@ def getStyle(styleName):
assert theDoc.getErrors() == []
assert xmlToText(theDoc._xText) == (
''
- 'Some text. Next line '
+ 'Some text. Next line '
' '
)
@@ -379,7 +381,7 @@ def getStyle(styleName):
assert theDoc.getErrors() == []
assert xmlToText(theDoc._xText) == (
''
- ' Item 1 Item 2 '
+ ' Item 1 Item 2 '
' '
)
@@ -393,7 +395,7 @@ def getStyle(styleName):
assert xmlToText(theDoc._xText) == (
''
'Some '
- 'bold text '
+ 'bold text'
' '
)
@@ -413,8 +415,8 @@ def getStyle(styleName):
''
'Scene '
'Hello World '
- 'Hello World '
- 'Hello World '
+ 'Hello World '
+ 'Hello World '
' '
)
@@ -474,9 +476,9 @@ def getStyle(styleName):
assert theDoc.getErrors() == []
assert xmlToText(theDoc._xText) == (
''
- ' '
+ ' '
'Text '
- ' '
+ ' '
'Text '
' '
)
@@ -540,7 +542,7 @@ def getStyle(styleName):
''
'Scene '
'Regular paragraph '
- 'with break '
+ 'with break '
'Left Align '
' '
)
@@ -592,7 +594,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
assert (
''
- ' '
+ ' '
' '
) in xmlToText(theDoc._xAuto)
assert xmlToText(theDoc._xText) == (
@@ -613,7 +615,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
assert (
''
- ' '
+ ' '
' '
) in xmlToText(theDoc._xAuto)
assert xmlToText(theDoc._xText) == (
@@ -723,15 +725,10 @@ def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
stylOut = tstPaths.outDir / "coreToOdt_SaveFull" / "styles.xml"
def prettifyXml(inFile, outFile):
- with open(outFile, mode="wb") as fileStream:
- fileStream.write(
- etree.tostring(
- etree.parse(str(inFile)),
- pretty_print=True,
- encoding="utf-8",
- xml_declaration=True
- )
- )
+ with open(outFile, mode="wb") as fStream:
+ xml = ET.parse(inFile)
+ xmlIndent(xml)
+ xml.write(fStream, encoding="utf-8", xml_declaration=True)
prettifyXml(maniOut, maniFile)
prettifyXml(settOut, settFile)
@@ -949,20 +946,16 @@ def testCoreToOdt_ODTParagraphStyle():
# Pack XML
# ========
- xStyle = etree.Element("test", nsmap={
- "style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
- "loext": "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
- "fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
- })
+ xStyle = ET.Element("test")
parStyle.packXML(xStyle, "test")
assert xmlToText(xStyle) == (
''
''
' '
+ 'fo:margin-left="0.000cm" fo:margin-right="0.000cm" fo:line-height="1.15" />'
' '
+ 'fo:font-size="12pt" fo:color="#000000" loext:opacity="1.00" />'
' '
' '
)
@@ -1059,15 +1052,12 @@ def testCoreToOdt_ODTTextStyle():
txtStyle.setFontStyle("italic")
txtStyle.setStrikeStyle("solid")
txtStyle.setStrikeType("single")
- xStyle = etree.Element("test", nsmap={
- "style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
- "fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
- })
+ xStyle = ET.Element("test")
txtStyle.packXML(xStyle, "test")
assert xmlToText(xStyle) == (
' '
+ 'style:text-line-through-type="single" />'
)
# END Test testCoreToOdt_ODTTextStyle
@@ -1077,20 +1067,11 @@ def testCoreToOdt_ODTTextStyle():
def testCoreToOdt_XMLParagraph():
"""Test XML encoding of paragraph.
"""
- nsMap = {
- "office": "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
- "style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
- "loext": "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
- "text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
- "meta": "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
- "fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
- }
-
# Stage 1 : Text
# ==============
- xRoot = etree.Element("root", nsmap=nsMap)
- xElem = etree.SubElement(xRoot, "{%s}p" % nsMap["text"])
+ xRoot = ET.Element("root")
+ xElem = ET.SubElement(xRoot, _mkTag("text", "p"))
xmlPar = XMLParagraph(xElem)
# Plain Text
@@ -1126,15 +1107,15 @@ def testCoreToOdt_XMLParagraph():
# Stage 2 : Line Breaks
# =====================
- xRoot = etree.Element("root", nsmap=nsMap)
- xElem = etree.SubElement(xRoot, "{%s}p" % nsMap["text"])
+ xRoot = ET.Element("root")
+ xElem = ET.SubElement(xRoot, _mkTag("text", "p"))
xmlPar = XMLParagraph(xElem)
# Plain Text w/Line Break
xmlPar.appendText("Hello\nWorld\n!!")
assert xmlToText(xRoot) == (
''
- 'Hello World !! '
+ 'Hello World !! '
' '
)
@@ -1142,8 +1123,8 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendSpan("spanned\ntext", "T1")
assert xmlToText(xRoot) == (
''
- 'Hello World !!'
- 'spanned text '
+ 'Hello World !!'
+ 'spanned text '
' '
)
@@ -1151,9 +1132,9 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendText("more\ntext")
assert xmlToText(xRoot) == (
''
- 'Hello World !!'
- 'spanned text '
- 'more text '
+ 'Hello World !!'
+ 'spanned text '
+ 'more text '
' '
)
@@ -1162,15 +1143,15 @@ def testCoreToOdt_XMLParagraph():
# Stage 3 : Tabs
# ==============
- xRoot = etree.Element("root", nsmap=nsMap)
- xElem = etree.SubElement(xRoot, "{%s}p" % nsMap["text"])
+ xRoot = ET.Element("root")
+ xElem = ET.SubElement(xRoot, _mkTag("text", "p"))
xmlPar = XMLParagraph(xElem)
# Plain Text w/Line Break
xmlPar.appendText("Hello\tWorld\t!!")
assert xmlToText(xRoot) == (
''
- 'Hello World !! '
+ 'Hello World !! '
' '
)
@@ -1178,8 +1159,8 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendSpan("spanned\ttext", "T1")
assert xmlToText(xRoot) == (
''
- 'Hello World !!'
- 'spanned text '
+ 'Hello World !!'
+ 'spanned text '
' '
)
@@ -1187,9 +1168,9 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendText("more\ttext")
assert xmlToText(xRoot) == (
''
- 'Hello World !!'
- 'spanned text '
- 'more text '
+ 'Hello World !!'
+ 'spanned text '
+ 'more text '
' '
)
@@ -1198,15 +1179,15 @@ def testCoreToOdt_XMLParagraph():
# Stage 4 : Spaces
# ================
- xRoot = etree.Element("root", nsmap=nsMap)
- xElem = etree.SubElement(xRoot, "{%s}p" % nsMap["text"])
+ xRoot = ET.Element("root")
+ xElem = ET.SubElement(xRoot, _mkTag("text", "p"))
xmlPar = XMLParagraph(xElem)
# Plain Text w/Spaces
xmlPar.appendText("Hello World !!")
assert xmlToText(xRoot) == (
''
- 'Hello World !! '
+ 'Hello World !! '
' '
)
@@ -1214,8 +1195,8 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendSpan("spanned text", "T1")
assert xmlToText(xRoot) == (
''
- 'Hello World !!'
- 'spanned text '
+ 'Hello World !!'
+ 'spanned text '
' '
)
@@ -1223,9 +1204,9 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendText("more text")
assert xmlToText(xRoot) == (
''
- 'Hello World !!'
- 'spanned text '
- 'more text '
+ 'Hello World !!'
+ 'spanned text '
+ 'more text '
' '
)
@@ -1234,15 +1215,15 @@ def testCoreToOdt_XMLParagraph():
# Stage 5 : Lots of Spaces
# ========================
- xRoot = etree.Element("root", nsmap=nsMap)
- xElem = etree.SubElement(xRoot, "{%s}p" % nsMap["text"])
+ xRoot = ET.Element("root")
+ xElem = ET.SubElement(xRoot, _mkTag("text", "p"))
xmlPar = XMLParagraph(xElem)
# Plain Text w/Many Spaces
xmlPar.appendText(" \t A \n B ")
assert xmlToText(xRoot) == (
''
- ' A B '
+ ' A B '
' '
)
@@ -1250,9 +1231,9 @@ def testCoreToOdt_XMLParagraph():
xmlPar.appendSpan(" C \t D \n E ", "T1")
assert xmlToText(xRoot) == (
''
- ' A B '
- ' C D '
- ' E '
+ ' A B '
+ ' C D '
+ ' E '
' '
)
@@ -1261,8 +1242,8 @@ def testCoreToOdt_XMLParagraph():
# Check Error
# ===========
- xRoot = etree.Element("root", nsmap=nsMap)
- xElem = etree.SubElement(xRoot, "{%s}p" % nsMap["text"])
+ xRoot = ET.Element("root")
+ xElem = ET.SubElement(xRoot, _mkTag("text", "p"))
xmlPar = XMLParagraph(xElem)
xmlPar.appendText("A")
diff --git a/tests/tools.py b/tests/tools.py
index a9933bc48..7463e3a17 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -27,7 +27,7 @@
from PyQt5.QtWidgets import qApp
XML_IGNORE = ("