Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Links

on:
push:
pull_request:
schedule:
- cron: "0 13 * * 1" # weekly, to catch external link rot without a commit
workflow_dispatch:

permissions:
contents: read

jobs:
linkChecker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Setup mise
uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1
with:
install: false

# Install only lychee (not the repo's full toolchain) and run the check.
- name: Check links
env:
MISE_AUTO_INSTALL: "false"
run: |
mise install lychee
mise run check-links
7 changes: 5 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ jobs:
persist-credentials: false

- name: Install the latest version of uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # 8.1.0
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
# Disable caching in the release workflow (zizmor cache-poisoning).
enable-cache: false

- name: Build
run: uv build
Expand All @@ -47,4 +50,4 @@ jobs:
name: artifact
path: dist

- uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # 1.14.0
- uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
submodules: true
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # 8.1.0
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- name: Install tox
run: uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv --with tox-gh
- name: Install Python
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ MANIFEST

# Claude Code
.claude

.lycheecache
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ uv run tox

## Additional Resources

- [API Documentation](https://minfraud.readthedocs.io/)
- [API Documentation](https://minfraud.readthedocs.io/en/latest/)
- [minFraud Web Services Docs](https://dev.maxmind.com/minfraud/)
- [Report Transaction API](https://dev.maxmind.com/minfraud/report-a-transaction)
- [Report Transaction API](https://dev.maxmind.com/minfraud/report-a-transaction/)
- GitHub Issues: https://github.com/maxmind/minfraud-api-python/issues
2 changes: 1 addition & 1 deletion README.dev.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ Steps for doing a release:
release script.
7. Run ``dev-bin/release.sh`` and follow the prompts.
8. Verify the release on `GitHub <https://github.com/maxmind/minfraud-api-python/releases>`_
and `PyPI <https://pypi.python.org/pypi/minfraud>`_.
and `PyPI <https://pypi.org/project/minfraud/>`_.
12 changes: 6 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Description
This package provides an API for the `MaxMind minFraud Score, Insights, and
Factors web services <https://dev.maxmind.com/minfraud/>`_ as well as the
`Report Transaction web service
<https://dev.maxmind.com/minfraud/report-a-transaction?lang=en>`_.
<https://dev.maxmind.com/minfraud/report-a-transaction/?lang=en>`_.

Installation
------------
Expand All @@ -30,7 +30,7 @@ Documentation
-------------

Complete API documentation is available on `Read the Docs
<https://minfraud.readthedocs.io/>`_.
<https://minfraud.readthedocs.io/en/latest/>`_.

Usage
-----
Expand Down Expand Up @@ -79,7 +79,7 @@ The Score web service is called with the ``score()`` method:
Each of these methods takes a dictionary representing the transaction to be sent
to the web service. The structure of this dictionary should be in `the format
specified in the REST API documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`__.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`__.
All fields are optional.

Report Transactions Usage
Expand All @@ -97,7 +97,7 @@ Report Transaction web service is called with the ``report()`` method:
The method takes a dictionary representing the report to be sent to the web
service. The structure of this dictionary should be in `the format specified
in the REST API documentation
<https://dev.maxmind.com/minfraud/report-a-transaction?lang=en>`__. The
<https://dev.maxmind.com/minfraud/report-a-transaction/?lang=en>`__. The
required fields are ``tag`` and one or more of the following: ``ip_address``,
``maxmind_id``, ``minfraud_id``, ``transaction_id``.

Expand Down Expand Up @@ -134,7 +134,7 @@ The possible errors are:
Additionally, ``score``, ``insights`` and ``factors`` may also raise:

* ``minfraud.InsufficientFundsError`` - This will be raised when `your
account <https://www.maxmind.com/en/account>`_ is out of funds.
account <https://www.maxmind.com/en/accounts/current/people/current>`_ is out of funds.

Examples
--------
Expand Down Expand Up @@ -322,7 +322,7 @@ Please report all issues with this code using the `GitHub issue tracker
<https://github.com/maxmind/minfraud-api-python/issues>`_.

If you are having an issue with a MaxMind service that is not specific to the
client API, please contact `MaxMind support <https://www.maxmind.com/en/support>`_
client API, please contact `MaxMind support <https://support.maxmind.com/knowledge-base>`_
for assistance.

Copyright and License
Expand Down
70 changes: 70 additions & 0 deletions lychee.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Lychee link checker configuration
# https://lychee.cli.rs/#/usage/config
#
# Run locally with:
# lychee './**/*.md' './**/*.rst' './src/minfraud/**/*.py' './pyproject.toml'

# Include URL fragments in checks
include_fragments = true

# Don't allow any redirects, so links that have moved are surfaced and can be
# updated to their canonical destination.
max_redirects = 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting max_redirects = 0 makes the link checker extremely sensitive to standard, benign redirects (such as trailing slashes, HTTPS upgrades, or locale-based redirection like https://www.maxmind.com/ -> https://www.maxmind.com/en/home). This forces the use of fragile, over-specific, and verbose URLs in the documentation (like https://www.maxmind.com/en/accounts/current/people/current instead of https://www.maxmind.com/en/account), which are harder to maintain and may break if internal routing changes.

Consider allowing a small number of redirects (e.g., max_redirects = 3 or 5) to balance link health with maintenance overhead.

Suggested change
max_redirects = 0
max_redirects = 3

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentionally keeping max_redirects = 0. Surfacing moved/redirecting links is the goal of this change (STF-557), and it matches the dev-site and blog-site lychee configs; redirects are resolved by updating the link to its canonical target.

— Claude (posted on Greg's behalf)


# Accept these HTTP status codes
# 100-103: Informational responses
# 200-299: Success responses
# 403: Forbidden (some sites use this for rate limiting)
# 429: Too Many Requests
# 500-599: Server errors (temporary issues shouldn't fail CI)
# 999: LinkedIn's custom status code
accept = ["100..=103", "200..=299", "403", "429", "500..=599", "999"]

# Exclude URL patterns from checking (treated as regular expressions)
exclude = [
# GitHub blob URLs with line-number fragments (not parseable as page anchors)
'^https://github\.com/[^/]+/[^/]+/blob/[0-9a-fA-F]+/.+#L\d+$',
# dev.maxmind.com API docs are a JS-rendered single-page app, so its in-page
# anchors (e.g. response-schema fragments) aren't present in the static HTML
# lychee fetches. The pages themselves are verified without the fragment.
'^https://dev\.maxmind\.com/minfraud/api-documentation/responses/.*#',
# referrer_uri example value in a docstring/doctest (not a documentation link)
'^http://www\.amazon\.com/$',
# Live / auth-gated MaxMind endpoints: appear as code string literals or
# require login, so they can't be verified by an anonymous request.
'^https://geoip\.maxmind\.com',
'^https://geolite\.info',
'^https://minfraud\.maxmind\.com',
'^https://sandbox\.maxmind\.com',
'^https://updates\.maxmind\.com',
'^https://www\.maxmind\.com/en/accounts/',
'^https://www\.maxmind\.com/en/account/login',
# Local / placeholder URLs (e.g. the proxy example in docstrings)
'^file://',
'^https?://example\.(com|org|net)',
'^http://localhost',
'127\.0\.0\.1',
]

# Exclude file paths from getting checked (regular expressions, matched against
# the path relative to the working directory). Patterns are segment-anchored
# with (^|/) so short names like "build" don't match unintended paths.
exclude_path = [
'(^|/)node_modules/',
'(^|/)\.venv/',
'(^|/)venv/',
'(^|/)build/',
'(^|/)dist/',
'(^|/)\.eggs/',
'(^|/)[^/]*\.egg-info/',
'(^|/)docs/_build/',
# Changelog: historical entries are preserved as-is, not rewritten
'(^|/)HISTORY\.rst$',
]

# Cache results for 1 day to speed up repeated checks
cache = true
max_cache_age = "1d"

# Skip missing input files instead of erroring
skip_missing = true
29 changes: 29 additions & 0 deletions mise.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html

[[tools.lychee]]
version = "0.23.0"
backend = "aqua:lycheeverse/lychee"

[tools.lychee."platforms.linux-arm64"]
checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0"
url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz"

[tools.lychee."platforms.linux-arm64-musl"]
checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0"
url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz"

[tools.lychee."platforms.linux-x64"]
checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a"
url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz"

[tools.lychee."platforms.linux-x64-musl"]
checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a"
url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz"

[tools.lychee."platforms.macos-arm64"]
checksum = "sha256:4c8034900e11083b68ac6f6582c377ff1f704e268991999e09d717973e493e7f"
url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-arm64-macos.dmg"

[tools.lychee."platforms.windows-x64"]
checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824"
url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe"
9 changes: 9 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[settings]
lockfile = true

[tools]
lychee = "latest"

[tasks.check-links]
description = "Check links with lychee"
run = "lychee --no-progress './**/*.md' './**/*.rst' './src/minfraud/**/*.py' './pyproject.toml'"
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ lint = [
]

[project.urls]
Homepage = "https://www.maxmind.com/"
Documentation = "https://minfraud.readthedocs.org/"
Homepage = "https://www.maxmind.com/en/home"
Documentation = "https://minfraud.readthedocs.io/en/latest/"
"Source Code" = "https://github.com/maxmind/minfraud-api-python"
"Issue Tracker" = "https://github.com/maxmind/minfraud-api-python/issues"

Expand Down
6 changes: 3 additions & 3 deletions src/minfraud/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class GeoIP2Location(geoip2.records.Location):
local_time: str | None
"""The date and time of the transaction in the time
zone associated with the IP address. The value is formatted according to
`RFC 3339 <https://tools.ietf.org/html/rfc3339>`_. For instance, the
`RFC 3339 <https://datatracker.ietf.org/doc/html/rfc3339>`_. For instance, the
local time in Boston might be returned as 2015-04-27T19:17:24-04:00."""

def __init__(self, *args: Any, **kwargs: Any) -> None:
Expand Down Expand Up @@ -211,7 +211,7 @@ class Device(_Serializable):

In order to receive device output from minFraud Insights or minFraud
Factors, you must be using the `Device Tracking Add-on
<https://dev.maxmind.com/minfraud/track-devices?lang=en>`_.
<https://dev.maxmind.com/minfraud/track-devices/?lang=en>`_.
"""

confidence: float | None
Expand Down Expand Up @@ -620,7 +620,7 @@ class ServiceWarning(_Serializable):
code: str | None
"""This value is a machine-readable code identifying the
warning. See the `response warnings documentation
<https://dev.maxmind.com/minfraud/api-documentation/responses?lang=en#schema--response--warning>`_
<https://dev.maxmind.com/minfraud/api-documentation/responses/?lang=en#schema--response--warning>`_
for the current list of of warning codes."""

warning: str | None
Expand Down
20 changes: 10 additions & 10 deletions src/minfraud/webservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ async def factors(
:param transaction: A dictionary containing the transaction to be
sent to the minFraud Factors web service as specified in the `REST
API documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`_.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`_.
:type transaction: dict
:param validate: If set to false, validation of the transaction
dictionary will be disabled. This validation helps ensure that your
Expand Down Expand Up @@ -313,7 +313,7 @@ async def insights(
:param transaction: A dictionary containing the transaction to be
sent to the minFraud Insights web service as specified in the `REST
API documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`_.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`_.
:type transaction: dict
:param validate: If set to false, validation of the transaction
dictionary will be disabled. This validation helps ensure that your
Expand Down Expand Up @@ -352,7 +352,7 @@ async def score(
:param transaction: A dictionary containing the transaction to be
sent to the minFraud Score web service as specified in the `REST API
documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`_.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`_.
:type transaction: dict
:param validate: If set to false, validation of the transaction
dictionary will be disabled. This validation helps ensure that your
Expand Down Expand Up @@ -388,9 +388,9 @@ async def report(
"""Send a transaction report to the Report Transaction endpoint.

:param report: A dictionary containing the transaction report to be sent
to the Report Transations web service as specified in the `REST API`
to the Report Transations web service as specified in the `REST API
documentation
<https://dev.maxmind.com/minfraud/report-a-transaction?lang=en>_.
<https://dev.maxmind.com/minfraud/report-a-transaction/?lang=en>`_.
:type report: dict
:param validate: If set to false, validation of the report dictionary
will be disabled. This validation helps ensure that your request is
Expand Down Expand Up @@ -538,7 +538,7 @@ def factors(
:param transaction: A dictionary containing the transaction to be
sent to the minFraud Factors web service as specified in the `REST
API documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`_.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`_.
:type transaction: dict
:param validate: If set to false, validation of the transaction
dictionary will be disabled. This validation helps ensure that your
Expand Down Expand Up @@ -577,7 +577,7 @@ def insights(
:param transaction: A dictionary containing the transaction to be
sent to the minFraud Insights web service as specified in the `REST
API documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`_.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`_.
:type transaction: dict
:param validate: If set to false, validation of the transaction
dictionary will be disabled. This validation helps ensure that your
Expand Down Expand Up @@ -616,7 +616,7 @@ def score(
:param transaction: A dictionary containing the transaction to be
sent to the minFraud Score web service as specified in the `REST API
documentation
<https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en>`_.
<https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en>`_.
:type transaction: dict
:param validate: If set to false, validation of the transaction
dictionary will be disabled. This validation helps ensure that your
Expand Down Expand Up @@ -652,9 +652,9 @@ def report(
"""Send a transaction report to the Report Transaction endpoint.

:param report: A dictionary containing the transaction report to be sent
to the Report Transations web service as specified in the `REST API`
to the Report Transations web service as specified in the `REST API
documentation
<https://dev.maxmind.com/minfraud/report-transaction/#Request_Body>_.
<https://dev.maxmind.com/minfraud/report-a-transaction/?lang=en>`_.
:type report: dict
:param validate: If set to false, validation of the report dictionary
will be disabled. This validation helps ensure that your request is
Expand Down
Loading