diff --git a/src/mkdocs_git_revision_date_localized_plugin/dates.py b/src/mkdocs_git_revision_date_localized_plugin/dates.py
index 3fd4dd6..c66e4a5 100644
--- a/src/mkdocs_git_revision_date_localized_plugin/dates.py
+++ b/src/mkdocs_git_revision_date_localized_plugin/dates.py
@@ -43,49 +43,49 @@ def get_date_formats(
def strftime_to_babel_format(fmt: str) -> str:
"""
Convert strftime format string to Babel format pattern.
-
+
Args:
fmt (str): strftime format string
-
+
Returns:
str: Babel format pattern
"""
# Dictionary mapping strftime directives to Babel format patterns
mapping = {
- '%a': 'EEE', # Weekday abbreviated
- '%A': 'EEEE', # Weekday full
- '%b': 'MMM', # Month abbreviated
- '%B': 'MMMM', # Month full
- '%c': '', # Locale's date and time (not directly mappable)
- '%d': 'dd', # Day of month zero-padded
- '%-d': 'd', # Day of month
- '%e': 'd', # Day of month space-padded
- '%f': 'SSSSSS', # Microsecond
- '%H': 'HH', # Hour 24h zero-padded
- '%-H': 'H', # Hour 24h
- '%I': 'hh', # Hour 12h zero-padded
- '%-I': 'h', # Hour 12h
- '%j': 'DDD', # Day of year
- '%m': 'MM', # Month zero-padded
- '%-m': 'M', # Month
- '%M': 'mm', # Minute zero-padded
- '%-M': 'm', # Minute
- '%p': 'a', # AM/PM
- '%S': 'ss', # Second zero-padded
- '%-S': 's', # Second
- '%w': 'e', # Weekday as number
- '%W': 'w', # Week of year
- '%x': '', # Locale's date (not directly mappable)
- '%X': '', # Locale's time (not directly mappable)
- '%y': 'yy', # Year without century
- '%Y': 'yyyy', # Year with century
- '%z': 'Z', # UTC offset
- '%Z': 'z', # Timezone name
- '%%': '%' # Literal %
+ "%a": "EEE", # Weekday abbreviated
+ "%A": "EEEE", # Weekday full
+ "%b": "MMM", # Month abbreviated
+ "%B": "MMMM", # Month full
+ "%c": "", # Locale's date and time (not directly mappable)
+ "%d": "dd", # Day of month zero-padded
+ "%-d": "d", # Day of month
+ "%e": "d", # Day of month space-padded
+ "%f": "SSSSSS", # Microsecond
+ "%H": "HH", # Hour 24h zero-padded
+ "%-H": "H", # Hour 24h
+ "%I": "hh", # Hour 12h zero-padded
+ "%-I": "h", # Hour 12h
+ "%j": "DDD", # Day of year
+ "%m": "MM", # Month zero-padded
+ "%-m": "M", # Month
+ "%M": "mm", # Minute zero-padded
+ "%-M": "m", # Minute
+ "%p": "a", # AM/PM
+ "%S": "ss", # Second zero-padded
+ "%-S": "s", # Second
+ "%w": "e", # Weekday as number
+ "%W": "w", # Week of year
+ "%x": "", # Locale's date (not directly mappable)
+ "%X": "", # Locale's time (not directly mappable)
+ "%y": "yy", # Year without century
+ "%Y": "yyyy", # Year with century
+ "%z": "Z", # UTC offset
+ "%Z": "z", # Timezone name
+ "%%": "%", # Literal %
}
-
+
result = fmt
for strftime_code, babel_code in mapping.items():
result = result.replace(strftime_code, babel_code)
-
- return result
\ No newline at end of file
+
+ return result
diff --git a/src/mkdocs_git_revision_date_localized_plugin/plugin.py b/src/mkdocs_git_revision_date_localized_plugin/plugin.py
index 126bee2..495251b 100644
--- a/src/mkdocs_git_revision_date_localized_plugin/plugin.py
+++ b/src/mkdocs_git_revision_date_localized_plugin/plugin.py
@@ -10,6 +10,7 @@
import os
import time
import multiprocessing
+from pathlib import Path
from mkdocs import __version__ as mkdocs_version
from mkdocs.config import config_options
@@ -28,7 +29,7 @@
from packaging.version import Version
-HERE = os.path.dirname(os.path.abspath(__file__))
+HERE = Path(__file__).parent.absolute()
class GitRevisionDateLocalizedPlugin(BasePlugin):
@@ -144,19 +145,18 @@ def on_config(self, config: config_options.Config, **kwargs) -> Dict[str, Any]:
return config
-
def parallel_compute_commit_timestamps(self, files, original_source: Optional[Dict] = None, is_first_commit=False):
pool = multiprocessing.Pool(processes=min(10, multiprocessing.cpu_count()))
results = []
- for file in files:
- if file.is_documentation_page():
- abs_src_path = file.abs_src_path
+ for f in files:
+ if f.is_documentation_page():
+ abs_src_path = f.abs_src_path
# Support plugins like monorep that might have moved the files from the original source that is under git
if original_source and abs_src_path in original_source:
abs_src_path = original_source[abs_src_path]
- result = pool.apply_async(
- self.util.get_git_commit_timestamp, args=(abs_src_path, is_first_commit)
- )
+ assert Path(abs_src_path).exists()
+ abs_src_path = str(Path(abs_src_path).absolute())
+ result = pool.apply_async(self.util.get_git_commit_timestamp, args=(abs_src_path, is_first_commit))
results.append((abs_src_path, result))
pool.close()
pool.join()
@@ -173,18 +173,21 @@ def on_files(self, files: Files, config: MkDocsConfig):
"""
if not self.config.get("enabled") or not self.config.get("enable_parallel_processing"):
return
-
+
# Support monorepo/techdocs, which copies the docs_dir to a temporary directory
- if "monorepo" in config.get('plugins', {}):
- original_source = config.get('plugins').get('monorepo').merger.files_source_dir
+ if "monorepo" in config.get("plugins", {}):
+ original_source = config.get("plugins").get("monorepo").merger.files_source_dir
else:
original_source = None
- if not self.last_revision_commits:
- self.parallel_compute_commit_timestamps(files=files, original_source=original_source, is_first_commit=False)
- if not self.created_commits:
- self.parallel_compute_commit_timestamps(files=files, original_source=original_source, is_first_commit=True)
-
+ try:
+ if not self.last_revision_commits:
+ self.parallel_compute_commit_timestamps(files=files, original_source=original_source, is_first_commit=False)
+ if not self.created_commits:
+ self.parallel_compute_commit_timestamps(files=files, original_source=original_source, is_first_commit=True)
+ except Exception as e:
+ logging.warning(f"Parallel processing failed: {str(e)}.\n To fall back to serial processing, use 'enable_parallel_processing: False' setting.")
+
def on_page_markdown(self, markdown: str, page: Page, config: config_options.Config, files, **kwargs) -> str:
"""
@@ -240,7 +243,9 @@ def on_page_markdown(self, markdown: str, page: Page, config: config_options.Con
if getattr(page.file, "generated_by", None):
last_revision_hash, last_revision_timestamp = "", int(time.time())
else:
- last_revision_hash, last_revision_timestamp = self.last_revision_commits.get(page.file.abs_src_path, (None, None))
+ last_revision_hash, last_revision_timestamp = self.last_revision_commits.get(
+ str(Path(page.file.abs_src_path).absolute()), (None, None)
+ )
if last_revision_timestamp is None:
last_revision_hash, last_revision_timestamp = self.util.get_git_commit_timestamp(
path=page.file.abs_src_path,
@@ -314,8 +319,10 @@ def on_page_markdown(self, markdown: str, page: Page, config: config_options.Con
if getattr(page.file, "generated_by", None):
first_revision_hash, first_revision_timestamp = "", int(time.time())
else:
- first_revision_hash, first_revision_timestamp = self.created_commits.get(page.file.abs_src_path, (None, None))
- if first_revision_timestamp is None:
+ first_revision_hash, first_revision_timestamp = self.created_commits.get(
+ str(Path(page.file.abs_src_path).absolute()), (None, None)
+ )
+ if first_revision_timestamp is None:
first_revision_hash, first_revision_timestamp = self.util.get_git_commit_timestamp(
path=page.file.abs_src_path,
is_first_commit=True,
@@ -374,8 +381,8 @@ def on_post_build(self, config: Dict[str, Any], **kwargs) -> None:
"js/timeago_mkdocs_material.js",
"css/timeago.css",
]
- for file in files:
- dest_file_path = os.path.join(config["site_dir"], file)
- src_file_path = os.path.join(HERE, file)
- assert os.path.exists(src_file_path)
- copy_file(src_file_path, dest_file_path)
+ for f in files:
+ dest_file_path = Path(config["site_dir"]) / f
+ src_file_path = HERE / f
+ assert src_file_path.exists()
+ copy_file(str(src_file_path), str(dest_file_path))
diff --git a/src/mkdocs_git_revision_date_localized_plugin/util.py b/src/mkdocs_git_revision_date_localized_plugin/util.py
index 43dbedb..5c43cca 100644
--- a/src/mkdocs_git_revision_date_localized_plugin/util.py
+++ b/src/mkdocs_git_revision_date_localized_plugin/util.py
@@ -3,6 +3,7 @@
import logging
import os
import time
+from pathlib import Path
from mkdocs_git_revision_date_localized_plugin.ci import raise_ci_warnings
from mkdocs_git_revision_date_localized_plugin.dates import get_date_formats
@@ -34,7 +35,7 @@ def __init__(self, config: Dict, mkdocs_dir: str):
self.repo_cache = {}
ignore_commits_file = self.config.get("ignored_commits_file")
- ignore_commits_filepath = os.path.join(mkdocs_dir, ignore_commits_file) if ignore_commits_file else None
+ ignore_commits_filepath = Path(mkdocs_dir) / ignore_commits_file if ignore_commits_file else None
self.ignored_commits = self.parse_git_ignore_revs(ignore_commits_filepath) if ignore_commits_file else []
def _get_repo(self, path: str) -> Git:
diff --git a/tests/fixtures/basic_project/mkdocs_no_parallel.yml b/tests/fixtures/basic_project/mkdocs_no_parallel.yml
new file mode 100644
index 0000000..8807c99
--- /dev/null
+++ b/tests/fixtures/basic_project/mkdocs_no_parallel.yml
@@ -0,0 +1,7 @@
+site_name: test gitrevisiondatelocalized_plugin
+use_directory_urls: true
+
+plugins:
+ - search
+ - git-revision-date-localized:
+ enable_parallel_processing: False
\ No newline at end of file
diff --git a/tests/fixtures/mkdocs-gen-files/gen_pages.py b/tests/fixtures/mkdocs-gen-files/gen_pages.py
index 059b0d4..0825cfb 100644
--- a/tests/fixtures/mkdocs-gen-files/gen_pages.py
+++ b/tests/fixtures/mkdocs-gen-files/gen_pages.py
@@ -2,4 +2,3 @@
with mkdocs_gen_files.open("foo.md", "w") as f:
print("Hello, world!", file=f)
-
diff --git a/tests/fixtures/monorepo/.gitignore b/tests/fixtures/monorepo/.gitignore
new file mode 100644
index 0000000..0c98940
--- /dev/null
+++ b/tests/fixtures/monorepo/.gitignore
@@ -0,0 +1,2 @@
+site/
+build/
\ No newline at end of file
diff --git a/tests/fixtures/monorepo/mkdocs_reverse_order.yml b/tests/fixtures/monorepo/mkdocs_reverse_order.yml
new file mode 100644
index 0000000..c341095
--- /dev/null
+++ b/tests/fixtures/monorepo/mkdocs_reverse_order.yml
@@ -0,0 +1,19 @@
+site_name: Cats API
+
+nav:
+ - Intro: 'index.md'
+ - Authentication: 'authentication.md'
+ - Components: '*include ./components/*/mkdocs.yml'
+ - API:
+ - v1: '!include ./v1/mkdocs.yml'
+ - v2: '!include ./v2/mkdocs.yml'
+ - v3: '!include ./v3/mkdocs.yml'
+
+theme:
+ name: material
+
+plugins:
+ - search
+ # Note; here monorepo is defined after git-revision-date-localized
+ - monorepo
+ - git-revision-date-localized
diff --git a/tests/fixtures/with_mknotebooks/docs/demo.ipynb b/tests/fixtures/with_mknotebooks/docs/demo.ipynb
index 05bcb32..66ee88a 100644
--- a/tests/fixtures/with_mknotebooks/docs/demo.ipynb
+++ b/tests/fixtures/with_mknotebooks/docs/demo.ipynb
@@ -1,30 +1,4 @@
{
- "metadata": {
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.3-final"
- },
- "orig_nbformat": 2,
- "kernelspec": {
- "name": "Python 3.8.3 64-bit ('base': conda)",
- "display_name": "Python 3.8.3 64-bit ('base': conda)",
- "metadata": {
- "interpreter": {
- "hash": "61a9efb557ee20b19fda2d58cb63f9a3bf86c2530fcd43d63aa6e0adea42a5e4"
- }
- }
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
@@ -35,6 +9,7 @@
"import pandas as pd\n",
"import numpy as np\n",
"import datetime\n",
+ "\n",
"%matplotlib inline"
]
},
@@ -44,8 +19,8 @@
"metadata": {},
"outputs": [
{
- "output_type": "stream",
"name": "stdout",
+ "output_type": "stream",
"text": [
"This notebook last ran at 2020-10-26 15:45:16.815445\n"
]
@@ -56,11 +31,11 @@
]
},
{
+ "cell_type": "markdown",
+ "metadata": {},
"source": [
"## A df"
- ],
- "cell_type": "markdown",
- "metadata": {}
+ ]
},
{
"cell_type": "code",
@@ -68,8 +43,8 @@
"metadata": {},
"outputs": [
{
- "output_type": "execute_result",
"data": {
+ "text/html": "
\n\n
\n \n \n | \n time | \n amplitude | \n
\n \n \n \n | 0 | \n 0.0 | \n 0.000000 | \n
\n \n | 1 | \n 0.1 | \n 0.099833 | \n
\n \n | 2 | \n 0.2 | \n 0.198669 | \n
\n \n | 3 | \n 0.3 | \n 0.295520 | \n
\n \n | 4 | \n 0.4 | \n 0.389418 | \n
\n \n
\n
",
"text/plain": [
" time amplitude\n",
"0 0.0 0.000000\n",
@@ -77,39 +52,65 @@
"2 0.2 0.198669\n",
"3 0.3 0.295520\n",
"4 0.4 0.389418"
- ],
- "text/html": "\n\n
\n \n \n | \n time | \n amplitude | \n
\n \n \n \n | 0 | \n 0.0 | \n 0.000000 | \n
\n \n | 1 | \n 0.1 | \n 0.099833 | \n
\n \n | 2 | \n 0.2 | \n 0.198669 | \n
\n \n | 3 | \n 0.3 | \n 0.295520 | \n
\n \n | 4 | \n 0.4 | \n 0.389418 | \n
\n \n
\n
"
+ ]
},
+ "execution_count": 4,
"metadata": {},
- "execution_count": 4
+ "output_type": "execute_result"
}
],
"source": [
- "df = pd.DataFrame({\"time\":np.arange(0, 10, 0.1)})\n",
- "df[\"amplitude\"] = np.sin(df.time)\n",
+ "df = pd.DataFrame({\"time\": np.arange(0, 10, 0.1)})\n",
+ "df[\"amplitude\"] = np.sin(df.time)\n",
"df.head(5)"
]
},
{
- "source": [
- "ax = df.plot()"
- ],
"cell_type": "code",
- "metadata": {},
"execution_count": 5,
+ "metadata": {},
"outputs": [
{
- "output_type": "display_data",
"data": {
- "text/plain": "",
+ "image/png": "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\n",
"image/svg+xml": "\n\n\n\n",
- "image/png": "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\n"
+ "text/plain": ""
},
"metadata": {
"needs_background": "light"
- }
+ },
+ "output_type": "display_data"
}
+ ],
+ "source": [
+ "ax = df.plot()"
]
}
- ]
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3.8.3 64-bit ('base': conda)",
+ "metadata": {
+ "interpreter": {
+ "hash": "61a9efb557ee20b19fda2d58cb63f9a3bf86c2530fcd43d63aa6e0adea42a5e4"
+ }
+ },
+ "name": "Python 3.8.3 64-bit ('base': conda)"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.3-final"
+ },
+ "orig_nbformat": 2
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
\ No newline at end of file
diff --git a/tests/test_builds.py b/tests/test_builds.py
index ab10cc6..a85022e 100644
--- a/tests/test_builds.py
+++ b/tests/test_builds.py
@@ -13,6 +13,7 @@
# standard lib
import logging
import os
+import sys
import re
import shutil
from contextlib import contextmanager
@@ -44,6 +45,7 @@
# ########## Helpers ###############
# ##################################
+
@contextmanager
def working_directory(path):
"""
@@ -77,14 +79,9 @@ def get_plugin_config_from_mkdocs(mkdocs_path) -> dict:
logging.info("Fixture configuration loaded: " + str(cfg))
if plugin_loaded.config.get("enabled"):
- assert (
- plugin_loaded.config.get("locale") is not None
- ), "Locale should never be None after plugin is loaded"
+ assert plugin_loaded.config.get("locale") is not None, "Locale should never be None after plugin is loaded"
- logging.info(
- "Locale '%s' determined from %s"
- % (plugin_loaded.config.get("locale"), mkdocs_path)
- )
+ logging.info("Locale '%s' determined from %s" % (plugin_loaded.config.get("locale"), mkdocs_path))
return plugin_loaded.config
@@ -121,7 +118,7 @@ def setup_clean_mkdocs_folder(mkdocs_yml_path, output_path):
shutil.copytree("tests/fixtures/i18n/docs", str(testproject_path / "docs"))
else:
shutil.copytree("tests/fixtures/basic_project/docs", str(testproject_path / "docs"))
-
+
shutil.copyfile(mkdocs_yml_path, str(testproject_path / "mkdocs.yml"))
if "gen-files" in mkdocs_yml_path:
@@ -148,65 +145,80 @@ def setup_commit_history(testproject_path):
Returns:
repo (repo): git.Repo object
"""
- assert not os.path.exists(str(testproject_path / ".git"))
- testproject_path = str(testproject_path)
+ assert not (testproject_path / ".git").exists()
repo = git.Repo.init(testproject_path, bare=False)
repo.git.checkout("-b", "master")
author = "Test Person "
-
with working_directory(testproject_path):
-
# page_with_tags contains tags we replace and test
if os.path.exists("docs/page_with_tag.md"):
repo.git.add("docs/page_with_tag.md")
- repo.git.commit(message="add homepage", author=author, date="1500854705") # Mon Jul 24 2017 00:05:05 GMT+0000
+ repo.git.commit(
+ message="add homepage", author=author, date="1500854705"
+ ) # Mon Jul 24 2017 00:05:05 GMT+0000
- file_name = os.path.join(testproject_path, "docs/page_with_tag.md")
+ file_name = testproject_path / "docs/page_with_tag.md"
with open(file_name, "a") as the_file:
the_file.write("test\n")
repo.git.add("docs/page_with_tag.md")
- repo.git.commit(message="update homepage #1", author=author, date="1525475836") # Fri May 04 2018 23:17:16 GMT+0000
+ repo.git.commit(
+ message="update homepage #1", author=author, date="1525475836"
+ ) # Fri May 04 2018 23:17:16 GMT+0000
with open(file_name, "a") as the_file:
the_file.write("awa\n")
repo.git.add("docs/page_with_tag.md")
- repo.git.commit(message="update homepage #2", author=author, date="1642911026") # Sun Jan 23 2022 04:10:26 GMT+0000
+ repo.git.commit(
+ message="update homepage #2", author=author, date="1642911026"
+ ) # Sun Jan 23 2022 04:10:26 GMT+0000
if os.path.exists("docs/page_with_renamed.md"):
- bf_file_name = os.path.join(testproject_path, "docs/page_with_renamed.md")
- af_file_name = os.path.join(testproject_path, "docs/subfolder/page_with_renamed.md")
+ bf_file_name = testproject_path / "docs/page_with_renamed.md"
+ af_file_name = testproject_path / "docs/subfolder/page_with_renamed.md"
# Since git.mv would actually remove the file, move page_with_renamed.md back to docs if it has been moved
- if os.path.exists(af_file_name):
+ if af_file_name.exists():
os.replace(af_file_name, bf_file_name)
repo.git.add("docs/page_with_renamed.md")
- repo.git.commit(message="page_with_renamed.md before renamed", author=author, date="1655229469") # Tue Jun 14 2022 17:57:49 GMT+0000
+ repo.git.commit(
+ message="page_with_renamed.md before renamed", author=author, date="1655229469"
+ ) # Tue Jun 14 2022 17:57:49 GMT+0000
repo.git.mv("docs/page_with_renamed.md", "docs/subfolder/page_with_renamed.md")
- repo.git.commit(message="page_with_renamed.md after renamed", author=author, date="1655229515") # Tue Jun 14 2022 17:58:35 GMT+0000
+ repo.git.commit(
+ message="page_with_renamed.md after renamed", author=author, date="1655229515"
+ ) # Tue Jun 14 2022 17:58:35 GMT+0000
if os.path.exists("docs/first_page.md"):
repo.git.add("docs/first_page.md")
- repo.git.commit(message="first page", author=author, date="1500854705") # Mon Jul 24 2017 00:05:05 GMT+0000
- file_name = os.path.join(testproject_path, "docs/first_page.md")
+ repo.git.commit(message="first page", author=author, date="1500854705") # Mon Jul 24 2017 00:05:05 GMT+0000
+ file_name = testproject_path / "docs/first_page.md"
with open(file_name, "w+") as the_file:
the_file.write("Hello\n")
repo.git.add("docs/first_page.md")
- repo.git.commit(message="first page update 1", author=author, date="1519964705") # Fri Mar 02 2018 04:25:05 GMT+0000
+ repo.git.commit(
+ message="first page update 1", author=author, date="1519964705"
+ ) # Fri Mar 02 2018 04:25:05 GMT+0000
with open(file_name, "w") as the_file:
the_file.write("# First Test Page Edited\n\nSome Lorem text")
repo.git.add("docs/first_page.md")
- repo.git.commit(message="first page update 2", author=author, date="1643911026") # Thu Feb 03 2022 17:57:06 GMT+0000
+ repo.git.commit(
+ message="first page update 2", author=author, date="1643911026"
+ ) # Thu Feb 03 2022 17:57:06 GMT+0000
repo.git.add("mkdocs.yml")
- repo.git.commit(message="add mkdocs", author=author, date="1500854705 -0700") # Mon Jul 24 2017 00:05:05 GMT+0000
+ repo.git.commit(
+ message="add mkdocs", author=author, date="1500854705 -0700"
+ ) # Mon Jul 24 2017 00:05:05 GMT+0000
- if os.path.exists("docs/second_page.md"):
+ if Path("docs/second_page.md").exists():
repo.git.add("docs/second_page.md")
- repo.git.commit(message="second page", author=author, date="1643911026") # Thu Feb 03 2022 17:57:06 GMT+0000
-
+ repo.git.commit(
+ message="second page", author=author, date="1643911026"
+ ) # Thu Feb 03 2022 17:57:06 GMT+0000
+
repo.git.add("docs/index.md")
- repo.git.commit(message="homepage", author=author, date="1643911026") # Thu Feb 03 2022 17:57:06 GMT+0000
+ repo.git.commit(message="homepage", author=author, date="1643911026") # Thu Feb 03 2022 17:57:06 GMT+0000
return repo
@@ -251,21 +263,21 @@ def validate_build(testproject_path, plugin_config: dict = {}):
# Make sure with markdown tag has valid
# git revision date tag
- if not plugin_config.get('enabled'):
- return
-
+ if not plugin_config.get("enabled"):
+ return
+
page_with_tag = testproject_path / "site/page_with_tag/index.html"
contents = page_with_tag.read_text(encoding="utf8")
assert re.search(r"renders as\:\s[|\w].+", contents)
repo = Util(config=plugin_config, mkdocs_dir=testproject_path)
- commit_hash, commit_timestamp =repo.get_git_commit_timestamp(
- path=str(testproject_path / "docs/page_with_tag.md"),
- is_first_commit=False,
- )
+ commit_hash, commit_timestamp = repo.get_git_commit_timestamp(
+ path=str(testproject_path / "docs/page_with_tag.md"),
+ is_first_commit=False,
+ )
date_formats = repo.get_date_formats_for_timestamp(
commit_timestamp,
- locale=plugin_config['locale'],
+ locale=plugin_config["locale"],
add_spans=True,
)
@@ -273,11 +285,14 @@ def validate_build(testproject_path, plugin_config: dict = {}):
assert any(searches), "No correct revision date formats output was found"
if plugin_config.get("enable_creation_date"):
- commit_hash, commit_timestamp = repo.get_git_commit_timestamp(path=str(testproject_path / "docs/page_with_tag.md"),is_first_commit=True,)
+ commit_hash, commit_timestamp = repo.get_git_commit_timestamp(
+ path=str(testproject_path / "docs/page_with_tag.md"),
+ is_first_commit=True,
+ )
assert commit_timestamp == 1500854705
date_formats = repo.get_date_formats_for_timestamp(
commit_timestamp=commit_timestamp,
- locale=plugin_config['locale'],
+ locale=plugin_config["locale"],
add_spans=True,
)
@@ -285,12 +300,12 @@ def validate_build(testproject_path, plugin_config: dict = {}):
assert any(searches), "No correct creation date formats output was found"
if os.path.exists(str(testproject_path / "docs/subfolder/page_with_renamed.md")):
- commit_hash, commit_timestamp=repo.get_git_commit_timestamp(
- path=str(testproject_path / "docs/subfolder/page_with_renamed.md"),
- is_first_commit=True
+ commit_hash, commit_timestamp = repo.get_git_commit_timestamp(
+ path=str(testproject_path / "docs/subfolder/page_with_renamed.md"), is_first_commit=True
)
assert commit_timestamp == 1655229469
+
def validate_mkdocs_file(temp_path: str, mkdocs_yml_file: str):
"""
Creates a clean mkdocs project
@@ -300,50 +315,46 @@ def validate_mkdocs_file(temp_path: str, mkdocs_yml_file: str):
temp_path (PosixPath): Path to temporary folder
mkdocs_yml_file (PosixPath): Path to mkdocs.yml file
"""
- testproject_path = setup_clean_mkdocs_folder(
- mkdocs_yml_path=mkdocs_yml_file, output_path=temp_path
- )
+ testproject_path = setup_clean_mkdocs_folder(mkdocs_yml_path=mkdocs_yml_file, output_path=temp_path)
setup_commit_history(testproject_path)
result = build_docs_setup(testproject_path)
assert result.exit_code == 0, f"'mkdocs build' command failed with output:\n{result.stdout}"
# validate build with locale retrieved from mkdocs config file
- validate_build(
- testproject_path, plugin_config=get_plugin_config_from_mkdocs(mkdocs_yml_file)
- )
+ validate_build(testproject_path, plugin_config=get_plugin_config_from_mkdocs(mkdocs_yml_file))
return testproject_path
-
MKDOCS_FILES = [
- 'basic_project/mkdocs_creation_date.yml',
- 'basic_project/mkdocs_custom_type.yml',
- 'basic_project/mkdocs_datetime.yml',
- 'basic_project/mkdocs_exclude.yml',
- 'basic_project/mkdocs_fallback_to_build_date.yml',
- 'basic_project/mkdocs_locale.yml',
- 'basic_project/mkdocs_meta.yml',
- 'basic_project/mkdocs_plugin_locale.yml',
- 'basic_project/mkdocs.yml',
- 'basic_project/mkdocs_theme_timeago_locale.yml',
- 'basic_project/mkdocs_theme_language.yml',
- 'basic_project/mkdocs_theme_locale_and_language.yml',
- 'basic_project/mkdocs_theme_locale_disabled.yml',
- 'basic_project/mkdocs_theme_timeago.yml',
- 'basic_project/mkdocs_theme_locale.yml',
- 'basic_project/mkdocs_theme_no_locale.yml',
- 'basic_project/mkdocs_theme_timeago_override.yml',
- 'basic_project/mkdocs_theme_timeago_instant.yml',
- 'basic_project/mkdocs_timeago_locale.yml',
- 'basic_project/mkdocs_timeago.yml',
- 'basic_project/mkdocs_with_override.yml',
+ "basic_project/mkdocs_creation_date.yml",
+ "basic_project/mkdocs_custom_type.yml",
+ "basic_project/mkdocs_datetime.yml",
+ "basic_project/mkdocs_exclude.yml",
+ "basic_project/mkdocs_fallback_to_build_date.yml",
+ "basic_project/mkdocs_locale.yml",
+ "basic_project/mkdocs_meta.yml",
+ "basic_project/mkdocs_no_parallel.yml",
+ "basic_project/mkdocs_plugin_locale.yml",
+ "basic_project/mkdocs.yml",
+ "basic_project/mkdocs_theme_timeago_locale.yml",
+ "basic_project/mkdocs_theme_language.yml",
+ "basic_project/mkdocs_theme_locale_and_language.yml",
+ "basic_project/mkdocs_theme_locale_disabled.yml",
+ "basic_project/mkdocs_theme_timeago.yml",
+ "basic_project/mkdocs_theme_locale.yml",
+ "basic_project/mkdocs_theme_no_locale.yml",
+ "basic_project/mkdocs_theme_timeago_override.yml",
+ "basic_project/mkdocs_theme_timeago_instant.yml",
+ "basic_project/mkdocs_timeago_locale.yml",
+ "basic_project/mkdocs_timeago.yml",
+ "basic_project/mkdocs_with_override.yml",
# 'i18n/mkdocs.yml'
]
INVALID_MKDOCS_FILES = [
- ('basic_project/mkdocs_unknown_type.yml', "AssertionError"),
- ('i18n/mkdocs_wrong_order.yml', "should be defined after the i18n plugin in your mkdocs.yml"),
+ ("basic_project/mkdocs_unknown_type.yml", "AssertionError"),
+ ("i18n/mkdocs_wrong_order.yml", "should be defined after the i18n plugin in your mkdocs.yml"),
]
@@ -357,27 +368,23 @@ def test_tags_are_replaced(tmp_path, mkdocs_file):
"""
Make sure the {{ }} tags are replaced properly.
"""
- testproject_path = setup_clean_mkdocs_folder(
- mkdocs_yml_path=f"tests/fixtures/{mkdocs_file}", output_path=tmp_path
- )
+ testproject_path = setup_clean_mkdocs_folder(mkdocs_yml_path=f"tests/fixtures/{mkdocs_file}", output_path=tmp_path)
setup_commit_history(testproject_path)
result = build_docs_setup(testproject_path)
assert result.exit_code == 0, "'mkdocs build' command failed"
- plugin_config=get_plugin_config_from_mkdocs(str(testproject_path / "mkdocs.yml"))
+ plugin_config = get_plugin_config_from_mkdocs(str(testproject_path / "mkdocs.yml"))
tags_file = testproject_path / "site/page_with_tag/index.html"
contents = tags_file.read_text(encoding="utf8")
# validate the build
- validate_build(
- testproject_path, plugin_config=plugin_config
- )
+ validate_build(testproject_path, plugin_config=plugin_config)
if plugin_config.get("enabled") == False:
return True
if plugin_config.get("type") == "timeago":
- pytest.skip("Not necessary to test the JS library")
+ pytest.skip("Not necessary to test the JS library")
# Make sure count_commits() works
# We created 11 commits in setup_commit_history()
@@ -385,62 +392,56 @@ def test_tags_are_replaced(tmp_path, mkdocs_file):
u = Util(config={}, mkdocs_dir=os.getcwd())
assert commit_count(u._get_repo("docs/page_with_tag.md")) == 11
-
# the revision date was in 'setup_commit_history' was set to 1642911026 (Sun Jan 23 2022 04:10:26 GMT+0000)
# Assert {{ git_revision_date_localized }} is replaced
- date_formats_revision_date = get_date_formats(1642911026,
+ date_formats_revision_date = get_date_formats(
+ 1642911026,
locale=plugin_config.get("locale"),
time_zone=plugin_config.get("timezone"),
- custom_format=plugin_config.get("custom_format")
+ custom_format=plugin_config.get("custom_format"),
)
for k, v in date_formats_revision_date.items():
assert v is not None
-
- date = date_formats_revision_date.get(plugin_config.get('type'))
+
+ date = date_formats_revision_date.get(plugin_config.get("type"))
assert re.search(rf"{date}\<\/span.+", contents)
# The last site revision was set in setup_commit_history to 1643911026 (Thu Feb 03 2022 17:57:06 GMT+0000)
# Assert {{ git_site_revision_date_localized }} is replaced
- date_formats_revision_date = get_date_formats(1643911026,
+ date_formats_revision_date = get_date_formats(
+ 1643911026,
locale=plugin_config.get("locale"),
time_zone=plugin_config.get("timezone"),
- custom_format=plugin_config.get("custom_format")
+ custom_format=plugin_config.get("custom_format"),
)
for k, v in date_formats_revision_date.items():
assert v is not None
- date = date_formats_revision_date.get(plugin_config.get('type'))
+ date = date_formats_revision_date.get(plugin_config.get("type"))
assert re.search(rf"{date}\<\/span.+", contents)
# Note {{ git_creation_date_localized }} is only replaced when configured in the config
if plugin_config.get("enable_creation_date"):
# The creation of page_with_tag.md was set in setup_commit_history to 1500854705 ( Mon Jul 24 2017 00:05:05 GMT+0000 )
- date_formats_revision_date = get_date_formats(1500854705,
+ date_formats_revision_date = get_date_formats(
+ 1500854705,
locale=plugin_config.get("locale"),
time_zone=plugin_config.get("timezone"),
- custom_format=plugin_config.get("custom_format")
+ custom_format=plugin_config.get("custom_format"),
)
for k, v in date_formats_revision_date.items():
assert v is not None
- date = date_formats_revision_date.get(plugin_config.get('type'))
+ date = date_formats_revision_date.get(plugin_config.get("type"))
assert re.search(rf"{date}\<\/span.+", contents)
-
-
-
-
def test_git_not_available(tmp_path, recwarn):
"""
When there is no GIT repo, this should fail
"""
- testproject_path = setup_clean_mkdocs_folder(
- "tests/fixtures/basic_project/mkdocs.yml", tmp_path
- )
+ testproject_path = setup_clean_mkdocs_folder("tests/fixtures/basic_project/mkdocs.yml", tmp_path)
result = build_docs_setup(testproject_path)
- assert (
- result.exit_code == 1
- ), "'mkdocs build' command succeeded while there is no GIT repo"
+ assert result.exit_code == 1, "'mkdocs build' command succeeded while there is no GIT repo"
# assert there's a no error when fallback to build date is set to true
testproject_path = setup_clean_mkdocs_folder(
@@ -450,16 +451,12 @@ def test_git_not_available(tmp_path, recwarn):
assert result.exit_code == 0
-
-
def test_build_material_theme(tmp_path):
"""
When using mkdocs-material theme, test correct working
"""
# theme set to 'material' with 'language' set to 'de'
- testproject_path = validate_mkdocs_file(
- tmp_path, "tests/fixtures/basic_project/mkdocs_theme_language.yml"
- )
+ testproject_path = validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs_theme_language.yml")
# In mkdocs-material, a 'last update' should appear
# in German because locale is set to 'de'
@@ -473,9 +470,7 @@ def test_material_theme_locale(tmp_path):
When using mkdocs-material theme, test correct working
"""
# theme set to 'material' with 'locale' set to 'de'
- testproject_path = validate_mkdocs_file(
- tmp_path, "tests/fixtures/basic_project/mkdocs_theme_locale.yml"
- )
+ testproject_path = validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs_theme_locale.yml")
# In mkdocs-material, a 'last update' should appear
# in english instead of German because you should use 'language' and not locale.
@@ -490,9 +485,7 @@ def test_material_theme_locale_disabled(tmp_path):
When using mkdocs-material theme, test correct working
"""
# theme set to 'material' with 'locale' set to 'de'
- testproject_path = validate_mkdocs_file(
- tmp_path, "tests/fixtures/basic_project/mkdocs_theme_locale_disabled.yml"
- )
+ testproject_path = validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs_theme_locale_disabled.yml")
# In mkdocs-material, a 'last update' should appear
# in english instead of German because you should use 'language' and not locale.
@@ -507,9 +500,7 @@ def test_material_theme_no_locale(tmp_path):
When using mkdocs-material theme, test correct working
"""
# theme set to 'material' with 'language' set to 'de'
- testproject_path = validate_mkdocs_file(
- tmp_path, "tests/fixtures/basic_project/mkdocs_theme_no_locale.yml"
- )
+ testproject_path = validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs_theme_no_locale.yml")
# In mkdocs-material, a 'last update' should appear
# in english because default locale is set to 'en'
@@ -518,15 +509,14 @@ def test_material_theme_no_locale(tmp_path):
assert re.search(r"Last update", contents)
-
@pytest.mark.parametrize("mkdocs_file, error", INVALID_MKDOCS_FILES)
def test_type_unknown(mkdocs_file, error, tmp_path):
"""
Make sure invalid mkdocs.yml specification raise the correct errors.
"""
testproject_path = setup_clean_mkdocs_folder(
- mkdocs_yml_path=f"tests/fixtures/{ mkdocs_file }", # mkdocs_file, # tmp_path, ,
- output_path=tmp_path
+ mkdocs_yml_path=f"tests/fixtures/{mkdocs_file}", # mkdocs_file, # tmp_path, ,
+ output_path=tmp_path,
)
# Setup git commit history
assert not os.path.exists(str(testproject_path / ".git"))
@@ -538,7 +528,7 @@ def test_type_unknown(mkdocs_file, error, tmp_path):
with working_directory(testproject_path):
# page_with_tags contains tags we replace and test
repo.git.add(".")
- repo.git.commit(message="add all", author=author, date="1500854705") # Mon Jul 24 2017 00:05:05 GMT+0000
+ repo.git.commit(message="add all", author=author, date="1500854705") # Mon Jul 24 2017 00:05:05 GMT+0000
result = build_docs_setup(testproject_path)
assert result.exit_code == 1
@@ -546,16 +536,12 @@ def test_type_unknown(mkdocs_file, error, tmp_path):
assert error in result.stdout or error in str(result.exc_info[0])
-
-
def test_exclude_pages(tmp_path):
"""
When using mkdocs-material theme, test correct working
"""
# theme set to 'material' with 'locale' set to 'de'
- testproject_path = validate_mkdocs_file(
- tmp_path, "tests/fixtures/basic_project/mkdocs_exclude.yml"
- )
+ testproject_path = validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs_exclude.yml")
# Make sure revision date does not exist in excluded pages
first_page = testproject_path / "site/first_page/index.html"
@@ -567,16 +553,13 @@ def test_exclude_pages(tmp_path):
assert not re.search(r"Last update\:\s[',
- "custom": "01. January 1970"
+ "custom": "01. January 1970",
}
assert get_date_formats(0) == expected_output
@@ -22,7 +21,7 @@ def test_get_dates():
new_expected_output = expected_output.copy()
new_expected_output["timeago"] = ''
assert get_date_formats(0, locale="en_US") == new_expected_output
-
+
# Test with different locale
expected_output = {
"date": "1 janvier 1970",
@@ -30,7 +29,7 @@ def test_get_dates():
"iso_date": "1970-01-01",
"iso_datetime": "1970-01-01 00:00:00",
"timeago": '',
- "custom": "01. janvier 1970"
+ "custom": "01. janvier 1970",
}
assert get_date_formats(0, locale="fr") == expected_output
@@ -41,7 +40,7 @@ def test_get_dates():
"iso_date": "1970-01-01",
"iso_datetime": "1970-01-01 00:00:00",
"timeago": '',
- "custom": "01. janeiro 1970"
+ "custom": "01. janeiro 1970",
}
assert get_date_formats(0, locale="pt_BR") == expected_output
@@ -56,7 +55,7 @@ def test_get_dates():
"iso_date": "1970-01-01",
"iso_datetime": "1970-01-01 00:00:00",
"timeago": '',
- "custom": "01. Jan 1970"
+ "custom": "01. Jan 1970",
}
assert get_date_formats(0, locale="en", time_zone="UTC", custom_format="%d. %b %Y") == expected_output
@@ -67,7 +66,7 @@ def test_get_dates():
"iso_date": "1970-01-01",
"iso_datetime": "1970-01-01 02:00:00",
"timeago": '',
- "custom": "01. January 1970"
+ "custom": "01. January 1970",
}
loc_dt = datetime(1970, 1, 1, 1, 0, 0, tzinfo=get_timezone("Europe/Berlin"))
unix_timestamp = loc_dt.replace(tzinfo=timezone.utc).timestamp()
@@ -75,7 +74,7 @@ def test_get_dates():
# Test with missing arguments
with pytest.raises(TypeError):
- get_date_formats() # noqa
+ get_date_formats() # noqa
# Test with invalid timezone
with pytest.raises(LookupError):
@@ -83,21 +82,20 @@ def test_get_dates():
# Test with more recent date
expected_output = {
- 'date': 'October 15, 2023',
- 'datetime': 'October 15, 2023 13:32:04',
- 'iso_date': '2023-10-15',
- 'iso_datetime': '2023-10-15 13:32:04',
- 'timeago': '',
- 'custom': '15. October 2023'
+ "date": "October 15, 2023",
+ "datetime": "October 15, 2023 13:32:04",
+ "iso_date": "2023-10-15",
+ "iso_datetime": "2023-10-15 13:32:04",
+ "timeago": '',
+ "custom": "15. October 2023",
}
assert get_date_formats(1697369524, time_zone="Europe/Amsterdam") == expected_output
-
assert get_date_formats(1582397529) == {
"date": "February 22, 2020",
"datetime": "February 22, 2020 18:52:09",
"iso_date": "2020-02-22",
"iso_datetime": "2020-02-22 18:52:09",
"timeago": '',
- "custom": '22. February 2020',
- }
\ No newline at end of file
+ "custom": "22. February 2020",
+ }
diff --git a/tests/test_exclude.py b/tests/test_exclude.py
index dd19cc9..7f87d3b 100644
--- a/tests/test_exclude.py
+++ b/tests/test_exclude.py
@@ -1,8 +1,8 @@
from mkdocs_git_revision_date_localized_plugin.exclude import exclude
import pytest
-def test_exclude():
+def test_exclude():
with pytest.raises(AssertionError):
exclude("fsdfs", "not a list")
@@ -16,4 +16,4 @@ def test_exclude():
globs = ["folder/*"]
assert exclude("folder/index.md", globs)
- assert not exclude("subfolder/index.md", globs)
\ No newline at end of file
+ assert not exclude("subfolder/index.md", globs)
diff --git a/tests/test_parse_git_ignore_revs.py b/tests/test_parse_git_ignore_revs.py
index f22d9fd..7ada34a 100644
--- a/tests/test_parse_git_ignore_revs.py
+++ b/tests/test_parse_git_ignore_revs.py
@@ -9,9 +9,10 @@
("\n\n\n\n\nabc123\n\n\n\n\n", ["abc123"]),
]
+
@pytest.mark.parametrize("test_input,expected", TEST_PARAMS)
def test_parse_git_ignore_revs(test_input, expected):
- with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', delete=False) as fp:
+ with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as fp:
fp.write(test_input)
temp_file_name = fp.name
try: