Skip to content

SDK-2614: Python - Support configuration for IDV shortened flow - python#459

Open
mehmet-yoti wants to merge 1 commit into
masterfrom
websdk-auto/SDK-2614-python-python---support-configuration-for-idv-shortened-flow
Open

SDK-2614: Python - Support configuration for IDV shortened flow - python#459
mehmet-yoti wants to merge 1 commit into
masterfrom
websdk-auto/SDK-2614-python-python---support-configuration-for-idv-shortened-flow

Conversation

@mehmet-yoti
Copy link
Copy Markdown
Contributor

Summary

Adds support for configuring the IDV shortened flow by allowing consumers to suppress specific screens from the IDV journey. A new suppressed_screens field is exposed on SdkConfig via the builder, and seven screen-name constants are added to identify the screens that can be omitted (e.g. ID document education, liveness education, flow completion).

Changes

  • yoti_python_sdk/doc_scan/constants.py: Added seven new constants for suppressible screens — ID_DOCUMENT_EDUCATION, ID_DOCUMENT_REQUIREMENTS, SUPPLEMENTARY_DOCUMENT_EDUCATION, ZOOM_LIVENESS_EDUCATION, STATIC_LIVENESS_EDUCATION, FACE_CAPTURE_EDUCATION, FLOW_COMPLETION.
  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:
    • Added suppressed_screens parameter to SdkConfig.__init__ and corresponding read-only property.
    • Included suppressed_screens in to_json() (null values continue to be stripped via remove_null_values).
    • Added with_suppressed_screens(list) and with_suppressed_screen(str) builder methods on SdkConfigBuilder to set the list wholesale or append a single screen.
  • yoti_python_sdk/tests/doc_scan/session/create/test_sdk_config.py: Added tests covering default value, single/multiple screen setters, JSON serialization (present when set, omitted when unset), fluent builder return values, and constant value assertions. Extended the existing test_should_build_correctly test to include the new field.

QA Test Steps

  1. Setup
    • Check out the branch websdk-auto/SDK-2614-python-python---support-configuration-for-idv-shortened-flow.
    • Install dependencies: pip install -e . and pip install -r requirements.txt.
  2. Unit tests — happy path
    • Run: pytest yoti_python_sdk/tests/doc_scan/session/create/test_sdk_config.py -v.
    • Verify all tests pass, including the new ones: test_suppressed_screens_default_to_none, test_should_add_individual_suppressed_screens, test_suppressed_screens_serialized_when_set, test_suppressed_screens_omitted_when_not_set, test_with_suppressed_screens_returns_builder, test_with_suppressed_screen_returns_builder, test_suppressed_screen_constants_defined.
  3. Regression — full doc_scan test suite
    • Run: pytest yoti_python_sdk/tests/doc_scan/ -v and confirm no existing tests regress.
  4. Manual builder verification (happy path)
    • In a Python REPL:
      from yoti_python_sdk.doc_scan import constants
      from yoti_python_sdk.doc_scan.session.create import SdkConfigBuilder
      from yoti_python_sdk.utils import YotiEncoder
      import json
      
      cfg = (SdkConfigBuilder()
             .with_suppressed_screens([constants.ID_DOCUMENT_EDUCATION, constants.FLOW_COMPLETION])
             .build())
      print(json.dumps(cfg, cls=YotiEncoder))
    • Confirm output JSON contains "suppressed_screens": ["ID_DOCUMENT_EDUCATION", "FLOW_COMPLETION"].
  5. Manual builder verification (single-screen append)
    • In the REPL, chain .with_suppressed_screen(...) calls and confirm screens accumulate in insertion order in the serialized JSON.
  6. Edge case — omitted field
    • Build an SdkConfig without calling either suppressed-screen method.
    • Serialize and confirm suppressed_screens is not present in the resulting JSON (verifies remove_null_values behavior).
  7. Edge case — empty list
    • Call .with_suppressed_screens([]) and verify the JSON contains an empty "suppressed_screens": [] array (empty list is not null and should be sent through).
  8. Integration smoke test (if a sandbox is available)
    • Create a doc-scan session via DocScanClient.create_session() using an SdkConfig with suppressed_screens populated, and confirm the API accepts the payload without 4xx errors and the returned session honors the shortened flow.

