Skip to content
Merged
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
62 changes: 0 additions & 62 deletions .circleci/config.yml

This file was deleted.

28 changes: 28 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Lint

on:
push:
branches: [master, develop]
pull_request:

jobs:
ruff:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install ruff
run: |
python -m pip install --upgrade pip
pip install -e ".[lint]"

- name: Run ruff
run: |
ruff check castle
ruff format --check castle
31 changes: 31 additions & 0 deletions .github/workflows/specs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Specs

on:
push:
branches: [master, develop]
pull_request:

jobs:
specs:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[test]"

- name: Run tests
run: python -m unittest -v castle.test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
*.pyo
*.egg-info
.eggs
__pycache__/
.pytest_cache
.ruff_cache
/dist
/build
.coverage
/htmlcov
.venv/
.vscode/
.idea/
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10.2
3.13
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python 3.13.3
29 changes: 29 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
master
------

7.0.0 (2026-05-29)
------------------

Breaking Changes:
~~~~~~~~~~~~~~~~~
- require Python 3.9 or newer (3.4–3.8 are no longer supported)
- remove ``track``, ``authenticate``, device management, and impersonation
client methods; use ``risk``, ``filter``, and ``log`` instead
- remove ``ImpersonationFailed``

Features:
~~~~~~~~~
- add Lists and List Items APIs
- add Privacy API (``request_user_data``, ``delete_user_data``)
- add ``RateLimitError`` for HTTP 429 responses

Bug fixes:
~~~~~~~~~~
- fix ``Client.filter`` and ``Client.risk`` failover when ``user`` is missing;
fall back to ``matching_user_id``

Enhancements:
~~~~~~~~~~~~~
- remove unused ``ValidatorsNotSupported`` validator
- migrate CI to GitHub Actions (Python 3.9–3.13)
- migrate packaging to ``pyproject.toml`` (PEP 621)
- replace ``pylint``/``autopep8`` with ``ruff``
- bump ``requests`` minimum to ``2.31``

6.1.0 (2022-03-14)
------------------
- `#111 <https://github.com/castle/castle-python/pull/111>`__ fix context preparation issues
Expand Down
22 changes: 14 additions & 8 deletions DEVELOPMENT.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,37 @@ Installation

$ git clone git@github.com:castle/castle-python.git
$ cd castle-python
$ python3 setup.py install
$ pip3 install -e ".[test,lint]"


Test
------------

.. code-block:: console

$ python3 setup.py test
$ python3 -m unittest castle.test

Linting
------------

.. code-block:: console

$ pip3 install pylint
$ pip3 install --upgrade pep8
$ pip3 install --upgrade autopep8
$ pylint --rcfile=./pylintrc castle
$ autopep8 --in-place -r castle
$ pip3 install ruff
$ ruff check castle
$ ruff format --check castle

To auto-fix and format:

.. code-block:: console

$ ruff check --fix castle
$ ruff format castle

Coverage
------------

.. code-block:: console

$ pip3 install coverage
$ coverage run setup.py test
$ coverage run -m unittest castle.test
$ coverage report
2 changes: 0 additions & 2 deletions MANIFEST.in

This file was deleted.

39 changes: 20 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
PIP = pip3
PYTHON = python3

.PHONY = help ci-lint coverage lint pre-lint setup test
.PHONY = help ci-lint coverage lint format setup test
.DEFAULT_GOAL = help

help:
@echo "---------------HELP-----------------"
@echo "To check the project coverage type make coverage"
@echo "To install the project type make setup"
@echo "To run the tests type make test"
@echo "To lint the project type make lint"
@echo "To setup the project type make setup"
@echo "To test the project type make test"
@echo "To auto-format the project type make format"
@echo "To check coverage type make coverage"
@echo "------------------------------------"

coverage:
${PIP} install coverage
coverage run setup.py test

ci-lint: pre-lint lint
setup:
${PIP} install -e ".[test,lint]"

pre-lint:
${PIP} install pylint
${PIP} install --upgrade pep8
${PIP} install --upgrade autopep8
test:
${PYTHON} -m unittest -v castle.test

lint:
pylint --rcfile=./pylintrc castle
autopep8 --in-place -r castle
ruff check castle
ruff format --check castle

