Compare commits

..

4 Commits

Author SHA1 Message Date
Bastian Venthur
8656780e5b added type annotations 2023-11-12 17:11:25 +01:00
Bastian Venthur
ff1099de60 wip 2023-11-12 17:04:53 +01:00
Bastian Venthur
a0374a777e put import at correct place 2023-11-12 17:03:53 +01:00
Bastian Venthur
55eb9d7482 WIP 2023-11-12 17:02:03 +01:00
21 changed files with 149 additions and 103 deletions

View File

@@ -17,13 +17,19 @@ jobs:
- macos-latest - macos-latest
- windows-latest - windows-latest
python-version: python-version:
- "3.8"
- "3.9"
- "3.10" - "3.10"
- "3.11" - "3.11"
- "3.12" - "3.12"
exclude:
# 3.8 on windows fails due to some pip issue
- os: windows-latest
python-version: "3.8"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
@@ -37,7 +43,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"
@@ -51,7 +57,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"
@@ -66,7 +72,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"

View File

@@ -1,11 +1,5 @@
# Changelog # Changelog
## [2.3.0] -- 2024-04-24
* fixed devsever so it does not crash anymore when the (re-)build fails
* dropped support for Python 3.8 and 3.9
* updated dependencies
## [2.2.1] -- 2023-11-11 ## [2.2.1] -- 2023-11-11
* fixed `suggests` to blag-doc * fixed `suggests` to blag-doc

View File

@@ -24,7 +24,7 @@ blag is named after [the blag of the webcomic xkcd][blagxkcd].
* Integrated devserver * Integrated devserver
* Available on [PyPI][] * Available on [PyPI][]
blag runs on Linux, Mac and Windows and requires Python >= 3.10 blag runs on Linux, Mac and Windows and requires Python >= 3.8
[markdown]: https://daringfireball.net/projects/markdown/ [markdown]: https://daringfireball.net/projects/markdown/
[jinja2]: https://palletsprojects.com/p/jinja/ [jinja2]: https://palletsprojects.com/p/jinja/

View File

