-
Notifications
You must be signed in to change notification settings - Fork 0
feat: robust test and docs toolchain with uv support #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a0fac91
4c87bdf
7c45424
ff3337f
6f36161
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main, master ] | ||
| pull_request: | ||
| branches: [ main, master ] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v8.2.0 | ||
| with: | ||
| enable-cache: true | ||
| cache-dependency-glob: "uv.lock" | ||
| - name: Set up Python ${{ matrix.python-version }} | ||
| run: uv python install ${{ matrix.python-version }} | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| - name: Install dependencies | ||
| run: uv sync --all-extras --python ${{ matrix.python-version }} | ||
| - name: Run tests | ||
| run: uv run --python ${{ matrix.python-version }} pytest --cov=mkdocs_document_dates tests/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| name: Docs | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main, master ] | ||
| pull_request: | ||
| branches: [ main, master ] | ||
|
|
||
| jobs: | ||
| build-docs: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v8.2.0 | ||
| with: | ||
| enable-cache: true | ||
| cache-dependency-glob: "uv.lock" | ||
| - name: Set up Python | ||
| run: uv python install 3.12 | ||
| - name: Install dependencies | ||
| run: uv sync --extra docs --locked --python 3.12 | ||
| - name: Build documentation | ||
| run: uv run --python 3.12 properdocs build -f properdocs.yml |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # mkdocs-document-dates | ||
|
|
||
| A new generation MkDocs plugin for displaying exact creation date, last updated date, authors, email of documents. | ||
|
|
||
| ## Features | ||
|
|
||
| - Works in any environment. | ||
| - Elegant styling. | ||
| - Multi-language support. | ||
|
|
||
| ## Usage | ||
|
|
||
| ```yaml | ||
| plugins: | ||
| - document-dates | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| site_name: mkdocs-document-dates | ||
| theme: | ||
| name: material | ||
|
|
||
| plugins: | ||
| - search | ||
| - document-dates: | ||
| show_created: true | ||
| show_updated: true | ||
| show_author: true | ||
|
|
||
| nav: | ||
| - Home: index.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,9 @@ requires-python = ">=3.9" | |
| license = "MIT" | ||
| authors = [{ name = "Aaron Wang", email = "aaronwqt@gmail.com" }] | ||
| dependencies = [ | ||
| "babel>=2.16" | ||
| "babel>=2.16", | ||
| "pyyaml>=6.0", | ||
| "mkdocs>=1.6,<2" | ||
| ] | ||
| classifiers = [ | ||
| "Programming Language :: Python :: 3", | ||
|
|
@@ -20,8 +22,13 @@ classifiers = [ | |
|
|
||
| [project.optional-dependencies] | ||
| docs = [ | ||
| "mkdocs>=1.6,<=1.6.1", | ||
| "properdocs>=1.6.5", | ||
| "mkdocs-material>=9.5.0", | ||
| ] | ||
| test = [ | ||
| "pytest>=8.0.0", | ||
| "pytest-cov>=4.1.0", | ||
| "pytest-mock>=3.12.0", | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CRITICAL: Missing mkdocs in test extra causes import failure. The test extra does not include mkdocs, but tests/test_plugin.py imports mkdocs_document_dates.plugin which imports mkdocs.* modules. Running pip install .[test] will fail at import time. |
||
| ] | ||
|
qodo-code-review[bot] marked this conversation as resolved.
|
||
|
|
||
| [project.urls] | ||
|
|
@@ -54,3 +61,10 @@ mkdocs_document_dates = [ | |
| ".DS_Store", | ||
| "**/.DS_Store", | ||
| ] | ||
|
|
||
| [tool.pytest.ini_options] | ||
| testpaths = ["tests"] | ||
| python_files = "test_*.py" | ||
|
|
||
| [tool.coverage.run] | ||
| source = ["mkdocs_document_dates"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| import pytest | ||
| from unittest.mock import MagicMock, patch | ||
| from mkdocs_document_dates.plugin import DocumentDatesPlugin, Author | ||
| from datetime import datetime, timezone | ||
|
|
||
| def test_plugin_init(): | ||
| plugin = DocumentDatesPlugin() | ||
| assert plugin.data_cached == {} | ||
|
|
||
| def test_author_class(): | ||
| author = Author(name="Test", email="test@example.com") | ||
| assert author.name == "Test" | ||
| assert author.email == "test@example.com" | ||
|
|
||
| def test_on_config_basic(): | ||
| plugin = DocumentDatesPlugin() | ||
| plugin.config = { | ||
| 'type': 'date', | ||
| 'locale': 'en', | ||
| 'date_format': '%Y-%m-%d', | ||
| 'time_format': '%H:%M:%S', | ||
| 'position': 'top', | ||
| 'exclude': [], | ||
| 'show_created': True, | ||
| 'show_updated': True, | ||
| 'show_author': True, | ||
| 'readtime_wpm': 200, | ||
| 'readtime_wpm_cjk': 300, | ||
| 'recently-updated': {} | ||
| } | ||
|
|
||
| class Config(dict): | ||
| def __init__(self, *args, **kwargs): | ||
| super().__init__(*args, **kwargs) | ||
| self.docs_dir = 'docs' | ||
| self.theme = MagicMock() | ||
| self.theme.name = 'material' | ||
| self.plugins = MagicMock() | ||
| self['extra_css'] = [] | ||
| self['extra_javascript'] = [] | ||
|
|
||
| config = Config() | ||
|
|
||
| # Patch only Path.exists to return False to avoid complex nested mocking of Path divisions and globbing | ||
| with patch('mkdocs_document_dates.plugin.Path.exists', return_value=False): | ||
| plugin.on_config(config) | ||
|
|
||
| assert any('material-icons.css' in css for css in config['extra_css']) | ||
|
|
||
| def test_formatting_date(): | ||
| plugin = DocumentDatesPlugin() | ||
| plugin.config = { | ||
| 'type': 'date', | ||
| 'locale': 'en', | ||
| 'date_format': '%Y-%m-%d', | ||
| 'time_format': '%H:%M:%S' | ||
| } | ||
| dt = datetime(2023, 5, 20, 12, 0, 0, tzinfo=timezone.utc) | ||
| formatted = plugin._formatting_date(dt) | ||
| assert formatted == '2023-05-20' | ||
|
|
||
| def test_insert_date_info_top(): | ||
| plugin = DocumentDatesPlugin() | ||
| plugin.config = {'position': 'top'} | ||
| markdown = "# Title\nContent" | ||
| date_info = "<div>Date</div>" | ||
| result = plugin._insert_date_info(markdown, date_info) | ||
| assert "<div>Date</div>" in result | ||
| assert "# Title" in result | ||
|
|
||
| def test_insert_date_info_bottom(): | ||
| plugin = DocumentDatesPlugin() | ||
| plugin.config = {'position': 'bottom'} | ||
| markdown = "# Title\nContent" | ||
| date_info = "<div>Date</div>" | ||
| result = plugin._insert_date_info(markdown, date_info) | ||
| assert result.endswith("<div>Date</div>") |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,73 @@ | ||||||
| import pytest | ||||||
| from mkdocs_document_dates.utils import ( | ||||||
| analyze_markdown, | ||||||
| is_excluded, | ||||||
| compile_exclude_patterns, | ||||||
| DEFAULT_WPM, | ||||||
| DEFAULT_WPM_CJK | ||||||
| ) | ||||||
|
|
||||||
| def test_analyze_markdown_basic(): | ||||||
| md = """# Title | ||||||
| This is a test paragraph with some words. | ||||||
| """ | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| assert minutes == 1 | ||||||
| assert "This is a test paragraph" in summary | ||||||
|
|
||||||
| def test_analyze_markdown_cjk(): | ||||||
| md = "你好,这是一个测试。" # 9 characters | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| assert minutes >= 1 | ||||||
| assert "你好" in summary | ||||||
|
|
||||||
| def test_analyze_markdown_mixed(): | ||||||
| md = "Hello 你好" | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| assert minutes >= 1 | ||||||
|
|
||||||
| def test_analyze_markdown_frontmatter(): | ||||||
| md = """--- | ||||||
| title: My Page | ||||||
| date: 2023-01-01 | ||||||
| --- | ||||||
| # Actual Title | ||||||
| Content here. | ||||||
| """ | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| assert "title: My Page" not in summary | ||||||
| assert "Content here" in summary | ||||||
|
|
||||||
| def test_analyze_markdown_fence(): | ||||||
| md = """ | ||||||
| ```python | ||||||
| print("hello") | ||||||
| ``` | ||||||
| Text after code. | ||||||
| """ | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| assert 'print("hello")' not in summary | ||||||
| assert "Text after code" in summary | ||||||
|
|
||||||
| def test_exclude_patterns(): | ||||||
| patterns = ["temp.md", "blog/*", "*/index.md"] | ||||||
| compiled = compile_exclude_patterns(patterns) | ||||||
|
|
||||||
| assert is_excluded("temp.md", compiled) is True | ||||||
| assert is_excluded("blog/post1.md", compiled) is True | ||||||
| assert is_excluded("docs/index.md", compiled) is True | ||||||
| assert is_excluded("other.md", compiled) is False | ||||||
|
|
||||||
| def test_analyze_markdown_images(): | ||||||
| md = "" | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| # Reading time for an image alone should be very low, but the function ceils to 1 minute | ||||||
| assert minutes >= 1 | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The updated assertion is too weak ( Prompt for AI agents
Suggested change
|
||||||
| assert summary == "" | ||||||
|
Comment on lines
+61
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2 | Confidence: Medium The test Code Suggestion: def test_analyze_markdown_images():
md = ""
minutes, summary = analyze_markdown(md)
# Reading time for an image alone should be 0 minutes (ceil to 1 if following MkDocs convention)
# Consider adding a test with text to validate minute calculation
assert minutes >= 0
assert summary == "" |
||||||
|
|
||||||
| def test_analyze_markdown_long_content(): | ||||||
| # Create content long enough to exceed 1 minute | ||||||
| # Default WPM is 200. 300 words should be ~1.5 minutes, ceiled to 2. | ||||||
| md = "word " * 300 | ||||||
| minutes, summary = analyze_markdown(md) | ||||||
| assert minutes == 2 | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Downgrade from pinned SHA to mutable major tag reduces supply-chain security. Consider pinning to a full SHA or immutable tag.
Prompt for AI agents