diff options
| -rw-r--r-- | generalresearch/config.py | 23 | ||||
| -rw-r--r-- | generalresearch/managers/thl/ledger_manager/ledger.py | 14 | ||||
| -rw-r--r-- | generalresearch/models/thl/product.py | 63 | ||||
| -rw-r--r-- | pyproject.toml | 15 | ||||
| -rw-r--r-- | test_utils/conftest.py | 67 | ||||
| -rw-r--r-- | test_utils/incite/collections/conftest.py | 26 | ||||
| -rw-r--r-- | test_utils/incite/conftest.py | 72 | ||||
| -rw-r--r-- | test_utils/incite/mergers/conftest.py | 57 | ||||
| -rw-r--r-- | test_utils/managers/cashout_methods.py | 48 | ||||
| -rw-r--r-- | test_utils/managers/conftest.py | 44 | ||||
| -rw-r--r-- | test_utils/managers/contest/conftest.py | 72 | ||||
| -rw-r--r-- | test_utils/managers/ledger/conftest.py | 270 | ||||
| -rw-r--r-- | test_utils/models/conftest.py | 51 | ||||
| -rw-r--r-- | test_utils/spectrum/conftest.py | 18 | ||||
| -rw-r--r-- | tests/managers/thl/test_cashout_method.py | 6 | ||||
| -rw-r--r-- | tests/managers/thl/test_ledger/test_lm_accounts.py | 32 | ||||
| -rw-r--r-- | tests/managers/thl/test_ledger/test_user_txs.py | 63 |
17 files changed, 523 insertions, 418 deletions
diff --git a/generalresearch/config.py b/generalresearch/config.py index e44124b..1c3f6e6 100644 --- a/generalresearch/config.py +++ b/generalresearch/config.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone from typing import Optional +from pathlib import Path from pydantic import RedisDsn, Field, MariaDBDsn, DirectoryPath, PostgresDsn from pydantic_settings import BaseSettings @@ -36,24 +37,22 @@ def is_debug() -> bool: class GRLBaseSettings(BaseSettings): debug: bool = Field(default=True) - redis: Optional[RedisDsn] = Field(default="redis://127.0.0.1:6379") + redis: Optional[RedisDsn] = Field(default=None) redis_timeout: float = Field(default=0.10) - thl_redis: Optional[RedisDsn] = Field(default="redis://127.0.0.1:6379") + thl_redis: Optional[RedisDsn] = Field(default=None) - dask: Optional[DaskDsn] = Field(default="tcp://127.0.0.1:8786", description="") + dask: Optional[DaskDsn] = Field(default=None, description="") sentry: Optional[SentryDsn] = Field( default=None, description="The sentry.io DSN for connecting to a project" ) - thl_mkpl_rw_db: Optional[MariaDBDsn] = Field(default="mariadb://root:@127.0.0.1/") - thl_mkpl_rr_db: Optional[MariaDBDsn] = Field(default="mariadb://root:@127.0.0.1/") + thl_mkpl_rw_db: Optional[MariaDBDsn] = Field(default=None) + thl_mkpl_rr_db: Optional[MariaDBDsn] = Field(default=None) # Primary DB, SELECT permissions - thl_web_ro_db: Optional[PostgresDsn] = Field( - default="postgres://postgres:password@localhost:5432/thl" - ) + thl_web_ro_db: Optional[PostgresDsn] = Field(default=None) # Primary DB, SELECT, INSERT, UPDATE permissions thl_web_rw_db: Optional[PostgresDsn] = Field(default=None) # Primary DB, SELECT, INSERT, UPDATE, DELETE permissions @@ -61,7 +60,7 @@ class GRLBaseSettings(BaseSettings): # Slave/secondary/read-replica SELECT permission only thl_web_rr_db: Optional[PostgresDsn] = Field(default=None) - tmp_dir: DirectoryPath = Field(default="/tmp") + tmp_dir: DirectoryPath = Field(default=Path("/tmp")) spectrum_rw_db: Optional[MariaDBDsn] = Field(default=None) spectrum_rr_db: Optional[MariaDBDsn] = Field(default=None) @@ -71,7 +70,7 @@ class GRLBaseSettings(BaseSettings): # --- GR ---- gr_db: Optional[PostgresDsn] = Field(default=None) - gr_redis: Optional[RedisDsn] = Field(default="redis://127.0.0.1:6379") + gr_redis: Optional[RedisDsn] = Field(default=None) # --- GRL IQ --- grliq_db: Optional[PostgresDsn] = Field(default=None) @@ -93,8 +92,8 @@ class GRLBaseSettings(BaseSettings): tango_customer_id: Optional[str] = Field(default=None) # --- Keeping this here as we use these ids regardless of the AMT account - amt_bonus_cashout_method: Optional[str] = Field(default=None) - amt_assignment_cashout_method: Optional[str] = Field(default=None) + amt_bonus_cashout_method_id: Optional[str] = Field(default=None) + amt_assignment_cashout_method_id: Optional[str] = Field(default=None) # --- Maxmind Configuration --- maxmind_account_id: Optional[str] = Field(default=None) diff --git a/generalresearch/managers/thl/ledger_manager/ledger.py b/generalresearch/managers/thl/ledger_manager/ledger.py index 419f613..3c65cbd 100644 --- a/generalresearch/managers/thl/ledger_manager/ledger.py +++ b/generalresearch/managers/thl/ledger_manager/ledger.py @@ -1,7 +1,7 @@ import logging from collections import defaultdict -from datetime import timedelta, datetime, timezone -from typing import Optional, List, Dict, Callable, Collection, Tuple, Set +from datetime import datetime, timedelta, timezone +from typing import Callable, Collection, Dict, List, Optional, Set, Tuple from uuid import UUID import redis @@ -18,20 +18,20 @@ from generalresearch.managers.base import ( ) from generalresearch.managers.thl.ledger_manager.exceptions import ( LedgerAccountDoesntExistError, + LedgerTransactionConditionFailedError, + LedgerTransactionCreateError, + LedgerTransactionCreateLockError, LedgerTransactionDoesntExistError, LedgerTransactionFlagAlreadyExistsError, - LedgerTransactionCreateLockError, - LedgerTransactionConditionFailedError, LedgerTransactionReleaseLockError, - LedgerTransactionCreateError, ) from generalresearch.models.custom_types import UUIDStr, check_valid_uuid from generalresearch.models.thl.ledger import ( LedgerAccount, - LedgerTransaction, LedgerEntry, - UserLedgerTransactionTypesSummary, + LedgerTransaction, UserLedgerTransactionType, + UserLedgerTransactionTypesSummary, ) from generalresearch.pg_helper import PostgresConfig from generalresearch.redis_helper import RedisConfig diff --git a/generalresearch/models/thl/product.py b/generalresearch/models/thl/product.py index 8f1c668..949f1f8 100644 --- a/generalresearch/models/thl/product.py +++ b/generalresearch/models/thl/product.py @@ -3,39 +3,39 @@ from __future__ import annotations import copy import inspect import json +import math import warnings from collections import defaultdict from decimal import Decimal from enum import Enum -from functools import partial, cached_property +from functools import cached_property, partial from typing import ( - Optional, - List, - Callable, + TYPE_CHECKING, Any, - Literal, + Callable, Dict, + List, + Literal, + Optional, Set, - TYPE_CHECKING, ) -from urllib.parse import parse_qs, urlsplit, urlencode, urlunsplit +from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit from uuid import uuid4 -import math import pandas as pd from dask.distributed import Client from pydantic import ( BaseModel, + ConfigDict, Field, - model_validator, - field_validator, - field_serializer, - NonNegativeInt, NonNegativeFloat, - computed_field, - ConfigDict, - PositiveInt, + NonNegativeInt, PositiveFloat, + PositiveInt, + computed_field, + field_serializer, + field_validator, + model_validator, ) from pydantic.json_schema import SkipJsonSchema from typing_extensions import Self @@ -44,17 +44,21 @@ from generalresearch.currency import USDCent from generalresearch.decorators import LOG from generalresearch.models import Source from generalresearch.models.custom_types import ( - UUIDStr, AwareDatetimeISO, - HttpsUrlStr, CountryISOLike, + HttpsUrlStr, + UUIDStr, ) from generalresearch.models.thl.ledger import LedgerAccount from generalresearch.models.thl.payout_format import ( PayoutFormatType, + format_payout_format, +) +from generalresearch.models.thl.payout_format import ( description as payout_format_description, +) +from generalresearch.models.thl.payout_format import ( examples as payout_format_examples, - format_payout_format, ) from generalresearch.models.thl.supplier_tag import SupplierTag from generalresearch.models.thl.wallet import PayoutType @@ -62,21 +66,20 @@ from generalresearch.models.utils import decimal_to_usd_cents from generalresearch.redis_helper import RedisConfig if TYPE_CHECKING: - from generalresearch.models.thl.payout import ( - BrokerageProductPayoutEvent, - ) from generalresearch.incite.base import GRLDatasets - - from generalresearch.managers.thl.payout import ( - BrokerageProductPayoutEventManager, - ) + from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge from generalresearch.managers.thl.ledger_manager.thl_ledger import ( ThlLedgerManager, ) - from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge + from generalresearch.managers.thl.payout import ( + BrokerageProductPayoutEventManager, + ) from generalresearch.models.thl.finance import ( - ProductBalances, POPFinancial, + ProductBalances, + ) + from generalresearch.models.thl.payout import ( + BrokerageProductPayoutEvent, ) from generalresearch.models.thl.user import User @@ -1152,13 +1155,13 @@ class Product(BaseModel, validate_assignment=True): if self.bp_account is None: self.prefetch_bp_account(thl_lm=thl_lm) + from generalresearch.incite.schemas.mergers.pop_ledger import ( + numerical_col_names, + ) from generalresearch.models.admin.request import ( ReportRequest, ReportType, ) - from generalresearch.incite.schemas.mergers.pop_ledger import ( - numerical_col_names, - ) rr = ReportRequest(report_type=ReportType.POP_LEDGER, interval="5min") diff --git a/pyproject.toml b/pyproject.toml index 8039ae1..93bdca2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,22 +36,17 @@ dependencies = [ "wrapt", ] [project.optional-dependencies] -django = [ - "Django>=5.2", - "psycopg>=3.1", -] +django = ["Django>=5.2", "psycopg>=3.1"] [tool.setuptools.packages.find] where = ["."] -include = [ - "generalresearch", - "generalresearch.*", - "test_utils", - "test_utils.*", -] +include = ["generalresearch", "generalresearch.*", "test_utils", "test_utils.*"] [tool.setuptools.package-data] "generalresearch" = ["locales/*.json", "resources/*.csv"] "test_utils" = ["managers/upk/*.gz"] +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-v --tb=short" diff --git a/test_utils/conftest.py b/test_utils/conftest.py index 7acafc5..e074301 100644 --- a/test_utils/conftest.py +++ b/test_utils/conftest.py @@ -1,12 +1,13 @@ import os import shutil -from datetime import datetime, timezone from os.path import join as pjoin +from pathlib import Path from typing import TYPE_CHECKING, Callable from uuid import uuid4 import pytest import redis +from _pytest.config import Config from dotenv import load_dotenv from pydantic import MariaDBDsn from redis import Redis @@ -16,13 +17,15 @@ from generalresearch.redis_helper import RedisConfig from generalresearch.sql_helper import SqlHelper if TYPE_CHECKING: + from datetime import datetime + + from generalresearch.config import GRLBaseSettings from generalresearch.currency import USDCent from generalresearch.models.thl.session import Status - from generalresearch.config import GRLBaseSettings @pytest.fixture(scope="session") -def env_file_path(pytestconfig): +def env_file_path(pytestconfig: Config) -> str: root_path = pytestconfig.rootpath env_path = os.path.join(root_path, ".env.test") @@ -33,7 +36,7 @@ def env_file_path(pytestconfig): @pytest.fixture(scope="session") -def settings(env_file_path) -> "GRLBaseSettings": +def settings(env_file_path: str) -> "GRLBaseSettings": from generalresearch.config import GRLBaseSettings s = GRLBaseSettings(_env_file=env_file_path) @@ -53,7 +56,8 @@ def settings(env_file_path) -> "GRLBaseSettings": @pytest.fixture(scope="session") -def thl_web_rr(settings) -> PostgresConfig: +def thl_web_rr(settings: "GRLBaseSettings") -> PostgresConfig: + assert settings.thl_web_rr_db is not None assert "/unittest-" in settings.thl_web_rr_db.path return PostgresConfig( @@ -64,7 +68,8 @@ def thl_web_rr(settings) -> PostgresConfig: @pytest.fixture(scope="session") -def thl_web_rw(settings) -> PostgresConfig: +def thl_web_rw(settings: "GRLBaseSettings") -> PostgresConfig: + assert settings.thl_web_rw_db is not None assert "/unittest-" in settings.thl_web_rw_db.path return PostgresConfig( @@ -75,13 +80,14 @@ def thl_web_rw(settings) -> PostgresConfig: @pytest.fixture(scope="session") -def gr_db(settings) -> PostgresConfig: +def gr_db(settings: "GRLBaseSettings") -> PostgresConfig: assert "/unittest-" in settings.gr_db.path return PostgresConfig(dsn=settings.gr_db, connect_timeout=5, statement_timeout=2) @pytest.fixture(scope="session") -def spectrum_rw(settings) -> SqlHelper: +def spectrum_rw(settings: "GRLBaseSettings") -> SqlHelper: + assert settings.spectrum_rw_db is not None assert "/unittest-" in settings.spectrum_rw_db.path return SqlHelper( @@ -93,7 +99,8 @@ def spectrum_rw(settings) -> SqlHelper: @pytest.fixture(scope="session") -def grliq_db(settings) -> PostgresConfig: +def grliq_db(settings: "GRLBaseSettings") -> PostgresConfig: + assert settings.grliq_db is not None assert "/unittest-" in settings.grliq_db.path # test_words = {"localhost", "127.0.0.1", "unittest", "grliq-test"} @@ -108,7 +115,7 @@ def grliq_db(settings) -> PostgresConfig: @pytest.fixture(scope="session") -def thl_redis(settings) -> "Redis": +def thl_redis(settings: "GRLBaseSettings") -> "Redis": # todo: this should get replaced with redisconfig (in most places) # I'm not sure where this would be? in the domain name? assert "unittest" in str(settings.thl_redis) or "127.0.0.1" in str( @@ -126,7 +133,7 @@ def thl_redis(settings) -> "Redis": @pytest.fixture(scope="session") -def thl_redis_config(settings) -> RedisConfig: +def thl_redis_config(settings: "GRLBaseSettings") -> RedisConfig: assert "unittest" in str(settings.thl_redis) or "127.0.0.1" in str( settings.thl_redis ) @@ -139,7 +146,7 @@ def thl_redis_config(settings) -> RedisConfig: @pytest.fixture(scope="session") -def gr_redis_config(settings) -> "RedisConfig": +def gr_redis_config(settings: "GRLBaseSettings") -> "RedisConfig": assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis) return RedisConfig( @@ -151,7 +158,7 @@ def gr_redis_config(settings) -> "RedisConfig": @pytest.fixture(scope="session") -def gr_redis(settings) -> "Redis": +def gr_redis(settings: "GRLBaseSettings") -> "Redis": assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis) return redis.Redis.from_url( **{ @@ -163,8 +170,8 @@ def gr_redis(settings) -> "Redis": ) -@pytest.fixture() -def gr_redis_async(settings): +@pytest.fixture +def gr_redis_async(settings: "GRLBaseSettings"): assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis) import redis.asyncio as redis_async @@ -180,8 +187,10 @@ def gr_redis_async(settings): # === Random helpers === -@pytest.fixture(scope="function") -def start(): +@pytest.fixture +def start() -> "datetime": + from datetime import datetime, timezone + return datetime(year=1900, month=1, day=1, tzinfo=timezone.utc) @@ -192,44 +201,44 @@ def wall_status(request) -> "Status": return request.param if hasattr(request, "wall_status") else Status.COMPLETE -@pytest.fixture(scope="function") +@pytest.fixture def utc_now() -> "datetime": from datetime import datetime, timezone return datetime.now(tz=timezone.utc) -@pytest.fixture(scope="function") +@pytest.fixture def utc_hour_ago() -> "datetime": - from datetime import datetime, timezone, timedelta + from datetime import datetime, timedelta, timezone return datetime.now(tz=timezone.utc) - timedelta(hours=1) -@pytest.fixture(scope="function") +@pytest.fixture def utc_day_ago() -> "datetime": - from datetime import datetime, timezone, timedelta + from datetime import datetime, timedelta, timezone return datetime.now(tz=timezone.utc) - timedelta(hours=24) -@pytest.fixture(scope="function") +@pytest.fixture def utc_90days_ago() -> "datetime": - from datetime import datetime, timezone, timedelta + from datetime import datetime, timedelta, timezone return datetime.now(tz=timezone.utc) - timedelta(days=90) -@pytest.fixture(scope="function") +@pytest.fixture def utc_60days_ago() -> "datetime": - from datetime import datetime, timezone, timedelta + from datetime import datetime, timedelta, timezone return datetime.now(tz=timezone.utc) - timedelta(days=60) -@pytest.fixture(scope="function") +@pytest.fixture def utc_30days_ago() -> "datetime": - from datetime import datetime, timezone, timedelta + from datetime import datetime, timedelta, timezone return datetime.now(tz=timezone.utc) - timedelta(days=30) @@ -301,7 +310,7 @@ def amount_100(request) -> "USDCent": return USDCent(100) -def clear_directory(path): +def clear_directory(path: Path): for entry in os.listdir(path): full_path = os.path.join(path, entry) if os.path.isfile(full_path) or os.path.islink(full_path): diff --git a/test_utils/incite/collections/conftest.py b/test_utils/incite/collections/conftest.py index 1b61ed5..cf4f0ed 100644 --- a/test_utils/incite/collections/conftest.py +++ b/test_utils/incite/collections/conftest.py @@ -1,5 +1,6 @@ from datetime import timedelta, datetime from typing import TYPE_CHECKING, Optional, Callable +from generalresearch.pg_helper import PostgresConfig import pytest @@ -25,7 +26,7 @@ def user_collection( offset: str, duration: timedelta, start: datetime, - thl_web_rr, + thl_web_rr: PostgresConfig, ) -> "UserDFCollection": from generalresearch.incite.collections.thl_web import ( UserDFCollection, @@ -47,7 +48,7 @@ def wall_collection( offset: str, duration: timedelta, start: datetime, - thl_web_rr, + thl_web_rr: PostgresConfig, ) -> "WallDFCollection": from generalresearch.incite.collections.thl_web import ( WallDFCollection, @@ -69,7 +70,7 @@ def session_collection( offset: str, duration: timedelta, start: datetime, - thl_web_rr, + thl_web_rr: PostgresConfig, ) -> "SessionDFCollection": from generalresearch.incite.collections.thl_web import ( SessionDFCollection, @@ -153,7 +154,7 @@ def ledger_collection( offset: str, duration: timedelta, start: datetime, - thl_web_rr, + thl_web_rr: PostgresConfig, ) -> "LedgerDFCollection": from generalresearch.incite.collections.thl_web import ( LedgerDFCollection, @@ -170,11 +171,12 @@ def ledger_collection( @pytest.fixture(scope="function") -def rm_ledger_collection(ledger_collection) -> Callable: - def _rm_ledger_collection(): +def rm_ledger_collection(ledger_collection: "LedgerDFCollection") -> Callable: + + def _inner(): clear_directory(ledger_collection.archive_path) - return _rm_ledger_collection + return _inner # -------------------------- @@ -184,12 +186,12 @@ def rm_ledger_collection(ledger_collection) -> Callable: @pytest.fixture(scope="function") def df_collection( - mnt_filepath, + mnt_filepath: "GRLDatasets", df_collection_data_type: "DFCollectionType", - offset, - duration, - utc_90days_ago, - thl_web_rr, + offset: str, + duration: timedelta, + utc_90days_ago: datetime, + thl_web_rr: PostgresConfig, ) -> "DFCollection": from generalresearch.incite.collections import DFCollection diff --git a/test_utils/incite/conftest.py b/test_utils/incite/conftest.py index 759467a..9632ee5 100644 --- a/test_utils/incite/conftest.py +++ b/test_utils/incite/conftest.py @@ -1,33 +1,41 @@ -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone from os.path import join as pjoin from pathlib import Path from random import choice as randchoice from shutil import rmtree -from typing import Callable, TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Callable, Optional from uuid import uuid4 import pytest from _pytest.fixtures import SubRequest from faker import Faker -from test_utils.managers.ledger.conftest import session_with_tx_factory -from test_utils.models.conftest import session_factory +# from test_utils.managers.ledger.conftest import session_with_tx_factory +# from test_utils.models.conftest import session_factory if TYPE_CHECKING: - from generalresearch.models.thl.user import User + from generalresearch.config import GRLSettings from generalresearch.incite.base import GRLDatasets - from generalresearch.incite.mergers import MergeType from generalresearch.incite.collections import ( DFCollection, - DFCollectionType, DFCollectionItem, + DFCollectionType, ) + from generalresearch.incite.mergers import MergeType + from generalresearch.models.admin.request import ( + ReportRequest, + ReportType, + ) + from generalresearch.models.thl.product import Product + from generalresearch.models.thl.session import Session + from generalresearch.models.thl.user import User + fake = Faker() -@pytest.fixture(scope="function") -def mnt_gr_api_dir(request: SubRequest, settings): +@pytest.fixture +def mnt_gr_api_dir(request: SubRequest, settings: "GRLSettings") -> Path: p = Path(settings.mnt_gr_api_dir) p.mkdir(parents=True, exist_ok=True) @@ -49,8 +57,8 @@ def mnt_gr_api_dir(request: SubRequest, settings): return p -@pytest.fixture(scope="function") -def event_report_request(utc_hour_ago, start): +@pytest.fixture +def event_report_request(utc_hour_ago: datetime, start: datetime) -> "ReportRequest": from generalresearch.models.admin.request import ( ReportRequest, ReportType, @@ -65,8 +73,8 @@ def event_report_request(utc_hour_ago, start): ) -@pytest.fixture(scope="function") -def session_report_request(utc_hour_ago, start): +@pytest.fixture +def session_report_request(utc_hour_ago: datetime, start: datetime) -> "ReportRequest": from generalresearch.models.admin.request import ( ReportRequest, ReportType, @@ -81,10 +89,11 @@ def session_report_request(utc_hour_ago, start): ) -@pytest.fixture(scope="function") +@pytest.fixture def mnt_filepath(request: SubRequest) -> "GRLDatasets": - """Creates a temporary file path for all DFCollections & Mergers parquet - files. + """ + Creates a temporary file path for all DFCollections & + Mergers parquet files. """ from generalresearch.incite.base import GRLDatasets, NFSMount @@ -106,44 +115,45 @@ def mnt_filepath(request: SubRequest) -> "GRLDatasets": return instance -@pytest.fixture(scope="function") -def start(utc_90days_ago) -> "datetime": +@pytest.fixture +def start(utc_90days_ago: datetime) -> "datetime": s = utc_90days_ago.replace(microsecond=0) return s -@pytest.fixture(scope="function") +@pytest.fixture def offset() -> str: return "15min" -@pytest.fixture(scope="function") +@pytest.fixture def duration() -> Optional["timedelta"]: return timedelta(hours=1) -@pytest.fixture(scope="function") +@pytest.fixture def df_collection_data_type() -> "DFCollectionType": from generalresearch.incite.collections import DFCollectionType return DFCollectionType.TEST -@pytest.fixture(scope="function") +@pytest.fixture def merge_type() -> "MergeType": from generalresearch.incite.mergers import MergeType return MergeType.TEST -@pytest.fixture(scope="function") +@pytest.fixture def incite_item_factory( - session_factory, - product, - user_factory, - session_with_tx_factory, -) -> Callable: - def _incite_item_factory( + session_factory: Callable[..., "Session"], + product: "Product", + user_factory: Callable[..., "User"], + session_with_tx_factory: Callable[..., "Session"], +) -> Callable[..., None]: + + def _inner( item: "DFCollectionItem", observations: int = 3, user: Optional["User"] = None, @@ -157,7 +167,7 @@ def incite_item_factory( collection: DFCollection = item._collection data_type: DFCollectionType = collection.data_type - for idx in range(5): + for _ in range(5): item_time = fake.date_time_between( start_date=item.start, end_date=item.finish, tzinfo=timezone.utc ) @@ -198,4 +208,4 @@ def incite_item_factory( return None - return _incite_item_factory + return _inner diff --git a/test_utils/incite/mergers/conftest.py b/test_utils/incite/mergers/conftest.py index e4e3bdd..010c44f 100644 --- a/test_utils/incite/mergers/conftest.py +++ b/test_utils/incite/mergers/conftest.py @@ -1,5 +1,5 @@ -from datetime import timedelta, datetime -from typing import TYPE_CHECKING, Optional, Callable +from datetime import datetime, timedelta +from typing import TYPE_CHECKING, Callable, Optional import pytest @@ -7,14 +7,8 @@ from test_utils.conftest import clear_directory from test_utils.incite.conftest import mnt_filepath if TYPE_CHECKING: - from generalresearch.incite.mergers import MergeType - from generalresearch.incite.mergers.ym_wall_summary import ( - YMWallSummaryMerge, - YMWallSummaryMergeItem, - ) - from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge - from generalresearch.incite.mergers.ym_survey_wall import YMSurveyWallMerge from generalresearch.incite.base import GRLDatasets + from generalresearch.incite.mergers import MergeType from generalresearch.incite.mergers.foundations.enriched_session import ( EnrichedSessionMerge, ) @@ -27,9 +21,15 @@ if TYPE_CHECKING: from generalresearch.incite.mergers.foundations.user_id_product import ( UserIdProductMerge, ) + from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge from generalresearch.incite.mergers.ym_survey_wall import ( + YMSurveyWallMerge, YMSurveyWallMergeCollectionItem, ) + from generalresearch.incite.mergers.ym_wall_summary import ( + YMWallSummaryMerge, + YMWallSummaryMergeItem, + ) # -------------------------- @@ -38,11 +38,12 @@ if TYPE_CHECKING: @pytest.fixture(scope="function") -def rm_pop_ledger_merge(pop_ledger_merge) -> Callable: - def _rm_pop_ledger_merge(): +def rm_pop_ledger_merge(pop_ledger_merge) -> Callable[..., None]: + + def _inner(): clear_directory(pop_ledger_merge.archive_path) - return _rm_pop_ledger_merge + return _inner @pytest.fixture(scope="function") @@ -52,8 +53,9 @@ def pop_ledger_merge( start: datetime, duration: timedelta, ) -> "PopLedgerMerge": - from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge + from generalresearch.incite.mergers import MergeType + from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge return PopLedgerMerge( start=start, @@ -65,9 +67,10 @@ def pop_ledger_merge( @pytest.fixture(scope="function") def pop_ledger_merge_item( - start, - pop_ledger_merge, + start: datetime, + pop_ledger_merge: "PopLedgerMerge", ) -> "PopLedgerMergeItem": + from generalresearch.incite.mergers.pop_ledger import PopLedgerMergeItem return PopLedgerMergeItem( @@ -81,8 +84,8 @@ def ym_survey_wall_merge( mnt_filepath: "GRLDatasets", start: datetime, ) -> "YMSurveyWallMerge": - from generalresearch.incite.mergers.ym_survey_wall import YMSurveyWallMerge from generalresearch.incite.mergers import MergeType + from generalresearch.incite.mergers.ym_survey_wall import YMSurveyWallMerge return YMSurveyWallMerge( start=None, @@ -93,7 +96,7 @@ def ym_survey_wall_merge( @pytest.fixture(scope="function") def ym_survey_wall_merge_item( - start, ym_survey_wall_merge + start: datetime, ym_survey_wall_merge: "YMSurveyWallMerge" ) -> "YMSurveyWallMergeCollectionItem": from generalresearch.incite.mergers.ym_survey_wall import ( YMSurveyWallMergeCollectionItem, @@ -112,8 +115,8 @@ def ym_wall_summary_merge( duration: timedelta, start: datetime, ) -> "YMWallSummaryMerge": - from generalresearch.incite.mergers.ym_wall_summary import YMWallSummaryMerge from generalresearch.incite.mergers import MergeType + from generalresearch.incite.mergers.ym_wall_summary import YMWallSummaryMerge return YMWallSummaryMerge( start=start, @@ -124,7 +127,7 @@ def ym_wall_summary_merge( def ym_wall_summary_merge_item( - start, ym_wall_summary_merge + start: datetime, ym_wall_summary_merge: "YMWallSummaryMerge" ) -> "YMWallSummaryMergeItem": from generalresearch.incite.mergers.ym_wall_summary import ( YMWallSummaryMergeItem, @@ -148,10 +151,10 @@ def enriched_session_merge( duration: timedelta, start: datetime, ) -> "EnrichedSessionMerge": + from generalresearch.incite.mergers import MergeType from generalresearch.incite.mergers.foundations.enriched_session import ( EnrichedSessionMerge, ) - from generalresearch.incite.mergers import MergeType return EnrichedSessionMerge( start=start, @@ -168,10 +171,10 @@ def enriched_task_adjust_merge( duration: timedelta, start: datetime, ) -> "EnrichedTaskAdjustMerge": + from generalresearch.incite.mergers import MergeType from generalresearch.incite.mergers.foundations.enriched_task_adjust import ( EnrichedTaskAdjustMerge, ) - from generalresearch.incite.mergers import MergeType return EnrichedTaskAdjustMerge( start=start, @@ -207,13 +210,13 @@ def enriched_wall_merge( def user_id_product_merge( mnt_filepath: "GRLDatasets", duration: timedelta, - offset, + offset: str, start: datetime, ) -> "UserIdProductMerge": + from generalresearch.incite.mergers import MergeType from generalresearch.incite.mergers.foundations.user_id_product import ( UserIdProductMerge, ) - from generalresearch.incite.mergers import MergeType return UserIdProductMerge( start=start, @@ -230,11 +233,11 @@ def user_id_product_merge( @pytest.fixture(scope="function") def merge_collection( - mnt_filepath, + mnt_filepath: "GRLDatasets", merge_type: "MergeType", - offset, - duration, - start, + offset: str, + duration: timedelta, + start: datetime, ): from generalresearch.incite.mergers import MergeCollection diff --git a/test_utils/managers/cashout_methods.py b/test_utils/managers/cashout_methods.py index c338676..96d33cf 100644 --- a/test_utils/managers/cashout_methods.py +++ b/test_utils/managers/cashout_methods.py @@ -49,28 +49,28 @@ EXAMPLE_TANGO_CASHOUT_METHODS = [ ), ] -AMT_ASSIGNMENT_CASHOUT_METHOD = CashoutMethod( - id=uuid4().hex, - last_updated="2021-06-23T20:45:38.239182Z", - is_live=True, - type=PayoutType.AMT, - ext_id=None, - name="AMT Assignment", - data=AmtCashoutMethodData(), - user=None, - min_value=1, - max_value=5, -) +# AMT_ASSIGNMENT_CASHOUT_METHOD = CashoutMethod( +# id=uuid4().hex, +# last_updated="2021-06-23T20:45:38.239182Z", +# is_live=True, +# type=PayoutType.AMT, +# ext_id=None, +# name="AMT Assignment", +# data=AmtCashoutMethodData(), +# user=None, +# min_value=1, +# max_value=5, +# ) -AMT_BONUS_CASHOUT_METHOD = CashoutMethod( - id=uuid4().hex, - last_updated="2021-06-23T20:45:38.239182Z", - is_live=True, - type=PayoutType.AMT, - ext_id=None, - name="AMT Bonus", - data=AmtCashoutMethodData(), - user=None, - min_value=7, - max_value=4000, -) +# AMT_BONUS_CASHOUT_METHOD = CashoutMethod( +# id=uuid4().hex, +# last_updated="2021-06-23T20:45:38.239182Z", +# is_live=True, +# type=PayoutType.AMT, +# ext_id=None, +# name="AMT Bonus", +# data=AmtCashoutMethodData(), +# user=None, +# min_value=7, +# max_value=4000, +# ) diff --git a/test_utils/managers/conftest.py b/test_utils/managers/conftest.py index 3a237d1..f1f774e 100644 --- a/test_utils/managers/conftest.py +++ b/test_utils/managers/conftest.py @@ -1,4 +1,4 @@ -from typing import Callable, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable import pymysql import pytest @@ -7,8 +7,6 @@ from generalresearch.managers.base import Permission from generalresearch.models import Source from test_utils.managers.cashout_methods import ( EXAMPLE_TANGO_CASHOUT_METHODS, - AMT_ASSIGNMENT_CASHOUT_METHOD, - AMT_BONUS_CASHOUT_METHOD, ) if TYPE_CHECKING: @@ -21,26 +19,18 @@ if TYPE_CHECKING: from generalresearch.grliq.managers.forensic_results import ( GrlIqCategoryResultsReader, ) - from generalresearch.managers.thl.userhealth import AuditLogManager - from generalresearch.managers.thl.payout import ( - BusinessPayoutEventManager, - ) - from generalresearch.managers.thl.maxmind.basic import ( - MaxmindBasicManager, - ) - from generalresearch.managers.gr.authentication import ( - GRUserManager, GRTokenManager, + GRUserManager, ) from generalresearch.managers.gr.business import ( - BusinessManager, BusinessAddressManager, BusinessBankAccountManager, + BusinessManager, ) from generalresearch.managers.gr.team import ( - TeamManager, MembershipManager, + TeamManager, ) from generalresearch.managers.thl.contest_manager import ContestManager from generalresearch.managers.thl.ipinfo import ( @@ -49,22 +39,28 @@ if TYPE_CHECKING: IPInformationManager, ) from generalresearch.managers.thl.ledger_manager.ledger import ( - LedgerTransactionManager, - LedgerManager, LedgerAccountManager, + LedgerManager, + LedgerTransactionManager, ) from generalresearch.managers.thl.ledger_manager.thl_ledger import ( ThlLedgerManager, ) from generalresearch.managers.thl.maxmind import MaxmindManager - from generalresearch.managers.thl.payout import PayoutEventManager + from generalresearch.managers.thl.maxmind.basic import ( + MaxmindBasicManager, + ) from generalresearch.managers.thl.payout import ( + BrokerageProductPayoutEventManager, + BusinessPayoutEventManager, PayoutEventManager, UserPayoutEventManager, - BrokerageProductPayoutEventManager, ) from generalresearch.managers.thl.product import ProductManager from generalresearch.managers.thl.session import SessionManager + from generalresearch.managers.thl.task_adjustment import ( + TaskAdjustmentManager, + ) from generalresearch.managers.thl.user_manager.user_manager import ( UserManager, ) @@ -73,18 +69,14 @@ if TYPE_CHECKING: ) from generalresearch.managers.thl.userhealth import ( AuditLogManager, - IPRecordManager, - UserIpHistoryManager, IPGeonameManager, IPInformationManager, IPRecordManager, + UserIpHistoryManager, ) from generalresearch.managers.thl.wall import ( - WallManager, WallCacheManager, - ) - from generalresearch.managers.thl.task_adjustment import ( - TaskAdjustmentManager, + WallManager, ) @@ -539,7 +531,9 @@ def delete_cashoutmethod_db(thl_web_rw) -> Callable: @pytest.fixture(scope="session") -def setup_cashoutmethod_db(cashout_method_manager, delete_cashoutmethod_db): +def setup_cashoutmethod_db(settings, cashout_method_manager, delete_cashoutmethod_db): + settings.amt_ + delete_cashoutmethod_db() for x in EXAMPLE_TANGO_CASHOUT_METHODS: cashout_method_manager.create(x) diff --git a/test_utils/managers/contest/conftest.py b/test_utils/managers/contest/conftest.py index c2d4ef6..0a25185 100644 --- a/test_utils/managers/contest/conftest.py +++ b/test_utils/managers/contest/conftest.py @@ -1,6 +1,6 @@ from datetime import datetime, timezone from decimal import Decimal -from typing import Callable, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable from uuid import uuid4 import pytest @@ -8,29 +8,27 @@ import pytest from generalresearch.currency import USDCent if TYPE_CHECKING: - from generalresearch.models.thl.contest.contest import Contest + from generalresearch.managers.thl.contest_manager import ContestManager from generalresearch.models.thl.contest import ( - ContestPrize, ContestEndCondition, + ContestPrize, ) - + from generalresearch.models.thl.contest.contest import Contest from generalresearch.models.thl.contest.definitions import ( - ContestType, ContestPrizeKind, + ContestType, ) from generalresearch.models.thl.contest.io import contest_create_to_contest from generalresearch.models.thl.contest.leaderboard import ( LeaderboardContestCreate, ) from generalresearch.models.thl.contest.milestone import ( - MilestoneContestCreate, ContestEntryTrigger, + MilestoneContestCreate, MilestoneContestEndCondition, ) from generalresearch.models.thl.contest.raffle import ( ContestEntryType, - ) - from generalresearch.models.thl.contest.raffle import ( RaffleContestCreate, ) from generalresearch.models.thl.product import Product @@ -39,19 +37,17 @@ if TYPE_CHECKING: @pytest.fixture def raffle_contest_create() -> "RaffleContestCreate": - from generalresearch.models.thl.contest.raffle import ( - RaffleContestCreate, - ) from generalresearch.models.thl.contest import ( - ContestPrize, ContestEndCondition, + ContestPrize, ) from generalresearch.models.thl.contest.definitions import ( - ContestType, ContestPrizeKind, + ContestType, ) from generalresearch.models.thl.contest.raffle import ( ContestEntryType, + RaffleContestCreate, ) # This is what we'll get from the fastapi endpoint @@ -74,7 +70,7 @@ def raffle_contest_create() -> "RaffleContestCreate": def raffle_contest_in_db( product_user_wallet_yes: "Product", raffle_contest_create: "RaffleContestCreate", - contest_manager, + contest_manager: "ContestManager", ) -> "Contest": return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create @@ -96,16 +92,17 @@ def raffle_contest( def raffle_contest_factory( product_user_wallet_yes: "Product", raffle_contest_create: "RaffleContestCreate", - contest_manager, -) -> Callable: - def _create_contest(**kwargs): + contest_manager: "ContestManager", +) -> Callable[..., "Contest"]: + + def _inner(**kwargs): raffle_contest_create.update(**kwargs) return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create, ) - return _create_contest + return _inner @pytest.fixture @@ -114,12 +111,12 @@ def milestone_contest_create() -> "MilestoneContestCreate": ContestPrize, ) from generalresearch.models.thl.contest.definitions import ( - ContestType, ContestPrizeKind, + ContestType, ) from generalresearch.models.thl.contest.milestone import ( - MilestoneContestCreate, ContestEntryTrigger, + MilestoneContestCreate, MilestoneContestEndCondition, ) @@ -154,7 +151,7 @@ def milestone_contest_create() -> "MilestoneContestCreate": def milestone_contest_in_db( product_user_wallet_yes: "Product", milestone_contest_create: "MilestoneContestCreate", - contest_manager, + contest_manager: "ContestManager", ) -> "Contest": return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create @@ -177,31 +174,32 @@ def milestone_contest( def milestone_contest_factory( product_user_wallet_yes: "Product", milestone_contest_create: "MilestoneContestCreate", - contest_manager, -) -> Callable: - def _create_contest(**kwargs): + contest_manager: "ContestManager", +) -> Callable[..., "Contest"]: + + def _inner(**kwargs): milestone_contest_create.update(**kwargs) return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create, ) - return _create_contest + return _inner @pytest.fixture def leaderboard_contest_create( product_user_wallet_yes: "Product", ) -> "LeaderboardContestCreate": - from generalresearch.models.thl.contest.leaderboard import ( - LeaderboardContestCreate, - ) from generalresearch.models.thl.contest import ( ContestPrize, ) from generalresearch.models.thl.contest.definitions import ( - ContestType, ContestPrizeKind, + ContestType, + ) + from generalresearch.models.thl.contest.leaderboard import ( + LeaderboardContestCreate, ) # This is what we'll get from the fastapi endpoint @@ -232,7 +230,7 @@ def leaderboard_contest_create( def leaderboard_contest_in_db( product_user_wallet_yes: "Product", leaderboard_contest_create: "LeaderboardContestCreate", - contest_manager, + contest_manager: "ContestManager", ) -> "Contest": return contest_manager.create( product_id=product_user_wallet_yes.uuid, @@ -257,21 +255,25 @@ def leaderboard_contest( def leaderboard_contest_factory( product_user_wallet_yes: "Product", leaderboard_contest_create: "LeaderboardContestCreate", - contest_manager, -) -> Callable: - def _create_contest(**kwargs): + contest_manager: "ContestManager", +) -> Callable[..., "Contest"]: + + def _inner(**kwargs): leaderboard_contest_create.update(**kwargs) return contest_manager.create( product_id=product_user_wallet_yes.uuid, contest_create=leaderboard_contest_create, ) - return _create_contest + return _inner @pytest.fixture def user_with_money( - request, user_factory, product_user_wallet_yes: "Product", thl_lm + request, + user_factory: Callable[..., "User"], + product_user_wallet_yes: "Product", + thl_lm, ) -> "User": from generalresearch.models.thl.user import User diff --git a/test_utils/managers/ledger/conftest.py b/test_utils/managers/ledger/conftest.py index b96d612..aafdaf7 100644 --- a/test_utils/managers/ledger/conftest.py +++ b/test_utils/managers/ledger/conftest.py @@ -1,25 +1,26 @@ from datetime import datetime from decimal import Decimal from random import randint -from typing import Optional, Dict, Callable, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable, Dict, Optional from uuid import uuid4 import pytest from generalresearch.currency import USDCent +from generalresearch.managers.base import PostgresManager from test_utils.models.conftest import ( - product_factory, - user, + payout_config, product, - user_factory, - product_user_wallet_no, - wall, product_amt_true, + product_factory, + product_user_wallet_no, product_user_wallet_yes, - session_factory, session, + session_factory, + user, + user_factory, + wall, wall_factory, - payout_config, ) _ = ( @@ -35,24 +36,36 @@ _ = ( ) if TYPE_CHECKING: + from datetime import datetime, timedelta + from generalresearch.currency import LedgerCurrency + from generalresearch.managers.thl.ledger_manager.ledger import LedgerManager + from generalresearch.managers.thl.ledger_manager.thl_ledger import ( + ThlLedgerManager, + ) from generalresearch.models.thl.ledger import ( - Direction, AccountType, + Direction, + LedgerAccount, + LedgerEntry, LedgerTransaction, ) - from generalresearch.models.thl.ledger import ( - LedgerEntry, - LedgerAccount, + from generalresearch.models.thl.payout import ( + BrokerageProductPayoutEvent, + UserPayoutEvent, ) - from generalresearch.models.thl.payout import UserPayoutEvent + from generalresearch.models.thl.product import Product + from generalresearch.models.thl.session import Session + from generalresearch.models.thl.user import User -@pytest.fixture(scope="function") -def ledger_account(request, lm, currency) -> "LedgerAccount": +@pytest.fixture +def ledger_account( + request, lm: "LedgerManager", currency: "LedgerCurrency" +) -> "LedgerAccount": from generalresearch.models.thl.ledger import ( - Direction, AccountType, + Direction, LedgerAccount, ) @@ -73,19 +86,22 @@ def ledger_account(request, lm, currency) -> "LedgerAccount": return lm.create_account(account=acct_model) -@pytest.fixture(scope="function") -def ledger_account_factory(request, thl_lm, lm, currency) -> Callable: +@pytest.fixture +def ledger_account_factory( + request, thl_lm: "ThlLedgerManager", lm: "LedgerManager", currency: "LedgerCurrency" +) -> Callable[..., "LedgerAccount"]: + from generalresearch.models.thl.ledger import ( - Direction, AccountType, + Direction, LedgerAccount, ) - def _ledger_account_factory( - product, + def _inner( + product: "Product", account_type: AccountType = AccountType.CASH, direction: Direction = Direction.CREDIT, - ): + ) -> "LedgerAccount": thl_lm.get_account_or_create_bp_wallet(product=product) acct_uuid = uuid4().hex qn = ":".join([currency, account_type, acct_uuid]) @@ -100,12 +116,14 @@ def ledger_account_factory(request, thl_lm, lm, currency) -> Callable: ) return lm.create_account(account=acct_model) - return _ledger_account_factory + return _inner -@pytest.fixture(scope="function") -def ledger_account_credit(request, lm, currency) -> "LedgerAccount": - from generalresearch.models.thl.ledger import Direction, AccountType +@pytest.fixture +def ledger_account_credit( + request, lm: "LedgerManager", currency: "LedgerCurrency" +) -> "LedgerAccount": + from generalresearch.models.thl.ledger import AccountType, Direction account_type = AccountType.REVENUE acct_uuid = uuid4().hex @@ -124,9 +142,11 @@ def ledger_account_credit(request, lm, currency) -> "LedgerAccount": return lm.create_account(account=acct_model) -@pytest.fixture(scope="function") -def ledger_account_debit(request, lm, currency) -> "LedgerAccount": - from generalresearch.models.thl.ledger import Direction, AccountType +@pytest.fixture +def ledger_account_debit( + request, lm: "LedgerManager", currency: "LedgerCurrency" +) -> "LedgerAccount": + from generalresearch.models.thl.ledger import AccountType, Direction account_type = AccountType.EXPENSE acct_uuid = uuid4().hex @@ -145,8 +165,8 @@ def ledger_account_debit(request, lm, currency) -> "LedgerAccount": return lm.create_account(account=acct_model) -@pytest.fixture(scope="function") -def tag(request, lm) -> str: +@pytest.fixture +def tag(request, lm: "LedgerManager") -> str: from generalresearch.currency import LedgerCurrency return ( @@ -156,16 +176,20 @@ def tag(request, lm) -> str: ) -@pytest.fixture(scope="function") +@pytest.fixture def usd_cent(request) -> USDCent: amount = randint(99, 9_999) return request.param if hasattr(request, "usd_cent") else USDCent(amount) -@pytest.fixture(scope="function") +@pytest.fixture def bp_payout_event( - product, usd_cent, business_payout_event_manager, thl_lm + product: "Product", + usd_cent, + business_payout_event_manager, + thl_lm: "ThlLedgerManager", ) -> "UserPayoutEvent": + return business_payout_event_manager.create_bp_payout_event( thl_ledger_manager=thl_lm, product=product, @@ -176,13 +200,18 @@ def bp_payout_event( @pytest.fixture -def bp_payout_event_factory(brokerage_product_payout_event_manager, thl_lm) -> Callable: - from generalresearch.models.thl.product import Product +def bp_payout_event_factory( + brokerage_product_payout_event_manager: "BrokerageProductPayoutEventManager", + thl_lm: "ThlLedgerManager", +) -> Callable[..., "BrokerageProductPayoutEvent"]: + from generalresearch.currency import USDCent + from generalresearch.models.thl.product import Product - def _create_bp_payout_event( + def _inner( product: Product, usd_cent: USDCent, ext_ref_id: Optional[str] = None - ): + ) -> "BrokerageProductPayoutEvent": + return brokerage_product_payout_event_manager.create_bp_payout_event( thl_ledger_manager=thl_lm, product=product, @@ -192,16 +221,16 @@ def bp_payout_event_factory(brokerage_product_payout_event_manager, thl_lm) -> C skip_one_per_day_check=True, ) - return _create_bp_payout_event + return _inner -@pytest.fixture(scope="function") -def currency(lm) -> "LedgerCurrency": +@pytest.fixture +def currency(lm: "LedgerManager") -> "LedgerCurrency": # return request.param if hasattr(request, "currency") else LedgerCurrency.TEST return lm.currency -@pytest.fixture(scope="function") +@pytest.fixture def tx_metadata(request) -> Optional[Dict[str, str]]: return ( request.param @@ -210,15 +239,15 @@ def tx_metadata(request) -> Optional[Dict[str, str]]: ) -@pytest.fixture(scope="function") +@pytest.fixture def ledger_tx( request, ledger_account_credit, ledger_account_debit, tag, - currency, + currency: "LedgerCurrency", tx_metadata, - lm, + lm: "LedgerManager", ) -> "LedgerTransaction": from generalresearch.models.thl.ledger import Direction, LedgerEntry @@ -240,13 +269,16 @@ def ledger_tx( return lm.create_tx(entries=entries, tag=tag, metadata=tx_metadata) -@pytest.fixture(scope="function") -def create_main_accounts(lm, currency) -> Callable: - def _create_main_accounts(): +@pytest.fixture +def create_main_accounts( + lm: "LedgerManager", currency: "LedgerCurrency" +) -> Callable[..., None]: + + def _inner() -> None: from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) account = LedgerAccount( @@ -268,12 +300,15 @@ def create_main_accounts(lm, currency) -> Callable: lm.get_account_or_create(account=account) - return _create_main_accounts + return None + + return _inner -@pytest.fixture(scope="function") -def delete_ledger_db(thl_web_rw) -> Callable: - def _delete_ledger_db(): +@pytest.fixture +def delete_ledger_db(thl_web_rw: "PostgresManager") -> Callable[..., None]: + + def _inner(): for table in [ "ledger_transactionmetadata", "ledger_entry", @@ -284,12 +319,15 @@ def delete_ledger_db(thl_web_rw) -> Callable: query=f"DELETE FROM {table};", ) - return _delete_ledger_db + return _inner + +@pytest.fixture +def wipe_main_accounts( + thl_web_rw: "PostgresManager", lm: "LedgerManager", currency: "LedgerCurrency" +) -> Callable[..., None]: -@pytest.fixture(scope="function") -def wipe_main_accounts(thl_web_rw, lm, currency) -> Callable: - def _wipe_main_accounts(): + def _inner() -> None: db_table = thl_web_rw.db_name qual_names = [ f"{currency.value}:revenue:task_complete", @@ -352,15 +390,17 @@ def wipe_main_accounts(thl_web_rw, lm, currency) -> Callable: commit=True, ) - return _wipe_main_accounts + return None + return _inner -@pytest.fixture(scope="function") -def account_cash(lm, currency) -> "LedgerAccount": + +@pytest.fixture +def account_cash(lm: "LedgerManager", currency: "LedgerCurrency") -> "LedgerAccount": from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) account = LedgerAccount( @@ -373,12 +413,14 @@ def account_cash(lm, currency) -> "LedgerAccount": return lm.get_account_or_create(account=account) -@pytest.fixture(scope="function") -def account_revenue_task_complete(lm, currency) -> "LedgerAccount": +@pytest.fixture +def account_revenue_task_complete( + lm: "LedgerManager", currency: "LedgerCurrency" +) -> "LedgerAccount": from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) account = LedgerAccount( @@ -391,12 +433,14 @@ def account_revenue_task_complete(lm, currency) -> "LedgerAccount": return lm.get_account_or_create(account=account) -@pytest.fixture(scope="function") -def account_expense_tango(lm, currency) -> "LedgerAccount": +@pytest.fixture +def account_expense_tango( + lm: "LedgerManager", currency: "LedgerCurrency" +) -> "LedgerAccount": from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) account = LedgerAccount( @@ -409,12 +453,14 @@ def account_expense_tango(lm, currency) -> "LedgerAccount": return lm.get_account_or_create(account=account) -@pytest.fixture(scope="function") -def user_account_user_wallet(lm, user, currency) -> "LedgerAccount": +@pytest.fixture +def user_account_user_wallet( + lm: "LedgerManager", user, currency: "LedgerCurrency" +) -> "LedgerAccount": from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) account = LedgerAccount( @@ -429,12 +475,14 @@ def user_account_user_wallet(lm, user, currency) -> "LedgerAccount": return lm.get_account_or_create(account=account) -@pytest.fixture(scope="function") -def product_account_bp_wallet(lm, product, currency) -> "LedgerAccount": +@pytest.fixture +def product_account_bp_wallet( + lm: "LedgerManager", product: "Product", currency: "LedgerCurrency" +) -> "LedgerAccount": from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) account = LedgerAccount.model_validate( @@ -451,12 +499,17 @@ def product_account_bp_wallet(lm, product, currency) -> "LedgerAccount": return lm.get_account_or_create(account=account) -@pytest.fixture(scope="function") -def setup_accounts(product_factory, lm, user, currency) -> None: +@pytest.fixture +def setup_accounts( + product_factory: Callable[..., "Product"], + lm: "LedgerManager", + user: "User", + currency: "LedgerCurrency", +) -> None: from generalresearch.models.thl.ledger import ( - LedgerAccount, - Direction, AccountType, + Direction, + LedgerAccount, ) # BP's wallet and a revenue from their commissions account. @@ -522,24 +575,25 @@ def setup_accounts(product_factory, lm, user, currency) -> None: lm.get_account_or_create(account=account) -@pytest.fixture(scope="function") +@pytest.fixture def session_with_tx_factory( - user_factory, - product, - session_factory, + user_factory: Callable[..., "User"], + product: "Product", + session_factory: Callable[..., "Session"], session_manager, wall_manager, - utc_hour_ago, - thl_lm, -) -> Callable: + utc_hour_ago: datetime, + thl_lm: "ThlLedgerManager", +) -> Callable[..., "Session"]: + from generalresearch.models.thl.session import ( - Status, Session, + Status, StatusCode1, ) from generalresearch.models.thl.user import User - def _session_with_tx_factory( + def _inner( user: User, final_status: Status = Status.COMPLETE, wall_req_cpi: Decimal = Decimal(".50"), @@ -583,18 +637,21 @@ def session_with_tx_factory( return s - return _session_with_tx_factory + return _inner -@pytest.fixture(scope="function") -def adj_to_fail_with_tx_factory(session_manager, wall_manager, thl_lm) -> Callable: +@pytest.fixture +def adj_to_fail_with_tx_factory( + session_manager, wall_manager, thl_lm: "ThlLedgerManager" +) -> Callable[..., None]: + from datetime import datetime, timedelta + + from generalresearch.models.thl.definitions import WallAdjustedStatus from generalresearch.models.thl.session import ( Session, ) - from datetime import timedelta - from generalresearch.models.thl.definitions import WallAdjustedStatus - def _adj_to_fail_with_tx_factory( + def _inner( session: Session, created: datetime, ) -> None: @@ -636,18 +693,21 @@ def adj_to_fail_with_tx_factory(session_manager, wall_manager, thl_lm) -> Callab return None - return _adj_to_fail_with_tx_factory + return _inner -@pytest.fixture(scope="function") -def adj_to_complete_with_tx_factory(session_manager, wall_manager, thl_lm) -> Callable: +@pytest.fixture +def adj_to_complete_with_tx_factory( + session_manager, wall_manager, thl_lm: "ThlLedgerManager" +) -> Callable[..., None]: + from datetime import timedelta + + from generalresearch.models.thl.definitions import WallAdjustedStatus from generalresearch.models.thl.session import ( Session, ) - from datetime import timedelta - from generalresearch.models.thl.definitions import WallAdjustedStatus - def _adj_to_complete_with_tx_factory( + def _inner( session: Session, created: datetime, ) -> None: @@ -675,4 +735,4 @@ def adj_to_complete_with_tx_factory(session_manager, wall_manager, thl_lm) -> Ca return None - return _adj_to_complete_with_tx_factory + return _inner diff --git a/test_utils/models/conftest.py b/test_utils/models/conftest.py index ecfd82b..dcc3b66 100644 --- a/test_utils/models/conftest.py +++ b/test_utils/models/conftest.py @@ -1,7 +1,8 @@ -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone from decimal import Decimal -from random import randint, choice as randchoice -from typing import Callable, TYPE_CHECKING, Optional, List, Dict +from random import choice as randchoice +from random import randint +from typing import TYPE_CHECKING, Callable, Dict, List, Optional from uuid import uuid4 import pytest @@ -12,40 +13,40 @@ from generalresearch.models.thl.definitions import ( WALL_ALLOWED_STATUS_STATUS_CODE, Status, ) +from generalresearch.models.thl.survey.model import Buyer, Survey from test_utils.managers.conftest import ( - product_manager, - user_manager, - wall_manager, - session_manager, + business_address_manager, + business_manager, gr_um, membership_manager, + product_manager, + session_manager, team_manager, - business_manager, - business_address_manager, + user_manager, + wall_manager, ) -from generalresearch.models.thl.survey.model import Survey, Buyer if TYPE_CHECKING: - from generalresearch.models.thl.userhealth import AuditLog, AuditLogLevel - from generalresearch.models.thl.payout import UserPayoutEvent - from generalresearch.models.gr.authentication import GRUser, GRToken - from generalresearch.models.gr.team import Team, Membership + from generalresearch.currency import USDCent + from generalresearch.models.gr.authentication import GRToken, GRUser from generalresearch.models.gr.business import ( Business, BusinessAddress, BusinessBankAccount, ) - from generalresearch.models.thl.user import User - from generalresearch.models.thl.product import Product - from generalresearch.models.thl.session import Session, Wall - from generalresearch.currency import USDCent + from generalresearch.models.gr.team import Membership, Team + from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation + from generalresearch.models.thl.payout import UserPayoutEvent from generalresearch.models.thl.product import ( PayoutConfig, PayoutTransformation, PayoutTransformationPercentArgs, + Product, ) + from generalresearch.models.thl.session import Session, Wall + from generalresearch.models.thl.user import User from generalresearch.models.thl.user_iphistory import IPRecord - from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation + from generalresearch.models.thl.userhealth import AuditLog, AuditLogLevel # === THL === @@ -145,10 +146,10 @@ def wall(session, user, wall_manager) -> Optional["Wall"]: @pytest.fixture(scope="function") def session_factory( wall_factory, session_manager, wall_manager, utc_hour_ago -) -> Callable: +) -> Callable[..., "Session"]: from generalresearch.models.thl.session import Source - def _create_session( + def _inner( user: "User", # Wall details wall_count: int = 5, @@ -202,7 +203,7 @@ def session_factory( return s - return _create_session + return _inner @pytest.fixture(scope="function") @@ -250,7 +251,7 @@ def finished_session_factory( @pytest.fixture(scope="function") def session(user, session_manager, wall_manager) -> "Session": - from generalresearch.models.thl.session import Wall, Session + from generalresearch.models.thl.session import Session, Wall session: Session = session_manager.create_dummy(user=user, country_iso="us") wall: Wall = wall_manager.create_dummy( @@ -316,8 +317,8 @@ def payout_config(request) -> "PayoutConfig": @pytest.fixture(scope="function") def product_user_wallet_yes(payout_config, product_manager) -> "Product": - from generalresearch.models.thl.product import UserWalletConfig from generalresearch.managers.thl.product import ProductManager + from generalresearch.models.thl.product import UserWalletConfig product_manager: ProductManager return product_manager.create_dummy( @@ -327,8 +328,8 @@ def product_user_wallet_yes(payout_config, product_manager) -> "Product": @pytest.fixture(scope="function") def product_user_wallet_no(product_manager) -> "Product": - from generalresearch.models.thl.product import UserWalletConfig from generalresearch.managers.thl.product import ProductManager + from generalresearch.models.thl.product import UserWalletConfig product_manager: ProductManager return product_manager.create_dummy( diff --git a/test_utils/spectrum/conftest.py b/test_utils/spectrum/conftest.py index b7887f6..d737730 100644 --- a/test_utils/spectrum/conftest.py +++ b/test_utils/spectrum/conftest.py @@ -1,24 +1,30 @@ import logging - import time +from datetime import datetime, timezone +from typing import TYPE_CHECKING import pytest -from datetime import datetime, timezone + from generalresearch.managers.spectrum.survey import ( - SpectrumSurveyManager, SpectrumCriteriaManager, + SpectrumSurveyManager, ) from generalresearch.models.spectrum.survey import SpectrumSurvey from generalresearch.sql_helper import SqlHelper -from .surveys_json import SURVEYS_JSON, CONDITIONS +from .surveys_json import CONDITIONS, SURVEYS_JSON + +if TYPE_CHECKING: + from generalresearch.config import GRLBaseSettings @pytest.fixture(scope="session") -def spectrum_rw(settings) -> SqlHelper: - print(f"{settings.spectrum_rw_db=}") +def spectrum_rw(settings: "GRLBaseSettings") -> SqlHelper: logging.info(f"{settings.spectrum_rw_db=}") + + assert settings.spectrum_rw_db is not None assert "/unittest-" in settings.spectrum_rw_db.path + return SqlHelper( dsn=settings.spectrum_rw_db, read_timeout=2, diff --git a/tests/managers/thl/test_cashout_method.py b/tests/managers/thl/test_cashout_method.py index fe561d3..ee52188 100644 --- a/tests/managers/thl/test_cashout_method.py +++ b/tests/managers/thl/test_cashout_method.py @@ -3,13 +3,11 @@ import pytest from generalresearch.models.thl.wallet import PayoutType from generalresearch.models.thl.wallet.cashout_method import ( CashMailCashoutMethodData, - USDeliveryAddress, PaypalCashoutMethodData, + USDeliveryAddress, ) from test_utils.managers.cashout_methods import ( EXAMPLE_TANGO_CASHOUT_METHODS, - AMT_ASSIGNMENT_CASHOUT_METHOD, - AMT_BONUS_CASHOUT_METHOD, ) @@ -34,8 +32,10 @@ class TestAMTCashoutMethods: def test_create_and_get(self, cashout_method_manager, setup_cashoutmethod_db): res = cashout_method_manager.filter(payout_types=[PayoutType.AMT]) assert len(res) == 2 + cm = [x for x in res if x.name == "AMT Assignment"][0] assert AMT_ASSIGNMENT_CASHOUT_METHOD == cm + cm = [x for x in res if x.name == "AMT Bonus"][0] assert AMT_BONUS_CASHOUT_METHOD == cm diff --git a/tests/managers/thl/test_ledger/test_lm_accounts.py b/tests/managers/thl/test_ledger/test_lm_accounts.py index e0d9b0b..be9cf5b 100644 --- a/tests/managers/thl/test_ledger/test_lm_accounts.py +++ b/tests/managers/thl/test_ledger/test_lm_accounts.py @@ -1,5 +1,6 @@ from itertools import product as iproduct from random import randint +from typing import TYPE_CHECKING, Callable from uuid import uuid4 import pytest @@ -10,11 +11,20 @@ from generalresearch.managers.thl.ledger_manager.exceptions import ( LedgerAccountDoesntExistError, ) from generalresearch.managers.thl.ledger_manager.ledger import LedgerManager -from generalresearch.models.thl.ledger import LedgerAccount, AccountType, Direction from generalresearch.models.thl.ledger import ( + AccountType, + Direction, + LedgerAccount, LedgerEntry, ) -from test_utils.managers.ledger.conftest import ledger_account + +if TYPE_CHECKING: + from generalresearch.config import GRLSettings + from generalresearch.currency import LedgerCurrency + from generalresearch.models.thl.product import Product + from generalresearch.models.thl.session import Session + from generalresearch.models.thl.user import User + from generalresearch.models.thl.wallet import PayoutType @pytest.mark.parametrize( @@ -23,13 +33,15 @@ from test_utils.managers.ledger.conftest import ledger_account iproduct( ["USD", "test", "EUR"], ["expense", "wallet", "revenue", "cash"], - [uuid4().hex for i in range(3)], + [uuid4().hex for _ in range(3)], ) ), ) class TestLedgerAccountManagerNoResults: - def test_get_account_no_results(self, currency, kind, acct_id, lm): + def test_get_account_no_results( + self, currency: "LedgerCurrency", kind, acct_id, lm + ): """Try to query for accounts that we know don't exist and confirm that we either get the expected None result or it raises the correct exception @@ -46,7 +58,9 @@ class TestLedgerAccountManagerNoResults: # (2) .get_account_if_exists is another wrapper assert lm.get_account(qualified_name=qn, raise_on_error=False) is None - def test_get_account_no_results_many(self, currency, kind, acct_id, lm): + def test_get_account_no_results_many( + self, currency: "LedgerCurrency", kind, acct_id, lm + ): qn = ":".join([currency, kind, acct_id]) # (1) .get_many_ @@ -81,7 +95,7 @@ class TestLedgerAccountManagerNoResults: class TestLedgerAccountManagerCreate: def test_create_account_error_permission( - self, currency, account_type, direction, lm + self, currency: "LedgerCurrency", account_type, direction, lm ): """Confirm that the Permission values that are set on the Ledger Manger allow the Creation action to occur. @@ -126,7 +140,7 @@ class TestLedgerAccountManagerCreate: str(excinfo.value) == "LedgerManager does not have sufficient permissions" ) - def test_create(self, currency, account_type, direction, lm): + def test_create(self, currency: "LedgerCurrency", account_type, direction, lm): """Confirm that the Permission values that are set on the Ledger Manger allow the Creation action to occur. """ @@ -149,7 +163,9 @@ class TestLedgerAccountManagerCreate: res = lm.get_account(qualified_name=qn, raise_on_error=True) assert account.uuid == res.uuid - def test_get_or_create(self, currency, account_type, direction, lm): + def test_get_or_create( + self, currency: "LedgerCurrency", account_type, direction, lm + ): """Confirm that the Permission values that are set on the Ledger Manger allow the Creation action to occur. """ diff --git a/tests/managers/thl/test_ledger/test_user_txs.py b/tests/managers/thl/test_ledger/test_user_txs.py index d81b244..ecf146f 100644 --- a/tests/managers/thl/test_ledger/test_user_txs.py +++ b/tests/managers/thl/test_ledger/test_user_txs.py @@ -1,39 +1,42 @@ -from datetime import timedelta, datetime, timezone +from datetime import datetime, timedelta, timezone from decimal import Decimal +from typing import TYPE_CHECKING, Callable from uuid import uuid4 -from generalresearch.managers.thl.payout import ( - AMT_ASSIGNMENT_CASHOUT_METHOD, - AMT_BONUS_CASHOUT_METHOD, -) +from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager from generalresearch.managers.thl.user_compensate import user_compensate from generalresearch.models.thl.definitions import ( Status, WallAdjustedStatus, ) from generalresearch.models.thl.ledger import ( + TransactionType, UserLedgerTransactionTypesSummary, UserLedgerTransactionTypeSummary, - TransactionType, ) -from generalresearch.models.thl.session import Session -from generalresearch.models.thl.user import User -from generalresearch.models.thl.wallet import PayoutType + +if TYPE_CHECKING: + from generalresearch.config import GRLSettings + from generalresearch.models.thl.product import Product + from generalresearch.models.thl.session import Session + from generalresearch.models.thl.user import User + from generalresearch.models.thl.wallet import PayoutType def test_user_txs( - user_factory, - product_amt_true, - create_main_accounts, - thl_lm, + user_factory: Callable[..., "User"], + product_amt_true: "Product", + create_main_accounts: Callable[..., None], + thl_lm: ThlLedgerManager, lm, - delete_ledger_db, + delete_ledger_db: Callable[..., None], session_with_tx_factory, adj_to_fail_with_tx_factory, adj_to_complete_with_tx_factory, session_factory, user_payout_event_manager, - utc_now, + utc_now: datetime, + settings: "GRLSettings", ): delete_ledger_db() create_main_accounts() @@ -53,7 +56,7 @@ def test_user_txs( pe = user_payout_event_manager.create( uuid=uuid4().hex, debit_account_uuid=account.uuid, - cashout_method_uuid=AMT_ASSIGNMENT_CASHOUT_METHOD, + cashout_method_uuid=settings.amt_assignment_cashout_method_id, amount=5, created=utc_now, payout_type=PayoutType.AMT_HIT, @@ -66,7 +69,7 @@ def test_user_txs( pe = user_payout_event_manager.create( uuid=uuid4().hex, debit_account_uuid=account.uuid, - cashout_method_uuid=AMT_BONUS_CASHOUT_METHOD, + cashout_method_uuid=settings.amt_bonus_cashout_method_id, amount=127, created=utc_now, payout_type=PayoutType.AMT_BONUS, @@ -133,16 +136,16 @@ def test_user_txs( def test_user_txs_pagination( - user_factory, - product_amt_true, - create_main_accounts, - thl_lm, - lm, - delete_ledger_db, - session_with_tx_factory, + user_factory: Callable[..., "User"], + product_amt_true: "Product", + create_main_accounts: Callable[..., None], + thl_lm: "ThlLedgerManager", + lm: "LedgerManager", + delete_ledger_db: Callable[..., None], + session_with_tx_factory: Callable[..., "Session"], adj_to_fail_with_tx_factory, user_payout_event_manager, - utc_now, + utc_now: datetime, ): delete_ledger_db() create_main_accounts() @@ -212,15 +215,16 @@ def test_user_txs_pagination( def test_user_txs_rolling_balance( - user_factory, - product_amt_true, + user_factory: Callable[..., "User"], + product_amt_true: "Product", create_main_accounts, thl_lm, lm, - delete_ledger_db, + delete_ledger_db: Callable[..., None], session_with_tx_factory, adj_to_fail_with_tx_factory, user_payout_event_manager, + settings: "GRLSettings", ): """ Creates 3 $1.00 bonuses (postive), @@ -242,10 +246,11 @@ def test_user_txs_rolling_balance( amount_int=100, skip_flag_check=True, ) + pe = user_payout_event_manager.create( uuid=uuid4().hex, debit_account_uuid=account.uuid, - cashout_method_uuid=AMT_BONUS_CASHOUT_METHOD, + cashout_method_uuid=settings.amt_bonus_cashout_method_id, amount=150, payout_type=PayoutType.AMT_BONUS, request_data=dict(), |