setup:
${PYTHON} setup.py install
ci-lint: lint

test:
${PYTHON} setup.py test
format:
ruff check --fix castle
ruff format castle

coverage:
${PIP} install coverage
coverage run -m unittest castle.test
coverage report
34 changes: 17 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Python SDK for Castle
=====================

.. image:: https://circleci.com/gh/castle/castle-python.svg?style=shield&branch=master
.. image:: https://github.com/castle/castle-python/actions/workflows/specs.yml/badge.svg?branch=master
:alt: Build Status
:target: https://circleci.com/gh/castle/castle-python
:target: https://github.com/castle/castle-python/actions/workflows/specs.yml

`Castle <https://castle.io>`_ **analyzes user behavior in web and mobile apps to stop fraud before it happens.**

Expand All @@ -19,15 +19,14 @@ Import and configure the library with your Castle API secret.

.. code:: python

from castle.configuration import configuration, DEFAULT_ALLOWLIST
from castle.configuration import configuration, DEFAULT_ALLOWLIST, TRUSTED_PROXIES

# Same as setting it through Castle.api_secret
configuration.api_secret = ':YOUR-API-SECRET'

# For authenticate method you can set failover strategies: allow(default), deny, challenge, throw
# For risk/filter methods you can set failover strategies: allow(default), deny, challenge, throw
configuration.failover_strategy = 'deny'

# Castle::RequestError is raised when timing out in milliseconds (default: 1000 milliseconds)
# RequestError is raised when timing out in milliseconds (default: 1000 milliseconds)
configuration.request_timeout = 1500

# Base Castle API url
Expand Down Expand Up @@ -84,7 +83,7 @@ Import and configure the library with your Castle API secret.
configuration.trust_proxy_chain = false
# *Warning*: this mode is highly promiscuous and could lead to wrongly trusting a spoofed IP if the request passes through a malicious proxy

# *Note: the default list of proxies that are always marked as "trusted" can be found in: Castle::Configuration::TRUSTED_PROXIES
# *Note: the default list of proxies that are always marked as "trusted" can be found in TRUSTED_PROXIES

Usage
-------------------------------
Expand All @@ -101,26 +100,31 @@ It is also possible to define multiple configs within one application.

from castle.configuration import Configuration

# Initialize new instance of Castle::Configuration
# Initialize a separate Configuration instance
config = Configuration()
config.api_secret = ':YOUR-API-SECRET'

After a successful setup, you can pass the config to any API command as follows:
After a successful setup, you can pass the config to a client and call any API as follows:

.. code:: python

from castle.api.get_device import APIGetDevice
from castle.client import Client

# Get device data
APIGetDevice.call(device_token, config)
client = Client({'context': {}})
client.risk({
'request_token': '<token>',
'event': '$login',
'status': '$succeeded',
'user': {'id': '1234'}
})


Signature
---------

.. code:: python

from secure_mode import signature
from castle.secure_mode import signature

signature(user_id)

Expand All @@ -132,7 +136,3 @@ Exceptions
``CastleError`` will be thrown if the Castle API returns a 400 or a 500
level HTTP response. You can also choose to catch a more `finegrained
error <https://github.com/castle/castle-python/blob/master/castle/errors.py>`__.


.. |Build Status| image:: https://travis-ci.org/castle/castle-python.svg?branch=master
:target: https://travis-ci.org/castle/castle-python
10 changes: 5 additions & 5 deletions RELEASING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ Releasing
#. Pull latest ``develop``, merge it to ``master``, and push it.
#. Make a release on Github from the ``master`` branch, specify tag as ``vX.Y.Z`` to create a tag.
#. ``git checkout master && git pull``
#. ``rm -rf dist``
#. ``python3 setup.py sdist bdist_wheel``
#. ``rm -rf dist build``
#. ``python3 -m build``
#. ``twine upload dist/*``

When you change something in the README.rst make sure it is in the
correct format, as pypi will ignore the file if it is not valid.

``pip3 install collective.checkdocs``
To validate the rendered metadata locally:

``pip3 install pygments``
``pip3 install build twine``

``python3 setup.py checkdocs``
``python3 -m build && twine check dist/*``

To upload to testpypi
``twine upload --repository-url https://test.pypi.org/legacy/ dist/*``
Loading
Loading