Models

Data models shared by the checks: extracted links (MarkdownPath, MarkdownURL) and runtime configuration (Config).

Base

Shared base dataclass for the two kinds of link markdown-checker extracts: URLs and paths.

class markdown_checker.models.base.MarkdownLinkBase(link, line_number, file_path, issue='', issue_level='error')

Bases: ABC

Base class for a single link found in a markdown file.

Parameters:
  • link (str)

  • line_number (int)

  • file_path (Path)

  • issue (str)

  • issue_level (Literal['error', 'warning'])

The raw link destination as written in the file (e.g. "https://example.com" or "../img.png").

line_number: int

1-based line number where the link was found.

file_path: Path

Path to the markdown file the link was found in.

issue: str

Human-readable description set by a check when this link fails it (e.g. "is broken"); empty when no issue was found.

issue_level: Literal['error', 'warning']

Severity of issue once set. "error" fails the CLI run (exit code 1); "warning" is reported but never fails it.

has_locale()

Check if the link has a locale

Returns:

True if the link has a locale, False otherwise

Return type:

bool

has_tracking()

Check if the link has a tracking ID

Returns:

True if the link has a tracking ID, False otherwise

Return type:

bool

Config

markdown_checker.models.config.create_http_client(headers=None)

Create a pre-configured httpx2.Client for URL checking.

Parameters:

headers (dict[str, str] | None) – Request headers to send. Defaults to DEFAULT_HEADERS, which impersonate a desktop browser so servers that block non-browser user agents (e.g. some CDNs) don’t reject the request.

Returns:

A client configured to follow redirects (up to 10 hops).

Return type:

Client

class markdown_checker.models.config.Config(skip_domains=<factory>, skip_urls_containing=<factory>, tracking_domains=<factory>, timeout=20, retries=3, retry_on_429=True, fallback_retry_delay=30, max_workers=10, per_host_delay=0.5, max_pending=200, output_mode='local')

Bases: object

Holds all runtime configuration for a check run.

Parameters:
skip_domains: list[str]

Hostnames to exclude from URL checks (substring match against the URL’s hostname). Used by check_broken_urls and check_urls_locale.

skip_urls_containing: list[str]

Substrings to exclude from URL checks (matched anywhere in the full URL). Used by the same checks as skip_domains.

tracking_domains: list[str]

Hostnames that must carry a wt.mc_id tracking parameter. Only used by check_urls_tracking; URLs on other hosts are ignored by that check.

timeout: int

Per-request timeout in seconds for URL checks.

retries: int

Number of attempts for a URL before it is reported as broken. Does not apply to rate-limit/auth responses, which return immediately (see MarkdownURL.check).

retry_on_429: bool

When True, honour a Retry-After header (or a bare 429) instead of the exponential backoff normally used for hard failures.

fallback_retry_delay: int

Seconds reported as retry_after when a 429 response carries no Retry-After header.

max_workers: int

Maximum number of concurrent URL-check worker threads shared across the whole run.

per_host_delay: float

Minimum delay in seconds enforced between two requests to the same host.

max_pending: int

Maximum number of in-flight (submitted but not yet resolved) URL checks before new submissions block; bounds memory use on very large runs.

output_mode: Literal['ci', 'local']

"ci" switches CLI output to GitHub Actions ::error/::warning annotations; "local" uses plain coloured console output.

Path

class markdown_checker.models.path.MarkdownPath(link, line_number, file_path, issue='', issue_level='error')

Bases: MarkdownLinkBase

A relative (or root-relative) file path extracted from a markdown link.

“Fragment” below always means the trailing ?query and/or #anchor part of the link, e.g. in docs/usage.md#section?wt.mc_id=x the fragment is #section?wt.mc_id=x and the path is docs/usage.md.

Parameters:
  • link (str)

  • line_number (int)

  • file_path (Path)

  • issue (str)

  • issue_level (Literal['error', 'warning'])

property path_without_fragments: Path

The link as a Path, with any query/anchor fragment stripped. Equivalent to Path(self.remove_fragments()).

remove_fragments()

Strip the tracking query string and any trailing ?query/#anchor fragment from the link, leaving just the file path portion.

Returns:

The link with its fragment removed, as a string.

Return type:

str

get_full_path()

Resolve the link (with its fragment stripped) to an absolute path, relative to the current working directory.

This is used for links that are themselves absolute (e.g. /docs/usage.md) or otherwise resolvable without knowing which file the link appeared in. If resolution fails (e.g. on an unusual path), falls back to get_full_path_relative().

Returns:

The resolved absolute path.

Return type:

Path

get_full_path_relative()

Resolve the link (with its fragment stripped) relative to the directory of the markdown file it was found in (self.file_path), e.g. a link ../img.png found in docs/usage.md resolves against docs/.

Returns:

The resolved path, as a normalized string.

Return type:

str

exists()

Check whether the link’s target file exists on disk.

Tries resolution relative to the containing markdown file first (see get_full_path_relative()), then as an absolute/CWD-relative path (see get_full_path()). Used by check_broken_paths to flag links whose target is missing.

Returns:

True if the path exists, False otherwise

Return type:

bool

URL

class markdown_checker.models.url.URLCheckResult(status, http_status_code=None, retry_after=None)

Bases: object

Typed outcome of checking whether a URL is reachable.

Parameters:
  • status (Literal['alive', 'broken', 'rate_limited', 'transient_error', 'unverifiable'])

  • http_status_code (int | None)

  • retry_after (int | None)

status: Literal['alive', 'broken', 'rate_limited', 'transient_error', 'unverifiable']

One of:

  • alive: A 2xx response was received. The link is healthy.

  • broken: All retries returned a non-2xx response with no rate-limit or auth signal. Reported as an error-level issue.

  • rate_limited: A 429 (or another non-success response carrying Retry-After) was seen. Reported as a warning-level issue; never fails the run.

  • unverifiable: Both HEAD and GET returned 401/403 - the server is reachable but blocking automated access. Reported as a warning-level issue.

  • transient_error: A network-level error (DNS failure, connection timeout, etc.) with no HTTP response at all. Reported as a warning-level issue.

http_status_code: int | None

The last HTTP status code observed, or None if no response was ever received (e.g. transient_error).

retry_after: int | None

Seconds the caller should wait before retrying, set only when status is rate_limited.

class markdown_checker.models.url.MarkdownURL(link, line_number, file_path, issue='', issue_level='error')

Bases: MarkdownLinkBase

A single web URL extracted from a markdown file, plus the ability to check it.

Parameters:
  • link (str)

  • line_number (int)

  • file_path (Path)

  • issue (str)

  • issue_level (Literal['error', 'warning'])

property parsed_url: ParseResult

Parse the URL and return the result

Returns:

ParseResult – The parsed URL

host_name()

Return the URL’s hostname (netloc), including any port but not the scheme, e.g. "example.com" for "https://example.com/path".

Return type:

str

check(timeout=20, retries=3, client=None, retry_on_429=True, fallback_retry_delay=30)

Check whether the URL is reachable and return a typed outcome.

Rate-limit signals (429, or any non-success response carrying a Retry-After header) and auth errors (401/403) are returned immediately without sleeping or retrying: retrying them wastes traffic against hosts that are already blocking or throttling us. Callers that want to wait out a rate limit (e.g. a host-level circuit breaker) should do so themselves using retry_after.

Parameters:
  • timeout (int) – Timeout for the request in seconds.

  • retries (int) – Number of retries if the request fails.

  • client (httpx2.Client | None) – Optional shared client for connection pooling.

  • retry_on_429 (bool) – When True, honour Retry-After headers on 429 responses.

  • fallback_retry_delay (int) – Seconds to wait when a 429 carries no Retry-After header.

Returns:

URLCheckResult with status one ofalive, broken, rate_limited, unverifiable, or transient_error.

Return type:

URLCheckResult