Notes

  • suppressed_screens defaults to None and is excluded from the JSON payload when unset, preserving backwards compatibility for callers that don't opt in.
  • with_suppressed_screens copies the input list (list(...)) so later mutations of the caller's list do not affect the built config; this matches the immutability conventions elsewhere in the builder.
  • Screen validation is intentionally left to the server; the SDK accepts any string. Constants are provided for convenience/discoverability but are not enforced — invalid screen names will surface as backend errors.
  • Constructor argument order: suppressed_screens was appended as the final positional parameter to avoid breaking existing callers using positional args (note that SdkConfigBuilder.build() already passes allow_handoff and privacy_policy_url in swapped positional order relative to __init__ — this pre-existing quirk was preserved, not changed in this PR).
  • No changes to public class exports or to DocScanClient; consumers pick up the new field purely through SdkConfigBuilder.

Related Jira: SDK-2614
Auto-generated by n8n + Claude CLI

@sonarqubecloud
Copy link
Copy Markdown

@mehmet-yoti
Copy link
Copy Markdown
Contributor Author

🤖 Claude Code Review

Code Review Findings

Critical

None

Major

None

Minor

  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:339-356 — No validation of screen names against the allowed set.
    The docstring enumerates the seven valid screen constants but with_suppressed_screens / with_suppressed_screen accept any string. A typo (e.g. "FLOW_COMPLETE") will silently serialize and be rejected only by the backend, often producing a confusing error far from the call site. Consider validating against an allow-list:

    _VALID_SUPPRESSED_SCREENS = frozenset({
        ID_DOCUMENT_EDUCATION, ID_DOCUMENT_REQUIREMENTS,
        SUPPLEMENTARY_DOCUMENT_EDUCATION, ZOOM_LIVENESS_EDUCATION,
        STATIC_LIVENESS_EDUCATION, FACE_CAPTURE_EDUCATION, FLOW_COMPLETION,
    })
    
    def with_suppressed_screen(self, screen):
        if screen not in _VALID_SUPPRESSED_SCREENS:
            raise ValueError("Unsupported suppressed screen: {}".format(screen))
        ...

    If validation is intentionally avoided to stay consistent with other free-form setters in this module, that is a defensible choice — but at minimum drop a warning or raise on None/non-string input in with_suppressed_screen.

  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:358-370 — Builder collection initialised inconsistently with rest of module.
    The peer builder NotificationConfigBuilder initialises its list field at construction (self.__topics = []) and with_topic just appends. Here __suppressed_screens is initialised to None and with_suppressed_screen lazily allocates. The two behaviours produce slightly different serialised payloads: calling only with_suppressed_screens([]) produces "suppressed_screens": [] in JSON (see next point), while never calling either setter omits the key. Aligning with the existing pattern would simplify the code and remove the empty-list edge case:

    def __init__(self):
        ...
        self.__suppressed_screens = None  # keep as None

    ...with with_suppressed_screen lazy-initialising as today is fine, OR adopt the topics-style [] default. Just pick one and document the resulting serialisation contract.

  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:165-180 — Empty suppressed_screens list is serialised, not omitted.
    remove_null_values only strips None, so with_suppressed_screens([]) (or removing all items individually) yields "suppressed_screens": [] in the request payload. Depending on the backend contract this may either be a no-op or be rejected. If callers should be able to "clear" suppression, normalise an empty list back to None in the builder (or in to_json):

    self.__suppressed_screens = (
        list(suppressed_screens) if suppressed_screens else None
    )
  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:355 — Defensive copy in with_suppressed_screens is asymmetric with the rest of the API.
    The plural setter takes a defensive copy via list(suppressed_screens), but suppressed_screens is then exposed via the getter at line 156-163 returning the same internal list (no copy) — so callers can still mutate state after build(). Either drop the defensive copy on input (consistent with how with_topic/with_check work) or also return a copy from the property. Minor, but the current half-measure is misleading.

  • yoti_python_sdk/tests/doc_scan/session/create/test_sdk_config.py:88 — Existing tests use is for string comparison; new test mixes idioms.
    The pre-existing assertions in test_should_build_correctly use assert result.error_url is self.SOME_ERROR_URL, which only works by accident (string interning of class attributes). The new assert result.suppressed_screens == self.SOME_SUPPRESSED_SCREENS correctly uses == for list equality. Not a defect in the new code — but consider adding a comment or, on a future cleanup pass, fixing the existing is usages to ==.