@@ -2,11 +2,15 @@
"""blag's core methods.""" """blag's core methods."""
# remove when we don't support py38 anymore
from __future__ import annotations
import argparse import argparse
import configparser import configparser
import logging import logging
import os import os
import shutil import shutil
import sqlite3
import sys import sys
from typing import Any from typing import Any
@@ -281,6 +285,8 @@ def build(args: argparse.Namespace) -> None:
generate_index(articles, index_template, args.output_dir) generate_index(articles, index_template, args.output_dir)
generate_archive(articles, archive_template, args.output_dir) generate_archive(articles, archive_template, args.output_dir)
generate_tags(articles, tags_template, tag_template, args.output_dir) generate_tags(articles, tags_template, tag_template, args.output_dir)
generate_search(articles, pages, 'corpus.db')
logger.info("Done.")
def process_markdown( def process_markdown(
@@ -508,5 +514,48 @@ def generate_tags(
fh.write(result) fh.write(result)
def generate_search(
articles: list[tuple[str, dict[str, Any]]],
pages: list[tuple[str, dict[str, Any]]],
db: str,
) -> None:
"""Generate Search.
Parameters
----------
articles, pages
db
path to sqlite file
"""
logger.info("Generating full text search.")
conn = sqlite3.connect(db)
with conn:
conn.executescript("""
drop table if exists corpus;
create virtual table corpus using fts5(
link,
text,
tokenize = porter
);
""")
with conn:
for dst, context in articles:
text = context['content']
conn.execute("""
insert into corpus(link, text)
values(:link, :text)
""", dict(link=dst, text=text))
for dst, context in pages:
text = context['content']
conn.execute("""
insert into corpus(link, text)
values(:link, :text)
""", dict(link=dst, text=text))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -6,6 +6,9 @@ site if necessary.
""" """
# remove when we don't support py38 anymore
from __future__ import annotations
import argparse import argparse
import logging import logging
import multiprocessing import multiprocessing
@@ -49,7 +52,7 @@ def get_last_modified(dirs: list[str]) -> float:
return last_mtime return last_mtime
def autoreload(args: argparse.Namespace, wait: int=1) -> NoReturn: def autoreload(args: argparse.Namespace) -> NoReturn:
"""Start the autoreloader. """Start the autoreloader.
This method monitors the given directories for changes (i.e. the This method monitors the given directories for changes (i.e. the
@@ -63,9 +66,6 @@ def autoreload(args: argparse.Namespace, wait: int=1) -> NoReturn:
---------- ----------
args args
contains the input-, template- and static dir contains the input-, template- and static dir
wait
number of seconds the devsever waits before checking for updated
content
""" """
dirs = [args.input_dir, args.template_dir, args.static_dir] dirs = [args.input_dir, args.template_dir, args.static_dir]
@@ -74,18 +74,12 @@ def autoreload(args: argparse.Namespace, wait: int=1) -> NoReturn:
# loop to avoid serving stale contents # loop to avoid serving stale contents
last_mtime = 0.0 last_mtime = 0.0
while True: while True:
# make sure the devsever does not crash when the build fails with an
# exception
try:
mtime = get_last_modified(dirs) mtime = get_last_modified(dirs)
if mtime > last_mtime: if mtime > last_mtime:
last_mtime = mtime last_mtime = mtime
logger.info("Change detected, rebuilding...") logger.info("Change detected, rebuilding...")
blag.build(args) blag.build(args)
time.sleep(wait) time.sleep(1)
except Exception:
logger.exception("Error occurred during rebuild:")
logger.info("Devserver did not crash, you may continue editing.")
def serve(args: argparse.Namespace) -> None: def serve(args: argparse.Namespace) -> None:

View File

@@ -5,6 +5,9 @@ processing.
""" """
# remove when we don't support py38 anymore
from __future__ import annotations
import logging import logging
from datetime import datetime from datetime import datetime
from urllib.parse import urlsplit, urlunsplit from urllib.parse import urlsplit, urlunsplit

View File

@@ -1,5 +1,8 @@
"""Helper methods for blag's quickstart command.""" """Helper methods for blag's quickstart command."""
# remove when we don't support py38 anymore
from __future__ import annotations
import argparse import argparse
import configparser import configparser
import os import os

View File

@@ -4,36 +4,35 @@ span.linenos { color: inherit; background-color: transparent; padding-left: 5px;
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.hll { background-color: #49483e } .hll { background-color: #49483e }
.c { color: #959077 } /* Comment */ .c { color: #75715e } /* Comment */
.err { color: #ed007e; background-color: #1e0010 } /* Error */ .err { color: #960050; background-color: #1e0010 } /* Error */
.esc { color: #f8f8f2 } /* Escape */ .esc { color: #f8f8f2 } /* Escape */
.g { color: #f8f8f2 } /* Generic */ .g { color: #f8f8f2 } /* Generic */
.k { color: #66d9ef } /* Keyword */ .k { color: #66d9ef } /* Keyword */
.l { color: #ae81ff } /* Literal */ .l { color: #ae81ff } /* Literal */
.n { color: #f8f8f2 } /* Name */ .n { color: #f8f8f2 } /* Name */
.o { color: #ff4689 } /* Operator */ .o { color: #f92672 } /* Operator */
.x { color: #f8f8f2 } /* Other */ .x { color: #f8f8f2 } /* Other */
.p { color: #f8f8f2 } /* Punctuation */ .p { color: #f8f8f2 } /* Punctuation */
.ch { color: #959077 } /* Comment.Hashbang */ .ch { color: #75715e } /* Comment.Hashbang */
.cm { color: #959077 } /* Comment.Multiline */ .cm { color: #75715e } /* Comment.Multiline */
.cp { color: #959077 } /* Comment.Preproc */ .cp { color: #75715e } /* Comment.Preproc */
.cpf { color: #959077 } /* Comment.PreprocFile */ .cpf { color: #75715e } /* Comment.PreprocFile */
.c1 { color: #959077 } /* Comment.Single */ .c1 { color: #75715e } /* Comment.Single */
.cs { color: #959077 } /* Comment.Special */ .cs { color: #75715e } /* Comment.Special */
.gd { color: #ff4689 } /* Generic.Deleted */ .gd { color: #f92672 } /* Generic.Deleted */
.ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */ .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */
.ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.gr { color: #f8f8f2 } /* Generic.Error */ .gr { color: #f8f8f2 } /* Generic.Error */
.gh { color: #f8f8f2 } /* Generic.Heading */ .gh { color: #f8f8f2 } /* Generic.Heading */
.gi { color: #a6e22e } /* Generic.Inserted */ .gi { color: #a6e22e } /* Generic.Inserted */
.go { color: #66d9ef } /* Generic.Output */ .go { color: #66d9ef } /* Generic.Output */
.gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */ .gp { color: #f92672; font-weight: bold } /* Generic.Prompt */
.gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */ .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */
.gu { color: #959077 } /* Generic.Subheading */ .gu { color: #75715e } /* Generic.Subheading */
.gt { color: #f8f8f2 } /* Generic.Traceback */ .gt { color: #f8f8f2 } /* Generic.Traceback */
.kc { color: #66d9ef } /* Keyword.Constant */ .kc { color: #66d9ef } /* Keyword.Constant */
.kd { color: #66d9ef } /* Keyword.Declaration */ .kd { color: #66d9ef } /* Keyword.Declaration */
.kn { color: #ff4689 } /* Keyword.Namespace */ .kn { color: #f92672 } /* Keyword.Namespace */
.kp { color: #66d9ef } /* Keyword.Pseudo */ .kp { color: #66d9ef } /* Keyword.Pseudo */
.kr { color: #66d9ef } /* Keyword.Reserved */ .kr { color: #66d9ef } /* Keyword.Reserved */
.kt { color: #66d9ef } /* Keyword.Type */ .kt { color: #66d9ef } /* Keyword.Type */
@@ -52,9 +51,9 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
.nn { color: #f8f8f2 } /* Name.Namespace */ .nn { color: #f8f8f2 } /* Name.Namespace */
.nx { color: #a6e22e } /* Name.Other */ .nx { color: #a6e22e } /* Name.Other */
.py { color: #f8f8f2 } /* Name.Property */ .py { color: #f8f8f2 } /* Name.Property */
.nt { color: #ff4689 } /* Name.Tag */ .nt { color: #f92672 } /* Name.Tag */
.nv { color: #f8f8f2 } /* Name.Variable */ .nv { color: #f8f8f2 } /* Name.Variable */
.ow { color: #ff4689 } /* Operator.Word */ .ow { color: #f92672 } /* Operator.Word */
.pm { color: #f8f8f2 } /* Punctuation.Marker */ .pm { color: #f8f8f2 } /* Punctuation.Marker */
.w { color: #f8f8f2 } /* Text.Whitespace */ .w { color: #f8f8f2 } /* Text.Whitespace */
.mb { color: #ae81ff } /* Literal.Number.Bin */ .mb { color: #ae81ff } /* Literal.Number.Bin */

View File

@@ -16,7 +16,6 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */ .gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */ .ge { font-style: italic } /* Generic.Emph */
.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.gr { color: #E40000 } /* Generic.Error */ .gr { color: #E40000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */ .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #008400 } /* Generic.Inserted */ .gi { color: #008400 } /* Generic.Inserted */

View File

@@ -1,3 +1,3 @@
"""Version information for the blag package.""" """Version information for the blag package."""
__VERSION__ = "2.3.0" __VERSION__ = "2.2.1"

8
debian/changelog vendored
View File

@@ -1,11 +1,3 @@
blag (2.3.0) unstable; urgency=medium
* fixed devsever so it does not crash anymore when the (re-)build fails
* dropped support for Python 3.8 and 3.9
* updated dependencies
-- Bastian Venthur <venthur@debian.org> Wed, 24 Apr 2024 22:25:31 +0200
blag (2.2.1) unstable; urgency=medium blag (2.2.1) unstable; urgency=medium
* fixed suggests field to blag-doc (Closes: #1055769) * fixed suggests field to blag-doc (Closes: #1055769)

View File

@@ -11,7 +11,7 @@ description = "blog-aware, static site generator"
keywords = ["markdown", "blag", "blog", "static site generator", "cli"] keywords = ["markdown", "blag", "blog", "static site generator", "cli"]
readme = "README.md" readme = "README.md"
license = { file="LICENSE" } license = { file="LICENSE" }
requires-python = ">=3.10" requires-python = ">=3.8"
dynamic = ["version"] dynamic = ["version"]
dependencies = [ dependencies = [
"markdown", "markdown",
@@ -64,10 +64,6 @@ addopts = """
""" """
[tool.ruff] [tool.ruff]
line-length = 79
target-version = "py310"
[tool.ruff.lint]
select = [ select = [
"F", # pyflakes "F", # pyflakes
"E", "W", # pycodestyle "E", "W", # pycodestyle
@@ -76,7 +72,11 @@ select = [
"D", # pydocstyle "D", # pydocstyle
"UP" # pyupgrade "UP" # pyupgrade
] ]
pydocstyle.convention = "numpy" line-length = 79
target-version = "py38"
[tool.ruff.pydocstyle]
convention = "numpy"
[tool.mypy] [tool.mypy]
files = "blag,tests" files = "blag,tests"

View File

@@ -1,11 +1,11 @@
build==1.0.3 build==1.0.3
mkdocs==1.5.3 mkdocs==1.5.3
mkdocs-material==9.5.18 mkdocs-material==9.4.8
mkdocstrings[python]==0.24.3 mkdocstrings[python]==0.23.0
twine==5.0.0 twine==4.0.2
wheel==0.42.0 wheel==0.41.3
pytest==8.1.1 pytest==7.4.3
pytest-cov==4.1.0 pytest-cov==4.1.0
ruff==0.4.1 ruff==0.1.5
mypy==1.8.0 mypy==1.6.1
types-markdown==3.5.0.20240129 types-markdown==3.5.0.1

View File

@@ -1,4 +1,4 @@
markdown==3.5.2 markdown==3.5.1
feedgenerator==2.1.0 feedgenerator==2.1.0
jinja2==3.1.3 jinja2==3.1.2
pygments==2.17.2 pygments==2.16.1

View File

@@ -1,9 +1,13 @@
"""Pytest fixtures.""" """Pytest fixtures."""
# remove when we don't support py38 anymore
from __future__ import annotations
import os import os
from argparse import Namespace from argparse import Namespace
from collections.abc import Callable, Iterator
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Callable, Iterator
import pytest import pytest
from jinja2 import Environment, Template from jinja2 import Environment, Template

View File

@@ -1,5 +1,9 @@
"""Test blag.""" """Test blag."""
# remove when we don't support py38 anymore
from __future__ import annotations
import os import os
from argparse import Namespace from argparse import Namespace
from datetime import datetime from datetime import datetime

View File

@@ -1,12 +1,16 @@
"""Tests for the devserver module.""" """Tests for the devserver module."""
# remove when we don't support py38 anymore
from __future__ import annotations
import threading import threading
import time import time
from argparse import Namespace from argparse import Namespace
from blag import devserver import pytest
WAITTIME = 0.1 from blag import devserver
def test_get_last_modified(cleandir: str) -> None: def test_get_last_modified(cleandir: str) -> None:
@@ -15,13 +19,13 @@ def test_get_last_modified(cleandir: str) -> None:
t1 = devserver.get_last_modified(["content"]) t1 = devserver.get_last_modified(["content"])
# wait a bit, create a file and measure again # wait a bit, create a file and measure again
time.sleep(WAITTIME) time.sleep(0.1)
with open("content/test", "w") as fh: with open("content/test", "w") as fh:
fh.write("boo") fh.write("boo")
t2 = devserver.get_last_modified(["content"]) t2 = devserver.get_last_modified(["content"])
# wait a bit and take time again # wait a bit and take time again
time.sleep(WAITTIME) time.sleep(0.1)
t3 = devserver.get_last_modified(["content"]) t3 = devserver.get_last_modified(["content"])
assert t2 > t1 assert t2 > t1
@@ -36,14 +40,14 @@ def test_autoreload_builds_immediately(args: Namespace) -> None:
t = threading.Thread( t = threading.Thread(
target=devserver.autoreload, target=devserver.autoreload,
args=(args, WAITTIME), args=(args,),
daemon=True, daemon=True,
) )
t0 = devserver.get_last_modified(["build"]) t0 = devserver.get_last_modified(["build"])
t.start() t.start()
# try for 5 seconds... # try for 5 seconds...
for i in range(5): for i in range(5):
time.sleep(WAITTIME) time.sleep(1)
t1 = devserver.get_last_modified(["build"]) t1 = devserver.get_last_modified(["build"])
print(t1) print(t1)
if t1 > t0: if t1 > t0:
@@ -51,11 +55,14 @@ def test_autoreload_builds_immediately(args: Namespace) -> None:
assert t1 > t0 assert t1 > t0
@pytest.mark.filterwarnings(
"ignore::pytest.PytestUnhandledThreadExceptionWarning"
)
def test_autoreload(args: Namespace) -> None: def test_autoreload(args: Namespace) -> None:
"""Test autoreload.""" """Test autoreload."""
t = threading.Thread( t = threading.Thread(
target=devserver.autoreload, target=devserver.autoreload,
args=(args, WAITTIME), args=(args,),
daemon=True, daemon=True,
) )
t.start() t.start()
@@ -68,32 +75,8 @@ def test_autoreload(args: Namespace) -> None:
# try for 5 seconds to see if we rebuild once... # try for 5 seconds to see if we rebuild once...
for i in range(5): for i in range(5):
time.sleep(WAITTIME) time.sleep(1)
t1 = devserver.get_last_modified(["build"]) t1 = devserver.get_last_modified(["build"])
if t1 > t0: if t1 > t0:
break break
assert t1 > t0 assert t1 > t0
def test_autoreload_does_not_crash(args: Namespace) -> None:
"""Test autoreload does not crash if build fails."""
t = threading.Thread(
target=devserver.autoreload,
args=(args, WAITTIME),
daemon=True,
)
t.start()
t0 = devserver.get_last_modified(["build"])
# create a file that causes build to crash
with open("content/test.md", "w") as fh:
fh.write("date: ")
# try for 5 seconds to see if we rebuild once...
for i in range(5):
time.sleep(WAITTIME)
t1 = devserver.get_last_modified(["build"])
if t1 > t0:
break
assert t.is_alive()

View File

@@ -1,5 +1,9 @@
"""Test markdown module.""" """Test markdown module."""
# remove when we don't support py38 anymore
from __future__ import annotations
from datetime import datetime from datetime import datetime
from typing import Any from typing import Any

View File

@@ -1,5 +1,9 @@
"""Tests for the quickstart module.""" """Tests for the quickstart module."""
# remove when we don't support py38 anymore
from __future__ import annotations
import os import os
from pytest import MonkeyPatch from pytest import MonkeyPatch

View File

@@ -1,5 +1,9 @@
"""Test the templates.""" """Test the templates."""
# remove when we don't support py38 anymore
from __future__ import annotations
import datetime import datetime
from jinja2 import Template from jinja2 import Template

View File

@@ -1,5 +1,9 @@
"""Test the version module.""" """Test the version module."""
# remove when we don't support py38 anymore
from __future__ import annotations
import blag import blag