Skip to content

[ShanaBoo] Bank Sync Connector Architecture#290

Open
genesisrevelationinc-debug wants to merge 5 commits intorohitdash08:mainfrom
genesisrevelationinc-debug:shanaboo-fix-75
Open

[ShanaBoo] Bank Sync Connector Architecture#290
genesisrevelationinc-debug wants to merge 5 commits intorohitdash08:mainfrom
genesisrevelationinc-debug:shanaboo-fix-75

Conversation

@genesisrevelationinc-debug

ShanaBoo Autonomous Fix

This PR was automatically generated by ShanaBoo Earn Engine to claim the $500.00 bounty on this issue.

Source: Github | Task: 3944785467

Closes #75


Auto-submitted by ShanaBoo CNS — NVIDIA NIM + Microsoft Agent Framework

Copy link

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 an initial “bank connector” abstraction under src/finmind/connectors to support pluggable bank integrations, including a simple registry and a mock connector implementation.

Changes:

  • Introduces BaseBankConnector + Transaction model as the connector interface.
  • Adds ConnectorRegistry for registering and retrieving connector implementations.
  • Provides MockBankConnector with import_transactions() and refresh_accounts() stubs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/finmind/connectors/base.py Defines the connector interface and Transaction representation.
src/finmind/connectors/registry.py Adds a registry for connector class registration/lookup.
src/finmind/connectors/mock.py Implements a mock connector for dev/testing flows.
src/finmind/connectors/init.py Exposes connector symbols via package exports.
src/finmind/init.py Adds top-level finmind package exports/version.

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

Comment on lines +1 to +5
from . import connectors

__version__ = "0.1.0"

__all__ = ["connectors"] No newline at end of file
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

This new src/finmind package isn’t currently included in the backend Docker image (it only copies packages/backend/app) and CI lint/tests run only under packages/backend. As-is, these connectors won’t ship with the backend or be exercised by CI; consider either moving them under packages/backend/app, or adding packaging/build steps so src/ is installed/copied and linted/tested.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +25
from typing import Dict, Type
from .base import BaseBankConnector


class ConnectorRegistry:
"""Registry for managing bank connector implementations."""

_connectors: Dict[str, Type[BaseBankConnector]] = {}

@classmethod
def register(cls, name: str, connector_class: Type[BaseBankConnector]) -> None:
"""Register a new bank connector."""
if not issubclass(connector_class, BaseBankConnector):
raise ValueError(f"{connector_class} must inherit from BaseBankConnector")
cls._connectors[name] = connector_class

@classmethod
def get(cls, name: str) -> Type[BaseBankConnector]:
"""Get a connector class by name."""
if name not in cls._connectors:
raise KeyError(f"Connector '{name}' not found. Available: {list(cls._connectors.keys())}")
return cls._connectors[name]

@classmethod
def list(cls) -> Dict[str, Type[BaseBankConnector]]:
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

This module uses legacy typing.Dict / typing.Type generics; elsewhere in the repo Python code uses built-in generics (e.g., dict[str, Any], list[...]) and | None unions. Updating the annotations here will keep typing style consistent across the codebase.

Suggested change
from typing import Dict, Type
from .base import BaseBankConnector
class ConnectorRegistry:
"""Registry for managing bank connector implementations."""
_connectors: Dict[str, Type[BaseBankConnector]] = {}
@classmethod
def register(cls, name: str, connector_class: Type[BaseBankConnector]) -> None:
"""Register a new bank connector."""
if not issubclass(connector_class, BaseBankConnector):
raise ValueError(f"{connector_class} must inherit from BaseBankConnector")
cls._connectors[name] = connector_class
@classmethod
def get(cls, name: str) -> Type[BaseBankConnector]:
"""Get a connector class by name."""
if name not in cls._connectors:
raise KeyError(f"Connector '{name}' not found. Available: {list(cls._connectors.keys())}")
return cls._connectors[name]
@classmethod
def list(cls) -> Dict[str, Type[BaseBankConnector]]:
from .base import BaseBankConnector
class ConnectorRegistry:
"""Registry for managing bank connector implementations."""
_connectors: dict[str, type[BaseBankConnector]] = {}
@classmethod
def register(cls, name: str, connector_class: type[BaseBankConnector]) -> None:
"""Register a new bank connector."""
if not issubclass(connector_class, BaseBankConnector):
raise ValueError(f"{connector_class} must inherit from BaseBankConnector")
cls._connectors[name] = connector_class
@classmethod
def get(cls, name: str) -> type[BaseBankConnector]:
"""Get a connector class by name."""
if name not in cls._connectors:
raise KeyError(f"Connector '{name}' not found. Available: {list(cls._connectors.keys())}")
return cls._connectors[name]
@classmethod
def list(cls) -> dict[str, type[BaseBankConnector]]:

Copilot uses AI. Check for mistakes.
self._authenticated = True
return True

def import_transactions(self, account_id: str, from_date: datetime, to_date: datetime) -> List[Transaction]:
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The import_transactions signature is over 88 characters and will violate the repo flake8 max-line-length if this module is linted. Wrap parameters onto multiple lines to match the repo’s formatting constraints.

Suggested change
def import_transactions(self, account_id: str, from_date: datetime, to_date: datetime) -> List[Transaction]:
def import_transactions(
self,
account_id: str,
from_date: datetime,
to_date: datetime,
) -> List[Transaction]:

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +18
account_id: str,
category: str = None,
metadata: Dict[str, Any] = None,
):
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

category and metadata default to None but are annotated as non-optional (str / Dict[...]). This is a type mismatch that will be flagged by type checkers; annotate them as optional (e.g., str | None, dict[...] | None) to reflect actual allowed values.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
from abc import ABC, abstractmethod
from typing import List, Dict, Any
from datetime import datetime
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

This file uses typing.List / typing.Dict generics. The existing Python code in this repo largely uses built-in generics (e.g., list[Transaction], dict[str, Any]) and | None unions; aligning to that style would keep annotations consistent.

Copilot uses AI. Check for mistakes.
def get(cls, name: str) -> Type[BaseBankConnector]:
"""Get a connector class by name."""
if name not in cls._connectors:
raise KeyError(f"Connector '{name}' not found. Available: {list(cls._connectors.keys())}")
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The KeyError f-string exceeds the repo’s flake8 max-line-length (88) and will fail linting if/when this module is included in the lint scope. Consider wrapping the message across multiple lines (and/or formatting the available connector names separately) to stay within 88 chars.

Suggested change
raise KeyError(f"Connector '{name}' not found. Available: {list(cls._connectors.keys())}")
available_connectors = ", ".join(cls._connectors.keys())
message = (
f"Connector '{name}' not found. "
f"Available connectors: {available_connectors}"
)
raise KeyError(message)

Copilot uses AI. Check for mistakes.
current_date = from_date

while current_date <= to_date:
# Generate 1-3 transactions per day
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The comment says “Generate 1-3 transactions per day”, but the code deterministically generates exactly 3 transactions per day (range(1, 4)). Either adjust the loop to sometimes generate fewer than 3, or update the comment so it matches actual behavior.

Suggested change
# Generate 1-3 transactions per day
# Generate 3 transactions per day

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +72
# Simulate balance changes
for account in self._accounts:
account["balance"] += round((hash(account["account_id"]) % 100) * 0.01 - 0.5, 2)

return self._accounts No newline at end of file
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

refresh_accounts() mutates and returns the internal _accounts list in-place, so callers can accidentally modify connector state. Also, using Python’s hash() makes the delta non-deterministic across processes (hash randomization) and it accumulates on every call, causing balances to drift. Consider returning a copy and using a deterministic/non-cumulative balance update strategy for predictable mock behavior.

Copilot uses AI. Check for mistakes.
pass

@abstractmethod
def import_transactions(self, account_id: str, from_date: datetime, to_date: datetime) -> List[Transaction]:
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The import_transactions abstract method signature exceeds the repo’s 88-character line limit. Wrap the parameters across multiple lines to avoid flake8 E501 when linting is enabled for this module.

Suggested change
def import_transactions(self, account_id: str, from_date: datetime, to_date: datetime) -> List[Transaction]:
def import_transactions(
self,
account_id: str,
from_date: datetime,
to_date: datetime,
) -> List[Transaction]:

Copilot uses AI. Check for mistakes.
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.

Bank Sync Connector Architecture

2 participants