Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
597b730
Update demo SDK version
davidgrayston Nov 16, 2020
412820e
Bump minor version
davidgrayston Nov 16, 2020
d4eebfb
Merge pull request #273 from getyoti/master-1.14.0
davidgrayston Nov 16, 2020
4102733
SDK-1825: Add support for custom privacy policy URL
davidgrayston Nov 12, 2020
85b0cc8
Bump protobuf from 3.13.0 to 3.14.0
dependabot[bot] Nov 16, 2020
24471eb
Merge pull request #276 from getyoti/master
echarrod Dec 1, 2020
f41f583
Bump cffi from 1.14.3 to 1.14.4
dependabot[bot] Dec 1, 2020
5468a72
Bump virtualenv from 20.1.0 to 20.2.1
dependabot[bot] Dec 1, 2020
7f8b1ed
Merge pull request #288 from getyoti/master
echarrod Mar 17, 2021
219b410
Bump virtualenv from 20.2.1 to 20.4.3
dependabot[bot] Mar 17, 2021
2a51312
Bump pytz from 2020.4 to 2021.1
dependabot[bot] Mar 17, 2021
7e04b10
Bump iso8601 from 0.1.13 to 0.1.14
dependabot[bot] Mar 17, 2021
fac56f2
Bump deprecated from 1.2.10 to 1.2.12
dependabot[bot] Mar 17, 2021
cb493e9
Bump protobuf from 3.14.0 to 3.15.8
dependabot[bot] Apr 13, 2021
9d7b92b
Bump cffi from 1.14.4 to 1.14.5
dependabot[bot] Apr 15, 2021
9b27c92
Bump protobuf from 3.15.8 to 3.17.1
dependabot[bot] Jun 1, 2021
ae48f84
Bump werkzeug from 1.0.1 to 2.0.1
dependabot[bot] Jun 1, 2021
1d21b3b
Bump virtualenv from 20.4.3 to 20.4.7
dependabot[bot] Jun 1, 2021
c1d7f9c
Bump protobuf from 3.17.1 to 3.17.3
dependabot[bot] Jul 1, 2021
8ed1890
Merge branch 'master' into development
echarrod Jul 6, 2021
885c7c6
adding myself to dependabot
MichalMilewiczYoti Jul 9, 2021
0691db9
Apply suggestions from code review
echarrod Aug 4, 2021
6cab71f
Bump virtualenv from 20.4.7 to 20.7.2
dependabot[bot] Sep 1, 2021
22907cb
Bump cffi from 1.14.5 to 1.14.6
dependabot[bot] Sep 3, 2021
3edba3f
Bump iso8601 from 0.1.14 to 0.1.16
dependabot[bot] Sep 24, 2021
afedb39
Bump virtualenv from 20.7.2 to 20.8.1
dependabot[bot] Oct 1, 2021
7950d4b
Bump deprecated from 1.2.12 to 1.2.13
dependabot[bot] Oct 1, 2021
c0bfbdb
Update supported Python versions: add later versions and remove 2.7
echarrod Oct 21, 2021
91bb167
Update pre-commit, use specific versions rather than floating branch
echarrod Oct 21, 2021
aa9e162
Remove travis, update references to point to Github workflow
echarrod Oct 21, 2021
2335e35
Update itsdangerous after incompatibility
echarrod Oct 21, 2021
6bd37fd
Fix pre-commit violations
echarrod Oct 21, 2021
818e073
Use Python 3.9 for examples, install distutils
echarrod Oct 21, 2021
bf7d59c
Bump protobuf from 3.17.3 to 3.19.0
dependabot[bot] Oct 21, 2021
a0887d8
Bump werkzeug from 2.0.1 to 2.0.2
dependabot[bot] Nov 1, 2021
767a8ad
Bump pytz from 2021.1 to 2021.3
dependabot[bot] Nov 1, 2021
fcf93bb
Bump protobuf from 3.19.0 to 3.19.1
dependabot[bot] Nov 1, 2021
1a7a0a0
Bump cffi from 1.14.6 to 1.15.0
dependabot[bot] Nov 1, 2021
c8562d7
[SDK-1998] adding handoff flag
MichalMilewiczYoti Oct 29, 2021
2f88484
[SDK-1998] code review fixies
MichalMilewiczYoti Nov 5, 2021
3838647
fixing test
MichalMilewiczYoti Nov 5, 2021
172b07d
Merge pull request #332 from getyoti/feature/handoff_flag
MichalMilewiczYoti Nov 5, 2021
d2d159d
Bump virtualenv from 20.8.1 to 20.10.0
dependabot[bot] Nov 1, 2021
07bb943
[SDK-2004] Add support for issuing authority sub check
MichalMilewiczYoti Nov 30, 2021
e3e31e9
Bump iso8601 from 0.1.16 to 1.0.2
dependabot[bot] Dec 1, 2021
5d46ab8
changes after CR
MichalMilewiczYoti Dec 1, 2021
8ca2f92
[SDK-1980] Add support for Session Deadline
MichalMilewiczYoti Dec 8, 2021
c5b6065
Merge pull request #344 from getyoti/feat/session_deadline
MichalMilewiczYoti Dec 17, 2021
25c3a7e
Merge pull request #341 from getyoti/feat/idv
MichalMilewiczYoti Dec 17, 2021
d408479
SDK-1901 adding WATCHLIST_SCREENING check
MichalMilewiczYoti Aug 30, 2021
e3be90a
Bump virtualenv from 20.10.0 to 20.12.0
dependabot[bot] Jan 1, 2022
0a4fce7
SDK-1838 auth_type for doc_scan session
MichalMilewiczYoti Sep 23, 2021
247b43d
Don't fix version of setuptools for "check examples"
echarrod Jan 12, 2022
81988d7
Revert "Don't fix version of setuptools for "check examples""
echarrod Jan 12, 2022
34acc24
Upgrade "six" package
echarrod Jan 12, 2022
bb391e3
Revert "Install python3.10-distutils"
echarrod Jan 12, 2022
6fe1937
Use actions/setup-python v2.3.1
echarrod Jan 12, 2022
d491b4e
Upgrade pip
echarrod Jan 12, 2022
3983747
Revert "Upgrade pip": already up to date
echarrod Jan 12, 2022
f6617ad
Use Python 3.10.0 until packages have been fixed by maintainers
echarrod Jan 12, 2022
259c1f6
Add 'sudo apt-get install python3-distutils'
echarrod Jan 12, 2022
1ca237c
Revert "Use Python 3.10.0 until packages have been fixed by maintainers"
echarrod Jan 12, 2022
adcce3e
Revert "Add 'sudo apt-get install python3-distutils'"
echarrod Jan 12, 2022
b59ddb7
Use .version instead of distutils (distuils is deprecated)
echarrod Jan 12, 2022
a00399f
Update packages: `future` causing a problem:
echarrod Jan 12, 2022
7e1dbec
Use requirements.in for aml example: need to fix the future version (…
echarrod Jan 12, 2022
829b5a5
Update wheel package
echarrod Jan 12, 2022
052066d
Add wheel to setup.py
echarrod Jan 12, 2022
af033f0
pip install wheel
echarrod Jan 12, 2022
7bffc05
Update django
echarrod Jan 12, 2022
c4cd552
Remove django check (for now)
echarrod Jan 12, 2022
d685ba9
Remove doc_scan check: problem with cffi & Python 3.10
echarrod Jan 12, 2022
b269b24
Update requirements.txt
echarrod Jan 12, 2022
fad2ce8
SDK-2027: adding non-latin support for session and supported documents
MichalMilewiczYoti Jan 18, 2022
9af34b3
Merge pull request #347 from getyoti/feat/non_latin_documents
MichalMilewiczYoti Jan 21, 2022
20c7c02
Merge pull request #321 from getyoti/feature/watchlist
MichalMilewiczYoti Jan 25, 2022
11224fc
Merge pull request #324 from getyoti/feature/extend_auth_type
MichalMilewiczYoti Jan 25, 2022
4c73bce
Update dependabot assignees
echarrod Jan 28, 2022
88f1461
Revert adding of strictly_latin to source constraints builder
echarrod Jan 28, 2022
5ba6408
Reinstate missing Github actions linting step
echarrod Jan 28, 2022
4c0658b
Update "check examples" steps
echarrod Jan 28, 2022
39e323d
&& pip install --upgrade pip
echarrod Jan 28, 2022
99d7650
Run on Python 3.9
echarrod Jan 28, 2022
0298997
Update jinja package (from Flask)
echarrod Jan 28, 2022
66a167c
Remove tests after removing associated code
echarrod Jan 28, 2022
9b2eff2
Bump pytz from 2021.1 to 2021.3
dependabot[bot] Feb 1, 2022
2daf3fc
Bump virtualenv from 20.12.0 to 20.13.0
dependabot[bot] Feb 1, 2022
8e89f01
Merge release/2.15.0 -> development
echarrod Feb 24, 2022
3094dd4
Bump protobuf from 3.19.3 to 3.19.4
dependabot[bot] Feb 24, 2022
cbfe2ef
Merge branch 'master' into development
echarrod Jun 21, 2022
a31e020
Bump pip-tools from 6.4.0 to 6.6.2
dependabot[bot] Jun 21, 2022
4af030a
Bump virtualenv from 20.13.0 to 20.14.1
dependabot[bot] Jun 21, 2022
2b697ec
Bump werkzeug from 2.0.2 to 2.1.2
dependabot[bot] Jun 21, 2022
64083ed
Merge branch 'master' into development
echarrod Jun 27, 2022
3fbf9c1
Bump virtualenv from 20.14.1 to 20.15.1
dependabot[bot] Jul 1, 2022
0441863
Merge pull request #417 from getyoti/python-library-updates
mehmet-yoti Jun 30, 2025
d1d8e58
added python static liveness check (#425)
mehmet-yoti Dec 1, 2025
6941d6f
update version files
mehmet-yoti Dec 15, 2025
3519a4a
Merge master into release/2.14.5 - Add Python 3.12 support and update…
mehmet-yoti Dec 16, 2025
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
1 change: 1 addition & 0 deletions examples/doc_scan/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def create_session():
.with_preset_issuing_country("GBR")
.with_success_url("{url}/success".format(url=YOTI_APP_BASE_URL))
.with_error_url("{url}/error".format(url=YOTI_APP_BASE_URL))
.with_privacy_policy_url("{url}/privacy-policy".format(url=YOTI_APP_BASE_URL))
.build()
)

Expand Down
1,136 changes: 595 additions & 541 deletions examples/doc_scan/templates/success.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ sonar.host.url = https://sonarcloud.io
sonar.organization = getyoti
sonar.projectKey = getyoti:python
sonar.projectName = Python SDK
sonar.projectVersion = 2.14.4
sonar.projectVersion = 2.14.5
sonar.exclusions = yoti_python_sdk/tests/**,examples/**,yoti_python_sdk/protobuf/**/*

sonar.python.pylint.reportPath = coverage.out
Expand Down
1 change: 1 addition & 0 deletions yoti_python_sdk/doc_scan/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
ID_DOCUMENT_FACE_MATCH = "ID_DOCUMENT_FACE_MATCH"
LIVENESS = "LIVENESS"
ZOOM = "ZOOM"
STATIC = "STATIC"
SUPPLEMENTARY_DOCUMENT_TEXT_DATA_CHECK = "SUPPLEMENTARY_DOCUMENT_TEXT_DATA_CHECK"
SUPPLEMENTARY_DOCUMENT_TEXT_DATA_EXTRACTION = (
"SUPPLEMENTARY_DOCUMENT_TEXT_DATA_EXTRACTION"
Expand Down
45 changes: 42 additions & 3 deletions yoti_python_sdk/doc_scan/session/create/check/liveness.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ class RequestedLivenessCheckConfig(YotiSerializable):
The configuration applied when creating a Liveness Check
"""

def __init__(self, liveness_type, max_retries):
def __init__(self, liveness_type, max_retries, manual_check=None):
"""
:param liveness_type: the liveness type
:type liveness_type: str
:param max_retries: the maximum number of retries
:type max_retries: int
:param manual_check: the manual check value
:type manual_check: str or None
"""
self.__liveness_type = liveness_type
self.__max_retries = max_retries
self.__manual_check = manual_check

@property
def liveness_type(self):
Expand All @@ -39,9 +42,23 @@ def max_retries(self):
"""
return self.__max_retries

@property
def manual_check(self):
"""
The manual check value for the liveness check

:return: the manual check value
:rtype: str or None
"""
return self.__manual_check

def to_json(self):
return remove_null_values(
{"liveness_type": self.liveness_type, "max_retries": self.max_retries}
{
"liveness_type": self.liveness_type,
"max_retries": self.max_retries,
"manual_check": self.manual_check,
}
)


Expand Down Expand Up @@ -74,6 +91,7 @@ class RequestedLivenessCheckBuilder(object):
def __init__(self):
self.__liveness_type = None
self.__max_retries = None
self.__manual_check = None

def for_zoom_liveness(self):
"""
Expand All @@ -84,6 +102,15 @@ def for_zoom_liveness(self):
"""
return self.with_liveness_type(constants.ZOOM)

def for_static_liveness(self):
"""
Sets the liveness type to "STATIC"

:return: the builder
:rtype: RequestedLivenessCheckBuilder
"""
return self.with_liveness_type(constants.STATIC)

def with_liveness_type(self, liveness_type):
"""
Sets the liveness type on the builder
Expand All @@ -109,6 +136,18 @@ def with_max_retries(self, max_retries):
self.__max_retries = max_retries
return self

def with_manual_check_never(self):
"""
Sets the manual check value to "NEVER"

:return: the builder
:rtype: RequestedLivenessCheckBuilder
"""
self.__manual_check = constants.NEVER
return self

def build(self):
config = RequestedLivenessCheckConfig(self.__liveness_type, self.__max_retries)
config = RequestedLivenessCheckConfig(
self.__liveness_type, self.__max_retries, self.__manual_check
)
return RequestedLivenessCheck(config)
32 changes: 32 additions & 0 deletions yoti_python_sdk/doc_scan/session/retrieve/image_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from .media_response import MediaResponse


class ImageResponse(object):
"""
Represents an image resource within a static liveness check
"""

def __init__(self, data=None):
"""
:param data: the data to parse
:type data: dict or None
"""
if data is None:
data = dict()

self.__media = (
MediaResponse(data["media"]) if "media" in data.keys() else None
)

@property
def media(self):
"""
Returns the media information for the image

:return: the media
:rtype: MediaResponse or None
"""
return self.__media
19 changes: 18 additions & 1 deletion yoti_python_sdk/doc_scan/session/retrieve/resource_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
LivenessResourceResponse,
ZoomLivenessResourceResponse,
)
from yoti_python_sdk.doc_scan.session.retrieve.static_liveness_resource_response import (
StaticLivenessResourceResponse,
)


class ResourceContainer(object):
Expand Down Expand Up @@ -54,7 +57,7 @@ def __parse_liveness_capture(liveness_capture):
:return: the parsed liveness capture
:rtype: LivenessResourceResponse
"""
types = {"ZOOM": ZoomLivenessResourceResponse}
types = {"ZOOM": ZoomLivenessResourceResponse, "STATIC": StaticLivenessResourceResponse}

clazz = types.get(
liveness_capture.get("liveness_type", None),
Expand Down Expand Up @@ -105,3 +108,17 @@ def zoom_liveness_resources(self):
for liveness in self.__liveness_capture
if isinstance(liveness, ZoomLivenessResourceResponse)
]

@property
def static_liveness_resources(self):
"""
Returns a filtered list of static liveness capture resources

:return: list of static liveness captures
:rtype: list[StaticLivenessResourceResponse]
"""
return [
liveness
for liveness in self.__liveness_capture
if isinstance(liveness, StaticLivenessResourceResponse)
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from .liveness_resource_response import LivenessResourceResponse
from .image_response import ImageResponse


class StaticLivenessResourceResponse(LivenessResourceResponse):
"""
Represents a Static Liveness resource for a given session
"""

def __init__(self, data=None):
"""
:param data: the data to parse
:type data: dict or None
"""
if data is None:
data = dict()

LivenessResourceResponse.__init__(self, data)

self.__image = (
ImageResponse(data["image"]) if "image" in data.keys() else None
)

@property
def image(self):
"""
Returns the associated image for the static liveness resource

:return: the image
:rtype: ImageResponse or None
"""
return self.__image
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,67 @@ def test_should_serialize_to_json_without_error(self):
s = json.dumps(result, cls=YotiEncoder)
assert s is not None and s != ""

def test_should_build_with_static_liveness_type(self):
result = (
RequestedLivenessCheckBuilder()
.for_static_liveness()
.with_max_retries(3)
.build()
)

assert result.type == "LIVENESS"
assert result.config.liveness_type == "STATIC"
assert result.config.max_retries == 3

def test_should_build_with_manual_check_never(self):
result = (
RequestedLivenessCheckBuilder()
.for_static_liveness()
.with_max_retries(3)
.with_manual_check_never()
.build()
)

assert result.config.liveness_type == "STATIC"
assert result.config.manual_check == "NEVER"

def test_should_serialize_static_liveness_to_json(self):
result = (
RequestedLivenessCheckBuilder()
.for_static_liveness()
.with_max_retries(3)
.with_manual_check_never()
.build()
)

json_str = json.dumps(result, cls=YotiEncoder)
assert json_str is not None

# Verify the JSON contains the expected fields
json_data = json.loads(json_str)
assert json_data["type"] == "LIVENESS"
assert json_data["config"]["liveness_type"] == "STATIC"
assert json_data["config"]["manual_check"] == "NEVER"
assert json_data["config"]["max_retries"] == 3

def test_should_omit_manual_check_when_not_set(self):
result = (
RequestedLivenessCheckBuilder()
.for_static_liveness()
.with_max_retries(3)
.build()
)

json_str = json.dumps(result, cls=YotiEncoder)
assert json_str is not None

# Verify the JSON does not contain the manual_check field
json_data = json.loads(json_str)
assert json_data["type"] == "LIVENESS"
assert json_data["config"]["liveness_type"] == "STATIC"
assert "manual_check" not in json_data["config"]
assert json_data["config"]["max_retries"] == 3


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ def test_should_filter_zoom_liveness_resources(self):
assert len(result.liveness_capture) == 2
assert len(result.zoom_liveness_resources) == 1

def test_should_filter_static_liveness_resources(self):
data = {
"liveness_capture": [
{"liveness_type": "STATIC"},
{"liveness_type": "someUnknown"},
]
}

result = ResourceContainer(data)

assert len(result.liveness_capture) == 2
assert len(result.static_liveness_resources) == 1


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import unittest
from yoti_python_sdk.doc_scan.session.retrieve.static_liveness_resource_response import (
StaticLivenessResourceResponse,
)
from yoti_python_sdk.doc_scan.session.retrieve.image_response import ImageResponse
from yoti_python_sdk.doc_scan.session.retrieve.media_response import MediaResponse


class StaticLivenessResourceResponseTest(unittest.TestCase):
def test_should_parse_static_liveness_resource(self):
data = {
"id": "bbbbbbb-5717-4562-b3fc-2c963f66afa6",
"source": {"type": "END_USER"},
"liveness_type": "STATIC",
"image": {
"media": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "IMAGE",
"created": "2021-06-11T11:39:24Z",
"last_updated": "2021-06-11T11:39:24Z",
}
},
"tasks": [],
}

result = StaticLivenessResourceResponse(data)

assert result.id == "bbbbbbb-5717-4562-b3fc-2c963f66afa6"
assert result.liveness_type == "STATIC"
assert isinstance(result.image, ImageResponse)
assert isinstance(result.image.media, MediaResponse)
assert result.image.media.id == "3fa85f64-5717-4562-b3fc-2c963f66afa6"
assert result.image.media.type == "IMAGE"

def test_should_handle_missing_image(self):
data = {
"id": "test-id",
"liveness_type": "STATIC",
"tasks": [],
}

result = StaticLivenessResourceResponse(data)

assert result.id == "test-id"
assert result.liveness_type == "STATIC"
assert result.image is None

def test_should_parse_media_id_for_retrieval(self):
data = {
"id": "resource-id",
"liveness_type": "STATIC",
"image": {
"media": {
"id": "media-id-123",
"type": "IMAGE",
"created": "2021-06-11T11:39:24Z",
"last_updated": "2021-06-11T11:39:24Z",
}
},
"tasks": [],
}

result = StaticLivenessResourceResponse(data)

# Verify we can access the media ID for content retrieval
assert result.image is not None
assert result.image.media is not None
assert result.image.media.id == "media-id-123"


if __name__ == "__main__":
unittest.main()
3 changes: 1 addition & 2 deletions yoti_python_sdk/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
# -*- coding: utf-8 -*-
__version__ = "2.14.4"

__version__ = "2.14.5"
Loading