Nit

  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:45-50 — Class __init__ docstring orders params out of signature order.
    The signature is ..., allow_handoff=None, privacy_policy_url=None, suppressed_screens=None, but the docstring lists privacy_policy_url before allow_handoff (pre-existing) and now appends suppressed_screens at the bottom. Re-ordering the docstring to match the signature would help readers and Sphinx output:

    :param allow_handoff: ...
    :param privacy_policy_url: ...
    :param suppressed_screens: ...
    
  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:339-356 — Long docstring with embedded constant list will drift.
    Hard-coding the seven valid constant names in the with_suppressed_screens docstring duplicates the source of truth in constants.py. If the list grows, both must be updated. Consider replacing the inline enumeration with a single sentence ("See :mod:yoti_python_sdk.doc_scan.constants for valid screen names") to avoid drift.

  • yoti_python_sdk/doc_scan/constants.py:43-49 — New constants lack a module-level grouping/comment.
    The file already separates groups with blank lines (capture methods, notification topics, document types, etc.). Adding a brief comment such as # Screens that can be suppressed in the IDV shortened flow above the seven new constants would aid discoverability.

  • yoti_python_sdk/tests/doc_scan/session/create/test_sdk_config.py:139-148test_suppressed_screen_constants_defined is low value.
    Asserting constants.X == "X" for each name effectively re-states the constants module. It adds noise without catching regressions that other tests wouldn't already catch (e.g. a typo would surface in test_should_add_individual_suppressed_screens). Consider dropping it, or, if you want a tripwire against renames, assert membership in a set instead.

  • yoti_python_sdk/doc_scan/session/create/sdk_config.py:355 — Line slightly exceeds project's apparent ~100 char width.

    self.__suppressed_screens = list(suppressed_screens) if suppressed_screens is not None else None

    Split for readability and to match the surrounding two-line style in this file.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for configuring an IDV “shortened flow” by allowing SDK consumers to suppress specific screens in the Doc Scan journey via a new suppressed_screens field on SdkConfig (builder + JSON serialization) and a set of screen-name constants.

Changes:

  • Added new suppressible-screen constants in doc_scan/constants.py.
  • Extended SdkConfig + SdkConfigBuilder to accept and serialize suppressed_screens (including single-screen append helper).
  • Added unit tests covering builder behavior and JSON serialization for the new field.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
yoti_python_sdk/doc_scan/constants.py Adds constants identifying suppressible IDV screens.
yoti_python_sdk/doc_scan/session/create/sdk_config.py Adds suppressed_screens to SdkConfig, builder setters, and JSON serialization.
yoti_python_sdk/tests/doc_scan/session/create/test_sdk_config.py Adds/extends tests for suppressed screen configuration and serialization.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 49 to +53
assert result.success_url is self.SOME_SUCCESS_URL
assert result.error_url is self.SOME_ERROR_URL
assert result.privacy_policy_url is self.SOME_PRIVACY_POLICY_URL
assert result.allow_handoff is True
assert result.suppressed_screens == self.SOME_SUPPRESSED_SCREENS
Comment on lines 45 to +49
:param privacy_policy_url: the privacy policy url
:type privacy_policy_url: str
:param allow_handoff: boolean flag for allow_handoff
:type allow_handoff: bool
:param suppressed_screens: list of screen names to be suppressed
self.__error_url,
self.__allow_handoff,
self.__privacy_policy_url,
self.__suppressed_screens,
Comment on lines +107 to +111
result = (
SdkConfigBuilder()
.with_suppressed_screens(self.SOME_SUPPRESSED_SCREENS)
.build()
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants