Skip to content

Commit 962472c

Browse files
author
Laurent Franceschetti
committed
Split test framework into DocProject (general) and MacrosDocProject
- issue #244
1 parent e164982 commit 962472c

File tree

9 files changed

+243
-142
lines changed

9 files changed

+243
-142
lines changed

.github/workflows/greetings.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ jobs:
1010
with:
1111
repo-token: ${{ secrets.GITHUB_TOKEN }}
1212
issue-message: 'Welcome to this project and thank you!'
13-
pr-message: 'Thank you for submitting a PR, this is appreciated. Please do not forget to submit a corresponding issue, and to reference its number in the PR''
13+
pr-message: 'Thank you for submitting a PR, this is appreciated. If not already done, please do not forget to submit a corresponding issue, and to reference its number in the PR'

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# Initialization
1313
# --------------------
1414

15-
VERSION_NUMBER = '1.3.1'
15+
VERSION_NUMBER = '1.3.2'
1616

1717
# required if you want to run document/test
1818
# pip install 'mkdocs-macros-plugin[test]'

test/fixture.py

Lines changed: 183 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,7 @@ def list_doc_projects(directory:str):
6161
"The default docs directory"
6262
DOCS_DEFAULT_DIRNAME = 'docs'
6363

64-
"The directory containing the macros rendered"
65-
RENDERED_MACROS_DIRNAME = '__docs_macros_rendered'
6664

67-
"The error string"
68-
MACRO_ERROR_STRING = '# _Macro Rendering Error_'
6965

7066
# ---------------------------
7167
# Log parsing
@@ -150,7 +146,7 @@ def parse_log(mkdocs_log: str) -> list[LogEntry]:
150146
return [SuperDict(item) for item in log_entries]
151147

152148
# ---------------------------
153-
# Target file
149+
# An Mkdocs Documentation project
154150
# ---------------------------
155151
@dataclass
156152
class MarkdownPage(object):
@@ -229,69 +225,12 @@ def find(self, pattern: str,
229225
header=header, header_level=header_level)
230226

231227

232-
@dataclass
233-
class TestMarkdownPage(MarkdownPage):
234-
"A subclass of markdown page, for MkDocs-Macros purposes"
235-
236-
"The source markdown page (before the rendering of macros)"
237-
source_page: MarkdownPage = field(init=False)
238-
239-
"The source doc dir (normally the docs dir)"
240-
source_doc_dir: str = DOCS_DEFAULT_DIRNAME
241-
242-
# "Difference of the source"
243-
# diff_markdown: str = field(init=False)
244-
245-
246-
def __post_init__(self):
247-
"Additional actions after the rest"
248-
super().__post_init__()
249-
self.source_page = MarkdownPage(self.filename,
250-
project_dir=self.project_dir,
251-
doc_dir=self.source_doc_dir)
252-
# this should be the case, always, or something is wrong
253-
assert self.filename == self.source_page.filename
254-
assert self.metadata == self.source_page.metadata
255-
256-
257-
@property
258-
def has_error(self) -> bool:
259-
"Checks whether there is an error"
260-
return self.markdown.startswith(MACRO_ERROR_STRING)
261-
262-
@property
263-
def is_rendered(self) -> bool:
264-
"""
265-
"Rendered" means that the target markdown
266-
is different from the source;
267-
more accurately, that the source markdown is not
268-
contained in the target markdown.
269-
270-
Hence "not rendered" is a "nothing happened".
271-
It covers these cases:
272-
1. An order to render was given, but there where actually
273-
NO jinja2 directives.
274-
2. A jinja2 rendering has not taken place at all
275-
(some order to exclude the page).
276-
3. A header and/or footer were added (in `on_pre_page_macros()
277-
or in `on_post_page_macro()`) but the text itself
278-
was not modified.
279-
"""
280-
# make sure that the source is stripped, to be sure.
281-
return self.source_page.markdown.strip() not in self.markdown
282-
283228

284-
def __repr__(self):
285-
"""
286-
Important for error printout
287-
"""
288-
return f"Markdown page ({self.filename}):\n{self.text}"
289-
290-
# ---------------------------
291-
# Main class
292-
# ---------------------------
293229
class DocProject(object):
294-
"An object that describes the current MkDocs project being tested."
230+
"""
231+
An object that describes the current MkDocs project being tested
232+
(any plugin).
233+
"""
295234

296235
def __init__(self, directory:str=''):
297236
"Initialize"
@@ -337,17 +276,24 @@ def config(self) -> SuperDict:
337276
return self._config
338277

339278

340-
341279
@property
342-
def target_doc_dir(self):
280+
def source_doc_dir(self):
343281
"The target directory of markdown files (rendered macros)"
344282
return os.path.join(REF_DIR,
345283
self.project_dir,
346-
RENDERED_MACROS_DIRNAME)
284+
DOCS_DEFAULT_DIRNAME)
285+
347286

348287

288+
349289

350290

291+
292+
293+
# ----------------------------------
294+
# Build
295+
# ----------------------------------
296+
351297

352298
def build(self, strict:bool=False,
353299
verbose:bool=True) -> subprocess.CompletedProcess:
@@ -493,6 +439,173 @@ def find_entry(self, title:str='',
493439
else:
494440
return None
495441

442+
# ----------------------------------
443+
# Get the Markdown pages
444+
# ----------------------------------
445+
446+
447+
@property
448+
def pages(self) -> List[MarkdownPage]:
449+
"The list of Markdown pages + the HTML produced by the build (TBD)"
450+
try:
451+
return self._pages
452+
except AttributeError:
453+
# Make the list and
454+
full_project_dir = os.path.join(REF_DIR, self.project_dir)
455+
full_doc_dir = os.path.join(REF_DIR, self.source_doc_dir)
456+
self._pages = [MarkdownPage(el,
457+
project_dir = full_project_dir,
458+
doc_dir=DOCS_DEFAULT_DIRNAME
459+
)
460+
for el in list_markdown_files(full_doc_dir)]
461+
return self._pages
462+
463+
def get_page(self, name:str):
464+
"""
465+
Find a name in the list of Markdown pages (filenames)
466+
using a name (full or partial, with or without extension).
467+
"""
468+
# get all the filenames of pages:
469+
filenames = [page.filename for page in self.pages]
470+
# get the filename we want, from that list:
471+
filename = find_page(name, filenames)
472+
# return the corresponding page:
473+
for page in self.pages:
474+
if page.filename == filename:
475+
return page
476+
477+
478+
def get_plugin(self, name:str) -> SuperDict:
479+
"Get the plugin by its plugin name"
480+
for el in self.config.plugins:
481+
if name in el:
482+
if isinstance(el, str):
483+
return SuperDict()
484+
elif isinstance(el, dict):
485+
plugin = el[name]
486+
return SuperDict(plugin)
487+
else:
488+
raise ValueError(f"Unexpected content of plugin {name}!")
489+
return SuperDict(self.config.plugins.get(name))
490+
491+
492+
493+
# ---------------------------
494+
# The Macros Doc project
495+
# ---------------------------
496+
497+
"The directory containing the macros rendered"
498+
RENDERED_MACROS_DIRNAME = '__docs_macros_rendered'
499+
500+
"The error string"
501+
MACRO_ERROR_STRING = '# _Macro Rendering Error_'
502+
503+
@dataclass
504+
class TestMarkdownPage(MarkdownPage):
505+
"A subclass of markdown page, for MkDocs-Macros purposes"
506+
507+
"The source markdown page (before the rendering of macros)"
508+
source_page: MarkdownPage = field(init=False)
509+
510+
"The source doc dir (normally the docs dir)"
511+
source_doc_dir: str = DOCS_DEFAULT_DIRNAME
512+
513+
# "Difference of the source"
514+
# diff_markdown: str = field(init=False)
515+
516+
517+
def __post_init__(self):
518+
"Additional actions after the rest"
519+
super().__post_init__()
520+
self.source_page = MarkdownPage(self.filename,
521+
project_dir=self.project_dir,
522+
doc_dir=self.source_doc_dir)
523+
# this should be the case, always, or something is wrong
524+
assert self.filename == self.source_page.filename
525+
assert self.metadata == self.source_page.metadata
526+
527+
528+
@property
529+
def has_error(self) -> bool:
530+
"Checks whether there is an error"
531+
return self.markdown.startswith(MACRO_ERROR_STRING)
532+
533+
@property
534+
def is_rendered(self) -> bool:
535+
"""
536+
"Rendered" means that the target markdown
537+
is different from the source;
538+
more accurately, that the source markdown is not
539+
contained in the target markdown.
540+
541+
Hence "not rendered" is a "nothing happened".
542+
It covers these cases:
543+
1. An order to render was given, but there where actually
544+
NO jinja2 directives.
545+
2. A jinja2 rendering has not taken place at all
546+
(some order to exclude the page).
547+
3. A header and/or footer were added (in `on_pre_page_macros()
548+
or in `on_post_page_macro()`) but the text itself
549+
was not modified.
550+
"""
551+
# make sure that the source is stripped, to be sure.
552+
return self.source_page.markdown.strip() not in self.markdown
553+
554+
555+
def __repr__(self):
556+
"""
557+
Important for error printout
558+
"""
559+
return f"Markdown page ({self.filename}):\n{self.text}"
560+
561+
562+
563+
564+
class MacrosDocProject(DocProject):
565+
"""
566+
An object that describes the current MkDocs-Macros project
567+
being tested.
568+
569+
The difference is that it relies heavily on the Markdown
570+
pages rendered by Jinja2. These are produced at the end of
571+
the `on_page_markdown()` method of the plugin.
572+
573+
The pages() property has thus been redefined.
574+
"""
575+
576+
577+
@property
578+
def target_doc_dir(self):
579+
"The target directory of markdown files (rendered macros)"
580+
return os.path.join(REF_DIR,
581+
self.project_dir,
582+
RENDERED_MACROS_DIRNAME)
583+
584+
@property
585+
def pages(self) -> List[TestMarkdownPage]:
586+
"""
587+
The list of Markdown pages produced by the build.
588+
It must be called after the build.
589+
"""
590+
try:
591+
return self._pages
592+
except AttributeError:
593+
# Make the list and
594+
full_project_dir = os.path.join(REF_DIR, self.project_dir)
595+
full_target_dir = os.path.join(REF_DIR, self.target_doc_dir)
596+
self._pages = [TestMarkdownPage(el,
597+
project_dir = full_project_dir,
598+
doc_dir=RENDERED_MACROS_DIRNAME,
599+
source_doc_dir=DOCS_DEFAULT_DIRNAME
600+
)
601+
for el in list_markdown_files(full_target_dir)]
602+
return self._pages
603+
604+
@property
605+
def macros_plugin(self) -> SuperDict:
606+
"Return the plugin config"
607+
return self.get_plugin('macros')
608+
496609

497610
# ----------------------------------
498611
# Smart properties (from log, etc.)
@@ -545,56 +658,4 @@ def filters(self) -> SuperDict:
545658
"""
546659
entry = self.find_entry('config filters', severity='debug')
547660
if entry and entry.payload:
548-
return SuperDict(json.loads(entry.payload))
549-
550-
@property
551-
def pages(self) -> List[TestMarkdownPage]:
552-
"The list of Markdown pages produced by the build"
553-
try:
554-
return self._pages
555-
except AttributeError:
556-
# Make the list and
557-
full_project_dir = os.path.join(REF_DIR, self.project_dir)
558-
full_target_dir = os.path.join(REF_DIR, self.target_doc_dir)
559-
self._pages = [TestMarkdownPage(el,
560-
project_dir = full_project_dir,
561-
doc_dir=RENDERED_MACROS_DIRNAME,
562-
source_doc_dir=DOCS_DEFAULT_DIRNAME
563-
)
564-
for el in list_markdown_files(full_target_dir)]
565-
return self._pages
566-
567-
def get_page(self, name:str):
568-
"""
569-
Find a name in the list of Markdown pages (filenames)
570-
using a name (full or partial, with or without extension).
571-
"""
572-
# get all the filenames of pages:
573-
filenames = [page.filename for page in self.pages]
574-
# get the filename we want, from that list:
575-
filename = find_page(name, filenames)
576-
# return the corresponding page:
577-
for page in self.pages:
578-
if page.filename == filename:
579-
return page
580-
581-
582-
def get_plugin(self, name:str) -> SuperDict:
583-
"Get the plugin by its plugin name"
584-
for el in self.config.plugins:
585-
if name in el:
586-
if isinstance(el, str):
587-
return SuperDict()
588-
elif isinstance(el, dict):
589-
plugin = el[name]
590-
return SuperDict(plugin)
591-
else:
592-
raise ValueError(f"Unexpected content of plugin {name}!")
593-
return SuperDict(self.config.plugins.get(name))
594-
595-
@property
596-
def macros_plugin(self) -> SuperDict:
597-
"Return the plugin config"
598-
return self.get_plugin('macros')
599-
600-
661+
return SuperDict(json.loads(entry.payload))

test/module/test_site.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
import pytest
99
import re
1010

11-
from test.fixture import DocProject, find_after
11+
from test.fixture import MacrosDocProject, find_after
1212

1313
CURRENT_PROJECT = 'module'
1414

1515

1616

1717
def test_pages():
18-
PROJECT = DocProject(CURRENT_PROJECT)
18+
PROJECT = MacrosDocProject(CURRENT_PROJECT)
1919
PROJECT.build()
2020
# did not fail
2121
assert not PROJECT.build_result.returncode
@@ -107,7 +107,7 @@ def test_pages():
107107

108108
def test_strict():
109109
"This project must fail"
110-
PROJECT = DocProject(CURRENT_PROJECT)
110+
PROJECT = MacrosDocProject(CURRENT_PROJECT)
111111

112112
# it must fail with the --strict option,
113113
# because the second page contains an error

0 commit comments

Comments
 (0)