From 0e60d93cf9dfff98bae4a459288c06c6fd7f2c07 Mon Sep 17 00:00:00 2001
From: stuppie
Date: Wed, 19 Aug 2026 16:58:43 -0600
Subject: working on BusinessPayoutEvent. create_from_ach_or_wire -> stage
payout events all at once. BusinessPayoutEvent standalone model instead of
computed from bp_payouts
---
test_utils/managers/ledger/conftest.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'test_utils/managers')
diff --git a/test_utils/managers/ledger/conftest.py b/test_utils/managers/ledger/conftest.py
index 0aa6cb3..852645d 100644
--- a/test_utils/managers/ledger/conftest.py
+++ b/test_utils/managers/ledger/conftest.py
@@ -596,8 +596,8 @@ def session_with_tx_factory(
final_status: Status = Status.COMPLETE,
wall_req_cpi: Decimal = Decimal(".50"),
started: datetime = utc_hour_ago,
- ) -> Session:
- s: Session = session_factory(
+ ) -> "Session":
+ s: "Session" = session_factory(
user=user,
wall_count=2,
final_status=final_status,
--
cgit v1.2.3
From 4fe0f6b5e0f0c744902e4c3ab8940e23a6f8a2e1 Mon Sep 17 00:00:00 2001
From: stuppie
Date: Fri, 21 Aug 2026 12:24:10 -0600
Subject: more test changes
---
test_utils/managers/ledger/conftest.py | 3 +-
tests/managers/thl/test_payout.py | 175 ++++-----------------------------
2 files changed, 19 insertions(+), 159 deletions(-)
(limited to 'test_utils/managers')
diff --git a/test_utils/managers/ledger/conftest.py b/test_utils/managers/ledger/conftest.py
index 852645d..105085d 100644
--- a/test_utils/managers/ledger/conftest.py
+++ b/test_utils/managers/ledger/conftest.py
@@ -192,8 +192,7 @@ def bp_payout_event(
thl_ledger_manager=thl_lm,
product=product,
amount=usd_cent,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
+ ext_ref_id=uuid4().hex
)
diff --git a/tests/managers/thl/test_payout.py b/tests/managers/thl/test_payout.py
index 03cd441..b79a209 100644
--- a/tests/managers/thl/test_payout.py
+++ b/tests/managers/thl/test_payout.py
@@ -293,37 +293,14 @@ class TestBusinessPayoutEventManager:
ach_id1 = uuid4().hex
ach_id2 = uuid4().hex
- bp_payout_factory(
- product=p1,
- amount=USDCent(1),
- ext_ref_id=None,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
- )
+ # ext_ref_id is required now
+ bp_payout_factory(product=p1,amount=USDCent(1),ext_ref_id="none")
- bp_payout_factory(
- product=p1,
- amount=USDCent(1),
- ext_ref_id=ach_id1,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
- )
+ bp_payout_factory(product=p1,amount=USDCent(1),ext_ref_id=ach_id1)
+ with pytest.raises(expected_exception=ValueError, match="Cannot create a BusinessPayoutEvent with an existing transaction_id"):
+ bp_payout_factory(product=p1,amount=USDCent(25),ext_ref_id=ach_id1)
- bp_payout_factory(
- product=p1,
- amount=USDCent(25),
- ext_ref_id=ach_id1,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
- )
-
- bp_payout_factory(
- product=p1,
- amount=USDCent(50),
- ext_ref_id=ach_id2,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
- )
+ bp_payout_factory(product=p1,amount=USDCent(50),ext_ref_id=ach_id2)
business.prebuild_payouts(
bpem=business_payout_event_manager,
@@ -333,11 +310,14 @@ class TestBusinessPayoutEventManager:
assert business.payouts_total == sum([pe.amount for pe in business.payouts])
assert business.payouts[0].created > business.payouts[1].created
assert len(business.payouts[0].bp_payouts) == 1
- assert len(business.payouts[1].bp_payouts) == 2
+
+ # Cannot pay out the same product twice in the same business payout
+ # assert len(business.payouts[1].bp_payouts) == 2
+ assert len(business.payouts[1].bp_payouts) == 1
assert business.payouts[0].ext_ref_id == ach_id2
assert business.payouts[1].ext_ref_id == ach_id1
- assert business.payouts[2].ext_ref_id is None
+ assert business.payouts[2].ext_ref_id == "none"
def test_update_ext_reference_ids(
self,
@@ -368,7 +348,6 @@ class TestBusinessPayoutEventManager:
p1: Product = product_factory(business=business)
u1: User = user_factory(product=p1)
thl_lm.get_account_or_create_bp_wallet(product=p1)
- business_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
# $250.00 to work with
for idx in range(1, 10):
@@ -381,12 +360,11 @@ class TestBusinessPayoutEventManager:
ach_id1 = uuid4().hex
ach_id2 = uuid4().hex
- with pytest.raises(expected_exception=Warning) as cm:
+ with pytest.raises(expected_exception=AssertionError, match="No Business Payout found"):
business_payout_event_manager.update_ext_reference_ids(
new_value=ach_id2,
current_value=ach_id1,
)
- assert "No event_payouts found to UPDATE" in str(cm)
# We must build the balance to issue ACH/Wire
ledger_collection.initial_load(client=None, sync=True)
@@ -407,6 +385,7 @@ class TestBusinessPayoutEventManager:
transaction_id=ach_id1,
)
assert isinstance(res, BusinessPayoutEvent)
+ assert business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id1)
# Okay, now that there is a payout_event, let's try to update the
# ext_reference_id
@@ -415,105 +394,10 @@ class TestBusinessPayoutEventManager:
current_value=ach_id1,
)
- res = business_payout_event_manager.filter_by(ext_ref_id=ach_id1)
- assert len(res) == 0
-
- res = business_payout_event_manager.filter_by(ext_ref_id=ach_id2)
- assert len(res) == 1
-
- def test_delete_failed_business_payout(
- self,
- brokerage_product_payout_event_manager,
- business_payout_event_manager,
- delete_ledger_db,
- create_main_accounts,
- thl_lm,
- thl_web_rr,
- product_factory,
- bp_payout_factory,
- currency,
- delete_df_collection,
- user_factory,
- ledger_collection,
- session_with_tx_factory,
- pop_ledger_merge,
- client_no_amm,
- mnt_filepath,
- lm,
- product_manager,
- start,
- business,
- ):
- delete_ledger_db()
- create_main_accounts()
- delete_df_collection(coll=ledger_collection)
-
- p1: Product = product_factory(business=business)
- u1: User = user_factory(product=p1)
- thl_lm.get_account_or_create_bp_wallet(product=p1)
- business_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
-
- # $250.00 to work with
- for idx in range(1, 10):
- session_with_tx_factory(
- user=u1,
- wall_req_cpi=Decimal("25.00"),
- started=start + timedelta(days=1, minutes=idx),
- )
-
- # We must build the balance to issue ACH/Wire
- ledger_collection.initial_load(client=None, sync=True)
- pop_ledger_merge.build(client=client_no_amm, ledger_coll=ledger_collection)
- business.prebuild_balance(
- thl_pg_config=thl_web_rr,
- lm=lm,
- ds=mnt_filepath,
- client=client_no_amm,
- pop_ledger=pop_ledger_merge,
- )
-
- ach_id1 = uuid4().hex
+ with pytest.raises(expected_exception=AssertionError, match="No Business Payout found"):
+ business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id1)
- res = business_payout_event_manager.create_from_ach_or_wire(
- business=business,
- amount=USDCent(100_01),
- pm=product_manager,
- thl_lm=thl_lm,
- transaction_id=ach_id1,
- )
- assert isinstance(res, BusinessPayoutEvent)
-
- # (1) Confirm the initial Event Payout, Tx, TxMeta, TxEntry all exist
- event_payouts = business_payout_event_manager.filter_by(ext_ref_id=ach_id1)
- event_payout_uuids = [i.uuid for i in event_payouts]
- assert len(event_payout_uuids) == 1
- tags = [f"{currency.value}:bp_payout:{x}" for x in event_payout_uuids]
- transactions = thl_lm.get_txs_by_tags(tags=tags)
- assert len(transactions) == 1
- tx_metadata_ids = thl_lm.get_tx_metadata_ids_by_txs(transactions=transactions)
- assert len(tx_metadata_ids) == 2
- tx_entries = thl_lm.get_tx_entries_by_txs(transactions=transactions)
- assert len(tx_entries) == 2
-
- # (2) Delete!
- business_payout_event_manager.delete_failed_business_payout(
- ext_ref_id=ach_id1, thl_lm=thl_lm
- )
-
- # (3) Confirm the initial Event Payout, Tx, TxMeta, TxEntry have
- # all been deleted
- res = business_payout_event_manager.filter_by(ext_ref_id=ach_id1)
- assert len(res) == 0
-
- # Note: b/c the event_payout shouldn't exist anymore, we are taking
- # the tag strings and transactions from when they did..
- res = thl_lm.get_txs_by_tags(tags=tags)
- assert len(res) == 0
-
- tx_metadata_ids = thl_lm.get_tx_metadata_ids_by_txs(transactions=transactions)
- assert len(tx_metadata_ids) == 0
- tx_entries = thl_lm.get_tx_entries_by_txs(transactions=transactions)
- assert len(tx_entries) == 0
+ assert business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id2)
def test_recoup_empty(self, business_payout_event_manager):
res = {uuid4().hex: USDCent(0) for i in range(100)}
@@ -664,7 +548,7 @@ class TestBusinessPayoutEventManager:
lm,
product_manager,
):
- """Test having a Business with three products.. one that lost money
+ """Test having a Business with three products. One that lost money
and two that gained money. Ensure that the Business balance
reflects that to compensate for the Product in the negative and only
assigns Brokerage Product payments from the 2 accounts that have
@@ -689,7 +573,6 @@ class TestBusinessPayoutEventManager:
wall_req_cpi=Decimal("5.00"),
started=start + timedelta(days=6),
)
- payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
bp_payout_factory(
product=u1.product,
amount=USDCent(475), # 95% of $5.00
@@ -712,31 +595,10 @@ class TestBusinessPayoutEventManager:
amount=USDCent(500),
pm=product_manager,
thl_lm=thl_lm,
+ transaction_id=uuid4().hex,
)
assert "Must issue Supplier Payouts at least $100 minimum." in str(cm)
- bpe = BusinessPayoutEvent(
- business_id=business.uuid,
- amount=USDCent(100_00),
- payout_type=PayoutType.ACH,
- )
- bpe.bp_payouts = [
- BrokerageProductPayoutEvent(
- product_id=uuid4().hex,
- payout_type=PayoutType.ACH,
- amount=USDCent(47_00),
- cashout_method_uuid=uuid4().hex,
- debit_account_uuid=uuid4().hex,
- ),
- BrokerageProductPayoutEvent(
- product_id=uuid4().hex,
- payout_type=PayoutType.ACH,
- amount=USDCent(53_00),
- cashout_method_uuid=uuid4().hex,
- debit_account_uuid=uuid4().hex,
- ),
- ]
-
def test_create_from_ach_or_wire(
self,
product,
@@ -916,7 +778,6 @@ class TestBusinessPayoutEventManager:
wall_req_cpi=Decimal("5.00"),
started=start + timedelta(days=1),
)
- payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
bp_payout_factory(
product=u1.product,
amount=USDCent(475), # 95% of $5.00
--
cgit v1.2.3
From 6cf7ccbaa8306700e64ada19d6f99807743b2865 Mon Sep 17 00:00:00 2001
From: Max Nanis
Date: Fri, 21 Aug 2026 17:19:41 -0700
Subject: Ruff auto updates to 3.14
---
generalresearch/__init__.py | 5 +-
generalresearch/config.py | 4 +-
generalresearch/grliq/managers/event_plotter.py | 6 +-
generalresearch/grliq/managers/forensic_data.py | 3 +-
generalresearch/grliq/managers/forensic_events.py | 29 +++----
generalresearch/grliq/managers/forensic_results.py | 23 +++---
generalresearch/grliq/managers/forensic_summary.py | 14 ++--
generalresearch/grliq/models/custom_types.py | 2 +-
generalresearch/grliq/models/decider.py | 4 +-
generalresearch/grliq/models/events.py | 32 ++++----
generalresearch/grliq/models/forensic_data.py | 6 +-
generalresearch/grliq/models/forensic_summary.py | 2 +-
generalresearch/grliq/models/useragents.py | 2 +-
generalresearch/grliq/utils.py | 4 +-
generalresearch/grpc.py | 8 +-
generalresearch/incite/base.py | 25 +++---
generalresearch/incite/defaults.py | 60 +++++++-------
generalresearch/incite/mergers/__init__.py | 24 +++---
generalresearch/incite/mergers/ym_wall_summary.py | 2 +-
generalresearch/incite/schemas/__init__.py | 4 +-
.../mergers/foundations/enriched_task_adjust.py | 2 +-
generalresearch/incite/schemas/thl_web.py | 10 +--
generalresearch/locales/__init__.py | 4 +-
generalresearch/locales/timezone.py | 4 +-
generalresearch/managers/cint/profiling.py | 2 +-
generalresearch/managers/cint/survey.py | 4 +-
generalresearch/managers/criteria.py | 4 +-
generalresearch/managers/dynata/profiling.py | 2 +-
generalresearch/managers/dynata/survey.py | 6 +-
generalresearch/managers/events.py | 6 +-
generalresearch/managers/gr/authentication.py | 12 +--
generalresearch/managers/gr/team.py | 4 +-
generalresearch/managers/innovate/survey.py | 6 +-
generalresearch/managers/leaderboard/manager.py | 6 +-
generalresearch/managers/morning/survey.py | 8 +-
generalresearch/managers/network/label.py | 6 +-
generalresearch/managers/precision/survey.py | 6 +-
generalresearch/managers/prodege/survey.py | 8 +-
generalresearch/managers/repdata/survey.py | 6 +-
generalresearch/managers/sago/survey.py | 8 +-
generalresearch/managers/spectrum/survey.py | 8 +-
generalresearch/managers/thl/buyer.py | 4 +-
generalresearch/managers/thl/cashout_method.py | 4 +-
generalresearch/managers/thl/contest_manager.py | 8 +-
.../managers/thl/ledger_manager/conditions.py | 7 +-
.../managers/thl/ledger_manager/ledger.py | 13 ++--
.../managers/thl/ledger_manager/thl_ledger.py | 17 ++--
generalresearch/managers/thl/product.py | 4 +-
generalresearch/managers/thl/profiling/uqa.py | 4 +-
generalresearch/managers/thl/profiling/user_upk.py | 4 +-
generalresearch/managers/thl/session.py | 20 ++---
generalresearch/managers/thl/survey.py | 4 +-
generalresearch/managers/thl/task_adjustment.py | 6 +-
generalresearch/managers/thl/user_compensate.py | 4 +-
.../thl/user_manager/mysql_user_manager.py | 6 +-
generalresearch/managers/thl/userhealth.py | 8 +-
generalresearch/managers/thl/wall.py | 12 ++-
generalresearch/managers/thl/wallet/__init__.py | 4 +-
generalresearch/managers/thl/wallet/tango.py | 4 +-
generalresearch/models/admin/__init__.py | 14 ++--
generalresearch/models/admin/request.py | 12 +--
generalresearch/models/cint/__init__.py | 3 +-
generalresearch/models/cint/question.py | 9 +--
generalresearch/models/cint/survey.py | 13 ++--
generalresearch/models/cint/task_collection.py | 4 +-
generalresearch/models/custom_types.py | 15 ++--
generalresearch/models/dynata/survey.py | 11 ++-
generalresearch/models/events.py | 70 +++++++----------
generalresearch/models/gr/authentication.py | 11 ++-
generalresearch/models/gr/business.py | 11 ++-
generalresearch/models/gr/team.py | 7 +-
generalresearch/models/innovate/__init__.py | 2 +-
generalresearch/models/innovate/survey.py | 14 ++--
generalresearch/models/legacy/bucket.py | 3 +-
generalresearch/models/legacy/questions.py | 3 +-
generalresearch/models/lucid/__init__.py | 3 +-
generalresearch/models/lucid/question.py | 3 +-
generalresearch/models/marketplace/summary.py | 3 +-
generalresearch/models/morning/__init__.py | 2 +-
generalresearch/models/morning/question.py | 13 ++--
generalresearch/models/morning/survey.py | 84 ++++++++++----------
generalresearch/models/network/mtr/execute.py | 6 +-
generalresearch/models/network/nmap/parser.py | 6 +-
generalresearch/models/network/nmap/result.py | 4 +-
generalresearch/models/network/rdns/execute.py | 6 +-
generalresearch/models/precision/__init__.py | 2 +-
generalresearch/models/precision/survey.py | 69 ++++++++--------
.../models/precision/task_collection.py | 8 +-
generalresearch/models/prodege/__init__.py | 3 +-
generalresearch/models/prodege/question.py | 6 +-
generalresearch/models/prodege/survey.py | 12 +--
generalresearch/models/prodege/task_collection.py | 4 +-
generalresearch/models/repdata/survey.py | 13 ++--
generalresearch/models/sago/__init__.py | 2 +-
generalresearch/models/sago/survey.py | 13 ++--
generalresearch/models/spectrum/__init__.py | 2 +-
generalresearch/models/spectrum/question.py | 15 ++--
generalresearch/models/spectrum/survey.py | 19 ++---
generalresearch/models/string_utils.py | 2 +-
generalresearch/models/thl/category.py | 3 +-
generalresearch/models/thl/contest/__init__.py | 6 +-
generalresearch/models/thl/contest/contest.py | 19 +++--
.../models/thl/contest/contest_entry.py | 10 +--
generalresearch/models/thl/contest/io.py | 4 +-
generalresearch/models/thl/contest/leaderboard.py | 9 +--
generalresearch/models/thl/contest/milestone.py | 2 +-
generalresearch/models/thl/contest/raffle.py | 7 +-
generalresearch/models/thl/finance.py | 8 +-
generalresearch/models/thl/ipinfo.py | 13 ++--
generalresearch/models/thl/leaderboard.py | 8 +-
generalresearch/models/thl/ledger.py | 21 ++---
generalresearch/models/thl/ledger_example.py | 10 +--
generalresearch/models/thl/offerwall/__init__.py | 3 +-
generalresearch/models/thl/offerwall/base.py | 3 +-
generalresearch/models/thl/offerwall/cache.py | 10 +--
generalresearch/models/thl/payout_format.py | 2 +-
generalresearch/models/thl/product.py | 8 +-
.../models/thl/profiling/marketplace.py | 6 +-
.../models/thl/profiling/other_option.py | 2 +-
.../models/thl/profiling/upk_question.py | 13 ++--
.../models/thl/profiling/upk_question_answer.py | 9 +--
.../models/thl/profiling/user_question_answer.py | 14 ++--
generalresearch/models/thl/session.py | 27 +++----
generalresearch/models/thl/survey/__init__.py | 2 +-
generalresearch/models/thl/survey/buyer.py | 4 +-
generalresearch/models/thl/survey/condition.py | 3 +-
generalresearch/models/thl/survey/model.py | 17 ++--
generalresearch/models/thl/survey/penalty.py | 9 +--
generalresearch/models/thl/task_adjustment.py | 6 +-
generalresearch/models/thl/task_status.py | 3 +-
generalresearch/models/thl/user.py | 13 ++--
generalresearch/models/thl/user_iphistory.py | 8 +-
generalresearch/models/thl/user_profile.py | 3 +-
generalresearch/models/thl/user_quality_event.py | 6 +-
generalresearch/models/thl/userhealth.py | 21 +++--
.../models/thl/wallet/cashout_method.py | 6 +-
generalresearch/models/thl/wallet/payout.py | 8 +-
generalresearch/pg_helper.py | 4 +-
generalresearch/sql_helper.py | 4 +-
generalresearch/utils/aggregation.py | 2 +-
generalresearch/utils/copying_cache.py | 2 +-
generalresearch/utils/enum.py | 2 +-
generalresearch/wall_status_codes/__init__.py | 6 +-
generalresearch/wall_status_codes/cint.py | 6 +-
generalresearch/wall_status_codes/dynata.py | 16 ++--
generalresearch/wall_status_codes/fullcircle.py | 14 ++--
generalresearch/wall_status_codes/innovate.py | 12 +--
generalresearch/wall_status_codes/lucid.py | 16 ++--
generalresearch/wall_status_codes/morning.py | 14 ++--
generalresearch/wall_status_codes/pollfish.py | 14 ++--
generalresearch/wall_status_codes/precision.py | 12 +--
generalresearch/wall_status_codes/prodege.py | 10 +--
generalresearch/wall_status_codes/repdata.py | 14 ++--
generalresearch/wall_status_codes/sago.py | 16 ++--
generalresearch/wall_status_codes/spectrum.py | 12 +--
generalresearch/wall_status_codes/wxet.py | 14 ++--
generalresearch/wxet/models/definitions.py | 34 ++++----
generalresearch/wxet/models/finish_type.py | 8 +-
test_utils/conftest.py | 91 ++++++++++++++--------
test_utils/grliq/conftest.py | 8 +-
test_utils/incite/collections/conftest.py | 3 +-
test_utils/incite/conftest.py | 7 +-
test_utils/incite/mergers/conftest.py | 2 +-
test_utils/managers/conftest.py | 2 +-
test_utils/managers/gr/conftest.py | 2 +-
test_utils/managers/thl/conftest.py | 2 +-
test_utils/managers/upk/conftest.py | 2 +-
test_utils/models/conftest.py | 7 +-
test_utils/models/contest/conftest.py | 7 +-
test_utils/models/gr/conftest.py | 2 +-
test_utils/models/ledger/conftest.py | 3 +-
test_utils/models/network/conftest.py | 6 +-
test_utils/models/thl/conftest.py | 17 ++--
test_utils/spectrum/conftest.py | 16 ++--
tests/grliq/models/test_forensic_data.py | 8 +-
.../incite/collections/test_df_collection_base.py | 24 +++---
.../collections/test_df_collection_item_base.py | 20 ++---
.../collections/test_df_collection_item_thl_web.py | 10 +--
.../test_df_collection_thl_marketplaces.py | 6 +-
.../collections/test_df_collection_thl_web.py | 2 +-
.../mergers/foundations/test_enriched_session.py | 8 +-
.../mergers/foundations/test_enriched_wall.py | 16 ++--
.../mergers/foundations/test_user_id_product.py | 16 ++--
tests/incite/mergers/test_merge_collection.py | 8 +-
tests/incite/mergers/test_pop_ledger.py | 12 +--
tests/incite/mergers/test_ym_survey_merge.py | 18 ++---
tests/incite/schemas/test_admin_responses.py | 29 ++++---
tests/incite/test_collection_base.py | 22 +++---
tests/incite/test_collection_base_item.py | 6 +-
tests/managers/leaderboard.py | 14 ++--
tests/managers/test_events.py | 16 ++--
.../managers/thl/test_contest/test_leaderboard.py | 10 ++-
tests/managers/thl/test_contest/test_milestone.py | 16 ++--
tests/managers/thl/test_contest/test_raffle.py | 22 +++---
tests/managers/thl/test_harmonized_uqa.py | 12 +--
tests/managers/thl/test_ledger/test_lm_accounts.py | 65 ++++++++--------
tests/managers/thl/test_ledger/test_lm_tx_locks.py | 22 +++---
.../thl/test_ledger/test_thl_lm_bp_payout.py | 48 ++++++------
tests/managers/thl/test_ledger/test_thl_lm_tx.py | 55 +++++++------
.../test_ledger/test_thl_lm_tx__user_payouts.py | 10 +--
tests/managers/thl/test_ledger/test_user_txs.py | 31 ++++----
tests/managers/thl/test_maxmind.py | 7 +-
tests/managers/thl/test_profiling/test_user_upk.py | 4 +-
tests/managers/thl/test_survey.py | 12 +--
tests/managers/thl/test_task_adjustment.py | 12 ++-
tests/managers/thl/test_task_status.py | 16 ++--
tests/managers/thl/test_user_manager/test_base.py | 4 +-
tests/managers/thl/test_user_streak.py | 16 ++--
tests/managers/thl/test_userhealth.py | 8 +-
tests/managers/thl/test_wall_manager.py | 12 +--
tests/models/admin/test_report_request.py | 20 ++---
tests/models/custom_types/test_aware_datetime.py | 6 +-
tests/models/custom_types/test_dsn.py | 6 +-
tests/models/dynata/test_eligbility.py | 6 +-
tests/models/gr/test_authentication.py | 6 +-
tests/models/gr/test_base.py | 24 +++---
tests/models/gr/test_business.py | 20 ++---
tests/models/morning/test.py | 6 +-
tests/models/prodege/test_survey_participation.py | 6 +-
tests/models/spectrum/test_question.py | 14 ++--
tests/models/spectrum/test_survey.py | 26 +++----
tests/models/spectrum/test_survey_manager.py | 13 ++--
tests/models/test_finance.py | 10 +--
tests/models/thl/test_adjustments.py | 14 ++--
tests/models/thl/test_contest/test_contest.py | 2 +-
.../thl/test_contest/test_leaderboard_contest.py | 6 +-
tests/models/thl/test_ledger.py | 4 +-
tests/models/thl/test_product.py | 14 ++--
tests/models/thl/test_user.py | 40 +++++-----
tests/models/thl/test_user_iphistory.py | 4 +-
tests/models/thl/test_wall.py | 38 ++++-----
tests/models/thl/test_wall_session.py | 20 ++---
tests/test_postgres.py | 4 +-
233 files changed, 1298 insertions(+), 1379 deletions(-)
(limited to 'test_utils/managers')
diff --git a/generalresearch/__init__.py b/generalresearch/__init__.py
index 2100d41..604b7e2 100644
--- a/generalresearch/__init__.py
+++ b/generalresearch/__init__.py
@@ -1,7 +1,8 @@
import threading
import time
+from collections.abc import Callable
from functools import wraps
-from typing import Any, Callable, Optional
+from typing import Any, Optional
from decorator import decorator
from wrapt import FunctionWrapper, ObjectProxy
@@ -12,7 +13,7 @@ def retry(
tries: int = 4,
delay: float = 0.5,
backoff: int = 2,
- logger: Optional[Any] = None,
+ logger: Any | None = None,
) -> Callable:
"""
https://www.calazan.com/retry-decorator-for-python-3/
diff --git a/generalresearch/config.py b/generalresearch/config.py
index 44f3db7..76e3995 100644
--- a/generalresearch/config.py
+++ b/generalresearch/config.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import os
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from pathlib import Path
from pydantic import DirectoryPath, Field, MariaDBDsn, PostgresDsn, RedisDsn
@@ -125,4 +125,4 @@ EXAMPLE_PRODUCT_ID = "1108d053e4fa47c5b0dbdcd03a7981e7"
# AMT accounting was changed many times and txs before this date
# are either missing AMT bonuses, or not accounting for hit rewards.
JAMES_BILLINGS_BPID = "888dbc589987425fa846d6e2a8daed04"
-JAMES_BILLINGS_TX_CUTOFF = datetime(2026, 1, 1, tzinfo=timezone.utc)
+JAMES_BILLINGS_TX_CUTOFF = datetime(2026, 1, 1, tzinfo=UTC)
diff --git a/generalresearch/grliq/managers/event_plotter.py b/generalresearch/grliq/managers/event_plotter.py
index 54105ce..ed01d2e 100644
--- a/generalresearch/grliq/managers/event_plotter.py
+++ b/generalresearch/grliq/managers/event_plotter.py
@@ -11,7 +11,7 @@ from generalresearch.grliq.models.events import KeyboardEvent, MouseEvent
def make_events_svg(
- mouse_events: List[MouseEvent], keyboard_events: List[KeyboardEvent]
+ mouse_events: list[MouseEvent], keyboard_events: list[KeyboardEvent]
) -> str:
if len(mouse_events) + len(keyboard_events) == 0:
return f'"
@@ -119,8 +119,8 @@ def svg_multiline_text(
def group_input_events_by_xy(
- mouse_events: List[MouseEvent], keyboard_events: List[KeyboardEvent]
-) -> List[tuple[tuple[float, float], List[str]]]:
+ mouse_events: list[MouseEvent], keyboard_events: list[KeyboardEvent]
+) -> list[tuple[tuple[float, float], list[str]]]:
"""
Each keypress is its own event. For plotting, we want to group together
all keypresses that were made when the mouse was at the same position,
diff --git a/generalresearch/grliq/managers/forensic_data.py b/generalresearch/grliq/managers/forensic_data.py
index 739c520..7567552 100644
--- a/generalresearch/grliq/managers/forensic_data.py
+++ b/generalresearch/grliq/managers/forensic_data.py
@@ -1,7 +1,8 @@
from __future__ import annotations
from datetime import datetime
-from typing import Any, Collection
+from typing import Any
+from collections.abc import Collection
from psycopg import sql
from pydantic import NonNegativeInt, PositiveInt
diff --git a/generalresearch/grliq/managers/forensic_events.py b/generalresearch/grliq/managers/forensic_events.py
index bbc6b6d..85e9620 100644
--- a/generalresearch/grliq/managers/forensic_events.py
+++ b/generalresearch/grliq/managers/forensic_events.py
@@ -1,6 +1,7 @@
import json
from datetime import datetime
-from typing import Any, Collection, Dict, List, Optional
+from typing import Any, Dict, List, Optional
+from collections.abc import Collection
from uuid import uuid4
from psycopg import sql
@@ -25,7 +26,7 @@ class GrlIqEventManager:
def update_or_create_timing(
self,
session_uuid: UUIDStr,
- timing_data: Optional[TimingData] = None,
+ timing_data: TimingData | None = None,
) -> PositiveInt:
data = {
"session_uuid": session_uuid,
@@ -77,8 +78,8 @@ class GrlIqEventManager:
session_uuid: UUIDStr,
event_start: datetime,
event_end: datetime,
- events: Optional[List[Dict]] = None,
- mouse_events: Optional[List[Dict]] = None,
+ events: list[dict] | None = None,
+ mouse_events: list[dict] | None = None,
) -> PositiveInt:
data = {
"uuid": uuid4().hex,
@@ -135,14 +136,14 @@ class GrlIqEventManager:
def filter(
self,
- select_str: Optional[str] = None,
- session_uuid: Optional[str] = None,
- session_uuids: Optional[Collection[str]] = None,
- uuids: Optional[Collection[str]] = None,
- started_since: Optional[datetime] = None,
- limit: Optional[int] = None,
+ select_str: str | None = None,
+ session_uuid: str | None = None,
+ session_uuids: Collection[str] | None = None,
+ uuids: Collection[str] | None = None,
+ started_since: datetime | None = None,
+ limit: int | None = None,
order_by: str = "event_start DESC",
- ) -> List[Dict[str, Any]]:
+ ) -> list[dict[str, Any]]:
if not limit:
limit = 100
@@ -199,7 +200,7 @@ class GrlIqEventManager:
def filter_distinct_timing(
self,
session_uuids: Collection[str],
- ) -> List[Dict[str, Any]]:
+ ) -> list[dict[str, Any]]:
params = {"session_uuids": list(session_uuids)}
query = sql.SQL(
"""
@@ -229,7 +230,7 @@ class GrlIqEventManager:
return res
@staticmethod
- def process_mouse_events(pointer_moves: List[PointerMove], events: List[Dict]):
+ def process_mouse_events(pointer_moves: list[PointerMove], events: list[dict]):
"""
In the db column 'mouse_events' we put all 'pointermove' events. Pull
those out, and then any 'pointerdown' and 'pointerup' events from the
@@ -274,7 +275,7 @@ class GrlIqEventManager:
return mouse_events
@staticmethod
- def process_keyboard_events(events: List[Dict]):
+ def process_keyboard_events(events: list[dict]):
res = [
KeyboardEvent(
type=x["type"],
diff --git a/generalresearch/grliq/managers/forensic_results.py b/generalresearch/grliq/managers/forensic_results.py
index 30db53d..52bde99 100644
--- a/generalresearch/grliq/managers/forensic_results.py
+++ b/generalresearch/grliq/managers/forensic_results.py
@@ -1,5 +1,6 @@
from datetime import datetime
-from typing import Any, Collection, Dict, List, Optional, Tuple
+from typing import Any, Dict, List, Optional, Tuple
+from collections.abc import Collection
from generalresearch.grliq.models.forensic_result import (
GrlIqForensicCategoryResult,
@@ -16,16 +17,16 @@ class GrlIqCategoryResultsReader:
def filter_category_results(
self,
- session_uuid: Optional[str] = None,
- fingerprint: Optional[str] = None,
- phase: Optional[Phase] = None,
- uuids: Optional[Collection[str]] = None,
- product_ids: Optional[Collection[str]] = None,
- created_since: Optional[datetime] = None,
- created_between: Optional[Tuple[datetime, datetime]] = None,
- user: Optional[User] = None,
- limit: Optional[int] = None,
- ) -> List[Dict[str, Any]]:
+ session_uuid: str | None = None,
+ fingerprint: str | None = None,
+ phase: Phase | None = None,
+ uuids: Collection[str] | None = None,
+ product_ids: Collection[str] | None = None,
+ created_since: datetime | None = None,
+ created_between: tuple[datetime, datetime] | None = None,
+ user: User | None = None,
+ limit: int | None = None,
+ ) -> list[dict[str, Any]]:
"""
For retrieving GrlIqForensicCategoryResult objects from db.
diff --git a/generalresearch/grliq/managers/forensic_summary.py b/generalresearch/grliq/managers/forensic_summary.py
index 21b7e4b..5039a38 100644
--- a/generalresearch/grliq/managers/forensic_summary.py
+++ b/generalresearch/grliq/managers/forensic_summary.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import statistics
from collections import defaultdict
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from typing import Any, Dict, List
import numpy as np
@@ -27,7 +27,7 @@ from generalresearch.redis_helper import RedisConfig
def calculate_category_summary(
- res: List[GrlIqForensicCategoryResult],
+ res: list[GrlIqForensicCategoryResult],
) -> GrlIqForensicCategorySummary:
totals = defaultdict(int)
is_complete_count = 0
@@ -55,7 +55,7 @@ def calculate_category_summary(
def calculate_checker_summary(
- res: List[GrlIqCheckerResults],
+ res: list[GrlIqCheckerResults],
) -> GrlIqCheckerResultsSummary:
totals = defaultdict(list)
none_totals = defaultdict(int)
@@ -85,8 +85,8 @@ def calculate_checker_summary(
def calculate_timing_summary(
- redis_config: RedisConfig, timing_res: List[Dict[str, Any]]
-) -> Dict[str, TimingDataCountrySummary]:
+ redis_config: RedisConfig, timing_res: list[dict[str, Any]]
+) -> dict[str, TimingDataCountrySummary]:
country_median_rtts = defaultdict(list)
for x in timing_res:
@@ -137,7 +137,7 @@ def run_user_forensic_summary(
user: User,
) -> UserForensicSummary:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
created_between = (now - timedelta(days=90), now)
select_str = "id, session_uuid, product_id, product_user_id, created_at, result_data, category_result"
res = iq_dm.filter(
@@ -158,7 +158,7 @@ def run_user_forensic_summary(
)
session_uuids = {x["session_uuid"] for x in res}
- timing_res: List[Dict] = iq_em.filter_distinct_timing(session_uuids=session_uuids)
+ timing_res: list[dict] = iq_em.filter_distinct_timing(session_uuids=session_uuids)
country_timing_data_summary = (
calculate_timing_summary(redis_config=redis_config, timing_res=timing_res)
diff --git a/generalresearch/grliq/models/custom_types.py b/generalresearch/grliq/models/custom_types.py
index c5eb93c..5c7f155 100644
--- a/generalresearch/grliq/models/custom_types.py
+++ b/generalresearch/grliq/models/custom_types.py
@@ -1,5 +1,5 @@
import annotated_types
-from typing_extensions import Annotated
+from typing import Annotated
GrlIqScore = Annotated[int, annotated_types.Ge(0), annotated_types.Le(100)]
GrlIqAvgScore = Annotated[float, annotated_types.Ge(0), annotated_types.Le(100)]
diff --git a/generalresearch/grliq/models/decider.py b/generalresearch/grliq/models/decider.py
index 4464a7f..d24e150 100644
--- a/generalresearch/grliq/models/decider.py
+++ b/generalresearch/grliq/models/decider.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field
@@ -35,7 +35,7 @@ class GrlIqAttemptResult(BaseModel):
timestamp: AwareDatetimeISO = Field(
description="When this decision was made",
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
)
decider: Decider = Field(description="Where this decision was made")
decision: AttemptDecision = Field(
diff --git a/generalresearch/grliq/models/events.py b/generalresearch/grliq/models/events.py
index 7e9ebee..5daa032 100644
--- a/generalresearch/grliq/models/events.py
+++ b/generalresearch/grliq/models/events.py
@@ -14,7 +14,7 @@ from pydantic import (
NonNegativeInt,
PositiveFloat,
)
-from typing_extensions import Self
+from typing import Self
from generalresearch.models.custom_types import AwareDatetimeISO, IPvAnyAddressStr
@@ -37,14 +37,14 @@ class Event:
# in microseconds, since page load (?)
timeStamp: float
# optional ID of the event target (e.g.: where the mouse is hovering)
- _elementId: Optional[str] = None
+ _elementId: str | None = None
# optional tag name of the event target
- _elementTagName: Optional[str] = None
+ _elementTagName: str | None = None
# extracted coordinates for the element being interacted with
- _elementBounds: Optional[Bounds] = None
+ _elementBounds: Bounds | None = None
@classmethod
- def from_dict(cls, data: Dict[str, Any]) -> Self:
+ def from_dict(cls, data: dict[str, Any]) -> Self:
data = {k: v for k, v in data.items() if k in cls.__dataclass_fields__}
bounds = data.get("_elementBounds")
if bounds is not None and not isinstance(bounds, Bounds):
@@ -104,13 +104,13 @@ class KeyboardEvent(Event):
# "insertText", "insertCompositionText", "deleteCompositionText",
# "insertFromComposition", "deleteContentBackward"
- inputType: Optional[str]
+ inputType: str | None
# e.g., 'Enter', 'a', 'Backspace'
- key: Optional[str] = None
+ key: str | None = None
# This is the actual text, if applicable
- data: Optional[str] = None
+ data: str | None = None
@property
def key_text(self):
@@ -159,18 +159,18 @@ class TimingData(BaseModel):
"""
model_config = ConfigDict(extra="forbid", validate_assignment=True)
- client_rtts: List[float] = Field()
- server_rtts: List[float] = Field()
+ client_rtts: list[float] = Field()
+ server_rtts: list[float] = Field()
# Have to be optional for backwards-compatibility, but should always be set.
- started_at: Optional[AwareDatetimeISO] = Field(default=None)
- ended_at: Optional[AwareDatetimeISO] = Field(default=None)
- client_ip: Optional[IPvAnyAddressStr] = Field(
+ started_at: AwareDatetimeISO | None = Field(default=None)
+ ended_at: AwareDatetimeISO | None = Field(default=None)
+ client_ip: IPvAnyAddressStr | None = Field(
description="This comes from the websocket request's headers",
examples=["72.39.217.116"],
default=None,
)
- server_hostname: Optional[str] = Field(
+ server_hostname: str | None = Field(
description="The hostname of the server that handled this request",
examples=["grliq-web-0"],
default=None,
@@ -189,7 +189,7 @@ class TimingData(BaseModel):
def has_data(self):
return len(self.client_rtts) > 0 and len(self.server_rtts) > 0
- def filter_rtts(self, rtts: List[float]) -> List[float]:
+ def filter_rtts(self, rtts: list[float]) -> list[float]:
# Skip the first 5 pings, unless we have <10 pings, then get the last
# 5 instead.
# The first couple pings are usually outliers as they are running
@@ -234,7 +234,7 @@ class TimingData(BaseModel):
return rtts
@property
- def summarize(self) -> Optional[TimingDataSummary]:
+ def summarize(self) -> TimingDataSummary | None:
if len(self.filtered_rtts) < 5:
return None
diff --git a/generalresearch/grliq/models/forensic_data.py b/generalresearch/grliq/models/forensic_data.py
index f8bdd98..eda7186 100644
--- a/generalresearch/grliq/models/forensic_data.py
+++ b/generalresearch/grliq/models/forensic_data.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import hashlib
import re
from collections import Counter
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from enum import Enum
from functools import cached_property
from typing import Any, Literal
@@ -23,7 +23,7 @@ from pydantic import (
)
from pydantic.json_schema import SkipJsonSchema
from pydantic_extra_types.timezone_name import TimeZoneName
-from typing_extensions import Annotated, Self
+from typing import Annotated, Self
from generalresearch.grliq.models import (
AUDIO_CODEC_NAMES,
@@ -776,7 +776,7 @@ class GrlIqData(BaseModel):
), "product_user_id mismatch"
# validate the Session's mid is "recent"
- assert (datetime.now(tz=timezone.utc) - session.started) < timedelta(
+ assert (datetime.now(tz=UTC) - session.started) < timedelta(
minutes=90
), "expired session"
diff --git a/generalresearch/grliq/models/forensic_summary.py b/generalresearch/grliq/models/forensic_summary.py
index d6f46f8..5ecf1a4 100644
--- a/generalresearch/grliq/models/forensic_summary.py
+++ b/generalresearch/grliq/models/forensic_summary.py
@@ -228,7 +228,7 @@ class CountryRTTDistribution(BaseModel):
rtt_mean: float = Field(gt=0, examples=[179.302])
rtt_max: float = Field(gt=0, examples=[890.006])
rtt_std: float = Field(gt=0, examples=[46.831])
- rtt_percentiles: List[float] = Field(
+ rtt_percentiles: list[float] = Field(
min_length=101, max_length=101, examples=[example_rtt_percentiles]
)
diff --git a/generalresearch/grliq/models/useragents.py b/generalresearch/grliq/models/useragents.py
index 1953f6d..4bb340e 100644
--- a/generalresearch/grliq/models/useragents.py
+++ b/generalresearch/grliq/models/useragents.py
@@ -4,7 +4,7 @@ import hashlib
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field, field_validator
-from typing_extensions import Self
+from typing import Self
from user_agents import parse as ua_parse
from user_agents.parsers import UserAgent
diff --git a/generalresearch/grliq/utils.py b/generalresearch/grliq/utils.py
index 95390a8..ca8c6a1 100644
--- a/generalresearch/grliq/utils.py
+++ b/generalresearch/grliq/utils.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import os
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from pathlib import Path
from uuid import UUID
@@ -16,7 +16,7 @@ def get_screenshot_fp(
grliq_ss_dir_name: str = "canvas2html",
create_dir_if_not_exists: bool = True,
) -> Path | None:
- assert created_at.tzinfo == timezone.utc
+ assert created_at.tzinfo == UTC
if isinstance(forensic_uuid, UUID):
forensic_uuid = forensic_uuid.hex
diff --git a/generalresearch/grpc.py b/generalresearch/grpc.py
index 040fd26..178521e 100644
--- a/generalresearch/grpc.py
+++ b/generalresearch/grpc.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from google.protobuf.duration_pb2 import Duration
from google.protobuf.timestamp_pb2 import Timestamp
@@ -20,13 +20,13 @@ def timestamp_from_datetime_nullable(dt: datetime | None) -> Timestamp:
def timestamp_to_datetime(ts: Timestamp) -> datetime:
- return datetime.fromtimestamp(ts.seconds + ts.nanos / 1e9, tz=timezone.utc)
+ return datetime.fromtimestamp(ts.seconds + ts.nanos / 1e9, tz=UTC)
def timestamp_to_datetime_nullable(ts: Timestamp) -> datetime | None:
# grpc has no None. If a google.protobuf.Timestamp field is not set, it gets interpreted as timestamp 0
- default = datetime.fromtimestamp(0, tz=timezone.utc)
- d = datetime.fromtimestamp(ts.seconds + ts.nanos / 1e9, tz=timezone.utc)
+ default = datetime.fromtimestamp(0, tz=UTC)
+ d = datetime.fromtimestamp(ts.seconds + ts.nanos / 1e9, tz=UTC)
return None if d == default else d
diff --git a/generalresearch/incite/base.py b/generalresearch/incite/base.py
index a8088ac..6888ca2 100644
--- a/generalresearch/incite/base.py
+++ b/generalresearch/incite/base.py
@@ -8,7 +8,7 @@ import shutil
import subprocess
import warnings
from concurrent.futures import Future
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from os import R_OK, access, listdir
from os.path import isdir
from os.path import join as pjoin
@@ -17,9 +17,8 @@ from sys import platform
from typing import (
TYPE_CHECKING,
Any,
- Callable,
- Sequence,
)
+from collections.abc import Callable, Sequence
from uuid import uuid4
import dask
@@ -43,7 +42,7 @@ from pydantic import (
)
from pydantic.json_schema import SkipJsonSchema
from sentry_sdk import capture_exception
-from typing_extensions import Self
+from typing import Self
from generalresearch.config import is_debug
from generalresearch.incite.schemas import (
@@ -166,7 +165,7 @@ class CollectionBase(BaseModel):
offset: str = Field(default="72h", max_length=5)
start: AwareDatetimeISO = Field(
- default=datetime(year=2018, month=1, day=1, tzinfo=timezone.utc),
+ default=datetime(year=2018, month=1, day=1, tzinfo=UTC),
description="This is the starting point in which data will be retrieved"
"in chunks from.",
frozen=True,
@@ -208,7 +207,7 @@ class CollectionBase(BaseModel):
return self
offset_total_sec = pd.Timedelta(self.offset).total_seconds()
- start_total_sec = (datetime.now(tz=timezone.utc) - self.start).total_seconds()
+ start_total_sec = (datetime.now(tz=UTC) - self.start).total_seconds()
if offset_total_sec > start_total_sec:
raise ValueError("Offset must be equal to, or smaller the start timestamp")
@@ -294,14 +293,14 @@ class CollectionBase(BaseModel):
@property
def interval_range(self) -> list[tuple[datetime, datetime]]:
"""closed='left', so 0 <= x < 5"""
- end = self.finished or datetime.now(tz=timezone.utc).replace(microsecond=0)
+ end = self.finished or datetime.now(tz=UTC).replace(microsecond=0)
iv_r = self._interval_range(end)
return [(iv.left.to_pydatetime(), iv.right.to_pydatetime()) for iv in iv_r]
@property
def progress(self) -> pd.DataFrame:
records = [i.to_dict() for i in self.items]
- end = self.finished if self.finished else datetime.now(tz=timezone.utc)
+ end = self.finished if self.finished else datetime.now(tz=UTC)
return pd.DataFrame.from_records(records, index=self._interval_range(end))
@property
@@ -626,15 +625,15 @@ class CollectionBase(BaseModel):
return res
def get_items_from_year(self, year: int) -> Items:
- ts = datetime(year=year, month=1, day=1, tzinfo=timezone.utc)
+ ts = datetime(year=year, month=1, day=1, tzinfo=UTC)
return self.get_items(since=ts)
def get_items_last90(self) -> Items:
- ts = datetime.now(tz=timezone.utc) - timedelta(days=90)
+ ts = datetime.now(tz=UTC) - timedelta(days=90)
return self.get_items(since=ts)
def get_items_last365(self) -> Items:
- ts = datetime.now(tz=timezone.utc) - timedelta(days=365)
+ ts = datetime.now(tz=UTC) - timedelta(days=365)
return self.get_items(since=ts)
@@ -642,7 +641,7 @@ class CollectionItemBase(BaseModel):
# I want to intentionally keep these as native python types, and not
# pandas specific types.
start: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc).replace(microsecond=0)
+ default_factory=lambda: datetime.now(tz=UTC).replace(microsecond=0)
)
# --- Private attrs ---
@@ -839,7 +838,7 @@ class CollectionItemBase(BaseModel):
if archive_after is None:
return False
- return datetime.now(tz=timezone.utc) > self.finish + archive_after
+ return datetime.now(tz=UTC) > self.finish + archive_after
def set_empty(self):
assert (
diff --git a/generalresearch/incite/defaults.py b/generalresearch/incite/defaults.py
index 421710e..5a95607 100644
--- a/generalresearch/incite/defaults.py
+++ b/generalresearch/incite/defaults.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from generalresearch.incite.base import GRLDatasets
from generalresearch.incite.collections import DFCollectionType
@@ -37,69 +37,69 @@ from generalresearch.sql_helper import SqlHelper
def session_df_collection(
- ds: "GRLDatasets", pg_config: PostgresConfig
+ ds: GRLDatasets, pg_config: PostgresConfig
) -> SessionDFCollection:
return SessionDFCollection(
offset="37h",
pg_config=pg_config,
- start=datetime(year=2022, month=5, day=3, hour=12, tzinfo=timezone.utc),
+ start=datetime(year=2022, month=5, day=3, hour=12, tzinfo=UTC),
archive_path=ds.archive_path(enum_type=DFCollectionType.SESSION),
)
def wall_df_collection(
- ds: "GRLDatasets", pg_config: PostgresConfig
+ ds: GRLDatasets, pg_config: PostgresConfig
) -> WallDFCollection:
return WallDFCollection(
offset="49h",
pg_config=pg_config,
- start=datetime(year=2022, month=5, day=3, hour=12, tzinfo=timezone.utc),
+ start=datetime(year=2022, month=5, day=3, hour=12, tzinfo=UTC),
archive_path=ds.archive_path(enum_type=DFCollectionType.WALL),
)
def user_df_collection(
- ds: "GRLDatasets", pg_config: PostgresConfig
+ ds: GRLDatasets, pg_config: PostgresConfig
) -> UserDFCollection:
return UserDFCollection(
offset="73h",
pg_config=pg_config,
- start=datetime(year=2016, month=7, day=13, hour=1, tzinfo=timezone.utc),
+ start=datetime(year=2016, month=7, day=13, hour=1, tzinfo=UTC),
archive_path=ds.archive_path(enum_type=DFCollectionType.USER),
)
def task_df_collection(
- ds: "GRLDatasets", pg_config: PostgresConfig
+ ds: GRLDatasets, pg_config: PostgresConfig
) -> TaskAdjustmentDFCollection:
return TaskAdjustmentDFCollection(
offset="48h",
pg_config=pg_config,
- start=datetime(year=2022, month=7, day=16, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2022, month=7, day=16, hour=0, tzinfo=UTC),
archive_path=ds.archive_path(enum_type=DFCollectionType.TASK_ADJUSTMENT),
)
def ledger_df_collection(
- ds: "GRLDatasets", pg_config: PostgresConfig
+ ds: GRLDatasets, pg_config: PostgresConfig
) -> LedgerDFCollection:
return LedgerDFCollection(
offset="12d",
pg_config=pg_config,
# thl_web:ledger_transaction - 1st record is 2018-03-14 20:22:17.408232
- start=datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC),
archive_path=ds.archive_path(enum_type=DFCollectionType.LEDGER),
)
# --- Marketplace Specifics --- #
def innovate_survey_history_collection(
- ds: "GRLDatasets", sql_helper: SqlHelper
+ ds: GRLDatasets, sql_helper: SqlHelper
) -> InnovateSurveyHistoryCollection:
return InnovateSurveyHistoryCollection(
offset="12h",
sql_helper=sql_helper,
- start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=UTC),
archive_path=ds.archive_path(
enum_type=DFCollectionType.INNOVATE_SURVEY_HISTORY
),
@@ -107,12 +107,12 @@ def innovate_survey_history_collection(
def morning_survey_ts_collection(
- ds: "GRLDatasets", sql_helper: SqlHelper
+ ds: GRLDatasets, sql_helper: SqlHelper
) -> MorningSurveyTimeseriesCollection:
return MorningSurveyTimeseriesCollection(
offset="12h",
sql_helper=sql_helper,
- start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=UTC),
archive_path=ds.archive_path(
enum_type=DFCollectionType.MORNING_SURVEY_TIMESERIES
),
@@ -120,23 +120,23 @@ def morning_survey_ts_collection(
def sago_survey_history_collection(
- ds: "GRLDatasets", sql_helper: SqlHelper
+ ds: GRLDatasets, sql_helper: SqlHelper
) -> SagoSurveyHistoryCollection:
return SagoSurveyHistoryCollection(
offset="12h",
sql_helper=sql_helper,
- start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=UTC),
archive_path=ds.archive_path(enum_type=DFCollectionType.SAGO_SURVEY_HISTORY),
)
def spectrum_survey_ts_collection(
- ds: "GRLDatasets", sql_helper: SqlHelper
+ ds: GRLDatasets, sql_helper: SqlHelper
) -> SpectrumSurveyTimeseriesCollection:
return SpectrumSurveyTimeseriesCollection(
offset="12h",
sql_helper=sql_helper,
- start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2024, month=3, day=1, hour=0, tzinfo=UTC),
archive_path=ds.archive_path(
enum_type=DFCollectionType.SPECTRUM_SURVEY_TIMESERIES
),
@@ -144,50 +144,50 @@ def spectrum_survey_ts_collection(
# --- Mergers: Foundations --- #
-def user_id_product(ds: "GRLDatasets") -> UserIdProductMerge:
+def user_id_product(ds: GRLDatasets) -> UserIdProductMerge:
return UserIdProductMerge(
- start=datetime(year=2010, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=2010, month=1, day=1, tzinfo=UTC),
offset=None,
archive_path=ds.archive_path(enum_type=MergeType.USER_ID_PRODUCT),
)
-def enriched_session(ds: "GRLDatasets") -> EnrichedSessionMerge:
+def enriched_session(ds: GRLDatasets) -> EnrichedSessionMerge:
return EnrichedSessionMerge(
- start=datetime(year=2023, month=5, day=1, tzinfo=timezone.utc),
+ start=datetime(year=2023, month=5, day=1, tzinfo=UTC),
offset="14d",
archive_path=ds.archive_path(enum_type=MergeType.ENRICHED_SESSION),
)
-def enriched_wall(ds: "GRLDatasets") -> EnrichedWallMerge:
+def enriched_wall(ds: GRLDatasets) -> EnrichedWallMerge:
return EnrichedWallMerge(
# start=datetime(year=2022, month=5, day=1, tzinfo=timezone.utc),
- start=datetime(year=2023, month=7, day=23, tzinfo=timezone.utc),
+ start=datetime(year=2023, month=7, day=23, tzinfo=UTC),
offset="14d",
archive_path=ds.archive_path(enum_type=MergeType.ENRICHED_WALL),
)
-def enriched_task_adjust(ds: "GRLDatasets") -> EnrichedTaskAdjustMerge:
+def enriched_task_adjust(ds: GRLDatasets) -> EnrichedTaskAdjustMerge:
return EnrichedTaskAdjustMerge(
- start=datetime(year=2010, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=2010, month=1, day=1, tzinfo=UTC),
offset=None,
archive_path=ds.archive_path(enum_type=MergeType.ENRICHED_TASK_ADJUST),
)
# --- Mergers: Others --- #
-def pop_ledger(ds: "GRLDatasets") -> PopLedgerMerge:
+def pop_ledger(ds: GRLDatasets) -> PopLedgerMerge:
return PopLedgerMerge(
# thl_web:ledger_transaction - 1st record is 2018-03-14 20:22:17.408232
- start=datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc),
+ start=datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC),
offset="30d",
archive_path=ds.archive_path(enum_type=MergeType.POP_LEDGER),
)
-def ym_survey_wall(ds: "GRLDatasets") -> YMSurveyWallMerge:
+def ym_survey_wall(ds: GRLDatasets) -> YMSurveyWallMerge:
return YMSurveyWallMerge(
start=None,
offset="10D",
diff --git a/generalresearch/incite/mergers/__init__.py b/generalresearch/incite/mergers/__init__.py
index b9c3789..9c5276c 100644
--- a/generalresearch/incite/mergers/__init__.py
+++ b/generalresearch/incite/mergers/__init__.py
@@ -1,7 +1,7 @@
import logging
import os.path
import subprocess
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from enum import Enum
from sys import platform
from typing import List, Optional, Type
@@ -11,7 +11,7 @@ import pandas as pd
from dask.distributed import Client
from pandera.pandas import DataFrameSchema
from pydantic import Field, ValidationInfo, field_validator, model_validator
-from typing_extensions import Self
+from typing import Self
from generalresearch.incite.base import CollectionBase, CollectionItemBase
from generalresearch.incite.schemas import PARTITION_ON
@@ -80,7 +80,7 @@ class MergeCollectionItem(CollectionItemBase):
pd.Timestamp(self.start) + pd.Timedelta(self._collection.offset)
).to_pydatetime()
else:
- return datetime.now(tz=timezone.utc).replace(microsecond=0)
+ return datetime.now(tz=UTC).replace(microsecond=0)
@property
def filename(self) -> str:
@@ -236,20 +236,20 @@ class MergeCollection(CollectionBase):
# In a merge, we can set offset = None which indicates that there is only 1
# period/item where the range is 'start' until now.
- offset: Optional[str] = Field(default="72h")
+ offset: str | None = Field(default="72h")
# In a merge, we can set start = None which indicates that there is only 1
# period/item where the range is (now - offset) until now.
- start: Optional[AwareDatetimeISO] = Field(
+ start: AwareDatetimeISO | None = Field(
default=None,
description="This is the starting point in which data will"
" be retrieved in chunks from.",
frozen=True,
)
- merge_type: Optional[MergeType] = Field(default=None)
- group_by: Optional[str] = Field(default=None)
- grouped_key: Optional[str] = Field(default=None)
- collection_item_class: Type[MergeCollectionItem] = MergeCollectionItem
+ merge_type: MergeType | None = Field(default=None)
+ group_by: str | None = Field(default=None)
+ grouped_key: str | None = Field(default=None)
+ collection_item_class: type[MergeCollectionItem] = MergeCollectionItem
@model_validator(mode="after")
def check_start_and_offset_nullable(self) -> Self:
@@ -269,16 +269,16 @@ class MergeCollection(CollectionBase):
# --- Properties ---
@property
- def interval_start(self) -> Optional[datetime]:
+ def interval_start(self) -> datetime | None:
# if self.start is None and self.offset is set, the inferred start is (now - offset)
if self.start is None:
- return datetime.now(tz=timezone.utc).replace(microsecond=0) - pd.Timedelta(
+ return datetime.now(tz=UTC).replace(microsecond=0) - pd.Timedelta(
self.offset
)
return self.start
@property
- def items(self) -> List[MergeCollectionItem]:
+ def items(self) -> list[MergeCollectionItem]:
items = []
for iv in self.interval_range:
cm = self.collection_item_class(start=iv[0])
diff --git a/generalresearch/incite/mergers/ym_wall_summary.py b/generalresearch/incite/mergers/ym_wall_summary.py
index 2f5995f..4816c05 100644
--- a/generalresearch/incite/mergers/ym_wall_summary.py
+++ b/generalresearch/incite/mergers/ym_wall_summary.py
@@ -82,7 +82,7 @@ class YMWallSummaryMergeItem(MergeCollectionItem):
class YMWallSummaryMerge(MergeCollection):
merge_type: Literal[MergeType.YM_WALL_SUMMARY] = MergeType.YM_WALL_SUMMARY
_schema = YMWallSummarySchema
- collection_item_class: Type[YMWallSummaryMergeItem] = YMWallSummaryMergeItem
+ collection_item_class: type[YMWallSummaryMergeItem] = YMWallSummaryMergeItem
items: list[YMWallSummaryMergeItem] = Field(default_factory=list)
@field_validator("offset")
diff --git a/generalresearch/incite/schemas/__init__.py b/generalresearch/incite/schemas/__init__.py
index c0000d1..6fc83b0 100644
--- a/generalresearch/incite/schemas/__init__.py
+++ b/generalresearch/incite/schemas/__init__.py
@@ -11,8 +11,8 @@ ARCHIVE_AFTER = "archive_after"
PARTITION_ON = "partition_on"
-def empty_dataframe_from_schema(schema: pa.DataFrameSchema) -> "pd.DataFrame":
- index_names: List[str] = schema.index.names
+def empty_dataframe_from_schema(schema: pa.DataFrameSchema) -> pd.DataFrame:
+ index_names: list[str] = schema.index.names
columns = set(schema.dtypes.keys())
if len(index_names) > 1:
diff --git a/generalresearch/incite/schemas/mergers/foundations/enriched_task_adjust.py b/generalresearch/incite/schemas/mergers/foundations/enriched_task_adjust.py
index cc909f6..97e73a3 100644
--- a/generalresearch/incite/schemas/mergers/foundations/enriched_task_adjust.py
+++ b/generalresearch/incite/schemas/mergers/foundations/enriched_task_adjust.py
@@ -13,7 +13,7 @@ from generalresearch.models.thl.definitions import (
thl_task_adj_columns = THLTaskAdjustmentSchema.columns.copy()
-COUNTRY_ISOS: Set[str] = Localelator().get_all_countries()
+COUNTRY_ISOS: set[str] = Localelator().get_all_countries()
kosovo = "xk"
COUNTRY_ISOS.add(kosovo)
BIGINT = 9223372036854775807
diff --git a/generalresearch/incite/schemas/thl_web.py b/generalresearch/incite/schemas/thl_web.py
index 5073a18..b831b9a 100644
--- a/generalresearch/incite/schemas/thl_web.py
+++ b/generalresearch/incite/schemas/thl_web.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
import pandas as pd
from pandera.pandas import Check, Column, DataFrameSchema, Index, MultiIndex
@@ -105,7 +105,7 @@ THLWallSchema = DataFrameSchema(
),
"started": Column(
dtype=pd.DatetimeTZDtype(tz="UTC"),
- checks=[Check(lambda x: x < datetime.now(tz=timezone.utc))],
+ checks=[Check(lambda x: x < datetime.now(tz=UTC))],
nullable=False,
),
"session_id": Column(
@@ -205,12 +205,12 @@ THLSessionSchema = DataFrameSchema(
),
"started": Column(
dtype=pd.DatetimeTZDtype(tz="UTC"),
- checks=[Check(lambda x: x < datetime.now(tz=timezone.utc))],
+ checks=[Check(lambda x: x < datetime.now(tz=UTC))],
nullable=True,
),
"finished": Column(
dtype=pd.DatetimeTZDtype(tz="UTC"),
- checks=[Check(lambda x: x < datetime.now(tz=timezone.utc))],
+ checks=[Check(lambda x: x < datetime.now(tz=UTC))],
nullable=True,
),
"loi_min": Column(dtype="Int64", nullable=True),
@@ -450,7 +450,7 @@ THLTaskAdjustmentSchema = DataFrameSchema(
),
"started": Column(
dtype=pd.DatetimeTZDtype(tz="UTC"),
- checks=[Check(lambda x: x < datetime.now(tz=timezone.utc))],
+ checks=[Check(lambda x: x < datetime.now(tz=UTC))],
),
"source": Column(
dtype=str,
diff --git a/generalresearch/locales/__init__.py b/generalresearch/locales/__init__.py
index 88b72e6..813966e 100644
--- a/generalresearch/locales/__init__.py
+++ b/generalresearch/locales/__init__.py
@@ -43,11 +43,11 @@ class Localelator:
pkgutil.get_data(__name__, "country_default_lang.json")
)
- def get_all_languages(self) -> Set[str]:
+ def get_all_languages(self) -> set[str]:
# returns only the ISO 639-2/B (three-letter codes)
return set(self.lang_alpha2_to_alpha3b.values())
- def get_all_countries(self) -> Set[str]:
+ def get_all_countries(self) -> set[str]:
# returns only the ISO 3166-1 alpha-2 (two-letter codes)
return set(self.country_alpha3_to_alpha2.values())
diff --git a/generalresearch/locales/timezone.py b/generalresearch/locales/timezone.py
index 50d539d..fce6e0e 100644
--- a/generalresearch/locales/timezone.py
+++ b/generalresearch/locales/timezone.py
@@ -3,7 +3,7 @@ from typing import Optional
from pytz import country_timezones
-def get_default_timezone(country_iso: str) -> Optional[str]:
+def get_default_timezone(country_iso: str) -> str | None:
# to list all:
# from pytz import country_names, country_timezones
# [country_timezones.get(country) for country in country_names]
@@ -72,6 +72,6 @@ country_default_locale = {
}
-def get_default_locale(country_iso: str) -> Optional[str]:
+def get_default_locale(country_iso: str) -> str | None:
# todo: "https://cdn.simplelocalize.io/public/v1/locales" to fill in the rest?
return country_default_locale.get(country_iso, None)
diff --git a/generalresearch/managers/cint/profiling.py b/generalresearch/managers/cint/profiling.py
index d549e94..9216aa5 100644
--- a/generalresearch/managers/cint/profiling.py
+++ b/generalresearch/managers/cint/profiling.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import json
-from typing import Collection
+from collections.abc import Collection
from generalresearch.models.cint.question import CintQuestion
from generalresearch.sql_helper import SqlHelper
diff --git a/generalresearch/managers/cint/survey.py b/generalresearch/managers/cint/survey.py
index f80542e..da1ecd9 100644
--- a/generalresearch/managers/cint/survey.py
+++ b/generalresearch/managers/cint/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -107,7 +107,7 @@ class CintSurveyManager(SurveyManager):
return True
def update(self, surveys: list[CintSurvey]) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
for survey in surveys:
survey.last_updated = now
diff --git a/generalresearch/managers/criteria.py b/generalresearch/managers/criteria.py
index fe70732..b5d9830 100644
--- a/generalresearch/managers/criteria.py
+++ b/generalresearch/managers/criteria.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from abc import ABC
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from more_itertools import chunked
@@ -65,7 +65,7 @@ class CriteriaManager(SqlManager, ABC):
new_hashes = this_hashes - known_hashes
if new_hashes:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
values = [
condition.to_mysql()
for condition in conditions
diff --git a/generalresearch/managers/dynata/profiling.py b/generalresearch/managers/dynata/profiling.py
index 25afbe2..661bdad 100644
--- a/generalresearch/managers/dynata/profiling.py
+++ b/generalresearch/managers/dynata/profiling.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import json
-from typing import Collection
+from collections.abc import Collection
from generalresearch.models.dynata.question import DynataQuestion
from generalresearch.sql_helper import SqlHelper
diff --git a/generalresearch/managers/dynata/survey.py b/generalresearch/managers/dynata/survey.py
index 372a57d..3a15c4d 100644
--- a/generalresearch/managers/dynata/survey.py
+++ b/generalresearch/managers/dynata/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -102,7 +102,7 @@ class DynataSurveyManager(SurveyManager):
return surveys
def create(self, survey: DynataSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(True)
@@ -123,7 +123,7 @@ class DynataSurveyManager(SurveyManager):
return True
def update(self, surveys: list[DynataSurvey]) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
update_fields = self.SURVEY_FIELDS + ["last_updated"]
data = [survey.to_mysql() for survey in surveys]
diff --git a/generalresearch/managers/events.py b/generalresearch/managers/events.py
index 0be2bb9..f3c6a04 100644
--- a/generalresearch/managers/events.py
+++ b/generalresearch/managers/events.py
@@ -5,7 +5,7 @@ import math
import socket
import threading
import time
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from typing import TYPE_CHECKING
@@ -141,7 +141,7 @@ class UserStatsManager(RedisManager):
pipe.execute()
def mark_user_active(self, user: User) -> None:
- now = datetime.now(tz=timezone.utc).isoformat()
+ now = datetime.now(tz=UTC).isoformat()
r = self.redis_client
pipe = r.pipeline(transaction=False)
@@ -175,7 +175,7 @@ class UserStatsManager(RedisManager):
# This call is idempotent; it can be called multiple times (for the
# same user) and won't falsely increase a counter; it will just
# reset the expiration for this user (times out after 60 min)
- now = datetime.now(tz=timezone.utc).isoformat()
+ now = datetime.now(tz=UTC).isoformat()
r = self.redis_client
pipe = r.pipeline(transaction=False)
diff --git a/generalresearch/managers/gr/authentication.py b/generalresearch/managers/gr/authentication.py
index a402693..409cb10 100644
--- a/generalresearch/managers/gr/authentication.py
+++ b/generalresearch/managers/gr/authentication.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import binascii
import logging
import os
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from typing import TYPE_CHECKING, Any
from psycopg import sql
@@ -29,7 +29,7 @@ class GRUserManager(PostgresManagerWithRedis):
) -> GRUser:
from generalresearch.models.gr.authentication import GRUser
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
instance = GRUser.model_validate(
{
@@ -147,7 +147,7 @@ class GRUserManager(PostgresManagerWithRedis):
for item in res:
for k, v in item.items():
if isinstance(item[k], datetime):
- item[k] = item[k].replace(tzinfo=timezone.utc)
+ item[k] = item[k].replace(tzinfo=UTC)
return [GRUser.model_validate(item) for item in res]
@@ -216,7 +216,7 @@ class GRTokenManager(PostgresManager):
"key": api_key,
"user_id": gr_user.id,
"user": gr_user,
- "created": datetime.now(tz=timezone.utc),
+ "created": datetime.now(tz=UTC),
}
)
@@ -251,7 +251,7 @@ class GRTokenManager(PostgresManager):
token = GRToken.model_validate(
{
"key": binascii.hexlify(os.urandom(20)).decode(),
- "created": datetime.now(tz=timezone.utc),
+ "created": datetime.now(tz=UTC),
"user_id": user_id,
}
)
@@ -298,6 +298,6 @@ class GRTokenManager(PostgresManager):
for k, _ in res.items():
if isinstance(res[k], datetime):
- res[k] = res[k].replace(tzinfo=timezone.utc)
+ res[k] = res[k].replace(tzinfo=UTC)
return GRToken.model_validate(res)
diff --git a/generalresearch/managers/gr/team.py b/generalresearch/managers/gr/team.py
index 6de82b0..393f446 100644
--- a/generalresearch/managers/gr/team.py
+++ b/generalresearch/managers/gr/team.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from typing import TYPE_CHECKING
from uuid import uuid4
@@ -43,7 +43,7 @@ class MembershipManager(PostgresManager):
owner=False,
team_id=team.id,
user_id=gr_user.id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
data = membership.model_dump(by_alias=True)
diff --git a/generalresearch/managers/innovate/survey.py b/generalresearch/managers/innovate/survey.py
index 7db2f49..c65b100 100644
--- a/generalresearch/managers/innovate/survey.py
+++ b/generalresearch/managers/innovate/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -121,7 +121,7 @@ class InnovateSurveyManager(SurveyManager):
return surveys
def create(self, survey: InnovateSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(True)
@@ -142,7 +142,7 @@ class InnovateSurveyManager(SurveyManager):
return True
def update(self, surveys: list[InnovateSurvey]) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
update_fields = self.SURVEY_FIELDS + ["updated"]
data = [survey.to_mysql() for survey in surveys]
diff --git a/generalresearch/managers/leaderboard/manager.py b/generalresearch/managers/leaderboard/manager.py
index 0bf0312..71c3a73 100644
--- a/generalresearch/managers/leaderboard/manager.py
+++ b/generalresearch/managers/leaderboard/manager.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from decimal import Decimal
from functools import cached_property
from typing import TYPE_CHECKING
@@ -45,7 +45,7 @@ class LeaderboardManager:
self.country_iso = country_iso
self.within_time_aware = None
if within_time is None:
- self.within_time_aware = datetime.now(tz=timezone.utc).astimezone(
+ self.within_time_aware = datetime.now(tz=UTC).astimezone(
self.timezone
)
elif within_time.tzinfo is not None:
@@ -57,7 +57,7 @@ class LeaderboardManager:
@cached_property
def period(self) -> Period:
local_ts = self.within_time_aware
- assert local_ts.tzinfo != timezone.utc and local_ts.tzinfo is not None
+ assert local_ts.tzinfo != UTC and local_ts.tzinfo is not None
t = pd.Timestamp(local_ts).tz_localize(tz=None)
freq_pd = {
LeaderboardFrequency.WEEKLY: "W-SUN",
diff --git a/generalresearch/managers/morning/survey.py b/generalresearch/managers/morning/survey.py
index 2d86f0f..5fba70d 100644
--- a/generalresearch/managers/morning/survey.py
+++ b/generalresearch/managers/morning/survey.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import json
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -138,7 +138,7 @@ class MorningSurveyManager(SurveyManager):
return bids
def create(self, bid: MorningBid) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = bid.to_mysql()
create_fields = self.BID_FIELDS + ["created", "updated"]
@@ -179,14 +179,14 @@ class MorningSurveyManager(SurveyManager):
return True
def update(self, surveys: list[MorningBid]) -> None:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
for survey in surveys:
self.update_one(survey, now=now)
def update_one(self, bid: MorningBid, now: datetime | None = None) -> bool:
if now is None:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = bid.to_mysql()
d["updated"] = now
diff --git a/generalresearch/managers/network/label.py b/generalresearch/managers/network/label.py
index 1efe875..c5306a6 100644
--- a/generalresearch/managers/network/label.py
+++ b/generalresearch/managers/network/label.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from psycopg import sql
from pydantic import IPvAnyNetwork, TypeAdapter
@@ -48,8 +48,8 @@ class IPLabelManager(PostgresManager):
filters = []
params = {}
if labeled_after or labeled_before:
- time_end = labeled_before or datetime.now(tz=timezone.utc)
- time_start = labeled_after or datetime(2017, 1, 1, tzinfo=timezone.utc)
+ time_end = labeled_before or datetime.now(tz=UTC)
+ time_start = labeled_after or datetime(2017, 1, 1, tzinfo=UTC)
assert time_start.tzinfo.utcoffset(time_start) == timedelta(), "must be UTC"
assert time_end.tzinfo.utcoffset(time_end) == timedelta(), "must be UTC"
filters.append("labeled_at BETWEEN %(time_start)s AND %(time_end)s")
diff --git a/generalresearch/managers/precision/survey.py b/generalresearch/managers/precision/survey.py
index 6fb30f2..833cb28 100644
--- a/generalresearch/managers/precision/survey.py
+++ b/generalresearch/managers/precision/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -104,7 +104,7 @@ class PrecisionSurveyManager(SurveyManager):
return surveys
def create(self, survey: PrecisionSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(False)
@@ -151,7 +151,7 @@ class PrecisionSurveyManager(SurveyManager):
return True
def update_one(self, survey: PrecisionSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
d["updated"] = now
diff --git a/generalresearch/managers/prodege/survey.py b/generalresearch/managers/prodege/survey.py
index f555290..750383f 100644
--- a/generalresearch/managers/prodege/survey.py
+++ b/generalresearch/managers/prodege/survey.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
@@ -93,7 +93,7 @@ class ProdegeSurveyManager(SurveyManager):
return surveys
def create(self, survey: ProdegeSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(True)
@@ -114,7 +114,7 @@ class ProdegeSurveyManager(SurveyManager):
return True
def update(self, surveys: list[ProdegeSurvey]) -> None:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
# Do to stupidity with bid/actual loi/ir values (see ProdegeSurvey.to_mysql), we now
# can't do a bulk update b/c the fields may be different in different rows. Just do
@@ -124,7 +124,7 @@ class ProdegeSurveyManager(SurveyManager):
def update_one(self, survey: ProdegeSurvey, now=None) -> bool:
if now is None:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
# We have to have special logic for bid/actual loi/ir here. The api is
# stupid and only returns one set of them. If we just do the db
diff --git a/generalresearch/managers/repdata/survey.py b/generalresearch/managers/repdata/survey.py
index 2e2224f..1e1c3c6 100644
--- a/generalresearch/managers/repdata/survey.py
+++ b/generalresearch/managers/repdata/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import json
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
@@ -122,7 +122,7 @@ class RepDataSurveyManager(SurveyManager):
return list(surveys.values())
def create(self, survey: RepDataSurvey | RepDataSurveyHashed) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(True)
@@ -160,7 +160,7 @@ class RepDataSurveyManager(SurveyManager):
return True
def update(self, surveys: list[RepDataSurveyHashed]) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
update_fields = self.SURVEY_FIELDS + ["last_updated"]
data = [survey.to_mysql() for survey in surveys]
diff --git a/generalresearch/managers/sago/survey.py b/generalresearch/managers/sago/survey.py
index 325639f..2582902 100644
--- a/generalresearch/managers/sago/survey.py
+++ b/generalresearch/managers/sago/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -101,7 +101,7 @@ class SagoSurveyManager(SurveyManager):
return surveys
def create(self, survey: SagoSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(True)
@@ -122,7 +122,7 @@ class SagoSurveyManager(SurveyManager):
return True
def update(self, surveys: list[SagoSurvey]) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
update_fields = self.SURVEY_FIELDS + ["updated"]
data = [survey.to_mysql() for survey in surveys]
@@ -131,7 +131,7 @@ class SagoSurveyManager(SurveyManager):
return True
def update_field(self, survey: SagoSurvey, field: str) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
conn: pymysql.Connection = self.sql_helper.make_connection()
value = survey.to_mysql()[field]
c = conn.cursor()
diff --git a/generalresearch/managers/spectrum/survey.py b/generalresearch/managers/spectrum/survey.py
index 3ff2db8..58f8a1a 100644
--- a/generalresearch/managers/spectrum/survey.py
+++ b/generalresearch/managers/spectrum/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
import pymysql
from pymysql import IntegrityError
@@ -110,7 +110,7 @@ class SpectrumSurveyManager(SurveyManager):
return surveys
def create(self, survey: SpectrumSurvey) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
conn: pymysql.Connection = self.sql_helper.make_connection()
conn.autocommit(True)
@@ -134,7 +134,7 @@ class SpectrumSurveyManager(SurveyManager):
return True
def update(self, surveys: list[SpectrumSurvey]) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
# Due to stupidity with bid/actual loi/ir values (last block nonsense),
# we can't do a bulk update b/c the fields may be different in
@@ -146,7 +146,7 @@ class SpectrumSurveyManager(SurveyManager):
def update_one(self, survey: SpectrumSurvey, now: datetime | None = None) -> bool:
if now is None:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = survey.to_mysql()
# We have to have special logic for bid/actual loi/ir here. The api
diff --git a/generalresearch/managers/thl/buyer.py b/generalresearch/managers/thl/buyer.py
index 04452cd..ae40bc8 100644
--- a/generalresearch/managers/thl/buyer.py
+++ b/generalresearch/managers/thl/buyer.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from generalresearch.managers.base import Permission, PostgresManager
from generalresearch.models import Source
@@ -45,7 +45,7 @@ class BuyerManager(PostgresManager):
return None
def bulk_get_or_create(self, source: Source, codes: Collection[str]) -> list[Buyer]:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
buyers = []
params_seq = []
diff --git a/generalresearch/managers/thl/cashout_method.py b/generalresearch/managers/thl/cashout_method.py
index 7365878..94617f7 100644
--- a/generalresearch/managers/thl/cashout_method.py
+++ b/generalresearch/managers/thl/cashout_method.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from collections.abc import Collection
from copy import copy
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from typing import Any
from uuid import UUID, uuid4
@@ -21,7 +21,7 @@ from generalresearch.models.thl.wallet.cashout_method import (
class CashoutMethodManager(PostgresManager):
def create(self, cm: CashoutMethod) -> None:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
query = """
INSERT INTO accounting_cashoutmethod (
id, last_updated, is_live, provider,
diff --git a/generalresearch/managers/thl/contest_manager.py b/generalresearch/managers/thl/contest_manager.py
index 517f677..286de3d 100644
--- a/generalresearch/managers/thl/contest_manager.py
+++ b/generalresearch/managers/thl/contest_manager.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from typing import Any, Literal, cast
from uuid import UUID
@@ -199,10 +199,10 @@ class ContestBaseManager(PostgresManager):
params["contest_type"] = contest_type.value
filters.append("contest_type = %(contest_type)s")
if starts_at_before is True:
- params["starts_at"] = datetime.now(tz=timezone.utc)
+ params["starts_at"] = datetime.now(tz=UTC)
filters.append("starts_at < %(starts_at)s")
elif starts_at_before:
- assert starts_at_before.tzinfo == timezone.utc
+ assert starts_at_before.tzinfo == UTC
params["starts_at"] = starts_at_before
filters.append("starts_at < %(starts_at)s")
if name is not None:
@@ -822,7 +822,7 @@ class MilestoneContestManager(ContestBaseManager):
if decision:
contest.update(
status=ContestStatus.COMPLETED,
- ended_at=datetime.now(tz=timezone.utc),
+ ended_at=datetime.now(tz=UTC),
end_reason=reason,
)
self.end_milestone_contest(contest)
diff --git a/generalresearch/managers/thl/ledger_manager/conditions.py b/generalresearch/managers/thl/ledger_manager/conditions.py
index a457f30..f79a0f0 100644
--- a/generalresearch/managers/thl/ledger_manager/conditions.py
+++ b/generalresearch/managers/thl/ledger_manager/conditions.py
@@ -1,8 +1,9 @@
from __future__ import annotations
import logging
-from datetime import datetime, timedelta, timezone
-from typing import TYPE_CHECKING, Callable
+from datetime import datetime, timedelta, timezone, UTC
+from typing import TYPE_CHECKING
+from collections.abc import Callable
from generalresearch.config import JAMES_BILLINGS_BPID, JAMES_BILLINGS_TX_CUTOFF
from generalresearch.currency import USDCent
@@ -73,7 +74,7 @@ def generate_condition_bp_payout(
skip_one_per_day_check: bool = False,
skip_wallet_balance_check: bool = False,
) -> Callable[..., tuple[bool, str]]:
- created = datetime.now(tz=timezone.utc)
+ created = datetime.now(tz=UTC)
def _condition(
lm: ThlLedgerManager,
diff --git a/generalresearch/managers/thl/ledger_manager/ledger.py b/generalresearch/managers/thl/ledger_manager/ledger.py
index 864f1dd..00fac27 100644
--- a/generalresearch/managers/thl/ledger_manager/ledger.py
+++ b/generalresearch/managers/thl/ledger_manager/ledger.py
@@ -3,8 +3,9 @@ from __future__ import annotations
import logging
from collections import defaultdict
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
-from typing import Any, Callable
+from datetime import datetime, timedelta, timezone, UTC
+from typing import Any
+from collections.abc import Callable
from uuid import UUID
import redis
@@ -104,8 +105,8 @@ class LedgerManagerBasePostgres(PostgresManager, RedisManager):
filters = []
params = {}
if time_start or time_end:
- time_end = time_end or datetime.now(tz=timezone.utc)
- time_start = time_start or datetime(2017, 1, 1, tzinfo=timezone.utc)
+ time_end = time_end or datetime.now(tz=UTC)
+ time_start = time_start or datetime(2017, 1, 1, tzinfo=UTC)
assert time_start.tzinfo.utcoffset(time_start) == timedelta()
assert time_end.tzinfo.utcoffset(time_end) == timedelta()
filters.append("lt.created BETWEEN %(time_start)s AND %(time_end)s")
@@ -152,7 +153,7 @@ class LedgerTransactionManager(LedgerManagerBasePostgres):
if metadata is None:
metadata = dict()
if created is None:
- created = datetime.now(tz=timezone.utc)
+ created = datetime.now(tz=UTC)
t = LedgerTransaction(
created=created,
@@ -449,7 +450,7 @@ class LedgerTransactionManager(LedgerManagerBasePostgres):
id=row["transaction_id"],
entries=entries,
metadata=metadata,
- created=row["created"].replace(tzinfo=timezone.utc),
+ created=row["created"].replace(tzinfo=UTC),
ext_description=row["ext_description"],
tag=row["tag"],
)
diff --git a/generalresearch/managers/thl/ledger_manager/thl_ledger.py b/generalresearch/managers/thl/ledger_manager/thl_ledger.py
index 3119a46..c9203f6 100644
--- a/generalresearch/managers/thl/ledger_manager/thl_ledger.py
+++ b/generalresearch/managers/thl/ledger_manager/thl_ledger.py
@@ -2,9 +2,10 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from decimal import Decimal
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
+from collections.abc import Callable
from uuid import UUID
import numpy as np
@@ -244,10 +245,10 @@ class ThlLedgerManager(LedgerManager):
time_end: datetime | None = None,
):
if time_start is None:
- time_start = datetime(year=2017, month=1, day=1, tzinfo=timezone.utc)
+ time_start = datetime(year=2017, month=1, day=1, tzinfo=UTC)
if time_end is None:
- time_end = datetime.now(tz=timezone.utc)
+ time_end = datetime.now(tz=UTC)
assert all(
isinstance(item, str) for item in account_uuids
@@ -798,7 +799,7 @@ class ThlLedgerManager(LedgerManager):
skip_flag_check = True
assert (
- datetime.now(tz=timezone.utc) > created
+ datetime.now(tz=UTC) > created
), "created cannot be in the future"
f = lambda: self.create_tx_bp_payout_(
product=product,
@@ -904,7 +905,7 @@ class ThlLedgerManager(LedgerManager):
for retry of a failed previous call.
"""
assert (
- datetime.now(tz=timezone.utc) > created
+ datetime.now(tz=UTC) > created
), "created cannot be in the future"
assert isinstance(amount, int)
assert isinstance(amount, USDCent)
@@ -1837,7 +1838,7 @@ class ThlLedgerManager(LedgerManager):
user.product.user_wallet_config.enabled
), "Can't get wallet balance on non-managed account."
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
wallet = self.get_account_or_create_user_wallet(user)
if user.product_id == JAMES_BILLINGS_BPID:
assert since_days_ago is None
@@ -1867,7 +1868,7 @@ class ThlLedgerManager(LedgerManager):
After 3 days, about 25% of all "future" recons have happened,
7 days: 50%, 14 days: 75%, till end of next month: 100%.
"""
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
# The redeemable balance can NOT ever be more than the actual user_wallet_balance
# Sum up the redeemable amount for each complete
diff --git a/generalresearch/managers/thl/product.py b/generalresearch/managers/thl/product.py
index 46280b8..3b92361 100644
--- a/generalresearch/managers/thl/product.py
+++ b/generalresearch/managers/thl/product.py
@@ -4,7 +4,7 @@ import json
import logging
import operator
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from decimal import Decimal
from threading import Lock
from typing import TYPE_CHECKING
@@ -293,7 +293,7 @@ class ProductManager(PostgresManager):
UserWalletConfig,
)
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
# TODO: Add product_id, and possibly name uniqueness validation to the
# pydantic model definition itself. The create manager doesn't need
diff --git a/generalresearch/managers/thl/profiling/uqa.py b/generalresearch/managers/thl/profiling/uqa.py
index cbe39e7..3854333 100644
--- a/generalresearch/managers/thl/profiling/uqa.py
+++ b/generalresearch/managers/thl/profiling/uqa.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from generalresearch.managers.base import PostgresManagerWithRedis
from generalresearch.models.thl.profiling.user_question_answer import (
@@ -128,7 +128,7 @@ class UQAManager(PostgresManagerWithRedis):
def get_from_db(self, user: User) -> list[UserQuestionAnswer]:
logger.info(f"get_uqa_from_db: {user.user_id}")
# Only store the latest row per question_id. We don't need it multiple times.
- since = datetime.now(tz=timezone.utc) - timedelta(days=30)
+ since = datetime.now(tz=UTC) - timedelta(days=30)
# We CAN use the RR, b/c either
# 1) the cache expired and the user hasn't sent an answer recently
diff --git a/generalresearch/managers/thl/profiling/user_upk.py b/generalresearch/managers/thl/profiling/user_upk.py
index 1820103..ee36124 100644
--- a/generalresearch/managers/thl/profiling/user_upk.py
+++ b/generalresearch/managers/thl/profiling/user_upk.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import json
from collections import defaultdict
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from typing import Any
from uuid import UUID
@@ -56,7 +56,7 @@ class UserUpkManager(PostgresManagerWithRedis):
return res
def get_user_upk_mysql(self, user_id: int) -> list[UpkQuestionAnswer]:
- since = datetime.now(tz=timezone.utc) - timedelta(days=89)
+ since = datetime.now(tz=UTC) - timedelta(days=89)
query = """
SELECT
diff --git a/generalresearch/managers/thl/session.py b/generalresearch/managers/thl/session.py
index 746a518..771f882 100644
--- a/generalresearch/managers/thl/session.py
+++ b/generalresearch/managers/thl/session.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import datetime, timedelta, timezone, UTC
from decimal import Decimal
from typing import Any
from uuid import UUID, uuid4
@@ -188,7 +188,7 @@ class SessionManager(PostgresManager):
# validation errors. There doesn't seem to be a clean way of doing this.
# model_copy with update doesn't trigger the validators, so we
# re-run model_validate after
- finished = finished if finished else datetime.now(tz=timezone.utc)
+ finished = finished if finished else datetime.now(tz=UTC)
session.update(
**{
"status": status,
@@ -451,13 +451,13 @@ class SessionManager(PostgresManager):
params = {}
if started_before or started_after:
- started_after = started_after or datetime(2017, 1, 1, tzinfo=timezone.utc)
- started_before = started_before or datetime.now(tz=timezone.utc)
+ started_after = started_after or datetime(2017, 1, 1, tzinfo=UTC)
+ started_before = started_before or datetime.now(tz=UTC)
assert (
- started_after.tzinfo == timezone.utc
+ started_after.tzinfo == UTC
), "started_after must be tz-aware as UTC"
assert (
- started_before.tzinfo == timezone.utc
+ started_before.tzinfo == UTC
), "started_before must be tz-aware as UTC"
assert (
started_after < started_before
@@ -467,13 +467,13 @@ class SessionManager(PostgresManager):
params["started_before"] = started_before
if adjusted_before or adjusted_after:
- adjusted_after = adjusted_after or datetime(2017, 1, 1, tzinfo=timezone.utc)
- adjusted_before = adjusted_before or datetime.now(tz=timezone.utc)
+ adjusted_after = adjusted_after or datetime(2017, 1, 1, tzinfo=UTC)
+ adjusted_before = adjusted_before or datetime.now(tz=UTC)
assert (
- adjusted_after.tzinfo == timezone.utc
+ adjusted_after.tzinfo == UTC
), "adjusted_after must be tz-aware as UTC"
assert (
- adjusted_before.tzinfo == timezone.utc
+ adjusted_before.tzinfo == UTC
), "adjusted_before must be tz-aware as UTC"
assert (
adjusted_after < adjusted_before
diff --git a/generalresearch/managers/thl/survey.py b/generalresearch/managers/thl/survey.py
index c7671ce..966e96d 100644
--- a/generalresearch/managers/thl/survey.py
+++ b/generalresearch/managers/thl/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from collections import defaultdict
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import Any
import pandas as pd
@@ -544,7 +544,7 @@ class SurveyStatManager(PostgresManager):
VALUES ({values_str})
ON CONFLICT ({unique_cols_str})
DO UPDATE SET {update_str};"""
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
params = [ss.model_dump_sql() | {"updated_at": now} for ss in survey_stats]
with self.pg_config.make_connection() as conn:
diff --git a/generalresearch/managers/thl/task_adjustment.py b/generalresearch/managers/thl/task_adjustment.py
index e4736d4..3ec3d41 100644
--- a/generalresearch/managers/thl/task_adjustment.py
+++ b/generalresearch/managers/thl/task_adjustment.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from functools import cached_property
@@ -120,8 +120,8 @@ class TaskAdjustmentManager(PostgresManager):
CHANGES/DELTAS as just communicated by the marketplace, not
what the Wall's final adjusted_* will be.
"""
- alert_time = alert_time or datetime.now(tz=timezone.utc)
- assert alert_time.tzinfo == timezone.utc
+ alert_time = alert_time or datetime.now(tz=UTC)
+ assert alert_time.tzinfo == UTC
wall = self.wall_manager.get_from_uuid(wall_uuid)
session = self.session_manager.get_from_id(wall.session_id)
diff --git a/generalresearch/managers/thl/user_compensate.py b/generalresearch/managers/thl/user_compensate.py
index 543de87..c6c0747 100644
--- a/generalresearch/managers/thl/user_compensate.py
+++ b/generalresearch/managers/thl/user_compensate.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from uuid import uuid4
@@ -28,7 +28,7 @@ def user_compensate(
pg_config = ledger_manager.pg_config
redis_client = ledger_manager.redis_client
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
assert type(amount_int) is int
user.prefetch_product(pg_config=pg_config)
assert (
diff --git a/generalresearch/managers/thl/user_manager/mysql_user_manager.py b/generalresearch/managers/thl/user_manager/mysql_user_manager.py
index dbed5de..7931ba4 100644
--- a/generalresearch/managers/thl/user_manager/mysql_user_manager.py
+++ b/generalresearch/managers/thl/user_manager/mysql_user_manager.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from functools import lru_cache
from uuid import uuid4
@@ -26,7 +26,7 @@ class MysqlUserManager:
def _set_last_seen(self, user: User) -> None:
# Don't call this directly. Use UserManager.set_last_seen()
assert not self.is_read_replica
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
self.pg_config.execute_write(
"""
UPDATE thl_user
@@ -118,7 +118,7 @@ class MysqlUserManager:
if not self.product_id_exists(product_id=product_id):
raise ValueError(f"userprofile_brokerageproduct not found: {product_id}")
- now = created or datetime.now(tz=timezone.utc)
+ now = created or datetime.now(tz=UTC)
user_uuid = uuid4().hex
params = {
"user_uuid": user_uuid,
diff --git a/generalresearch/managers/thl/userhealth.py b/generalresearch/managers/thl/userhealth.py
index fe2163f..0bc60ec 100644
--- a/generalresearch/managers/thl/userhealth.py
+++ b/generalresearch/managers/thl/userhealth.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import ipaddress
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from itertools import zip_longest
from typing import Any
@@ -210,7 +210,7 @@ class IPRecordManager(PostgresManagerWithRedis):
data = {
"user_id": user_id,
"ip": ipaddress.ip_address(ip).exploded,
- "created": datetime.now(tz=timezone.utc),
+ "created": datetime.now(tz=UTC),
}
fips_cols = [
@@ -335,7 +335,7 @@ class AuditLogManager(PostgresManager):
al = AuditLog.model_validate(
{
"user_id": user_id,
- "created": datetime.now(tz=timezone.utc),
+ "created": datetime.now(tz=UTC),
"level": level,
"event_type": event_type,
"event_msg": event_msg,
@@ -495,7 +495,7 @@ class AuditLogManager(PostgresManager):
), "must pass user_id as int"
if created_after is None:
- created_after = datetime.now(tz=timezone.utc) - timedelta(days=7)
+ created_after = datetime.now(tz=UTC) - timedelta(days=7)
filters = [
"user_id = ANY(%(user_ids)s)",
diff --git a/generalresearch/managers/thl/wall.py b/generalresearch/managers/thl/wall.py
index c2eb821..7e413d7 100644
--- a/generalresearch/managers/thl/wall.py
+++ b/generalresearch/managers/thl/wall.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import logging
from collections import defaultdict
from collections.abc import Collection
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from functools import cached_property
from uuid import uuid4
@@ -360,12 +360,10 @@ class WallManager(PostgresManager):
params = {}
filters.append("user_id = %(user_id)s")
params["user_id"] = user_id
- default_started = datetime.now(tz=timezone.utc) - timedelta(days=90)
+ default_started = datetime.now(tz=UTC) - timedelta(days=90)
started_after = started_after or default_started
- started_before = started_before or datetime.now(tz=timezone.utc)
- assert (
- started_before.tzinfo == timezone.utc
- ), "started_before must be tz-aware as UTC"
+ started_before = started_before or datetime.now(tz=UTC)
+ assert started_before.tzinfo == UTC, "started_before must be tz-aware as UTC"
assert (
started_after < started_before
), "started_after must be before started_before"
@@ -412,7 +410,7 @@ class WallManager(PostgresManager):
started_before: datetime | None = None,
order_by: str | None = "-started",
) -> list[WallAttempt]:
- started_before = started_before or datetime.now(tz=timezone.utc)
+ started_before = started_before or datetime.now(tz=UTC)
res = []
page = 1
while True:
diff --git a/generalresearch/managers/thl/wallet/__init__.py b/generalresearch/managers/thl/wallet/__init__.py
index b063e54..9f3ae85 100644
--- a/generalresearch/managers/thl/wallet/__init__.py
+++ b/generalresearch/managers/thl/wallet/__init__.py
@@ -32,8 +32,8 @@ def manage_pending_cashout(
user_ip_history_manager: UserIpHistoryManager,
user_manager: UserManager,
ledger_manager: ThlLedgerManager,
- order_data: Optional[Union[Dict[str, Any], CashMailOrderData]] = None,
- tango_client: Optional[TangoClient] = None,
+ order_data: dict[str, Any] | CashMailOrderData | None = None,
+ tango_client: TangoClient | None = None,
) -> UserPayoutEvent:
"""
Called by a UI actions performed by Todd. This rejects/approves/cancels
diff --git a/generalresearch/managers/thl/wallet/tango.py b/generalresearch/managers/thl/wallet/tango.py
index 2f2dc52..445719d 100644
--- a/generalresearch/managers/thl/wallet/tango.py
+++ b/generalresearch/managers/thl/wallet/tango.py
@@ -65,8 +65,8 @@ def complete_tango_order(
def create_tango_order(
- request_data: Dict[str, Any], ref_id: str, tango_client: TangoClient
-) -> Dict[str, Any]:
+ request_data: dict[str, Any], ref_id: str, tango_client: TangoClient
+) -> dict[str, Any]:
"""
Create a tango gift card order.
Throws exception if anything is not right.
diff --git a/generalresearch/models/admin/__init__.py b/generalresearch/models/admin/__init__.py
index ebe839a..ad6302b 100644
--- a/generalresearch/models/admin/__init__.py
+++ b/generalresearch/models/admin/__init__.py
@@ -1,14 +1,14 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
import pandas as pd
from dateutil import relativedelta
def get_date_list(start_datetime: datetime, end_datetime: datetime | None = None):
- start_datetime = start_datetime.replace(tzinfo=timezone.utc)
- end_datetime = end_datetime if end_datetime else datetime.now(tz=timezone.utc)
+ start_datetime = start_datetime.replace(tzinfo=UTC)
+ end_datetime = end_datetime if end_datetime else datetime.now(tz=UTC)
return (
pd.date_range(start_datetime, end_datetime, freq="1D")
.strftime("%Y-%m-%d")
@@ -22,7 +22,7 @@ def year_start(periods_ago: int = 6) -> datetime:
years. Goal is to provide a simple way to
know when to do filters from
"""
- n: datetime = datetime.now(tz=timezone.utc)
+ n: datetime = datetime.now(tz=UTC)
d: datetime = n - relativedelta.relativedelta(years=periods_ago)
return d.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
@@ -33,7 +33,7 @@ def month_start(periods_ago: int = 6) -> datetime:
months. Goal is to provide a simple way to
know when to do filters from
"""
- n: datetime = datetime.now(tz=timezone.utc)
+ n: datetime = datetime.now(tz=UTC)
d: datetime = n - relativedelta.relativedelta(months=periods_ago)
return d.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
@@ -44,7 +44,7 @@ def day_start(periods_ago: int = 6) -> datetime:
days. Goal is to provide a simple way to
know when to do filters from
"""
- n: datetime = datetime.now(tz=timezone.utc)
+ n: datetime = datetime.now(tz=UTC)
d: datetime = n - relativedelta.relativedelta(days=periods_ago)
return d.replace(hour=0, minute=0, second=0, microsecond=0)
@@ -55,6 +55,6 @@ def hour_start(periods_ago: int = 6) -> datetime:
hours. Goal is to provide a simple way to
know when to do filters from
"""
- n: datetime = datetime.now(tz=timezone.utc)
+ n: datetime = datetime.now(tz=UTC)
d: datetime = n - relativedelta.relativedelta(hours=periods_ago)
return d.replace(minute=0, second=0, microsecond=0)
diff --git a/generalresearch/models/admin/request.py b/generalresearch/models/admin/request.py
index 67bd263..2d68de1 100644
--- a/generalresearch/models/admin/request.py
+++ b/generalresearch/models/admin/request.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from enum import Enum
from typing import Literal
@@ -25,9 +25,9 @@ class ReportRequest(BaseModel):
index1: str = Field(default="product_id")
start: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc) - timedelta(days=14)
+ default_factory=lambda: datetime.now(tz=UTC) - timedelta(days=14)
)
- end: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=timezone.utc))
+ end: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
interval: Literal["5min", "15min", "1h", "6h", "12h", "1d"] = "1h"
include_open_bucket: bool = Field(default=True)
@@ -35,7 +35,7 @@ class ReportRequest(BaseModel):
@computed_field(
title="Start floor",
description="The datetime that this report starts from",
- examples=[datetime(year=2025, month=5, day=1, tzinfo=timezone.utc)],
+ examples=[datetime(year=2025, month=5, day=1, tzinfo=UTC)],
return_type=datetime,
)
@property
@@ -60,7 +60,7 @@ class ReportRequest(BaseModel):
@model_validator(mode="after")
def check_start_end_tz(self):
- assert self.start.tzinfo == self.end.tzinfo == timezone.utc
+ assert self.start.tzinfo == self.end.tzinfo == UTC
return self
@model_validator(mode="after")
@@ -150,7 +150,7 @@ class ReportRequest(BaseModel):
start=self.ts_start_floor,
end=self.ts_end,
freq=self.interval,
- tz=timezone.utc,
+ tz=UTC,
)
def bucket_ranges(self) -> list[tuple[pd.Timestamp, pd.Timestamp]]:
diff --git a/generalresearch/models/cint/__init__.py b/generalresearch/models/cint/__init__.py
index 2c1be7e..d2713ab 100644
--- a/generalresearch/models/cint/__init__.py
+++ b/generalresearch/models/cint/__init__.py
@@ -1,5 +1,6 @@
+from typing import Annotated
+
from pydantic import Field
-from typing_extensions import Annotated
CintQuestionIdType = Annotated[
str, Field(min_length=1, max_length=16, pattern=r"^[0-9]+$")
diff --git a/generalresearch/models/cint/question.py b/generalresearch/models/cint/question.py
index 1ac9eea..5959141 100644
--- a/generalresearch/models/cint/question.py
+++ b/generalresearch/models/cint/question.py
@@ -1,13 +1,12 @@
from __future__ import annotations
import json
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
-from typing import TYPE_CHECKING, Any, Literal
+from typing import TYPE_CHECKING, Any, Literal, Self
from uuid import UUID
from pydantic import BaseModel, Field, field_validator, model_validator
-from typing_extensions import Self
from generalresearch.models import Source, string_utils
from generalresearch.models.cint import CintQuestionIdType
@@ -151,7 +150,7 @@ class CintQuestion(MarketplaceQuestion):
options = None
created_at = datetime.strptime(
d["create_date"], "%Y-%m-%dT%H:%M:%S%z"
- ).astimezone(timezone.utc)
+ ).astimezone(UTC)
if d.get("question_options"):
options = [
@@ -189,7 +188,7 @@ class CintQuestion(MarketplaceQuestion):
]
if d.get("created_at"):
- d["created_at"] = d["created_at"].replace(tzinfo=timezone.utc)
+ d["created_at"] = d["created_at"].replace(tzinfo=UTC)
return cls(
question_id=d["question_id"],
diff --git a/generalresearch/models/cint/survey.py b/generalresearch/models/cint/survey.py
index 56384e3..01615f6 100644
--- a/generalresearch/models/cint/survey.py
+++ b/generalresearch/models/cint/survey.py
@@ -2,9 +2,9 @@ from __future__ import annotations
import json
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
-from typing import Any, Literal, Type
+from typing import Annotated, Any, Literal, Self, Type
from more_itertools import flatten
from pydantic import (
@@ -15,7 +15,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Annotated, Self
from generalresearch.locales import Localelator
from generalresearch.models import Source, TaskCalculationType
@@ -291,7 +290,7 @@ class CintSurvey(MarketplaceTask):
return data
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return CintCondition
@property
@@ -390,7 +389,7 @@ class CintSurvey(MarketplaceTask):
d["conditions"][q.criterion_hash] = q
d["quotas"] = quotas
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d["created_at"] = now
d["last_updated"] = now
@@ -418,8 +417,8 @@ class CintSurvey(MarketplaceTask):
@classmethod
def from_mysql(cls, d: Dict[str, Any]) -> Self:
- d["created_at"] = d["created_at"].replace(tzinfo=timezone.utc)
- d["last_updated"] = d["last_updated"].replace(tzinfo=timezone.utc)
+ d["created_at"] = d["created_at"].replace(tzinfo=UTC)
+ d["last_updated"] = d["last_updated"].replace(tzinfo=UTC)
d["qualifications"] = json.loads(d["qualifications"])
d["used_question_ids"] = json.loads(d["used_question_ids"])
d["quotas"] = json.loads(d["quotas"])
diff --git a/generalresearch/models/cint/task_collection.py b/generalresearch/models/cint/task_collection.py
index 5d39090..efb6e95 100644
--- a/generalresearch/models/cint/task_collection.py
+++ b/generalresearch/models/cint/task_collection.py
@@ -35,8 +35,8 @@ CintTaskCollectionSchema = DataFrameSchema(
"bid_ir": Column(float, Check.between(0, 1), nullable=True),
"created_at": Column(dtype=pd.DatetimeTZDtype(tz="UTC")),
"last_updated": Column(dtype=pd.DatetimeTZDtype(tz="UTC")),
- "used_question_ids": Column(List[str]),
- "all_hashes": Column(List[str]), # set >> list for column support
+ "used_question_ids": Column(list[str]),
+ "all_hashes": Column(list[str]), # set >> list for column support
},
checks=[],
index=Index(
diff --git a/generalresearch/models/custom_types.py b/generalresearch/models/custom_types.py
index 84bf8e3..9346064 100644
--- a/generalresearch/models/custom_types.py
+++ b/generalresearch/models/custom_types.py
@@ -3,8 +3,8 @@ from __future__ import annotations
import json
import re
import sys as _sys
-from datetime import datetime, timedelta, timezone
-from typing import Any, Literal
+from datetime import UTC, datetime, timedelta, timezone
+from typing import Annotated, Any, Literal
from uuid import UUID
from pydantic import (
@@ -20,7 +20,6 @@ from pydantic.functional_serializers import PlainSerializer
from pydantic.functional_validators import AfterValidator, BeforeValidator
from pydantic.networks import IPvAnyNetwork, UrlConstraints
from pydantic_core import MultiHostHost, Url
-from typing_extensions import Annotated
from generalresearch.models import DeviceType, Source
@@ -57,19 +56,17 @@ def convert_str_dt(v: Any) -> AwareDatetime | None:
# to parse a str that was dumped using the iso8601 format with Z suffix.
if v is not None and type(v) is str:
assert v.endswith("Z") and "T" in v, "invalid format"
- return datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%fZ").replace(
- tzinfo=timezone.utc
- )
+ return datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=UTC)
return v
def assert_utc(v: AwareDatetime) -> AwareDatetime:
if isinstance(v, datetime):
# We need utcoffset b/c FastAPI parses datetimes using FixedTimezone
- assert v.tzinfo == timezone.utc or v.tzinfo.utcoffset(v) == timedelta(
+ assert v.tzinfo == UTC or v.tzinfo.utcoffset(v) == timedelta(
0
), "Timezone is not UTC"
- v = v.astimezone(timezone.utc)
+ v = v.astimezone(UTC)
return v
@@ -309,4 +306,4 @@ PropertyCode = Annotated[
def now_utc_factory():
- return datetime.now(tz=timezone.utc)
+ return datetime.now(tz=UTC)
diff --git a/generalresearch/models/dynata/survey.py b/generalresearch/models/dynata/survey.py
index 0e1b3e5..097eea2 100644
--- a/generalresearch/models/dynata/survey.py
+++ b/generalresearch/models/dynata/survey.py
@@ -2,10 +2,10 @@ from __future__ import annotations
import json
import logging
-from datetime import timezone
+from datetime import UTC, timezone
from decimal import Decimal
from functools import cached_property
-from typing import Any, Literal, Type
+from typing import Any, Literal, Self, Type
from more_itertools import flatten
from pydantic import (
@@ -17,7 +17,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.locales import Localelator
from generalresearch.models import Source, TaskCalculationType
@@ -500,7 +499,7 @@ class DynataSurvey(MarketplaceTask):
return res
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return DynataCondition
@property
@@ -552,8 +551,8 @@ class DynataSurvey(MarketplaceTask):
@classmethod
def from_db(cls, d: Dict[str, Any]) -> Self:
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
- d["last_updated"] = d["last_updated"].replace(tzinfo=timezone.utc)
+ d["created"] = d["created"].replace(tzinfo=UTC)
+ d["last_updated"] = d["last_updated"].replace(tzinfo=UTC)
d["filters"] = json.loads(d["filters"])
d["quotas"] = json.loads(d["quotas"])
d["used_question_ids"] = json.loads(d["used_question_ids"])
diff --git a/generalresearch/models/events.py b/generalresearch/models/events.py
index 63ed2a1..5efd4f6 100644
--- a/generalresearch/models/events.py
+++ b/generalresearch/models/events.py
@@ -1,6 +1,6 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from enum import StrEnum
-from typing import Dict, Literal, Optional, Union
+from typing import Annotated, Dict, Literal, Optional, Union
from uuid import uuid4
from pydantic import (
@@ -12,7 +12,6 @@ from pydantic import (
TypeAdapter,
model_validator,
)
-from typing_extensions import Annotated
from generalresearch.models import Source
from generalresearch.models.custom_types import (
@@ -63,7 +62,7 @@ class TaskEnterPayload(BaseModel):
source: Source = Field()
survey_id: str = Field(min_length=1, max_length=32, examples=["127492892"])
- quota_id: Optional[str] = Field(
+ quota_id: str | None = Field(
default=None,
max_length=32,
description="The marketplace's internal quota id",
@@ -76,9 +75,9 @@ class TaskFinishPayload(TaskEnterPayload):
duration_sec: PositiveFloat = Field()
status: Status
- status_code_1: Optional[StatusCode1] = None
- status_code_2: Optional[WallStatusCode2] = None
- cpi: Optional[NonNegativeInt] = Field(le=4000, default=None)
+ status_code_1: StatusCode1 | None = None
+ status_code_2: WallStatusCode2 | None = None
+ cpi: NonNegativeInt | None = Field(le=4000, default=None)
class SessionEnterPayload(BaseModel):
@@ -91,18 +90,13 @@ class SessionFinishPayload(SessionEnterPayload):
duration_sec: PositiveFloat = Field()
status: Status
- status_code_1: Optional[StatusCode1] = None
- status_code_2: Optional[SessionStatusCode2] = None
- user_payout: Optional[NonNegativeInt] = Field(default=None, le=4000, ge=0)
+ status_code_1: StatusCode1 | None = None
+ status_code_2: SessionStatusCode2 | None = None
+ user_payout: NonNegativeInt | None = Field(default=None, le=4000, ge=0)
EventPayload = Annotated[
- Union[
- TaskEnterPayload,
- TaskFinishPayload,
- SessionEnterPayload,
- SessionFinishPayload,
- ],
+ TaskEnterPayload | TaskFinishPayload | SessionEnterPayload | SessionFinishPayload,
Field(discriminator="event_type"),
]
@@ -110,12 +104,10 @@ EventPayload = Annotated[
class EventEnvelope(BaseModel):
event_uuid: UUIDStr = Field(default_factory=lambda: uuid4().hex)
event_type: EventType = Field()
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
version: int = 1
- product_user_id: Optional[str] = Field(
+ product_user_id: str | None = Field(
min_length=3,
max_length=128,
examples=["app-user-9329ebd"],
@@ -136,7 +128,7 @@ class EventEnvelope(BaseModel):
class AggregateBySource(BaseModel):
total: NonNegativeInt = Field(default=0)
- by_source: Dict[Source, NonNegativeInt] = Field(default_factory=dict)
+ by_source: dict[Source, NonNegativeInt] = Field(default_factory=dict)
@model_validator(mode="after")
def remove_zero(self):
@@ -145,8 +137,8 @@ class AggregateBySource(BaseModel):
class MaxGaugeBySource(BaseModel):
- value: Optional[NonNegativeInt] = Field(default=None)
- by_source: Dict[Source, NonNegativeInt] = Field(default_factory=dict)
+ value: NonNegativeInt | None = Field(default=None)
+ by_source: dict[Source, NonNegativeInt] = Field(default_factory=dict)
@model_validator(mode="after")
def remove_zero(self):
@@ -174,11 +166,9 @@ class StatsSnapshot(TaskStatsSnapshot):
model_config = ConfigDict(ser_json_timedelta="float")
# If this is set, then everything is scoped to this country.
- country_iso: Optional[CountryISOLike] = Field(default=None)
+ country_iso: CountryISOLike | None = Field(default=None)
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# Counts: User related
active_users_last_1h: NonNegativeInt = Field(
@@ -217,17 +207,17 @@ class StatsSnapshot(TaskStatsSnapshot):
)
# Rolling averages
- session_avg_payout_last_24h: Optional[NonNegativeInt] = Field(
+ session_avg_payout_last_24h: NonNegativeInt | None = Field(
description="Average (actual) payout of all tasks completed in the past 24 hrs"
)
- session_avg_user_payout_last_24h: Optional[NonNegativeInt] = Field(
+ session_avg_user_payout_last_24h: NonNegativeInt | None = Field(
description="Average (actual) user payout of all tasks completed in the past 24 hrs"
)
- session_fail_avg_loi_last_24h: Optional[timedelta] = Field(
+ session_fail_avg_loi_last_24h: timedelta | None = Field(
description="Average LOI of all tasks terminated in the past 24 hrs (excludes abandons)"
)
- session_complete_avg_loi_last_24h: Optional[timedelta] = Field(
+ session_complete_avg_loi_last_24h: timedelta | None = Field(
description="Average LOI of all tasks completed in the past 24 hrs"
)
@@ -246,34 +236,26 @@ class StatsSnapshot(TaskStatsSnapshot):
class EventMessage(BaseModel):
kind: Literal[MessageKind.EVENT] = Field(default=MessageKind.EVENT)
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
data: EventEnvelope
class StatsMessage(BaseModel):
kind: Literal[MessageKind.STATS] = Field(default=MessageKind.STATS)
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# The data/StatsSnapshot can optionally be scoped to a country
- country_iso: Optional[CountryISOLike] = Field(default=None)
+ country_iso: CountryISOLike | None = Field(default=None)
data: StatsSnapshot
class PingMessage(BaseModel):
kind: Literal[MessageKind.PING] = Field(default=MessageKind.PING)
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
class PongMessage(BaseModel):
kind: Literal[MessageKind.PONG] = Field(default=MessageKind.PONG)
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
class SubscribeMessage(BaseModel):
diff --git a/generalresearch/models/gr/authentication.py b/generalresearch/models/gr/authentication.py
index 4ee70f9..67a8fc2 100644
--- a/generalresearch/models/gr/authentication.py
+++ b/generalresearch/models/gr/authentication.py
@@ -3,8 +3,8 @@ from __future__ import annotations
import binascii
import json
import os
-from datetime import datetime, timezone
-from typing import TYPE_CHECKING, Any
+from datetime import UTC, datetime, timezone
+from typing import TYPE_CHECKING, Any, Self
from pydantic import (
AnyHttpUrl,
@@ -15,7 +15,6 @@ from pydantic import (
PositiveInt,
field_validator,
)
-from typing_extensions import Self
from generalresearch.decorators import LOG
from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr
@@ -199,7 +198,7 @@ class GRUser(BaseModel):
@field_validator("date_joined")
@classmethod
def date_joined_utc(cls, v: datetime) -> datetime:
- return v.replace(tzinfo=timezone.utc)
+ return v.replace(tzinfo=UTC)
# --- Properties ---
@property
@@ -290,7 +289,7 @@ class GRUser(BaseModel):
@classmethod
def from_postgresql(cls, d: dict) -> Self:
- d["date_joined"] = d["date_joined"].replace(tzinfo=timezone.utc)
+ d["date_joined"] = d["date_joined"].replace(tzinfo=UTC)
return GRUser.model_validate(d)
@classmethod
@@ -354,7 +353,7 @@ class GRToken(BaseModel):
@field_validator("created", mode="before")
@classmethod
def created_utc(cls, v: datetime) -> datetime:
- return v.replace(tzinfo=timezone.utc)
+ return v.replace(tzinfo=UTC)
# --- Properties ---
diff --git a/generalresearch/models/gr/business.py b/generalresearch/models/gr/business.py
index 51317da..a67cf48 100644
--- a/generalresearch/models/gr/business.py
+++ b/generalresearch/models/gr/business.py
@@ -3,10 +3,10 @@ from __future__ import annotations
import json
import logging
import os
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
from pathlib import Path
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Self
from uuid import uuid4
import pandas as pd
@@ -16,7 +16,6 @@ from psycopg.rows import dict_row
from pydantic import BaseModel, ConfigDict, Field, PositiveInt
from pydantic.json_schema import SkipJsonSchema
from pydantic_extra_types.phone_numbers import PhoneNumber
-from typing_extensions import Self
from generalresearch.currency import USDCent
from generalresearch.decorators import LOG
@@ -391,8 +390,8 @@ class Business(BaseModel):
pop_ledger = plm(ds=ds)
if at_timestamp is None:
- at_timestamp = datetime.now(tz=timezone.utc)
- assert at_timestamp.tzinfo == timezone.utc
+ at_timestamp = datetime.now(tz=UTC)
+ assert at_timestamp.tzinfo == UTC
ddf = pop_ledger.ddf(
force_rr_latest=False,
@@ -724,7 +723,7 @@ class Business(BaseModel):
if "pop_financial" in keys:
# We should explicitly pass the pop_financial years we want. By default,
# at least get this year.
- year = datetime.now(tz=timezone.utc).year
+ year = datetime.now(tz=UTC).year
keys = list(set(keys) | {f"pop_financial:{year}"})
rc = gr_redis_config.create_redis_client()
diff --git a/generalresearch/models/gr/team.py b/generalresearch/models/gr/team.py
index 8d60825..900062f 100644
--- a/generalresearch/models/gr/team.py
+++ b/generalresearch/models/gr/team.py
@@ -2,10 +2,10 @@ from __future__ import annotations
import json
import os
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
from pathlib import Path
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Self
from uuid import uuid4
import pandas as pd
@@ -18,7 +18,6 @@ from pydantic import (
field_validator,
)
from pydantic.json_schema import SkipJsonSchema
-from typing_extensions import Self
from generalresearch.decorators import LOG
from generalresearch.incite.mergers.foundations.enriched_session import (
@@ -92,7 +91,7 @@ class Membership(BaseModel):
@classmethod
def created_utc(cls, v: datetime | str) -> datetime | str:
if isinstance(v, datetime):
- return v.replace(tzinfo=timezone.utc)
+ return v.replace(tzinfo=UTC)
return v
# --- prefetch methods ---
diff --git a/generalresearch/models/innovate/__init__.py b/generalresearch/models/innovate/__init__.py
index 054c69d..26946e9 100644
--- a/generalresearch/models/innovate/__init__.py
+++ b/generalresearch/models/innovate/__init__.py
@@ -1,7 +1,7 @@
from enum import Enum
+from typing import Annotated
from pydantic import StringConstraints
-from typing_extensions import Annotated
# Note, this is called the KEY in the Question model
InnovateQuestionID = Annotated[
diff --git a/generalresearch/models/innovate/survey.py b/generalresearch/models/innovate/survey.py
index bcd50d3..0359bd6 100644
--- a/generalresearch/models/innovate/survey.py
+++ b/generalresearch/models/innovate/survey.py
@@ -2,13 +2,14 @@ from __future__ import annotations
import json
import logging
-from datetime import date, timezone
+from datetime import UTC, date, timezone
from decimal import Decimal
from functools import cached_property
from typing import (
Annotated,
Any,
Literal,
+ Self,
Type,
)
@@ -20,7 +21,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Self
from generalresearch.locales import Localelator
from generalresearch.models import (
@@ -290,7 +290,7 @@ class InnovateSurvey(MarketplaceTask):
return cls.model_validate(d)
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return InnovateCondition
@property
@@ -361,10 +361,10 @@ class InnovateSurvey(MarketplaceTask):
@classmethod
def from_db(cls, d: dict[str, Any]) -> Self:
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
- d["modified_api"] = d["modified_api"].replace(tzinfo=timezone.utc)
- d["created_api"] = d["created_api"].replace(tzinfo=timezone.utc)
+ d["created"] = d["created"].replace(tzinfo=UTC)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
+ d["modified_api"] = d["modified_api"].replace(tzinfo=UTC)
+ d["created_api"] = d["created_api"].replace(tzinfo=UTC)
d["qualifications"] = json.loads(d["qualifications"])
d["used_question_ids"] = json.loads(d["used_question_ids"])
d["quotas"] = json.loads(d["quotas"])
diff --git a/generalresearch/models/legacy/bucket.py b/generalresearch/models/legacy/bucket.py
index 2650b0b..812241d 100644
--- a/generalresearch/models/legacy/bucket.py
+++ b/generalresearch/models/legacy/bucket.py
@@ -4,7 +4,7 @@ import logging
import math
from datetime import timedelta
from decimal import Decimal
-from typing import Any, Literal
+from typing import Any, Literal, Self
from pydantic import (
BaseModel,
@@ -14,7 +14,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models import Source
from generalresearch.models.custom_types import (
diff --git a/generalresearch/models/legacy/questions.py b/generalresearch/models/legacy/questions.py
index 81e794c..8e19e57 100644
--- a/generalresearch/models/legacy/questions.py
+++ b/generalresearch/models/legacy/questions.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Annotated, Any, Self
from pydantic import (
BaseModel,
@@ -14,7 +14,6 @@ from pydantic import (
model_validator,
)
from sentry_sdk import capture_exception
-from typing_extensions import Annotated, Self
from generalresearch.models.custom_types import UUIDStr
from generalresearch.models.legacy.api_status import StatusResponse
diff --git a/generalresearch/models/lucid/__init__.py b/generalresearch/models/lucid/__init__.py
index c3365db..4653339 100644
--- a/generalresearch/models/lucid/__init__.py
+++ b/generalresearch/models/lucid/__init__.py
@@ -1,5 +1,6 @@
+from typing import Annotated
+
from pydantic import Field
-from typing_extensions import Annotated
LucidQuestionIdType = Annotated[
str, Field(min_length=1, max_length=16, pattern=r"^[0-9]+$")
diff --git a/generalresearch/models/lucid/question.py b/generalresearch/models/lucid/question.py
index 908ce70..6cbcb73 100644
--- a/generalresearch/models/lucid/question.py
+++ b/generalresearch/models/lucid/question.py
@@ -2,10 +2,9 @@ from __future__ import annotations
import logging
from enum import Enum
-from typing import TYPE_CHECKING, Any, Literal
+from typing import TYPE_CHECKING, Any, Literal, Self
from pydantic import BaseModel, Field, field_validator, model_validator
-from typing_extensions import Self
from generalresearch.models import Source
from generalresearch.models.lucid import LucidQuestionIdType
diff --git a/generalresearch/models/marketplace/summary.py b/generalresearch/models/marketplace/summary.py
index f75c530..9551417 100644
--- a/generalresearch/models/marketplace/summary.py
+++ b/generalresearch/models/marketplace/summary.py
@@ -2,11 +2,10 @@ from __future__ import annotations
from abc import ABC
from collections.abc import Collection
-from typing import Literal
+from typing import Literal, Self
import numpy as np
from pydantic import BaseModel, ConfigDict, Field, computed_field
-from typing_extensions import Self
from generalresearch.models.thl.stats import StatisticalSummary
diff --git a/generalresearch/models/morning/__init__.py b/generalresearch/models/morning/__init__.py
index 2c61c49..1bc15a7 100644
--- a/generalresearch/models/morning/__init__.py
+++ b/generalresearch/models/morning/__init__.py
@@ -1,7 +1,7 @@
from enum import Enum
+from typing import Annotated
from pydantic import StringConstraints
-from typing_extensions import Annotated
# This is text-based, in lowercase. e.g. 'age', 'household_income'
MorningQuestionID = Annotated[
diff --git a/generalresearch/models/morning/question.py b/generalresearch/models/morning/question.py
index 0ab5030..8a1f729 100644
--- a/generalresearch/models/morning/question.py
+++ b/generalresearch/models/morning/question.py
@@ -1,10 +1,9 @@
import json
from enum import Enum
-from typing import Any, Literal, Dict, List, Optional
+from typing import Any, Dict, List, Literal, Optional, Self
from uuid import UUID
from pydantic import BaseModel, Field, field_validator, model_validator
-from typing_extensions import Self
from generalresearch.locales import Localelator
from generalresearch.models import Source
@@ -54,7 +53,7 @@ class MorningQuestionType(str, Enum):
class MorningUserQuestionAnswer(MarketplaceUserQuestionAnswer):
question_id: MorningQuestionID = Field()
- question_type: Optional[MorningQuestionType] = Field(default=None)
+ question_type: MorningQuestionType | None = Field(default=None)
# Did this answer come from us asking, or was it passed back from the
# marketplace? Note, morning doesn't "pass back" answers, but we can
# retrieve a user's profile through API, so it is possible to populate
@@ -92,7 +91,7 @@ class MorningQuestion(MarketplaceQuestion):
frozen=True,
)
# API calls this "responses", but I think that is a confusing name
- options: Optional[List[MorningQuestionOption]] = Field(
+ options: list[MorningQuestionOption] | None = Field(
default=None, min_length=1, frozen=True
)
@@ -119,7 +118,7 @@ class MorningQuestion(MarketplaceQuestion):
return options
@classmethod
- def from_api(cls, d: Dict[str, Any], country_iso: str, language_iso: str):
+ def from_api(cls, d: dict[str, Any], country_iso: str, language_iso: str):
options = None
if d.get("responses"):
options = [
@@ -138,7 +137,7 @@ class MorningQuestion(MarketplaceQuestion):
)
@classmethod
- def from_db(cls, d: Dict[str, Any]) -> Self:
+ def from_db(cls, d: dict[str, Any]) -> Self:
options = None
if d["options"]:
options = [
@@ -162,7 +161,7 @@ class MorningQuestion(MarketplaceQuestion):
),
)
- def to_mysql(self) -> Dict[str, Any]:
+ def to_mysql(self) -> dict[str, Any]:
d = self.model_dump(mode="json", by_alias=True)
d["options"] = json.dumps(d["options"])
return d
diff --git a/generalresearch/models/morning/survey.py b/generalresearch/models/morning/survey.py
index 255a63c..3c5a0e0 100644
--- a/generalresearch/models/morning/survey.py
+++ b/generalresearch/models/morning/survey.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import json
import logging
-from datetime import timezone
+from datetime import UTC, timezone
from decimal import Decimal
from functools import cached_property
from typing import (
@@ -12,6 +12,7 @@ from typing import (
List,
Literal,
Optional,
+ Self,
Set,
Tuple,
Type,
@@ -27,7 +28,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Self
from generalresearch.locales import Localelator
from generalresearch.models import Source
@@ -79,14 +79,14 @@ class MorningStatistics(BaseModel):
# bid bid_loi: int = Field(validation_alias="estimated_length_of_interview",
# le=120 * 60)
# If num_completes == 0 , this gets returned as 0. it should be None
- obs_median_loi: Optional[NonNegativeInt] = Field(
+ obs_median_loi: NonNegativeInt | None = Field(
validation_alias="median_length_of_interview", default=None, le=120 * 60
)
# API returns 100 until 5 completes! Should be None.
# This is calculated as the total completes divided by the total number of
# finished sessions that passed the prescreener.
- qualified_conversion: Optional[float] = Field(
+ qualified_conversion: float | None = Field(
ge=0, le=1, description="conversion rate of qualified respondents"
)
@@ -142,7 +142,7 @@ class MorningTaskStatistics(MorningStatistics):
# relevant to quotas.
# API returns 100 until 5 completes! Should be None ...
- system_conversion: Optional[float] = Field(
+ system_conversion: float | None = Field(
description="conversion rate of the system. completes divided by total number of entrants to the system",
ge=0,
le=1,
@@ -166,8 +166,8 @@ class MorningTaskStatistics(MorningStatistics):
class MorningCondition(MarketplaceCondition):
model_config = ConfigDict(populate_by_name=True, frozen=False, extra="ignore")
- question_id: Optional[MorningQuestionID] = Field(validation_alias="id")
- values: List[Annotated[str, Field(max_length=128)]] = Field(
+ question_id: MorningQuestionID | None = Field(validation_alias="id")
+ values: list[Annotated[str, Field(max_length=128)]] = Field(
validation_alias="response_ids"
)
value_type: ConditionValueType = Field(default=ConditionValueType.LIST)
@@ -184,11 +184,11 @@ class MorningQuota(MorningStatistics, MarketplaceTask):
max_digits=5,
validation_alias="cost_per_interview",
)
- condition_hashes: List[str] = Field(min_length=1, default_factory=list)
+ condition_hashes: list[str] = Field(min_length=1, default_factory=list)
# since the Quota is the MarketplaceTask, it needs these fields, copied from the Bid
source: Literal[Source.MORNING_CONSULT] = Field(default=Source.MORNING_CONSULT)
- used_question_ids: Set[MorningQuestionID] = Field(default_factory=set)
+ used_question_ids: set[MorningQuestionID] = Field(default_factory=set)
country_iso: CountryISO = Field(frozen=True)
country_isos: CountryISOs = Field()
language_isos: LanguageISOs = Field(frozen=True)
@@ -219,11 +219,11 @@ class MorningQuota(MorningStatistics, MarketplaceTask):
@computed_field
@cached_property
- def all_hashes(self) -> Set[str]:
+ def all_hashes(self) -> set[str]:
return set(self.condition_hashes)
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return MorningCondition
@property
@@ -233,7 +233,7 @@ class MorningQuota(MorningStatistics, MarketplaceTask):
@property
def marketplace_genders(
self,
- ) -> Dict[Gender, Optional[MarketplaceCondition]]:
+ ) -> dict[Gender, MarketplaceCondition | None]:
return {
Gender.MALE: MorningCondition(
question_id="gender",
@@ -253,14 +253,14 @@ class MorningQuota(MorningStatistics, MarketplaceTask):
# num_available includes in-progress (they're already deducted)
return self.num_available >= self._min_open_spots
- def passes(self, criteria_evaluation: Dict[str, Optional[bool]]) -> bool:
+ def passes(self, criteria_evaluation: dict[str, bool | None]) -> bool:
# Passes means we 1) meet all conditions (aka "match") AND 2) the quota is open.
return self.is_open and self.matches(criteria_evaluation)
# TODO: I did some speed tests. This is faster than how this is implemented
# in sago/spectrum/dynata/etc. We should generalize this logic instead of
# copying/pasting it 7 times. (matches, matches_optional and _soft)
- def matches(self, criteria_evaluation: Dict[str, Optional[bool]]) -> bool:
+ def matches(self, criteria_evaluation: dict[str, bool | None]) -> bool:
# Matches means we meet all conditions.
# In Morning, all quotas are mutually exclusive. so if it doesn't
# matter if we match a closed quota, b/c that means that we won't
@@ -268,8 +268,8 @@ class MorningQuota(MorningStatistics, MarketplaceTask):
return self.matches_optional(criteria_evaluation) is True
def matches_optional(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Optional[bool]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> bool | None:
for c in self.condition_hashes:
eval_value = criteria_evaluation.get(c)
if eval_value is False:
@@ -279,8 +279,8 @@ class MorningQuota(MorningStatistics, MarketplaceTask):
return True
def matches_soft(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Tuple[Optional[bool], List[str]]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> tuple[bool | None, list[str]]:
# Passes back "matches" (T/F/none) and a list of unknown criterion hashes
unknowns = list()
for c in self.condition_hashes:
@@ -321,22 +321,22 @@ class MorningBid(MorningTaskStatistics):
timeout: PositiveInt = Field(le=24 * 60 * 60)
topic_id: str = Field(min_length=1, max_length=64)
- exclusions: List[MorningExclusion] = Field(default_factory=list)
+ exclusions: list[MorningExclusion] = Field(default_factory=list)
- quotas: List[MorningQuota] = Field(default_factory=list)
+ quotas: list[MorningQuota] = Field(default_factory=list)
source: Literal[Source.MORNING_CONSULT] = Field(default=Source.MORNING_CONSULT)
- used_question_ids: Set[MorningQuestionID] = Field(default_factory=set)
+ used_question_ids: set[MorningQuestionID] = Field(default_factory=set)
# This is a "special" key to store all conditions that are used (as
# "condition_hashes") throughout this survey. In the reduced representation
# of this task (nearly always, for db i/o, in global_vars) this field will
# be null.
- conditions: Optional[Dict[str, MorningCondition]] = Field(default=None)
+ conditions: dict[str, MorningCondition] | None = Field(default=None)
# This doesn't get stored in the db directly
- experimental_single_use_qualifications: Optional[List[MorningQuestion]] = Field(
+ experimental_single_use_qualifications: list[MorningQuestion] | None = Field(
default=None
)
@@ -345,8 +345,8 @@ class MorningBid(MorningTaskStatistics):
created_api: AwareDatetimeISO = Field(validation_alias="published_at")
# This does not come from the API. We set it when we update this in the db.
- created: Optional[AwareDatetimeISO] = Field(default=None)
- updated: Optional[AwareDatetimeISO] = Field(default=None)
+ created: AwareDatetimeISO | None = Field(default=None)
+ updated: AwareDatetimeISO | None = Field(default=None)
# ignoring from API: closed_at
@@ -373,7 +373,7 @@ class MorningBid(MorningTaskStatistics):
@computed_field
@cached_property
- def all_hashes(self) -> Set[str]:
+ def all_hashes(self) -> set[str]:
s = set()
for q in self.quotas:
s.update(set(q.condition_hashes))
@@ -387,7 +387,7 @@ class MorningBid(MorningTaskStatistics):
@model_validator(mode="before")
@classmethod
- def setup_quota_fields(cls, data: Dict[str, Any]) -> Dict[str, Any]:
+ def setup_quota_fields(cls, data: dict[str, Any]) -> dict[str, Any]:
# These fields get "inherited" by each quota from its bid.
quota_fields = [
"country_iso",
@@ -419,7 +419,7 @@ class MorningBid(MorningTaskStatistics):
@model_validator(mode="before")
@classmethod
- def setup_conditions(cls, data: Dict[str, Any]) -> Dict[str, Any]:
+ def setup_conditions(cls, data: dict[str, Any]) -> dict[str, Any]:
if "conditions" in data:
return data
@@ -448,7 +448,7 @@ class MorningBid(MorningTaskStatistics):
@model_validator(mode="before")
@classmethod
- def clean_alias(cls, data: Dict[str, Any]) -> Dict[str, Any]:
+ def clean_alias(cls, data: dict[str, Any]) -> dict[str, Any]:
# Make sure fields are named certain ways, so we don't have to check
# aliases within other validators
if "estimated_length_of_interview" in data:
@@ -503,18 +503,16 @@ class MorningBid(MorningTaskStatistics):
return d
@classmethod
- def from_db(cls, d: Dict[str, Any]) -> Self:
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
- d["expected_end"] = d["expected_end"].replace(tzinfo=timezone.utc)
- d["created_api"] = d["created_api"].replace(tzinfo=timezone.utc)
+ def from_db(cls, d: dict[str, Any]) -> Self:
+ d["created"] = d["created"].replace(tzinfo=UTC)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
+ d["expected_end"] = d["expected_end"].replace(tzinfo=UTC)
+ d["created_api"] = d["created_api"].replace(tzinfo=UTC)
d["used_question_ids"] = json.loads(d["used_question_ids"])
d["exclusions"] = json.loads(d["exclusions"])
return cls.model_validate(d)
- def passes_quotas(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Optional[str]:
+ def passes_quotas(self, criteria_evaluation: dict[str, bool | None]) -> str | None:
# Quotas are mutually-exclusive. A user can only possibly match 1 quota.
# Returns the passing quota ID or None (if user doesn't pass any quota)
for q in self.quotas:
@@ -522,8 +520,8 @@ class MorningBid(MorningTaskStatistics):
return q.id
def passes_quotas_soft(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Tuple[Optional[bool], Optional[List[str]], Optional[Set[str]]]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> tuple[bool | None, list[str] | None, set[str] | None]:
"""
Quotas are mutually-exclusive. A user can only possibly match 1
quota. As such, all unknown questions on any quota will be
@@ -547,15 +545,15 @@ class MorningBid(MorningTaskStatistics):
return False, None, None
def determine_eligibility(
- self, criteria_evaluation: dict[str, Optional[bool]]
- ) -> Optional[str]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> str | None:
if not self.is_open:
return None
return self.passes_quotas(criteria_evaluation)
def determine_eligibility_soft(
- self, criteria_evaluation: dict[str, Optional[bool]]
- ) -> Tuple[Optional[bool], Optional[List[str]], Optional[Set[str]]]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> tuple[bool | None, list[str] | None, set[str] | None]:
if not self.is_open:
return False, None, None
return self.passes_quotas_soft(criteria_evaluation)
diff --git a/generalresearch/models/network/mtr/execute.py b/generalresearch/models/network/mtr/execute.py
index d77e814..953124d 100644
--- a/generalresearch/models/network/mtr/execute.py
+++ b/generalresearch/models/network/mtr/execute.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from uuid import uuid4
from generalresearch.models.custom_types import UUIDStr
@@ -33,10 +33,10 @@ def execute_mtr(
),
)
- started_at = datetime.now(tz=timezone.utc)
+ started_at = datetime.now(tz=UTC)
tool_version = get_mtr_version()
result = run_mtr(config)
- finished_at = datetime.now(tz=timezone.utc)
+ finished_at = datetime.now(tz=UTC)
return MTRRun(
tool_name=ToolName.MTR,
diff --git a/generalresearch/models/network/nmap/parser.py b/generalresearch/models/network/nmap/parser.py
index e946e5f..6ad4ab4 100644
--- a/generalresearch/models/network/nmap/parser.py
+++ b/generalresearch/models/network/nmap/parser.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import xml.etree.ElementTree as ET
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import Any
from generalresearch.models.network.definitions import IPProtocol
@@ -123,7 +123,7 @@ class NmapXmlParser:
finished_at = None
ts = finished.attrib.get("time")
if ts:
- finished_at = datetime.fromtimestamp(int(ts), tz=timezone.utc)
+ finished_at = datetime.fromtimestamp(int(ts), tz=UTC)
return {
"finished_at": finished_at,
@@ -136,7 +136,7 @@ class NmapXmlParser:
nmaprun = dict(nmaprun_el.attrib)
nmap_data["command_line"] = nmaprun["args"]
nmap_data["started_at"] = datetime.fromtimestamp(
- float(nmaprun["start"]), tz=timezone.utc
+ float(nmaprun["start"]), tz=UTC
)
nmap_data["version"] = nmaprun["version"]
nmap_data["xmloutputversion"] = nmaprun["xmloutputversion"]
diff --git a/generalresearch/models/network/nmap/result.py b/generalresearch/models/network/nmap/result.py
index 3f9cae6..e6a0fd3 100644
--- a/generalresearch/models/network/nmap/result.py
+++ b/generalresearch/models/network/nmap/result.py
@@ -256,13 +256,13 @@ class NmapScanInfo(BaseModel):
services: str = Field()
@cached_property
- def port_set(self) -> Set[int]:
+ def port_set(self) -> set[int]:
"""
Expand the Nmap services string into a set of port numbers.
Example:
"22-25,80,443" -> {22,23,24,25,80,443}
"""
- ports: Set[int] = set()
+ ports: set[int] = set()
for part in self.services.split(","):
if "-" in part:
start, end = part.split("-", 1)
diff --git a/generalresearch/models/network/rdns/execute.py b/generalresearch/models/network/rdns/execute.py
index cabd13c..1d74df2 100644
--- a/generalresearch/models/network/rdns/execute.py
+++ b/generalresearch/models/network/rdns/execute.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from uuid import uuid4
from generalresearch.models.custom_types import UUIDStr
@@ -21,11 +21,11 @@ from generalresearch.models.network.tool_run_command import (
def execute_rdns(ip: str, scan_group_id: UUIDStr | None = None):
- started_at = datetime.now(tz=timezone.utc)
+ started_at = datetime.now(tz=UTC)
tool_version = get_dig_version()
config = RDNSRunCommand(options=RDNSRunCommandOptions(ip=ip))
result = run_rdns(config)
- finished_at = datetime.now(tz=timezone.utc)
+ finished_at = datetime.now(tz=UTC)
run = RDNSRun(
tool_name=ToolName.DIG,
diff --git a/generalresearch/models/precision/__init__.py b/generalresearch/models/precision/__init__.py
index 4bb2c6a..089c34a 100644
--- a/generalresearch/models/precision/__init__.py
+++ b/generalresearch/models/precision/__init__.py
@@ -1,7 +1,7 @@
from enum import Enum
+from typing import Annotated
from pydantic import StringConstraints
-from typing_extensions import Annotated
class PrecisionStatus(str, Enum):
diff --git a/generalresearch/models/precision/survey.py b/generalresearch/models/precision/survey.py
index 646d60e..be98a79 100644
--- a/generalresearch/models/precision/survey.py
+++ b/generalresearch/models/precision/survey.py
@@ -1,9 +1,9 @@
from __future__ import annotations
import json
-from datetime import timezone
+from datetime import UTC, timezone
from functools import cached_property
-from typing import Any, Dict, List, Literal, Optional, Self, Set, Tuple, Type
+from typing import Annotated, Any, Dict, List, Literal, Optional, Self, Set, Tuple, Type
from more_itertools import flatten
from pydantic import (
@@ -14,7 +14,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Annotated
from generalresearch.models import Source
from generalresearch.models.custom_types import (
@@ -34,8 +33,8 @@ from generalresearch.models.thl.survey.condition import (
class PrecisionCondition(MarketplaceCondition):
- question_id: Optional[PrecisionQuestionID] = Field()
- values: List[Annotated[str, Field(max_length=128)]] = Field()
+ question_id: PrecisionQuestionID | None = Field()
+ values: list[Annotated[str, Field(max_length=128)]] = Field()
value_type: ConditionValueType = Field(default=ConditionValueType.LIST)
_CONVERT_LIST_TO_RANGE = ["age"]
@@ -54,7 +53,7 @@ class PrecisionQuota(BaseModel):
termination_count: int = Field(ge=0)
overquota_count: int = Field(ge=0)
- condition_hashes: List[str] = Field(min_length=1, default_factory=list)
+ condition_hashes: list[str] = Field(min_length=1, default_factory=list)
# Min spots a quota should have open to be OPEN
_min_open_spots: int = PrivateAttr(default=3)
@@ -78,7 +77,7 @@ class PrecisionQuota(BaseModel):
# TODO: I did some speed tests. This is faster than how this is implemented
# in sago/spectrum/dynata/etc. We should generalize this logic instead of
# copying/pasting it 7 times. (matches, matches_optional and _soft)
- def matches(self, criteria_evaluation: Dict[str, Optional[bool]]) -> bool:
+ def matches(self, criteria_evaluation: dict[str, bool | None]) -> bool:
# Matches means we meet all conditions.
# In Morning, all quotas are mutually exclusive. so if it doesn't
# matter if we match a closed quota, b/c that means that we won't
@@ -86,8 +85,8 @@ class PrecisionQuota(BaseModel):
return self.matches_optional(criteria_evaluation) is True
def matches_optional(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Optional[bool]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> bool | None:
for c in self.condition_hashes:
eval_value = criteria_evaluation.get(c)
if eval_value is False:
@@ -97,8 +96,8 @@ class PrecisionQuota(BaseModel):
return True
def matches_soft(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Tuple[Optional[bool], List[str]]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> tuple[bool | None, list[str]]:
# Passes back "matches" (T/F/none) and a list of unknown criterion hashes
unknowns = list()
for c in self.condition_hashes:
@@ -128,7 +127,7 @@ class PrecisionSurvey(MarketplaceTask):
name: str = Field(validation_alias="prj_name")
survey_guid: UUIDStrCoerce = Field(validation_alias="prj_guid")
- category_id: Optional[str] = Field(validation_alias="sc_id", default=None)
+ category_id: str | None = Field(validation_alias="sc_id", default=None)
buyer_id: CoercedStr = Field(max_length=16)
# This seems to always be 0 ... ?
@@ -141,7 +140,7 @@ class PrecisionSurvey(MarketplaceTask):
bid_ir: float = Field(ge=0, le=1, validation_alias="ir")
# Be careful with this, it doesn't make any sense. See survey 452481, has 12 completes with a 100% live_ir,
# but the only quotas have 0 completes and 1052 terms. .... ??
- global_conversion: Optional[float] = Field(
+ global_conversion: float | None = Field(
ge=0,
le=1,
default=None,
@@ -156,31 +155,31 @@ class PrecisionSurvey(MarketplaceTask):
allowed_devices: DeviceTypes = Field(min_length=1)
entry_link: str = Field(validation_alias="url")
- excluded_surveys: Optional[AlphaNumStrSet] = Field(
+ excluded_surveys: AlphaNumStrSet | None = Field(
description="list of excluded survey ids",
default=None,
validation_alias="exclusion_project_id",
)
- quotas: List[PrecisionQuota] = Field(default_factory=list)
+ quotas: list[PrecisionQuota] = Field(default_factory=list)
source: Literal[Source.PRECISION] = Field(default=Source.PRECISION)
- used_question_ids: Set[PrecisionQuestionID] = Field(default_factory=set)
+ used_question_ids: set[PrecisionQuestionID] = Field(default_factory=set)
# This is a "special" key to store all conditions that are used (as "condition_hashes") throughout
# this survey. In the reduced representation of this task (nearly always, for db i/o, in global_vars)
# this field will be null.
- conditions: Optional[Dict[str, PrecisionCondition]] = Field(default=None)
+ conditions: dict[str, PrecisionCondition] | None = Field(default=None)
# This comes from the API
- expected_end_date: Optional[AwareDatetimeISO] = Field(
+ expected_end_date: AwareDatetimeISO | None = Field(
default=None, validation_alias="end_date"
)
# This does not come from the API. We set it when we update this in the db.
- created: Optional[AwareDatetimeISO] = Field(default=None)
- updated: Optional[AwareDatetimeISO] = Field(default=None)
+ created: AwareDatetimeISO | None = Field(default=None)
+ updated: AwareDatetimeISO | None = Field(default=None)
@property
def internal_id(self) -> str:
@@ -199,7 +198,7 @@ class PrecisionSurvey(MarketplaceTask):
@computed_field
@cached_property
- def all_hashes(self) -> Set[str]:
+ def all_hashes(self) -> set[str]:
s = set()
for q in self.quotas:
s.update(set(q.condition_hashes))
@@ -219,7 +218,7 @@ class PrecisionSurvey(MarketplaceTask):
return data
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return PrecisionCondition
@property
@@ -227,7 +226,7 @@ class PrecisionSurvey(MarketplaceTask):
return "age"
@property
- def marketplace_genders(self) -> Dict[Gender, Optional[MarketplaceCondition]]:
+ def marketplace_genders(self) -> dict[Gender, MarketplaceCondition | None]:
return {
Gender.MALE: PrecisionCondition(
question_id="gender",
@@ -262,7 +261,7 @@ class PrecisionSurvey(MarketplaceTask):
exclude={"updated", "conditions", "created"}
) == other.model_dump(exclude={"updated", "conditions", "created"})
- def to_mysql(self) -> Dict[str, Any]:
+ def to_mysql(self) -> dict[str, Any]:
d = self.model_dump(
mode="json",
exclude={
@@ -283,11 +282,11 @@ class PrecisionSurvey(MarketplaceTask):
return d
@classmethod
- def from_db(cls, d: Dict[str, Any]) -> Self:
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
+ def from_db(cls, d: dict[str, Any]) -> Self:
+ d["created"] = d["created"].replace(tzinfo=UTC)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
d["expected_end_date"] = (
- d["expected_end_date"].replace(tzinfo=timezone.utc)
+ d["expected_end_date"].replace(tzinfo=UTC)
if d["expected_end_date"]
else None
)
@@ -295,7 +294,7 @@ class PrecisionSurvey(MarketplaceTask):
d["used_question_ids"] = json.loads(d["used_question_ids"])
return cls.model_validate(d)
- def passes_quotas(self, criteria_evaluation: Dict[str, Optional[bool]]) -> bool:
+ def passes_quotas(self, criteria_evaluation: dict[str, bool | None]) -> bool:
# We have to match 1 or more quota.
# Quotas are exclusionary: they can NOT match a quota where currently_open=0
any_pass = False
@@ -308,8 +307,8 @@ class PrecisionSurvey(MarketplaceTask):
return any_pass
def passes_quotas_soft(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Tuple[Optional[bool], Set[str]]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> tuple[bool | None, set[str]]:
# Quotas are exclusionary. They can NOT match a quota where currently_open=0
quota_eval = {
quota: quota.matches_soft(criteria_evaluation) for quota in self.quotas
@@ -345,19 +344,19 @@ class PrecisionSurvey(MarketplaceTask):
return False, set()
def determine_eligibility(
- self, criteria_evaluation: Dict[str, Optional[bool]]
+ self, criteria_evaluation: dict[str, bool | None]
) -> bool:
return self.is_open and self.passes_quotas(criteria_evaluation)
def determine_eligibility_soft(
- self, criteria_evaluation: Dict[str, Optional[bool]]
- ) -> Tuple[Optional[bool], Optional[Set[str]]]:
+ self, criteria_evaluation: dict[str, bool | None]
+ ) -> tuple[bool | None, set[str] | None]:
if not self.is_open:
return False, None
return self.passes_quotas_soft(criteria_evaluation)
def participation_allowed(
- self, att_survey_ids: Set[str], att_group_ids: Set[str]
+ self, att_survey_ids: set[str], att_group_ids: set[str]
) -> bool:
"""
Checks if this user can participate in this survey
diff --git a/generalresearch/models/precision/task_collection.py b/generalresearch/models/precision/task_collection.py
index 233d329..daea448 100644
--- a/generalresearch/models/precision/task_collection.py
+++ b/generalresearch/models/precision/task_collection.py
@@ -36,8 +36,8 @@ PrecisionTaskCollectionSchema = DataFrameSchema(
"expected_end_date": Column(dtype=pd.DatetimeTZDtype(tz="UTC"), nullable=True),
"created": Column(dtype=pd.DatetimeTZDtype(tz="UTC")),
"updated": Column(dtype=pd.DatetimeTZDtype(tz="UTC")),
- "used_question_ids": Column(List[str]),
- "all_hashes": Column(List[str]), # set >> list for column support
+ "used_question_ids": Column(list[str]),
+ "all_hashes": Column(list[str]), # set >> list for column support
},
checks=[],
index=Index(
@@ -53,10 +53,10 @@ PrecisionTaskCollectionSchema = DataFrameSchema(
class PrecisionTaskCollection(TaskCollection):
- items: List[PrecisionSurvey]
+ items: list[PrecisionSurvey]
_schema = PrecisionTaskCollectionSchema
- def to_row(self, s: PrecisionSurvey) -> Dict[str, Any]:
+ def to_row(self, s: PrecisionSurvey) -> dict[str, Any]:
d = s.model_dump(
mode="json",
exclude={
diff --git a/generalresearch/models/prodege/__init__.py b/generalresearch/models/prodege/__init__.py
index d419c0c..5c6659a 100644
--- a/generalresearch/models/prodege/__init__.py
+++ b/generalresearch/models/prodege/__init__.py
@@ -1,8 +1,7 @@
from enum import Enum
-from typing import Literal
+from typing import Annotated, Literal
from pydantic import Field
-from typing_extensions import Annotated
ProdegeQuestionIdType = Annotated[
str, Field(min_length=1, max_length=16, pattern=r"^[0-9]+$")
diff --git a/generalresearch/models/prodege/question.py b/generalresearch/models/prodege/question.py
index 1c61ab9..3ef4772 100644
--- a/generalresearch/models/prodege/question.py
+++ b/generalresearch/models/prodege/question.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import json
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
from functools import cached_property
from typing import TYPE_CHECKING, Any, Literal
@@ -43,9 +43,7 @@ class ProdegeUserQuestionAnswer(BaseModel):
# This may be a pipe-separated string if the question_type is multi. regex means any chars except capital letters
option_id: str = Field(pattern=r"^[^A-Z]*$")
- created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# ISO 3166-1 alpha-2 (two-letter codes, lowercase)
country_iso: str = Field(
diff --git a/generalresearch/models/prodege/survey.py b/generalresearch/models/prodege/survey.py
index c12f130..1601fa3 100644
--- a/generalresearch/models/prodege/survey.py
+++ b/generalresearch/models/prodege/survey.py
@@ -4,7 +4,7 @@ from __future__ import annotations
import json
import logging
from collections import defaultdict
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from functools import cached_property
from typing import Any, Literal, Type
@@ -127,7 +127,7 @@ class ProdegeQuota(BaseModel):
return self.remaining_count >= min_open_spots
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return ProdegeCondition
@property
@@ -276,7 +276,7 @@ class ProdegeUserPastParticipation(BaseModel):
raise ValueError(f"Unknown ext_status_code_1: {self.ext_status_code_1}")
def days_ago(self) -> float:
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
return (now - self.started).total_seconds() / (3600 * 24)
@@ -486,7 +486,7 @@ class ProdegeSurvey(MarketplaceTask):
return data
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return ProdegeCondition
@property
@@ -656,8 +656,8 @@ class ProdegeSurvey(MarketplaceTask):
@classmethod
def from_db(cls, d: dict[str, Any]) -> ProdegeSurvey:
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
+ d["created"] = d["created"].replace(tzinfo=UTC)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
d["quotas"] = json.loads(d["quotas"])
for k in [
"max_clicks_settings",
diff --git a/generalresearch/models/prodege/task_collection.py b/generalresearch/models/prodege/task_collection.py
index 19e594f..d3e4a20 100644
--- a/generalresearch/models/prodege/task_collection.py
+++ b/generalresearch/models/prodege/task_collection.py
@@ -30,8 +30,8 @@ ProdegeTaskCollectionSchema = DataFrameSchema(
"conversion_rate": Column(float, Check.between(0, 1), nullable=True),
"created": Column(dtype=pd.DatetimeTZDtype(tz="UTC")),
"updated": Column(dtype=pd.DatetimeTZDtype(tz="UTC")),
- "used_question_ids": Column(List[str]),
- "all_hashes": Column(List[str]), # set >> list for column support
+ "used_question_ids": Column(list[str]),
+ "all_hashes": Column(list[str]), # set >> list for column support
"is_recontact": Column(bool),
# Not including here: entrance_url, max_clicks_settings, past_participation, include_psids, exclude_psids,
# quotas, source, conditions
diff --git a/generalresearch/models/repdata/survey.py b/generalresearch/models/repdata/survey.py
index 2290ca6..fa71c04 100644
--- a/generalresearch/models/repdata/survey.py
+++ b/generalresearch/models/repdata/survey.py
@@ -3,10 +3,10 @@ from __future__ import annotations
import json
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from functools import cached_property
-from typing import Any, Literal, Type
+from typing import Any, Literal, Self, Type
from uuid import UUID
from pydantic import (
@@ -17,7 +17,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.grpc import timestamp_from_datetime
from generalresearch.locales import Localelator
@@ -304,7 +303,7 @@ class RepDataStream(MarketplaceTask):
return self.stream_status == RepDataStatus.LIVE
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return RepDataCondition
@property
@@ -538,8 +537,8 @@ class RepDataSurveyHashed(RepDataSurvey):
DeviceType(int(x)) for x in res["allowed_devices"].split(",")
]
if res["created"] is not None:
- res["created"] = res["created"].replace(tzinfo=timezone.utc)
- res["last_updated"] = res["last_updated"].replace(tzinfo=timezone.utc)
+ res["created"] = res["created"].replace(tzinfo=UTC)
+ res["last_updated"] = res["last_updated"].replace(tzinfo=UTC)
return cls.model_validate(res)
def to_mysql(self) -> dict[str, Any]:
@@ -553,7 +552,7 @@ class RepDataSurveyHashed(RepDataSurvey):
return d
def to_grpc(self, repdata_pb2):
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
timestamp = timestamp_from_datetime(now)
return repdata_pb2.RepDataOpportunity(
diff --git a/generalresearch/models/sago/__init__.py b/generalresearch/models/sago/__init__.py
index 292f0f2..19e7b6d 100644
--- a/generalresearch/models/sago/__init__.py
+++ b/generalresearch/models/sago/__init__.py
@@ -1,7 +1,7 @@
from enum import Enum
+from typing import Annotated
from pydantic import Field
-from typing_extensions import Annotated
SagoQuestionIdType = Annotated[
str, Field(min_length=1, max_length=16, pattern=r"^[0-9]+$")
diff --git a/generalresearch/models/sago/survey.py b/generalresearch/models/sago/survey.py
index e73ddee..0b5830b 100644
--- a/generalresearch/models/sago/survey.py
+++ b/generalresearch/models/sago/survey.py
@@ -2,14 +2,13 @@ from __future__ import annotations
import json
import logging
-from datetime import timezone
+from datetime import UTC, timezone
from decimal import Decimal
from functools import cached_property
-from typing import Annotated, Any, Literal, Type
+from typing import Annotated, Any, Literal, Self, Type
from more_itertools import flatten
from pydantic import BaseModel, ConfigDict, Field, computed_field, model_validator
-from typing_extensions import Self
from generalresearch.locales import Localelator
from generalresearch.models import LogicalOperator, Source
@@ -235,7 +234,7 @@ class SagoSurvey(MarketplaceTask):
return data
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return SagoCondition
@property
@@ -314,9 +313,9 @@ class SagoSurvey(MarketplaceTask):
@classmethod
def from_db(cls, d: dict[str, Any]):
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
- d["modified_api"] = d["modified_api"].replace(tzinfo=timezone.utc)
+ d["created"] = d["created"].replace(tzinfo=UTC)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
+ d["modified_api"] = d["modified_api"].replace(tzinfo=UTC)
d["qualifications"] = json.loads(d["qualifications"])
d["used_question_ids"] = json.loads(d["used_question_ids"])
d["quotas"] = json.loads(d["quotas"])
diff --git a/generalresearch/models/spectrum/__init__.py b/generalresearch/models/spectrum/__init__.py
index b62c089..0040551 100644
--- a/generalresearch/models/spectrum/__init__.py
+++ b/generalresearch/models/spectrum/__init__.py
@@ -1,7 +1,7 @@
from enum import Enum
+from typing import Annotated
from pydantic import Field
-from typing_extensions import Annotated
SpectrumQuestionIdType = Annotated[
str, Field(min_length=1, max_length=16, pattern=r"^[0-9]+$")
diff --git a/generalresearch/models/spectrum/question.py b/generalresearch/models/spectrum/question.py
index db8a55d..81f8655 100644
--- a/generalresearch/models/spectrum/question.py
+++ b/generalresearch/models/spectrum/question.py
@@ -3,10 +3,10 @@ from __future__ import annotations
import json
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
from functools import cached_property
-from typing import TYPE_CHECKING, Any, Literal
+from typing import TYPE_CHECKING, Any, Literal, Self
from uuid import UUID
from pydantic import (
@@ -16,7 +16,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models import MAX_INT32, Source, string_utils
from generalresearch.models.custom_types import AwareDatetimeISO
@@ -50,9 +49,7 @@ class SpectrumUserQuestionAnswer(BaseModel):
# This may be a pipe-separated string if the question_type is multi. regex
# means any chars except capital letters
option_id: str = Field(pattern=r"^[^A-Z]*$")
- created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# ISO 3166-1 alpha-2 (two-letter codes, lowercase)
country_iso: str = Field(
max_length=2, min_length=2, pattern=r"^[a-z]{2}$", frozen=True
@@ -283,7 +280,7 @@ class SpectrumQuestion(MarketplaceQuestion):
]
created = (
- datetime.utcfromtimestamp(d["crtd_on"] / 1000).replace(tzinfo=timezone.utc)
+ datetime.utcfromtimestamp(d["crtd_on"] / 1000).replace(tzinfo=UTC)
if d.get("crtd_on")
else None
)
@@ -308,9 +305,7 @@ class SpectrumQuestion(MarketplaceQuestion):
SpectrumQuestionOption(id=r["id"], text=r["text"], order=r["order"])
for r in d["options"]
]
- d["created"] = (
- d["created"].replace(tzinfo=timezone.utc) if d["created"] else None
- )
+ d["created"] = d["created"].replace(tzinfo=UTC) if d["created"] else None
return cls(
question_id=d["question_id"],
diff --git a/generalresearch/models/spectrum/survey.py b/generalresearch/models/spectrum/survey.py
index a591445..f842f46 100644
--- a/generalresearch/models/spectrum/survey.py
+++ b/generalresearch/models/spectrum/survey.py
@@ -2,13 +2,12 @@ from __future__ import annotations
import json
import logging
-from datetime import timezone
+from datetime import UTC, timezone
from decimal import Decimal
-from typing import Any, Literal, Type
+from typing import Any, Literal, Self, Type
from more_itertools import flatten
from pydantic import BaseModel, ConfigDict, Field, computed_field, model_validator
-from typing_extensions import Self
from generalresearch.locales import Localelator
from generalresearch.models import Source, TaskCalculationType
@@ -297,7 +296,7 @@ class SpectrumSurvey(MarketplaceTask):
return data
@property
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
return SpectrumCondition
@property
@@ -389,16 +388,14 @@ class SpectrumSurvey(MarketplaceTask):
@classmethod
def from_db(cls, d: dict[str, Any]) -> Self:
- d["created_api"] = d["created_api"].replace(tzinfo=timezone.utc)
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
- d["modified_api"] = d["modified_api"].replace(tzinfo=timezone.utc)
+ d["created_api"] = d["created_api"].replace(tzinfo=UTC)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
+ d["modified_api"] = d["modified_api"].replace(tzinfo=UTC)
d["field_end_date"] = (
- d["field_end_date"].replace(tzinfo=timezone.utc)
- if d["field_end_date"]
- else None
+ d["field_end_date"].replace(tzinfo=UTC) if d["field_end_date"] else None
)
d["project_last_complete_date"] = (
- d["project_last_complete_date"].replace(tzinfo=timezone.utc)
+ d["project_last_complete_date"].replace(tzinfo=UTC)
if d["project_last_complete_date"]
else None
)
diff --git a/generalresearch/models/string_utils.py b/generalresearch/models/string_utils.py
index 23c1017..d76456f 100644
--- a/generalresearch/models/string_utils.py
+++ b/generalresearch/models/string_utils.py
@@ -2,7 +2,7 @@ import unicodedata
from typing import Optional
-def remove_nbsp(s: Optional[str]) -> Optional[str]:
+def remove_nbsp(s: str | None) -> str | None:
# Some text comes back from the API with lots of (copied from excel or
# something), and random unicode...
if s:
diff --git a/generalresearch/models/thl/category.py b/generalresearch/models/thl/category.py
index 1ed436a..ebfc840 100644
--- a/generalresearch/models/thl/category.py
+++ b/generalresearch/models/thl/category.py
@@ -1,10 +1,9 @@
from __future__ import annotations
-from typing import Any
+from typing import Any, Self
from uuid import uuid4
from pydantic import BaseModel, Field, PositiveInt, model_validator
-from typing_extensions import Self
from generalresearch.models.custom_types import UUIDStr
diff --git a/generalresearch/models/thl/contest/__init__.py b/generalresearch/models/thl/contest/__init__.py
index 363c8c0..0444586 100644
--- a/generalresearch/models/thl/contest/__init__.py
+++ b/generalresearch/models/thl/contest/__init__.py
@@ -1,6 +1,7 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
+from typing import Self
from uuid import uuid4
from pydantic import (
@@ -10,7 +11,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Self
from generalresearch.currency import USDCent
from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr
@@ -106,7 +106,7 @@ class ContestWinner(BaseModel):
uuid: UUIDStr = Field(default_factory=lambda: uuid4().hex)
created_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When this user won this prize",
)
diff --git a/generalresearch/models/thl/contest/contest.py b/generalresearch/models/thl/contest/contest.py
index 6889dcb..8c45f13 100644
--- a/generalresearch/models/thl/contest/contest.py
+++ b/generalresearch/models/thl/contest/contest.py
@@ -2,8 +2,8 @@ from __future__ import annotations
import json
from abc import ABC, abstractmethod
-from datetime import datetime, timezone
-from typing import Any
+from datetime import UTC, datetime, timezone
+from typing import Any, Self
from uuid import uuid4
from pydantic import (
@@ -14,7 +14,6 @@ from pydantic import (
NonNegativeInt,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr
from generalresearch.models.thl.contest import (
@@ -57,7 +56,7 @@ class ContestBase(BaseModel, ABC):
starts_at: AwareDatetimeISO = Field(
description="When the contest starts",
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
)
terms_and_conditions: HttpUrl | None = Field(default=None)
@@ -91,11 +90,11 @@ class Contest(ContestBase):
product_id: UUIDStr = Field(description="Contest applies only to a single BP")
created_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When this contest was created",
)
updated_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When this contest was last modified. Does not include "
"entries being created/modified",
)
@@ -139,7 +138,7 @@ class Contest(ContestBase):
def should_end(self) -> tuple[bool, ContestEndReason | None]:
if self.status == ContestStatus.ACTIVE:
if self.end_condition.ends_at:
- if datetime.now(tz=timezone.utc) >= self.end_condition.ends_at:
+ if datetime.now(tz=UTC) >= self.end_condition.ends_at:
return True, ContestEndReason.ENDS_AT
return False, None
@@ -158,14 +157,14 @@ class Contest(ContestBase):
if winners is not None:
self.update(
status=ContestStatus.COMPLETED,
- ended_at=datetime.now(tz=timezone.utc),
+ ended_at=datetime.now(tz=UTC),
end_reason=reason,
all_winners=winners,
)
else:
self.update(
status=ContestStatus.COMPLETED,
- ended_at=datetime.now(tz=timezone.utc),
+ ended_at=datetime.now(tz=UTC),
end_reason=reason,
)
return None
@@ -211,7 +210,7 @@ class ContestUserView(Contest):
)
def is_user_eligible(self, country_iso: str) -> tuple[bool, str]:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
assert country_iso.lower() == country_iso
if now < self.starts_at:
diff --git a/generalresearch/models/thl/contest/contest_entry.py b/generalresearch/models/thl/contest/contest_entry.py
index cddae14..31ef317 100644
--- a/generalresearch/models/thl/contest/contest_entry.py
+++ b/generalresearch/models/thl/contest/contest_entry.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from uuid import uuid4
from pydantic import (
@@ -39,12 +39,8 @@ class ContestEntryCreate(BaseModel):
class ContestEntry(BaseModel):
uuid: UUIDStr = Field(default_factory=lambda: uuid4().hex)
- created_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(timezone.utc)
- )
- updated_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(timezone.utc)
- )
+ created_at: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(UTC))
+ updated_at: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(UTC))
# entry_type and amount are the same as on ContestEntryCreate
entry_type: ContestEntryType = Field()
diff --git a/generalresearch/models/thl/contest/io.py b/generalresearch/models/thl/contest/io.py
index e68f76e..c6af719 100644
--- a/generalresearch/models/thl/contest/io.py
+++ b/generalresearch/models/thl/contest/io.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from uuid import uuid4
from generalresearch.models.thl.contest.definitions import ContestType
@@ -37,7 +37,7 @@ from generalresearch.models.thl.contest.contest import Contest
def contest_create_to_contest(
product_id: str, contest_create: ContestCreate
) -> Contest:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
d = contest_create.model_dump(mode="json")
d["uuid"] = uuid4().hex
d["product_id"] = product_id
diff --git a/generalresearch/models/thl/contest/leaderboard.py b/generalresearch/models/thl/contest/leaderboard.py
index 8167f46..c5e0626 100644
--- a/generalresearch/models/thl/contest/leaderboard.py
+++ b/generalresearch/models/thl/contest/leaderboard.py
@@ -1,7 +1,7 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
-from typing import Any, Literal
+from datetime import UTC, datetime, timedelta, timezone
+from typing import Any, Literal, Self
from pydantic import (
ConfigDict,
@@ -11,7 +11,6 @@ from pydantic import (
model_validator,
)
from redis import Redis
-from typing_extensions import Self
from generalresearch.decorators import LOG
from generalresearch.managers.leaderboard import country_timezone
@@ -195,7 +194,7 @@ class LeaderboardContest(LeaderboardContestCreate, Contest):
def should_end(self) -> tuple[bool, ContestEndReason | None]:
if self.status == ContestStatus.ACTIVE:
if self.end_condition.ends_at:
- if datetime.now(tz=timezone.utc) >= self.end_condition.ends_at:
+ if datetime.now(tz=UTC) >= self.end_condition.ends_at:
return True, ContestEndReason.ENDS_AT
return False, None
@@ -276,7 +275,7 @@ class LeaderboardContestUserView(LeaderboardContest, ContestUserView):
if self.user_winnings:
return False, "User already won"
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
if self.leaderboard_model.period_end_utc < now:
return False, "Contest is over"
if self.leaderboard_model.period_start_utc > now:
diff --git a/generalresearch/models/thl/contest/milestone.py b/generalresearch/models/thl/contest/milestone.py
index f62be8f..8b74d50 100644
--- a/generalresearch/models/thl/contest/milestone.py
+++ b/generalresearch/models/thl/contest/milestone.py
@@ -10,7 +10,7 @@ from pydantic import (
Field,
PositiveInt,
)
-from typing_extensions import Self
+from typing import Self
from generalresearch.models.custom_types import AwareDatetimeISO
from generalresearch.models.thl.contest.contest import (
diff --git a/generalresearch/models/thl/contest/raffle.py b/generalresearch/models/thl/contest/raffle.py
index d3157e3..b497a44 100644
--- a/generalresearch/models/thl/contest/raffle.py
+++ b/generalresearch/models/thl/contest/raffle.py
@@ -3,8 +3,8 @@ from __future__ import annotations
import logging
import random
from collections import defaultdict
-from datetime import datetime, timezone
-from typing import Any, Literal
+from datetime import UTC, datetime, timezone
+from typing import Any, Literal, Self
from pydantic import (
ConfigDict,
@@ -14,7 +14,6 @@ from pydantic import (
model_validator,
)
from scipy.stats import hypergeom
-from typing_extensions import Self
from generalresearch.currency import USDCent
from generalresearch.models.thl.contest import (
@@ -202,7 +201,7 @@ class RaffleContest(RaffleContestCreate, Contest):
c = self.end_condition
if c.target_entry_amount and self.current_amount >= c.target_entry_amount:
return True
- if c.ends_at and datetime.now(tz=timezone.utc) >= c.ends_at:
+ if c.ends_at and datetime.now(tz=UTC) >= c.ends_at:
return True
return False
diff --git a/generalresearch/models/thl/finance.py b/generalresearch/models/thl/finance.py
index b72ecf6..a992f78 100644
--- a/generalresearch/models/thl/finance.py
+++ b/generalresearch/models/thl/finance.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import random
-from datetime import timezone
+from datetime import UTC, timezone
from typing import TYPE_CHECKING
from uuid import uuid4
@@ -16,8 +16,8 @@ from pydantic import (
model_validator,
)
from pydantic.json_schema import SkipJsonSchema
-from generalresearch.config import is_debug
+from generalresearch.config import is_debug
from generalresearch.currency import USDCent
from generalresearch.decorators import LOG
from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr
@@ -150,7 +150,7 @@ class POPFinancial(BaseModel):
index: int # Not useful, just a RangeIndex
row: pd.DataFrame
- row["time_idx"] = row.time_idx.to_pydatetime().replace(tzinfo=timezone.utc)
+ row["time_idx"] = row.time_idx.to_pydatetime().replace(tzinfo=UTC)
instance = ProductBalances.from_pandas(row)
res.append(
@@ -842,12 +842,12 @@ class BusinessBalances(BaseModel):
from generalresearch.incite.schemas.mergers.pop_ledger import (
numerical_col_names,
)
+ from generalresearch.managers.thl.product import ProductManager
from generalresearch.models.thl.ledger import (
AccountType,
Direction,
)
from generalresearch.models.thl.product import Product
- from generalresearch.managers.thl.product import ProductManager
# Validate the input accounts
assert len(accounts) > 0, "Must provide accounts"
diff --git a/generalresearch/models/thl/ipinfo.py b/generalresearch/models/thl/ipinfo.py
index 0d254e2..3f212cf 100644
--- a/generalresearch/models/thl/ipinfo.py
+++ b/generalresearch/models/thl/ipinfo.py
@@ -1,8 +1,8 @@
from __future__ import annotations
import ipaddress
-from datetime import datetime, timezone
-from typing import Any, Literal
+from datetime import UTC, datetime, timezone
+from typing import Any, Literal, Self
from faker import Faker
from pydantic import (
@@ -13,7 +13,6 @@ from pydantic import (
PrivateAttr,
field_validator,
)
-from typing_extensions import Self
from generalresearch.models.custom_types import (
AwareDatetimeISO,
@@ -95,7 +94,7 @@ class IPGeoname(BaseModel):
is_in_european_union: bool | None = Field(default=None)
updated: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
)
@field_validator(
@@ -119,7 +118,7 @@ class IPGeoname(BaseModel):
@classmethod
def from_mysql(cls, d: dict[str, Any]) -> Self:
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
return cls.model_validate(d)
@@ -205,7 +204,7 @@ class IPInformation(BaseModel):
)
updated: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
)
_geoname: IPGeoname | None = PrivateAttr(default=None)
@@ -255,7 +254,7 @@ class IPInformation(BaseModel):
@classmethod
def from_mysql(cls, d: dict) -> Self:
- d["updated"] = d["updated"].replace(tzinfo=timezone.utc)
+ d["updated"] = d["updated"].replace(tzinfo=UTC)
return cls.model_validate(d)
diff --git a/generalresearch/models/thl/leaderboard.py b/generalresearch/models/thl/leaderboard.py
index 399a906..dce3280 100644
--- a/generalresearch/models/thl/leaderboard.py
+++ b/generalresearch/models/thl/leaderboard.py
@@ -2,10 +2,11 @@ from __future__ import annotations
import logging
import math
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from enum import Enum
from typing import Literal
from uuid import UUID, uuid3
+from zoneinfo import ZoneInfo
import pandas as pd
from pydantic import (
@@ -17,7 +18,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from zoneinfo import ZoneInfo
from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr
from generalresearch.models.legacy.api_status import StatusResponse
@@ -167,13 +167,13 @@ class Leaderboard(BaseModel):
def period_start_utc(self) -> datetime:
# The start of the time period covered by this board in UTC, tz-aware
# e.g. datetime(2024, 7, 12, 4, 0, 0, 0, tzinfo=timezone.utc)
- return self.period_start_local.astimezone(timezone.utc)
+ return self.period_start_local.astimezone(UTC)
@property
def period_end_utc(self) -> datetime:
# The end of the time period covered by this board in UTC, tz-aware
# e.g. datetime(2024, 7, 13, 3, 59, 59, 999999, tzinfo=timezone.utc)
- return self.period_end_local.astimezone(timezone.utc)
+ return self.period_end_local.astimezone(UTC)
@computed_field(
description="(unix timestamp) The start time of the time range this leaderboard covers.",
diff --git a/generalresearch/models/thl/ledger.py b/generalresearch/models/thl/ledger.py
index 3f8b123..dd37d98 100644
--- a/generalresearch/models/thl/ledger.py
+++ b/generalresearch/models/thl/ledger.py
@@ -1,8 +1,8 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
-from typing import Annotated, Any, Literal, Union
+from typing import Annotated, Any, Literal, Self, Union
from uuid import uuid4
from pydantic import (
@@ -15,7 +15,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models.custom_types import (
AwareDatetimeISO,
@@ -253,7 +252,7 @@ class LedgerTransaction(BaseModel):
id: int | None = Field(default=None)
created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When the Transaction (TX) was created into the database."
"This does not represent the exact time for any action"
"which may be responsible for this Transaction (TX), and "
@@ -283,9 +282,7 @@ class LedgerTransaction(BaseModel):
"""Created should not be in the future. This will mess up
LedgerAccountStatement / groupby rollups.
"""
- assert (
- datetime.now(tz=timezone.utc) > created
- ), "created cannot be in the future"
+ assert datetime.now(tz=UTC) > created, "created cannot be in the future"
return created
@field_validator("entries", mode="after")
@@ -536,12 +533,10 @@ class UserLedgerTransactionTaskAdjustment(UserLedgerTransaction):
UserLedgerTransactionType = Annotated[
- Union[
- UserLedgerTransactionUserPayout,
- UserLedgerTransactionUserBonus,
- UserLedgerTransactionTaskAdjustment,
- UserLedgerTransactionTaskComplete,
- ],
+ UserLedgerTransactionUserPayout
+ | UserLedgerTransactionUserBonus
+ | UserLedgerTransactionTaskAdjustment
+ | UserLedgerTransactionTaskComplete,
Field(discriminator="tx_type"),
]
diff --git a/generalresearch/models/thl/ledger_example.py b/generalresearch/models/thl/ledger_example.py
index 767be85..92ad83d 100644
--- a/generalresearch/models/thl/ledger_example.py
+++ b/generalresearch/models/thl/ledger_example.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import Any
from uuid import uuid4
@@ -16,7 +16,7 @@ def _example_user_tx_payout(schema: dict[str, Any]) -> None:
amount=-5,
description="HIT Reward",
payout_format="${payout/100:.2f}",
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
).model_dump(mode="json")
@@ -30,7 +30,7 @@ def _example_user_tx_bonus(schema: dict[str, Any]) -> None:
amount=100,
description="Compensation Bonus",
payout_format="${payout/100:.2f}",
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
).model_dump(mode="json")
@@ -44,7 +44,7 @@ def _example_user_tx_complete(schema: dict[str, Any]) -> None:
amount=38,
description="Task Complete",
payout_format="${payout/100:.2f}",
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
tsid=uuid4().hex,
).model_dump(mode="json")
@@ -59,6 +59,6 @@ def _example_user_tx_adjustment(schema: dict[str, Any]) -> None:
amount=-38,
description="Task Adjustment",
payout_format="${payout/100:.2f}",
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
tsid=uuid4().hex,
).model_dump(mode="json")
diff --git a/generalresearch/models/thl/offerwall/__init__.py b/generalresearch/models/thl/offerwall/__init__.py
index d2d7d36..3acc592 100644
--- a/generalresearch/models/thl/offerwall/__init__.py
+++ b/generalresearch/models/thl/offerwall/__init__.py
@@ -4,7 +4,7 @@ import hashlib
import json
from decimal import Decimal
from enum import Enum
-from typing import Any, Literal
+from typing import Any, Literal, Self
from pydantic import (
BaseModel,
@@ -13,7 +13,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models import Source
from generalresearch.models.custom_types import IPvAnyAddressStr
diff --git a/generalresearch/models/thl/offerwall/base.py b/generalresearch/models/thl/offerwall/base.py
index 3a867b6..33489df 100644
--- a/generalresearch/models/thl/offerwall/base.py
+++ b/generalresearch/models/thl/offerwall/base.py
@@ -4,7 +4,7 @@ import statistics
from datetime import timedelta
from decimal import Decimal
from string import Formatter
-from typing import Any
+from typing import Annotated, Any, Self
from uuid import uuid4
import numpy as np
@@ -18,7 +18,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Annotated, Self
from generalresearch.models import Source
from generalresearch.models.custom_types import HttpsUrl, UUIDStr
diff --git a/generalresearch/models/thl/offerwall/cache.py b/generalresearch/models/thl/offerwall/cache.py
index c36568e..82ab36d 100644
--- a/generalresearch/models/thl/offerwall/cache.py
+++ b/generalresearch/models/thl/offerwall/cache.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import Any
from pydantic import BaseModel, Field
@@ -26,9 +26,7 @@ class GetOfferWallCache(BaseModel):
request_id: str = Field()
offerwall: OfferwallBase = Field()
all_sids: list[str] = Field()
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(UTC))
latest_ip_info: dict[str, Any] = Field(
description="So we can easily check if user's IP info has changed"
)
@@ -51,9 +49,7 @@ class SessionInfoCache(BaseModel):
# will get pruned as tasks are attempted
tasks: list[ScoredTaskResult] = Field()
- started: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ started: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# The count of attempts per marketplace
mp_retry_count: dict[Source, int] = Field(default_factory=dict)
diff --git a/generalresearch/models/thl/payout_format.py b/generalresearch/models/thl/payout_format.py
index 9f22ace..a7fc4fb 100644
--- a/generalresearch/models/thl/payout_format.py
+++ b/generalresearch/models/thl/payout_format.py
@@ -2,9 +2,9 @@ from __future__ import annotations
import decimal
import re
+from typing import Annotated
from pydantic import AfterValidator, Field
-from typing_extensions import Annotated
# Matches only digits, parenthesis, + , -, *, / and the string payout.
xform_format_re = re.compile(pattern=r"^[\d()+\-*/.]*payout[\d()+\-*/.]*$")
diff --git a/generalresearch/models/thl/product.py b/generalresearch/models/thl/product.py
index 9b7d66a..8377e45 100644
--- a/generalresearch/models/thl/product.py
+++ b/generalresearch/models/thl/product.py
@@ -6,14 +6,15 @@ import json
import math
import warnings
from collections import defaultdict
+from collections.abc import Callable
from decimal import Decimal
from enum import Enum
from functools import cached_property, partial
from typing import (
TYPE_CHECKING,
Any,
- Callable,
Literal,
+ Self,
)
from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit
from uuid import uuid4
@@ -34,7 +35,6 @@ from pydantic import (
model_validator,
)
from pydantic.json_schema import SkipJsonSchema
-from typing_extensions import Self
from generalresearch.currency import USDCent
from generalresearch.decorators import LOG
@@ -941,9 +941,7 @@ class Product(BaseModel, validate_assignment=True):
# Initialization is deferred until unless it's called
# (see .prebuild_***())
- balance: ProductBalances | None = Field(
- default=None, description="Product Balance"
- )
+ balance: ProductBalances | None = Field(default=None, description="Product Balance")
payouts_total_str: str | None = Field(default=None)
payouts_total: USDCent | None = Field(default=None)
diff --git a/generalresearch/models/thl/profiling/marketplace.py b/generalresearch/models/thl/profiling/marketplace.py
index 027aa4c..9038cf6 100644
--- a/generalresearch/models/thl/profiling/marketplace.py
+++ b/generalresearch/models/thl/profiling/marketplace.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from abc import ABC, abstractmethod
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from functools import cached_property
from typing import Any
@@ -111,9 +111,7 @@ class MarketplaceUserQuestionAnswer(BaseModel):
# This may be a pipe-separated string if the question_type is multi. Regex
# means any chars except capital letters
option_id: str = Field(pattern=r"^[^A-Z]*$")
- created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
country_iso: CountryISO = Field(frozen=True)
language_iso: LanguageISO = Field(frozen=True)
diff --git a/generalresearch/models/thl/profiling/other_option.py b/generalresearch/models/thl/profiling/other_option.py
index ae58e90..6d789e5 100644
--- a/generalresearch/models/thl/profiling/other_option.py
+++ b/generalresearch/models/thl/profiling/other_option.py
@@ -40,7 +40,7 @@ texts_in = {
}
-def option_is_catch_all(c: "UpkQuestionChoice") -> bool:
+def option_is_catch_all(c: UpkQuestionChoice) -> bool:
"""
Exclusive not specifically in the sense that it is a multi-select question
and if this option is selected no others can be selected. But also in the
diff --git a/generalresearch/models/thl/profiling/upk_question.py b/generalresearch/models/thl/profiling/upk_question.py
index 307bc33..78f9511 100644
--- a/generalresearch/models/thl/profiling/upk_question.py
+++ b/generalresearch/models/thl/profiling/upk_question.py
@@ -5,7 +5,7 @@ import json
import re
from enum import Enum
from functools import cached_property
-from typing import Any, List, Literal, Union
+from typing import Annotated, Any, List, Literal, Union
from pydantic import (
BaseModel,
@@ -16,7 +16,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Annotated
from generalresearch.models import Source
from generalresearch.models.custom_types import UUIDStr
@@ -215,11 +214,9 @@ SelectorType = (
| UpkQuestionSelectorHIDDEN
)
Configuration = Annotated[
- Union[
- UpkQuestionConfigurationMC,
- UpkQuestionConfigurationTE,
- UpkQuestionConfigurationSLIDER,
- ],
+ UpkQuestionConfigurationMC
+ | UpkQuestionConfigurationTE
+ | UpkQuestionConfigurationSLIDER,
Field(discriminator="type"),
]
@@ -433,7 +430,7 @@ class UpkQuestion(BaseModel):
@field_validator("choices")
@classmethod
- def order_choices(cls, choices: List):
+ def order_choices(cls, choices: list):
if choices:
choices.sort(key=lambda x: x.order)
return choices
diff --git a/generalresearch/models/thl/profiling/upk_question_answer.py b/generalresearch/models/thl/profiling/upk_question_answer.py
index 0024e68..c59d99d 100644
--- a/generalresearch/models/thl/profiling/upk_question_answer.py
+++ b/generalresearch/models/thl/profiling/upk_question_answer.py
@@ -1,7 +1,7 @@
from __future__ import annotations
-from datetime import datetime, timezone
-from typing import Any
+from datetime import UTC, datetime, timezone
+from typing import Any, Self
from uuid import uuid4
from pydantic import (
@@ -12,7 +12,6 @@ from pydantic import (
computed_field,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models import MAX_INT32
from generalresearch.models.custom_types import (
@@ -60,9 +59,7 @@ class UpkQuestionAnswer(BaseModel):
# ISO 3166-1 alpha-2 (two-letter codes, lowercase)
country_iso: CountryISOLike = Field()
- created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# If the property is PropertyType.UPK_ITEM, it should have an item (and no value).
# If the property is UPK_NUMERICAL or UPK_TEXT, it'll have a value (and no item).
diff --git a/generalresearch/models/thl/profiling/user_question_answer.py b/generalresearch/models/thl/profiling/user_question_answer.py
index 8248623..a55b205 100644
--- a/generalresearch/models/thl/profiling/user_question_answer.py
+++ b/generalresearch/models/thl/profiling/user_question_answer.py
@@ -1,8 +1,9 @@
from __future__ import annotations
import json
-from datetime import datetime, timedelta, timezone
-from typing import Any, Iterator, Literal
+from collections.abc import Iterator
+from datetime import UTC, datetime, timedelta, timezone
+from typing import Any, Literal, Self
from pydantic import (
BaseModel,
@@ -12,7 +13,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.grpc import timestamp_to_datetime
from generalresearch.models import MAX_INT32, Source
@@ -28,9 +28,7 @@ class UserQuestionAnswer(BaseModel):
user_id: PositiveInt | None = Field(lt=MAX_INT32, default=None)
question_id: UUIDStr = Field()
answer: tuple[str, ...] = Field()
- timestamp: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ timestamp: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
country_iso: CountryISO | Literal["xx"] = Field()
language_iso: LanguageISO | Literal["xxx"] = Field()
@@ -105,7 +103,7 @@ class UserQuestionAnswer(BaseModel):
return True, ""
def is_stale(self) -> bool:
- return self.timestamp < datetime.now(tz=timezone.utc) - timedelta(days=30)
+ return self.timestamp < datetime.now(tz=UTC) - timedelta(days=30)
@classmethod
def from_grpc(cls, msg, default_timestamp: datetime) -> Self:
@@ -129,7 +127,7 @@ class UserQuestionAnswer(BaseModel):
DUMMY_UQA = UserQuestionAnswer(
question_id="f118edd01cf1476ba7200a175fb4351d",
answer=("0",),
- timestamp=datetime(2020, 1, 1, tzinfo=timezone.utc),
+ timestamp=datetime(2020, 1, 1, tzinfo=UTC),
country_iso="xx",
language_iso="xxx",
property_code="dummy",
diff --git a/generalresearch/models/thl/session.py b/generalresearch/models/thl/session.py
index 17142f3..c8e681c 100644
--- a/generalresearch/models/thl/session.py
+++ b/generalresearch/models/thl/session.py
@@ -2,9 +2,9 @@ from __future__ import annotations
import json
import logging
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
-from typing import TYPE_CHECKING, Annotated, Any
+from typing import TYPE_CHECKING, Annotated, Any, Self
from uuid import uuid4
from pydantic import (
@@ -17,7 +17,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models import DeviceType, Source
from generalresearch.models.custom_types import (
@@ -69,9 +68,7 @@ class WallBase(BaseModel):
buyer_id: str | None = Field(default=None, max_length=32)
req_survey_id: str = Field(max_length=32)
req_cpi: Decimal = Field(decimal_places=5, lt=1000, ge=0)
- started: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ started: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# These get set on creation, or updated when the wall event is finished. So
# they shouldn't really ever be NULL, but you don't have to pass them in
@@ -158,9 +155,7 @@ class WallBase(BaseModel):
@model_validator(mode="after")
def check_timestamps(self):
- assert self.started <= datetime.now(
- tz=timezone.utc
- ), "Started must not be in the future"
+ assert self.started <= datetime.now(tz=UTC), "Started must not be in the future"
if self.finished:
assert self.finished > self.started, "Finished must be after started"
assert self.finished - self.started <= timedelta(
@@ -278,7 +273,7 @@ class WallBase(BaseModel):
# This is just used in tests at the moment. This needs to be adjusted.
if finished is None:
- finished = datetime.now(tz=timezone.utc)
+ finished = datetime.now(tz=UTC)
self.update(
status=status,
@@ -313,7 +308,7 @@ class WallBase(BaseModel):
ext_status_code_3,
)
if finished is None:
- finished = datetime.now(tz=timezone.utc)
+ finished = datetime.now(tz=UTC)
self.update(
status=status,
status_code_1=status_code_1,
@@ -386,7 +381,7 @@ class WallBase(BaseModel):
TODO: Transition this over to use the ReportTask pydantic model.
"""
report_timestamp = (
- report_timestamp if report_timestamp else datetime.now(tz=timezone.utc)
+ report_timestamp if report_timestamp else datetime.now(tz=UTC)
)
if self.status is None and self.finished is None:
self.status = Status.ABANDON
@@ -587,9 +582,7 @@ class Session(BaseModel):
id: int | None = None
uuid: UUIDStr = Field(default_factory=lambda: uuid4().hex)
user: User
- started: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ started: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# This is the "bucket" the user clicked on to start this session. We only
# store the 4 fields: loi_min, loi_max, user_payout_min, user_payout_max
@@ -881,7 +874,7 @@ class Session(BaseModel):
if (
last_wall.status is None
and self.status is None
- and datetime.now(tz=timezone.utc)
+ and datetime.now(tz=UTC)
> self.started + timedelta(seconds=task_timeout_seconds)
):
last_wall.status = Status.TIMEOUT
@@ -962,7 +955,7 @@ class Session(BaseModel):
self, max_session_len: timedelta, max_session_hard_retry: int
) -> bool:
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
last_wall = self.get_last_visible_wall()
if last_wall and last_wall.status == Status.COMPLETE:
diff --git a/generalresearch/models/thl/survey/__init__.py b/generalresearch/models/thl/survey/__init__.py
index b6ac740..d6ba895 100644
--- a/generalresearch/models/thl/survey/__init__.py
+++ b/generalresearch/models/thl/survey/__init__.py
@@ -108,7 +108,7 @@ class MarketplaceTask(BaseModel, ABC):
@property
@abstractmethod
- def condition_model(self) -> Type[MarketplaceCondition]:
+ def condition_model(self) -> type[MarketplaceCondition]:
"""
The Condition Model for this survey class
"""
diff --git a/generalresearch/models/thl/survey/buyer.py b/generalresearch/models/thl/survey/buyer.py
index 6d4d7a1..384bab4 100644
--- a/generalresearch/models/thl/survey/buyer.py
+++ b/generalresearch/models/thl/survey/buyer.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from math import log
from typing import Annotated
@@ -46,7 +46,7 @@ class Buyer(BaseModel):
)
label: str | None = Field(default=None, max_length=255)
created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When this entry was made, or when the buyer was first seen",
)
diff --git a/generalresearch/models/thl/survey/condition.py b/generalresearch/models/thl/survey/condition.py
index 927b7e1..a85073c 100644
--- a/generalresearch/models/thl/survey/condition.py
+++ b/generalresearch/models/thl/survey/condition.py
@@ -4,7 +4,7 @@ import hashlib
from abc import ABC
from enum import Enum
from functools import cached_property
-from typing import Any
+from typing import Annotated, Any, Self
from pydantic import (
BaseModel,
@@ -16,7 +16,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Annotated, Self
from generalresearch.models import LogicalOperator
diff --git a/generalresearch/models/thl/survey/model.py b/generalresearch/models/thl/survey/model.py
index 3794c00..57bcbe2 100644
--- a/generalresearch/models/thl/survey/model.py
+++ b/generalresearch/models/thl/survey/model.py
@@ -1,8 +1,8 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
-from typing import Any
+from typing import Annotated, Any
from pydantic import (
BaseModel,
@@ -15,7 +15,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Annotated
from generalresearch.managers.thl.buyer import Buyer
from generalresearch.models import Source
@@ -71,12 +70,8 @@ class Survey(BaseModel):
min_length=1, max_length=128, default=None, examples=["124"]
)
- created_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
- updated_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created_at: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
+ updated_at: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
is_live: bool = Field(default=True)
is_recontact: bool = Field(default=False)
@@ -188,9 +183,7 @@ class SurveyStat(BaseModel):
# ---- Metadata ----
- updated_at: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ updated_at: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
@property
def natural_key(self) -> str:
diff --git a/generalresearch/models/thl/survey/penalty.py b/generalresearch/models/thl/survey/penalty.py
index e9515d4..05153fe 100644
--- a/generalresearch/models/thl/survey/penalty.py
+++ b/generalresearch/models/thl/survey/penalty.py
@@ -1,11 +1,10 @@
from __future__ import annotations
import abc
-from datetime import datetime, timezone
-from typing import Literal
+from datetime import UTC, datetime, timezone
+from typing import Annotated, Literal
from pydantic import BaseModel, ConfigDict, Field, TypeAdapter
-from typing_extensions import Annotated
from generalresearch.models import Source
from generalresearch.models.custom_types import (
@@ -29,9 +28,7 @@ class SurveyPenalty(BaseModel, abc.ABC):
penalty: float = Field(ge=0, le=1)
- created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
@property
def sid(self):
diff --git a/generalresearch/models/thl/task_adjustment.py b/generalresearch/models/thl/task_adjustment.py
index 89a3873..1834898 100644
--- a/generalresearch/models/thl/task_adjustment.py
+++ b/generalresearch/models/thl/task_adjustment.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from uuid import uuid4
@@ -26,11 +26,11 @@ class TaskAdjustmentEvent(BaseModel):
uuid: UUIDStr = Field(default_factory=lambda: uuid4().hex)
created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When this event was created in the db",
)
alerted: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
description="When we were notified about this change",
)
diff --git a/generalresearch/models/thl/task_status.py b/generalresearch/models/thl/task_status.py
index ee713a5..011d743 100644
--- a/generalresearch/models/thl/task_status.py
+++ b/generalresearch/models/thl/task_status.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from datetime import datetime
-from typing import Annotated, Any, Literal
+from typing import Annotated, Any, Literal, Self
from pydantic import (
BaseModel,
@@ -12,7 +12,6 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
from generalresearch.models.custom_types import (
AwareDatetimeISO,
diff --git a/generalresearch/models/thl/user.py b/generalresearch/models/thl/user.py
index 355e331..55bbd18 100644
--- a/generalresearch/models/thl/user.py
+++ b/generalresearch/models/thl/user.py
@@ -3,8 +3,8 @@ from __future__ import annotations
import json
import logging
import re
-from datetime import datetime, timezone
-from typing import TYPE_CHECKING
+from datetime import UTC, datetime, timezone
+from typing import TYPE_CHECKING, Annotated, Self
from uuid import UUID, uuid4
from pydantic import (
@@ -19,7 +19,6 @@ from pydantic import (
model_validator,
)
from sentry_sdk import set_tag, set_user
-from typing_extensions import Annotated, Self
from generalresearch.models import MAX_INT32
from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr
@@ -126,7 +125,7 @@ class User(BaseModel):
def check_not_in_future(cls, v: AwareDatetime) -> AwareDatetime:
if v is not None:
try:
- assert v < datetime.now(tz=timezone.utc)
+ assert v < datetime.now(tz=UTC)
except Exception:
raise ValueError("Input is in the future")
return v
@@ -137,7 +136,7 @@ class User(BaseModel):
def check_after_anno_domini(cls, v: AwareDatetime) -> AwareDatetime:
if v is not None:
try:
- assert v > datetime(year=2016, month=7, day=13, tzinfo=timezone.utc)
+ assert v > datetime(year=2016, month=7, day=13, tzinfo=UTC)
except Exception:
raise ValueError("Input is before Anno Domini")
return v
@@ -294,9 +293,9 @@ class User(BaseModel):
@classmethod
def from_db(cls, res) -> Self:
if res["created"]:
- res["created"] = res["created"].replace(tzinfo=timezone.utc)
+ res["created"] = res["created"].replace(tzinfo=UTC)
if res["last_seen"]:
- res["last_seen"] = res["last_seen"].replace(tzinfo=timezone.utc)
+ res["last_seen"] = res["last_seen"].replace(tzinfo=UTC)
res["product_id"] = UUID(res["product_id"]).hex
res["uuid"] = UUID(res["uuid"]).hex
return cls(
diff --git a/generalresearch/models/thl/user_iphistory.py b/generalresearch/models/thl/user_iphistory.py
index 5892d41..469f8ba 100644
--- a/generalresearch/models/thl/user_iphistory.py
+++ b/generalresearch/models/thl/user_iphistory.py
@@ -1,7 +1,8 @@
from __future__ import annotations
import ipaddress
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
+from typing import Self
from faker import Faker
from pydantic import (
@@ -11,7 +12,6 @@ from pydantic import (
PositiveInt,
field_validator,
)
-from typing_extensions import Self
from generalresearch.models.custom_types import (
AwareDatetimeISO,
@@ -113,7 +113,7 @@ class IPRecord(BaseModel):
# --- ORM ---
@classmethod
def from_mysql(cls, d: dict) -> Self:
- created = d["created"].replace(tzinfo=timezone.utc)
+ created = d["created"].replace(tzinfo=UTC)
d["created"] = created
d["forwarded_ip_records"] = []
@@ -169,7 +169,7 @@ class UserIPHistory(BaseModel):
def ips_timestamp(cls, ips):
if ips is None:
return None
- cutoff = datetime.now(tz=timezone.utc) - timedelta(days=28)
+ cutoff = datetime.now(tz=UTC) - timedelta(days=28)
return sorted(
[x for x in ips if x.created > cutoff],
key=lambda x: x.created,
diff --git a/generalresearch/models/thl/user_profile.py b/generalresearch/models/thl/user_profile.py
index e96266a..0ec605a 100644
--- a/generalresearch/models/thl/user_profile.py
+++ b/generalresearch/models/thl/user_profile.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import hashlib
-from typing import Any
+from typing import Annotated, Any, Self
from pydantic import (
BaseModel,
@@ -12,7 +12,6 @@ from pydantic import (
computed_field,
)
from pydantic.json_schema import SkipJsonSchema
-from typing_extensions import Annotated, Self
from generalresearch.models import MAX_INT32, Source
from generalresearch.models.custom_types import UUIDStr
diff --git a/generalresearch/models/thl/user_quality_event.py b/generalresearch/models/thl/user_quality_event.py
index d6ebddc..52903e3 100644
--- a/generalresearch/models/thl/user_quality_event.py
+++ b/generalresearch/models/thl/user_quality_event.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from enum import Enum
from typing import Literal
@@ -61,9 +61,7 @@ class TaskAdjustmentEvent(BaseModel):
mid: UUIDStr = Field()
source: Source = Field()
status: WallAdjustedStatus = Field()
- alert_time: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ alert_time: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
quality_event_type: Literal[QualityEventType.task_adjustment] = Field(
default=QualityEventType.task_adjustment
)
diff --git a/generalresearch/models/thl/userhealth.py b/generalresearch/models/thl/userhealth.py
index e556dc8..fb15572 100644
--- a/generalresearch/models/thl/userhealth.py
+++ b/generalresearch/models/thl/userhealth.py
@@ -1,11 +1,10 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from enum import Enum
-from typing import Dict, Optional
+from typing import Dict, Optional, Self
from pydantic import BaseModel, Field, NonNegativeFloat, PositiveInt
-from typing_extensions import Self
from generalresearch.models.custom_types import AwareDatetimeISO
@@ -26,12 +25,12 @@ class AuditLog(BaseModel):
are related to a User
"""
- id: Optional[PositiveInt] = Field(default=None)
+ id: PositiveInt | None = Field(default=None)
user_id: PositiveInt = Field()
created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc),
- examples=[datetime.now(tz=timezone.utc)],
+ default_factory=lambda: datetime.now(tz=UTC),
+ examples=[datetime.now(tz=UTC)],
description="When did this event occur",
)
@@ -51,14 +50,14 @@ class AuditLog(BaseModel):
# e.g. "upk-audit", "ip-audit", "entrance-limit"
event_type: str = Field(max_length=64, examples=["entrance-limit"])
- event_msg: Optional[str] = Field(
+ event_msg: str | None = Field(
default=None,
min_length=3,
max_length=256,
description="The event message. Could be displayed on user's page",
)
- event_value: Optional[NonNegativeFloat] = Field(
+ event_value: NonNegativeFloat | None = Field(
default=None,
description="Optionally store a numeric value associated with this "
"event. For e.g. if we recalculate the user's normalized "
@@ -68,12 +67,12 @@ class AuditLog(BaseModel):
examples=[0.42],
)
- def model_dump_mysql(self, **kwargs) -> Dict:
+ def model_dump_mysql(self, **kwargs) -> dict:
d = self.model_dump(mode="json", **kwargs)
d["created"] = self.created.replace(tzinfo=None)
return d
@classmethod
- def from_mysql(cls, d: Dict) -> Self:
- d["created"] = d["created"].replace(tzinfo=timezone.utc)
+ def from_mysql(cls, d: dict) -> Self:
+ d["created"] = d["created"].replace(tzinfo=UTC)
return AuditLog.model_validate(d)
diff --git a/generalresearch/models/thl/wallet/cashout_method.py b/generalresearch/models/thl/wallet/cashout_method.py
index 59cf721..4757eba 100644
--- a/generalresearch/models/thl/wallet/cashout_method.py
+++ b/generalresearch/models/thl/wallet/cashout_method.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import hashlib
import logging
-from datetime import datetime, timezone
+from datetime import datetime, timezone, UTC
from enum import Enum
from typing import Any, Literal
@@ -16,7 +16,7 @@ from pydantic import (
field_validator,
model_validator,
)
-from typing_extensions import Self
+from typing import Self
from generalresearch.currency import USDCent
from generalresearch.models.custom_types import (
@@ -145,7 +145,7 @@ class CashoutMethod(CashoutMethodBase):
"email associated.",
)
last_updated: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
+ default_factory=lambda: datetime.now(tz=UTC)
)
is_live: bool = Field(default=True)
diff --git a/generalresearch/models/thl/wallet/payout.py b/generalresearch/models/thl/wallet/payout.py
index 8c78bef..cbb37fe 100644
--- a/generalresearch/models/thl/wallet/payout.py
+++ b/generalresearch/models/thl/wallet/payout.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import json
from collections.abc import Collection
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import Any
from uuid import uuid4
@@ -50,9 +50,7 @@ class PayoutEvent(BaseModel, validate_assignment=True):
# populated from the db and so does not need to be set (there is no
# `description` field in event_payout)
description: str | None = Field(default=None)
- created: AwareDatetimeISO = Field(
- default_factory=lambda: datetime.now(tz=timezone.utc)
- )
+ created: AwareDatetimeISO = Field(default_factory=lambda: datetime.now(tz=UTC))
# In the smallest unit of the currency being transacted. For USD, this
# is cents.
@@ -159,7 +157,7 @@ class BPPayoutEvent(BaseModel):
created: AwareDatetimeISO = Field(
description="When the Brokerage Product was paid out",
- default_factory=lambda: datetime.now(tz=timezone.utc),
+ default_factory=lambda: datetime.now(tz=UTC),
)
amount: USDCent = Field(
diff --git a/generalresearch/pg_helper.py b/generalresearch/pg_helper.py
index b9a7d79..b5e124a 100644
--- a/generalresearch/pg_helper.py
+++ b/generalresearch/pg_helper.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from datetime import timezone
+from datetime import UTC, timezone
import psycopg
from psycopg.adapt import Buffer
@@ -24,7 +24,7 @@ class UTCTimestampLoader(TimestampLoader):
if dt is None:
return None
assert dt.tzinfo is None, "expected naive dt"
- return dt.replace(tzinfo=timezone.utc)
+ return dt.replace(tzinfo=UTC)
class BPCharLoader(TextLoader):
diff --git a/generalresearch/sql_helper.py b/generalresearch/sql_helper.py
index 2c526f3..2bbdbe5 100644
--- a/generalresearch/sql_helper.py
+++ b/generalresearch/sql_helper.py
@@ -130,7 +130,7 @@ def decode_uuids(row: dict[str, Any]) -> dict[str, Any]:
class SqlHelper(SqlConnector):
- def __init__(self, dsn: Optional[DataBaseDsn] = None, **kwargs):
+ def __init__(self, dsn: DataBaseDsn | None = None, **kwargs):
super().__init__(dsn, **kwargs)
def execute_sql_query(
@@ -281,7 +281,7 @@ class SqlHelper(SqlConnector):
cursor=None,
commit=True,
primary_key=None,
- ) -> Optional[int]:
+ ) -> int | None:
"""
Create the item in table `table_name`.
In postgresql, `primary_key` needs to be given in order to return the
diff --git a/generalresearch/utils/aggregation.py b/generalresearch/utils/aggregation.py
index 4023dc9..bd962f1 100644
--- a/generalresearch/utils/aggregation.py
+++ b/generalresearch/utils/aggregation.py
@@ -2,7 +2,7 @@ from collections import defaultdict
from typing import Any, Dict, List
-def group_by_year(records: List[Dict], datetime_field: str) -> Dict[int, List[Any]]:
+def group_by_year(records: list[dict], datetime_field: str) -> dict[int, list[Any]]:
"""Memory efficient - processes records one at a time"""
by_year = defaultdict(list)
diff --git a/generalresearch/utils/copying_cache.py b/generalresearch/utils/copying_cache.py
index ea13f69..a1cb37c 100644
--- a/generalresearch/utils/copying_cache.py
+++ b/generalresearch/utils/copying_cache.py
@@ -1,6 +1,6 @@
+from collections.abc import Callable
from copy import deepcopy
from functools import wraps
-from typing import Callable
def deepcopy_return(fn: Callable) -> Callable:
diff --git a/generalresearch/utils/enum.py b/generalresearch/utils/enum.py
index 14a31de..56706ba 100644
--- a/generalresearch/utils/enum.py
+++ b/generalresearch/utils/enum.py
@@ -41,7 +41,7 @@ class ReprEnumMeta(EnumMeta):
)
-def get_enum_comments(enum_class) -> Dict:
+def get_enum_comments(enum_class) -> dict:
source = inspect.getsource(enum_class)
# Regular expression to match multi-line comments and enum values
pattern = re.compile(r"((?:\s*#.*?\n)+)\s*(\w+)\s*=")
diff --git a/generalresearch/wall_status_codes/__init__.py b/generalresearch/wall_status_codes/__init__.py
index 3a0abb8..1d80924 100644
--- a/generalresearch/wall_status_codes/__init__.py
+++ b/generalresearch/wall_status_codes/__init__.py
@@ -22,9 +22,9 @@ from generalresearch.wall_status_codes import (
def annotate_status_code(
source: Source,
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, Optional[StatusCode1], Optional[str]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1 | None, str | None]:
"""
:params ext_status_code_1: marketplace-dependent code
:params ext_status_code_2: marketplace-dependent code
diff --git a/generalresearch/wall_status_codes/cint.py b/generalresearch/wall_status_codes/cint.py
index 8042cd2..ecb6219 100644
--- a/generalresearch/wall_status_codes/cint.py
+++ b/generalresearch/wall_status_codes/cint.py
@@ -6,9 +6,9 @@ from generalresearch.wall_status_codes import lucid
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
return lucid.annotate_status_code(
ext_status_code_1=ext_status_code_1,
ext_status_code_2=ext_status_code_2,
diff --git a/generalresearch/wall_status_codes/dynata.py b/generalresearch/wall_status_codes/dynata.py
index 958e06f..69f3e74 100644
--- a/generalresearch/wall_status_codes/dynata.py
+++ b/generalresearch/wall_status_codes/dynata.py
@@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_name: Dict[str, str] = {
+status_codes_name: dict[str, str] = {
"0.0": "Unknown",
"0.1": "Missing Language",
"0.2": "Missing Respondent ID",
@@ -51,10 +51,10 @@ status_codes_name: Dict[str, str] = {
"5.10": "Daily Limit",
}
-status_map: Dict[str, Status] = defaultdict(
+status_map: dict[str, Status] = defaultdict(
lambda: Status.FAIL, **{"1.0": Status.COMPLETE, "1.1": Status.COMPLETE}
)
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["1.0", "1.1"],
StatusCode1.BUYER_FAIL: ["2.2", "3.2"],
StatusCode1.BUYER_QUALITY_FAIL: ["5.1", "5.2"],
@@ -88,10 +88,10 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
"5.10",
],
}
-ext_status_code_map: Dict[str, StatusCode1] = dict()
+ext_status_code_map: dict[str, StatusCode1] = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -100,9 +100,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: this is from the callback url params:
disposition and status, '.'-joined
diff --git a/generalresearch/wall_status_codes/fullcircle.py b/generalresearch/wall_status_codes/fullcircle.py
index eda4d9c..f37ffda 100644
--- a/generalresearch/wall_status_codes/fullcircle.py
+++ b/generalresearch/wall_status_codes/fullcircle.py
@@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_map: Dict[str, str] = {
+status_codes_map: dict[str, str] = {
"1": "Complete",
"2": "Terminate",
"3": "Over-quota",
@@ -19,7 +19,7 @@ status_codes_map: Dict[str, str] = {
}
status_map = defaultdict(lambda: Status.FAIL, **{"1": Status.COMPLETE})
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["1"],
StatusCode1.BUYER_FAIL: ["2", "3"],
StatusCode1.BUYER_QUALITY_FAIL: ["4"],
@@ -29,10 +29,10 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
StatusCode1.PS_FAIL: [],
StatusCode1.PS_OVERQUOTA: [],
}
-ext_status_code_map: Dict[str, StatusCode1] = dict()
+ext_status_code_map: dict[str, StatusCode1] = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -41,9 +41,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: this is from the callback url param 's'
:params ext_status_code_2: not used
diff --git a/generalresearch/wall_status_codes/innovate.py b/generalresearch/wall_status_codes/innovate.py
index b650ade..fba3f54 100644
--- a/generalresearch/wall_status_codes/innovate.py
+++ b/generalresearch/wall_status_codes/innovate.py
@@ -13,7 +13,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_innovate: Dict[str, str] = {
+status_codes_innovate: dict[str, str] = {
"1": "Complete",
"2": "Buyer Fail",
"3": "Buyer Over Quota",
@@ -29,7 +29,7 @@ status_map = defaultdict(
lambda: Status.FAIL,
**{"1": Status.COMPLETE, "0": Status.ABANDON, "6": Status.ABANDON},
)
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.BUYER_FAIL: ["2", "3"],
StatusCode1.BUYER_QUALITY_FAIL: ["4"],
StatusCode1.PS_BLOCKED: [],
@@ -43,7 +43,7 @@ for k, v in status_codes_ext_map.items():
for vv in v:
ext_status_code_map[status_codes_ext_map.get(vv, vv)] = k
-category_innovate: Dict[str, StatusCode1] = {
+category_innovate: dict[str, StatusCode1] = {
"Selected threat potential score at joblevel not allow the survey": StatusCode1.PS_QUALITY,
"OE Validation": StatusCode1.PS_QUALITY,
"Unique IP": StatusCode1.PS_DUPLICATE,
@@ -78,9 +78,9 @@ category_innovate: Dict[str, StatusCode1] = {
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
Only quality terminate (4 and 8), and PS term (5) return a term_reason (af=).
diff --git a/generalresearch/wall_status_codes/lucid.py b/generalresearch/wall_status_codes/lucid.py
index c0098e6..3ce89b0 100644
--- a/generalresearch/wall_status_codes/lucid.py
+++ b/generalresearch/wall_status_codes/lucid.py
@@ -9,7 +9,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-mp_codes: Dict[str, str] = {
+mp_codes: dict[str, str] = {
"-6": "Pre-Client Intermediary Page Drop Off",
"-5": "Failure in the Post Answer Behavior",
"-1": "Failure to Load the Lucid Marketplace",
@@ -54,7 +54,7 @@ mp_codes: Dict[str, str] = {
}
# todo: finish, there's a bunch more
-client_status_map: Dict[str, StatusCode1] = {
+client_status_map: dict[str, StatusCode1] = {
"30": StatusCode1.BUYER_QUALITY_FAIL,
"33": StatusCode1.BUYER_QUALITY_FAIL,
"34": StatusCode1.BUYER_QUALITY_FAIL,
@@ -62,7 +62,7 @@ client_status_map: Dict[str, StatusCode1] = {
}
status_map = defaultdict(lambda: Status.FAIL, **{"s": Status.COMPLETE})
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: [],
StatusCode1.BUYER_FAIL: ["3"],
StatusCode1.BUYER_QUALITY_FAIL: [],
@@ -102,10 +102,10 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
StatusCode1.PS_OVERQUOTA: ["40", "41", "42"],
}
-ext_status_code_map: Dict[str, StatusCode1] = dict()
+ext_status_code_map: dict[str, StatusCode1] = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -115,9 +115,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: this indicates which callback url was hit. possible values {'s', *anything else*}
:params ext_status_code_2: this is from the callback url params: InitialStatus
diff --git a/generalresearch/wall_status_codes/morning.py b/generalresearch/wall_status_codes/morning.py
index 318d1b2..42e34b3 100644
--- a/generalresearch/wall_status_codes/morning.py
+++ b/generalresearch/wall_status_codes/morning.py
@@ -17,7 +17,7 @@ timeout: The respondent completed the survey after the timeout period had expire
in_progress: The respondent interview session is still in progress, such as in the prescreener or survey.
"""
-short_code_to_status_codes_morning: Dict[str, str] = {
+short_code_to_status_codes_morning: dict[str, str] = {
"att_che": "attention_check",
"banned": "banned",
"bid_clo": "bid_closed",
@@ -54,7 +54,7 @@ short_code_to_status_codes_morning: Dict[str, str] = {
}
status_map = defaultdict(lambda: Status.FAIL, **{"complete": Status.COMPLETE})
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["complete"],
StatusCode1.BUYER_FAIL: [
"in_survey_failure",
@@ -97,10 +97,10 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
"quota_invalid_for_bid",
],
}
-ext_status_code_map: Dict[str, StatusCode1] = dict()
+ext_status_code_map: dict[str, StatusCode1] = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -109,9 +109,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: from callback url params: &sti={{status_id}}
:params ext_status_code_2: from callback url params: &sdi={{status_detail_id}}
diff --git a/generalresearch/wall_status_codes/pollfish.py b/generalresearch/wall_status_codes/pollfish.py
index 361785d..1ae732d 100644
--- a/generalresearch/wall_status_codes/pollfish.py
+++ b/generalresearch/wall_status_codes/pollfish.py
@@ -1,9 +1,9 @@
from collections import defaultdict
-from typing import Any, Dict, List, Optional, Tuple
+from typing import Any
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_map: Dict[str, str] = {
+status_codes_map: dict[str, str] = {
"quo_ful": "quota_full",
"sur_clo": "survey_closed",
"profilin": "profiling",
@@ -29,7 +29,7 @@ status_codes_map: Dict[str, str] = {
"complete": "complete",
}
status_map = defaultdict(lambda: Status.FAIL, **{"complete": Status.COMPLETE})
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["complete"],
StatusCode1.BUYER_FAIL: ["third_party_termination", "screenout"],
StatusCode1.BUYER_QUALITY_FAIL: [
@@ -61,7 +61,7 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
ext_status_code_map = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -70,9 +70,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: from callback url params: &sti={{status_id}}
:params ext_status_code_2: from callback url params: &sdi={{status_detail_id}}
diff --git a/generalresearch/wall_status_codes/precision.py b/generalresearch/wall_status_codes/precision.py
index ffeaeca..d3c4471 100644
--- a/generalresearch/wall_status_codes/precision.py
+++ b/generalresearch/wall_status_codes/precision.py
@@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_precision: Dict[str, str] = {
+status_codes_precision: dict[str, str] = {
"10": "Complete",
"20": "Client Terminate",
"21": "PS Terminate",
@@ -46,7 +46,7 @@ status_codes_precision: Dict[str, str] = {
"80": "Final Complete",
}
status_map = defaultdict(lambda: Status.FAIL, **{"s": Status.COMPLETE})
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["10"],
StatusCode1.BUYER_FAIL: ["20", "30"],
StatusCode1.BUYER_QUALITY_FAIL: ["60"],
@@ -76,7 +76,7 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
ext_status_code_map = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -85,9 +85,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: from callback url params: status
:params ext_status_code_2: from callback url params: code
diff --git a/generalresearch/wall_status_codes/prodege.py b/generalresearch/wall_status_codes/prodege.py
index a1e25ea..aaac376 100644
--- a/generalresearch/wall_status_codes/prodege.py
+++ b/generalresearch/wall_status_codes/prodege.py
@@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
status_map = defaultdict(lambda: Status.FAIL, **{"1": Status.COMPLETE})
-status_code_map: Dict[StatusCode1, List[str]] = {
+status_code_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: [],
StatusCode1.BUYER_FAIL: ["1", "2"],
StatusCode1.BUYER_QUALITY_FAIL: ["10", "12"],
@@ -34,7 +34,7 @@ status_code_map: Dict[StatusCode1, List[str]] = {
status_class = dict()
for k, v in status_code_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -43,9 +43,9 @@ for k, v in status_code_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: status from redirect url
:params ext_status_code_2: termreason from redirect url
diff --git a/generalresearch/wall_status_codes/repdata.py b/generalresearch/wall_status_codes/repdata.py
index c502532..8b690b5 100644
--- a/generalresearch/wall_status_codes/repdata.py
+++ b/generalresearch/wall_status_codes/repdata.py
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_name: Dict[str, str] = {
+status_codes_name: dict[str, str] = {
"2": "Search Failed",
"3": "Activity Failed",
"4": "Review Failed",
@@ -26,7 +26,7 @@ status_codes_name: Dict[str, str] = {
"6003": "In-Survey maximum exceeded (Research Desk)",
}
# See: 02, and 13 are de-dupes
-rd_threat_name: Dict[str, str] = {
+rd_threat_name: dict[str, str] = {
"02": "Duplicate entrant into survey",
"03": "Emulator Usage",
"04": "VPN usage detected",
@@ -47,7 +47,7 @@ rd_threat_name: Dict[str, str] = {
}
status_map = defaultdict(lambda: Status.FAIL, **{"complete": Status.COMPLETE})
-status_code_map: Dict[StatusCode1, List[str]] = {
+status_code_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["1000"],
StatusCode1.BUYER_FAIL: ["2000", "4000"],
StatusCode1.BUYER_QUALITY_FAIL: ["3000"],
@@ -61,7 +61,7 @@ status_code_map: Dict[StatusCode1, List[str]] = {
status_class = dict()
for k, v in status_code_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -70,9 +70,9 @@ for k, v in status_code_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: the redirect urls category (as defined in url param 549f3710b)
{'term', 'overquota', 'fraud', 'complete'}
diff --git a/generalresearch/wall_status_codes/sago.py b/generalresearch/wall_status_codes/sago.py
index 9c8710f..028192b 100644
--- a/generalresearch/wall_status_codes/sago.py
+++ b/generalresearch/wall_status_codes/sago.py
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_schlesinger: Dict[str, str] = {
+status_codes_schlesinger: dict[str, str] = {
"1": "Complete",
"2": "Buyer Fail",
"3": "Buyer Fail",
@@ -20,7 +20,7 @@ status_codes_schlesinger: Dict[str, str] = {
"11": "Abandon", # really it is "Buyer Abandon"
}
-status_reason_name: Dict[str, str] = {
+status_reason_name: dict[str, str] = {
"1": "Not a Unique Sample Cube User",
"4": "GeoIP - wrong country",
"7": "Duplicate - not a unique IP",
@@ -121,7 +121,7 @@ status_map = defaultdict(
lambda: Status.FAIL, **{"1": Status.COMPLETE, "0": Status.ABANDON}
)
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["48"],
StatusCode1.BUYER_FAIL: ["16", "29", "49", "50", "78", "114", "110", "114"],
StatusCode1.BUYER_QUALITY_FAIL: ["26", "52", "68", "81", "84"],
@@ -167,10 +167,10 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
StatusCode1.PS_FAIL: ["7", "29", "36", "47", "56", "58", "64"],
StatusCode1.PS_OVERQUOTA: ["29", "46", "33", "31"],
}
-ext_status_code_map: Dict[str, StatusCode1] = dict()
+ext_status_code_map: dict[str, StatusCode1] = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -179,9 +179,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: from callback url params: scstatus
:params ext_status_code_2: from callback url params: scsecuritystatus
diff --git a/generalresearch/wall_status_codes/spectrum.py b/generalresearch/wall_status_codes/spectrum.py
index 9e9e0a2..cf200a9 100644
--- a/generalresearch/wall_status_codes/spectrum.py
+++ b/generalresearch/wall_status_codes/spectrum.py
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
from generalresearch.models.thl.definitions import Status, StatusCode1
-status_codes_spectrum: Dict[str, str] = {
+status_codes_spectrum: dict[str, str] = {
"11": "PS Drop",
"12": "PS Quota Full Core",
"13": "PS Termination Core",
@@ -80,7 +80,7 @@ status_codes_spectrum: Dict[str, str] = {
"88": "PS_Supplier_Allocation_Throttle",
}
status_map = defaultdict(lambda: Status.FAIL, **{"21": Status.COMPLETE})
-status_codes_ext_map: Dict[StatusCode1, List[str]] = {
+status_codes_ext_map: dict[StatusCode1, list[str]] = {
StatusCode1.COMPLETE: ["21"],
StatusCode1.BUYER_FAIL: ["16", "17", "18", "19", "30", "59", "84"],
StatusCode1.BUYER_QUALITY_FAIL: ["20", "31"],
@@ -143,7 +143,7 @@ status_codes_ext_map: Dict[StatusCode1, List[str]] = {
ext_status_code_map = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[str]
+ v: list[str]
for vv in v:
vv: str
@@ -152,9 +152,9 @@ for k, v in status_codes_ext_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[Any]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, Any | None]:
"""
:params ext_status_code_1: from url params: ps_rstatus
https://purespectrum.atlassian.net/wiki/spaces/PA/pages/33613201/Minimizing+Clickwaste+with+ps+rstatus
diff --git a/generalresearch/wall_status_codes/wxet.py b/generalresearch/wall_status_codes/wxet.py
index e7cf67d..1b7c514 100644
--- a/generalresearch/wall_status_codes/wxet.py
+++ b/generalresearch/wall_status_codes/wxet.py
@@ -8,10 +8,10 @@ from generalresearch.wxet.models.definitions import (
WXETStatusCode2,
)
-status_map: Dict[WXETStatus, Status] = defaultdict(
+status_map: dict[WXETStatus, Status] = defaultdict(
lambda: Status.FAIL, **{WXETStatus.COMPLETE: Status.COMPLETE}
)
-status_codes_ext_map: Dict[StatusCode1, List[WXETStatusCode1]] = {
+status_codes_ext_map: dict[StatusCode1, list[WXETStatusCode1]] = {
StatusCode1.COMPLETE: [WXETStatusCode1.COMPLETE],
StatusCode1.BUYER_FAIL: [
WXETStatusCode1.BUYER_DUPLICATE,
@@ -33,13 +33,13 @@ status_codes_ext_map: Dict[StatusCode1, List[WXETStatusCode1]] = {
ext_status_code_map = dict()
for k, v in status_codes_ext_map.items():
k: StatusCode1
- v: List[WXETStatusCode1]
+ v: list[WXETStatusCode1]
for vv in v:
vv: WXETStatusCode1
ext_status_code_map[vv] = k
-status_code2_map: Dict[StatusCode1, List[WXETStatusCode2]] = {
+status_code2_map: dict[StatusCode1, list[WXETStatusCode2]] = {
StatusCode1.PS_QUALITY: [],
StatusCode1.PS_DUPLICATE: [
WXETStatusCode2.WORKER_INELIGIBLE,
@@ -67,9 +67,9 @@ for k, v in status_code2_map.items():
def annotate_status_code(
ext_status_code_1: str,
- ext_status_code_2: Optional[str] = None,
- ext_status_code_3: Optional[str] = None,
-) -> Tuple[Status, StatusCode1, Optional[WXETStatusCode2]]:
+ ext_status_code_2: str | None = None,
+ ext_status_code_3: str | None = None,
+) -> tuple[Status, StatusCode1, WXETStatusCode2 | None]:
"""
:params ext_status_code_1: WXETStatus
:params ext_status_code_2: WXETStatusCode1
diff --git a/generalresearch/wxet/models/definitions.py b/generalresearch/wxet/models/definitions.py
index 8d0d6b8..b08e178 100644
--- a/generalresearch/wxet/models/definitions.py
+++ b/generalresearch/wxet/models/definitions.py
@@ -166,8 +166,8 @@ class WXETStatusCode2(int, Enum, metaclass=ReprEnumMeta):
def check_wxet_status_consistent(
status: WXETStatus,
- status_code_1: Optional[WXETStatusCode1] = None,
- status_code_2: Optional[WXETStatusCode2] = None,
+ status_code_1: WXETStatusCode1 | None = None,
+ status_code_2: WXETStatusCode2 | None = None,
) -> bool:
"""
Raises an AssertionError if inconsistent
@@ -203,13 +203,13 @@ def check_wxet_status_consistent(
def check_wxet_adjusted_status_attempt_consistent(
status: WXETStatus,
- status_code_1: Optional[WXETStatusCode1] = None,
- cpi: Optional[USDMill] = None,
- adjusted_status: Optional[WXETAdjustedStatus] = None,
- adjusted_cpi: Optional[USDMill] = None,
- new_adjusted_status: Optional[WXETAdjustedStatus] = None,
- new_adjusted_cpi: Optional[USDMill] = None,
-) -> Tuple[bool, str]:
+ status_code_1: WXETStatusCode1 | None = None,
+ cpi: USDMill | None = None,
+ adjusted_status: WXETAdjustedStatus | None = None,
+ adjusted_cpi: USDMill | None = None,
+ new_adjusted_status: WXETAdjustedStatus | None = None,
+ new_adjusted_cpi: USDMill | None = None,
+) -> tuple[bool, str]:
"""
Raises an AssertionError if inconsistent.
- status, status_code_1, adjusted_status, adjusted_cpi, cpi are the attempt's CURRENT values
@@ -233,12 +233,12 @@ def check_wxet_adjusted_status_attempt_consistent(
def _check_wxet_adjusted_status_attempt_consistent(
status: WXETStatus,
- status_code_1: Optional[WXETStatusCode1] = None,
- cpi: Optional[USDMill] = None,
- adjusted_status: Optional[WXETAdjustedStatus] = None,
- adjusted_cpi: Optional[USDMill] = None,
- new_adjusted_status: Optional[WXETAdjustedStatus] = None,
- new_adjusted_cpi: Optional[USDMill] = None,
+ status_code_1: WXETStatusCode1 | None = None,
+ cpi: USDMill | None = None,
+ adjusted_status: WXETAdjustedStatus | None = None,
+ adjusted_cpi: USDMill | None = None,
+ new_adjusted_status: WXETAdjustedStatus | None = None,
+ new_adjusted_cpi: USDMill | None = None,
) -> None:
"""
Raises an AssertionError if inconsistent.
@@ -297,8 +297,8 @@ def _check_wxet_adjusted_status_attempt_consistent(
def _check_wxet_adjusted_status_consistent(
- adjusted_status: Optional[WXETAdjustedStatus] = None,
- adjusted_cpi: Optional[USDMill] = None,
+ adjusted_status: WXETAdjustedStatus | None = None,
+ adjusted_cpi: USDMill | None = None,
) -> None:
"""
Raises an AssertionError if inconsistent.
diff --git a/generalresearch/wxet/models/finish_type.py b/generalresearch/wxet/models/finish_type.py
index af60fe6..a57dce8 100644
--- a/generalresearch/wxet/models/finish_type.py
+++ b/generalresearch/wxet/models/finish_type.py
@@ -33,7 +33,7 @@ class FinishType(str, Enum, metaclass=ReprEnumMeta):
FAIL = "fail"
@property
- def finish_statuses(self) -> Set[Optional[WXETStatus]]:
+ def finish_statuses(self) -> set[WXETStatus | None]:
"""For this particular FinishType, what are the different WXETStatus
values that are consider
"""
@@ -64,9 +64,9 @@ class FinishType(str, Enum, metaclass=ReprEnumMeta):
def is_a_finish(
- status: Optional[WXETStatus],
- status_code_1: Optional[WXETStatusCode1],
- finish_type: Optional[FinishType],
+ status: WXETStatus | None,
+ status_code_1: WXETStatusCode1 | None,
+ finish_type: FinishType | None,
) -> bool:
"""Determines if a wall event should be considered a finish or not.
diff --git a/test_utils/conftest.py b/test_utils/conftest.py
index 378b9cc..ffe458c 100644
--- a/test_utils/conftest.py
+++ b/test_utils/conftest.py
@@ -6,16 +6,17 @@ import stat
import subprocess
import sys
import tempfile
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable, Generator
+from datetime import UTC, datetime, timedelta, timezone
from os.path import join as pjoin
from pathlib import Path
-from typing import Callable, Generator
from uuid import uuid4
import pytest
from _pytest.config import Config
from dotenv import load_dotenv
from pydantic import MariaDBDsn, PostgresDsn, TypeAdapter
+from pytest import TempPathFactory
from generalresearch.config import GRLBaseSettings
from generalresearch.currency import USDCent
@@ -93,7 +94,7 @@ def postgres_instance(settings: GRLBaseSettings) -> Generator[PostgresDsn]:
from psycopg import connect
from psycopg.sql import SQL, Identifier
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
ts: str = now.strftime("%Y-%m-%d")
db_name = f"unittest-{ts}-{uuid4().hex[:6]}"
@@ -152,38 +153,48 @@ def postgres_instance_host(
yield value
-# @pytest.fixture(scope="session")
-# def git_key_path(settings: GRLBaseSettings) -> Path:
-# return Path('/tmp/')
-
-
@pytest.fixture(scope="session")
def git_key_path(
+ tmp_path_factory: TempPathFactory,
settings: GRLBaseSettings,
) -> Generator[Path]:
+ # We are using the tmp_path_factory because unlike the tmp_path (which
+ # is function scoped), this is session scoped.
- assert settings.git_creds
- with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix="_id_rsa") as f:
- f.write(settings.git_creds)
- key_path = f.name
-
- os.chmod(key_path, stat.S_IRUSR | stat.S_IWUSR)
+ assert settings.git_creds, "Must define key to download alternative models"
+ fn = tmp_path_factory.mktemp("keys") / "git_creds"
+ fn.write_text(settings.git_creds, encoding="utf-8")
+ os.chmod(fn, stat.S_IRUSR | stat.S_IWUSR)
- yield Path(key_path)
+ yield Path(fn)
- os.unlink(key_path)
+ os.unlink(fn)
@pytest.fixture(scope="session")
-def gr_repo(git_key_path: Path) -> Callable[..., Path]:
+def gr_repo(
+ git_key_path: Path,
+ tmp_path_factory: TempPathFactory,
+) -> Callable[..., Path | None]:
repo_url = "ssh://code.g-r-l.com/general-research/gr-carer.git"
- repo_path = Path("/tmp/gr-carer")
+
+ _ran = {}
+ if _ran.get(repo_url, False):
+ print(f"Already ran django_db_factory.{repo_url}")
+ return
+
+ _ran[repo_url] = True
+
+ fn = tmp_path_factory.mktemp("repos")
+ repo_path = fn / "gr-carer"
+ repo_path.mkdir(parents=True, exist_ok=True)
def _inner() -> Path:
+
ssh_cmd = (
f"ssh -i {git_key_path} "
"-o IdentitiesOnly=yes "
- "-o StrictHostKeyChecking=no " # or accept-new, see note below
+ "-o StrictHostKeyChecking=no "
)
env = {"GIT_SSH_COMMAND": ssh_cmd}
@@ -196,6 +207,11 @@ def gr_repo(git_key_path: Path) -> Callable[..., Path]:
env=env,
)
+ result = subprocess.run(
+ ["cat", git_key_path], capture_output=True, text=True, check=False
+ )
+ print(repr(result.stdout))
+
return repo_path
return _inner
@@ -206,21 +222,29 @@ def django_db_factory(
postgres_instance: PostgresDsn,
postgres_instance_dict: PostgresDict,
gr_repo: Callable[..., Path],
-) -> Callable[..., PostgresDsn]:
+) -> Callable[..., PostgresDsn | None]:
+
+ _ran = {}
import django
+ from django.apps import apps
from django.conf import settings as django_settings
from django.core.management import call_command
- def _inner(django_project: str = "generalresearch.thl_django"):
+ def _inner(
+ django_project: str = "generalresearch.thl_django",
+ ) -> PostgresDsn | None:
+
+ if _ran.get(django_project, False):
+ print(f"Already ran django_db_factory.{django_project}")
+ return
+ _ran[django_project] = True
if "gr" in django_project:
# We need model files that are NOT in this repo.
gr_path = gr_repo()
sys.path.insert(0, str(gr_path))
- print(sys.path)
-
# 1. Bootstrapping Django settings
if not django_settings.configured:
django_settings.configure(
@@ -242,10 +266,11 @@ def django_db_factory(
)
django.setup()
- # for model in apps.get_models():
- # print(f"Discovered model: {model._meta.label}")
+ for model in apps.get_models():
+ print(f"Discovered model: {model._meta.label}")
# 2. Run migrations directly during fixture activation
+ call_command("makemigrations", "gr", interactive=False)
call_command("migrate")
# 3. Return the Dsn so the factory gives a way to connect
@@ -276,37 +301,37 @@ def spectrum_rw(settings: GRLBaseSettings) -> SqlHelper:
@pytest.fixture
def start() -> datetime:
- return datetime(year=1900, month=1, day=1, tzinfo=timezone.utc)
+ return datetime(year=1900, month=1, day=1, tzinfo=UTC)
@pytest.fixture
def utc_now() -> datetime:
- return datetime.now(tz=timezone.utc)
+ return datetime.now(tz=UTC)
@pytest.fixture
def utc_hour_ago() -> datetime:
- return datetime.now(tz=timezone.utc) - timedelta(hours=1)
+ return datetime.now(tz=UTC) - timedelta(hours=1)
@pytest.fixture
def utc_day_ago() -> datetime:
- return datetime.now(tz=timezone.utc) - timedelta(hours=24)
+ return datetime.now(tz=UTC) - timedelta(hours=24)
@pytest.fixture
def utc_90days_ago() -> datetime:
- return datetime.now(tz=timezone.utc) - timedelta(days=90)
+ return datetime.now(tz=UTC) - timedelta(days=90)
@pytest.fixture
def utc_60days_ago() -> datetime:
- return datetime.now(tz=timezone.utc) - timedelta(days=60)
+ return datetime.now(tz=UTC) - timedelta(days=60)
@pytest.fixture
def utc_30days_ago() -> datetime:
- return datetime.now(tz=timezone.utc) - timedelta(days=30)
+ return datetime.now(tz=UTC) - timedelta(days=30)
# === Clean up ===
@@ -322,7 +347,7 @@ def delete_df_collection(
DFCollectionType,
)
- def _inner(coll: "DFCollection"):
+ def _inner(coll: DFCollection):
match coll.data_type:
case DFCollectionType.LEDGER:
for table in [
diff --git a/test_utils/grliq/conftest.py b/test_utils/grliq/conftest.py
index e8175a5..7665b52 100644
--- a/test_utils/grliq/conftest.py
+++ b/test_utils/grliq/conftest.py
@@ -1,7 +1,7 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
-from typing import Callable
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from uuid import uuid4
import pytest
@@ -83,7 +83,7 @@ def grliq_data() -> GrlIqData:
g.id = None
g.uuid = uuid4().hex
- g.created_at = datetime.now(tz=timezone.utc)
+ g.created_at = datetime.now(tz=UTC)
g.timestamp = g.created_at - timedelta(seconds=10)
return g
@@ -117,7 +117,7 @@ def grliq_data_factory(grliq_dm: GrlIqDataManager) -> Callable[..., GrlIqData]:
product_user_id = product_user_id or uuid4().hex
uuid = uuid or uuid4().hex
mid = mid or uuid4().hex
- created_at = created_at or datetime.now(tz=timezone.utc)
+ created_at = created_at or datetime.now(tz=UTC)
res["data"].product_id = product_id
res["data"].product_user_id = product_user_id
diff --git a/test_utils/incite/collections/conftest.py b/test_utils/incite/collections/conftest.py
index 88eef72..631bb7b 100644
--- a/test_utils/incite/collections/conftest.py
+++ b/test_utils/incite/collections/conftest.py
@@ -1,7 +1,8 @@
from __future__ import annotations
+from collections.abc import Callable
from datetime import datetime, timedelta
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import pytest
diff --git a/test_utils/incite/conftest.py b/test_utils/incite/conftest.py
index 12e57c5..87ea7ae 100644
--- a/test_utils/incite/conftest.py
+++ b/test_utils/incite/conftest.py
@@ -1,11 +1,12 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, 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 TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
@@ -166,7 +167,7 @@ def incite_item_factory(
for _ in range(5):
item_time = fake.date_time_between(
- start_date=item.start, end_date=item.finish, tzinfo=timezone.utc
+ start_date=item.start, end_date=item.finish, tzinfo=UTC
)
match data_type:
diff --git a/test_utils/incite/mergers/conftest.py b/test_utils/incite/mergers/conftest.py
index e9970c2..c0f0bcf 100644
--- a/test_utils/incite/mergers/conftest.py
+++ b/test_utils/incite/mergers/conftest.py
@@ -1,7 +1,7 @@
from __future__ import annotations
+from collections.abc import Callable
from datetime import datetime, timedelta
-from typing import Callable
import pytest
diff --git a/test_utils/managers/conftest.py b/test_utils/managers/conftest.py
index d2e5d20..4dacb29 100644
--- a/test_utils/managers/conftest.py
+++ b/test_utils/managers/conftest.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import Callable
+from collections.abc import Callable
import pytest
diff --git a/test_utils/managers/gr/conftest.py b/test_utils/managers/gr/conftest.py
index 37da164..4da8fe3 100644
--- a/test_utils/managers/gr/conftest.py
+++ b/test_utils/managers/gr/conftest.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import Callable
+from collections.abc import Callable
import pytest
import redis.asyncio as redis_async
diff --git a/test_utils/managers/thl/conftest.py b/test_utils/managers/thl/conftest.py
index 5b70961..21b2007 100644
--- a/test_utils/managers/thl/conftest.py
+++ b/test_utils/managers/thl/conftest.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import Callable
+from collections.abc import Callable
import pytest
from pydantic import PostgresDsn
diff --git a/test_utils/managers/upk/conftest.py b/test_utils/managers/upk/conftest.py
index d8f956c..7eabee1 100644
--- a/test_utils/managers/upk/conftest.py
+++ b/test_utils/managers/upk/conftest.py
@@ -1,4 +1,4 @@
-from typing import Callable, Generator
+from collections.abc import Callable, Generator
import pytest
diff --git a/test_utils/models/conftest.py b/test_utils/models/conftest.py
index 93e2f44..3a9e45c 100644
--- a/test_utils/models/conftest.py
+++ b/test_utils/models/conftest.py
@@ -1,10 +1,11 @@
from __future__ import annotations
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from random import choice as randchoice
from random import randint
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
@@ -124,7 +125,7 @@ def wall_factory(wall_manager: WallManager) -> Callable[..., Wall]:
) -> Wall:
assert session.started <= datetime.now(
- tz=timezone.utc
+ tz=UTC
), "Session can't start in the future"
if session.wall_events:
diff --git a/test_utils/models/contest/conftest.py b/test_utils/models/contest/conftest.py
index bfbe9f8..0060946 100644
--- a/test_utils/models/contest/conftest.py
+++ b/test_utils/models/contest/conftest.py
@@ -1,14 +1,13 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timezone
from decimal import Decimal
-from typing import Callable
from uuid import uuid4
import pytest
from pytest import FixtureRequest as Request
-
from generalresearch.currency import USDCent
from generalresearch.managers.thl.contest_manager import ContestManager
from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
@@ -136,7 +135,7 @@ def milestone_contest_create() -> MilestoneContestCreate:
),
],
end_condition=MilestoneContestEndCondition(
- ends_at=datetime(year=2030, month=1, day=1, tzinfo=timezone.utc),
+ ends_at=datetime(year=2030, month=1, day=1, tzinfo=UTC),
max_winners=5,
),
entry_trigger=ContestEntryTrigger.TASK_COMPLETE,
diff --git a/test_utils/models/gr/conftest.py b/test_utils/models/gr/conftest.py
index df97306..90b86aa 100644
--- a/test_utils/models/gr/conftest.py
+++ b/test_utils/models/gr/conftest.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import Callable
+from collections.abc import Callable
from uuid import uuid4
import pytest
diff --git a/test_utils/models/ledger/conftest.py b/test_utils/models/ledger/conftest.py
index 14a7465..b428468 100644
--- a/test_utils/models/ledger/conftest.py
+++ b/test_utils/models/ledger/conftest.py
@@ -1,9 +1,10 @@
from __future__ import annotations
+from collections.abc import Callable
from datetime import datetime
from decimal import Decimal
from random import randint
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
diff --git a/test_utils/models/network/conftest.py b/test_utils/models/network/conftest.py
index bebc691..cabd8dc 100644
--- a/test_utils/models/network/conftest.py
+++ b/test_utils/models/network/conftest.py
@@ -1,5 +1,5 @@
import os
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from uuid import uuid4
import pytest
@@ -90,7 +90,7 @@ def rdns_result(dig_raw_output: str) -> RDNSResult:
def rdns_run(rdns_result: RDNSResult, scan_group_id: str):
r = rdns_result
ip = "45.33.32.156"
- utc_now = datetime.now(tz=timezone.utc)
+ utc_now = datetime.now(tz=UTC)
config = RDNSRunCommand(command="dig", options=RDNSRunCommandOptions(ip=ip))
return RDNSRun(
tool_version="1.2.3",
@@ -121,7 +121,7 @@ def mtr_result(mtr_raw_output: str) -> MTRResult:
@pytest.fixture(scope="session")
def mtr_run(mtr_result: MTRResult, scan_group_id: str):
r = mtr_result
- utc_now = datetime.now(tz=timezone.utc)
+ utc_now = datetime.now(tz=UTC)
config = MTRRunCommand(
command="mtr",
options=MTRRunCommandOptions(
diff --git a/test_utils/models/thl/conftest.py b/test_utils/models/thl/conftest.py
index cf8d2fa..a2adcce 100644
--- a/test_utils/models/thl/conftest.py
+++ b/test_utils/models/thl/conftest.py
@@ -1,11 +1,12 @@
from __future__ import annotations
-from datetime import datetime, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timezone
from decimal import ROUND_DOWN, Decimal
from random import choice as rand_choice
from random import choice as rchoice
from random import randint, random
-from typing import Any, Callable
+from typing import Any
from uuid import uuid4
import faker
@@ -105,9 +106,9 @@ def wall_factory(
user_id = user_id or fake.random_int(min=1, max=2_147_483_648)
started = started or fake.date_time_between(
- start_date=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
- end_date=datetime.now(tz=timezone.utc),
- tzinfo=timezone.utc,
+ start_date=datetime(year=1900, month=1, day=1, tzinfo=UTC),
+ end_date=datetime.now(tz=UTC),
+ tzinfo=UTC,
)
if session_id is None:
@@ -199,9 +200,9 @@ def session_factory(session_manager: SessionManager):
) -> Session:
"""To be used in tests, where we don't care about certain fields"""
started = started or fake.date_time_between(
- start_date=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
- end_date=datetime(year=2000, month=1, day=1, tzinfo=timezone.utc),
- tzinfo=timezone.utc,
+ start_date=datetime(year=1900, month=1, day=1, tzinfo=UTC),
+ end_date=datetime(year=2000, month=1, day=1, tzinfo=UTC),
+ tzinfo=UTC,
)
user = user or User(
user_id=fake.random_int(min=1, max=2_147_483_648), uuid=uuid4().hex
diff --git a/test_utils/spectrum/conftest.py b/test_utils/spectrum/conftest.py
index 0afc3f5..9c067d3 100644
--- a/test_utils/spectrum/conftest.py
+++ b/test_utils/spectrum/conftest.py
@@ -1,6 +1,6 @@
import logging
import time
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import TYPE_CHECKING
import pytest
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
@pytest.fixture(scope="session")
-def spectrum_rw(settings: "GRLBaseSettings") -> SqlHelper:
+def spectrum_rw(settings: GRLBaseSettings) -> SqlHelper:
logging.info(f"{settings.spectrum_rw_db=}")
assert settings.spectrum_rw_db is not None
@@ -49,11 +49,11 @@ def spectrum_survey_manager(spectrum_rw: SqlHelper) -> SpectrumSurveyManager:
def setup_spectrum_surveys(
spectrum_rw: SqlHelper, spectrum_survey_manager, spectrum_criteria_manager
) -> None:
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
# make sure these example surveys exist in db
surveys = [SpectrumSurvey.model_validate_json(x) for x in SURVEYS_JSON]
for s in surveys:
- s.modified_api = datetime.now(tz=timezone.utc)
+ s.modified_api = datetime.now(tz=UTC)
spectrum_survey_manager.create_or_update(surveys)
spectrum_criteria_manager.update(CONDITIONS)
@@ -66,10 +66,10 @@ def setup_spectrum_surveys(
["687", "GRL", "x", "x", "x", "x"],
commit=True,
)
- supplier687_pk = spectrum_rw.execute_sql_query(
- f"""
- select id from `{spectrum_rw.db}`.spectrum_supplier where supplier_id = '687'"""
- )[0]["id"]
+ supplier687_pk = spectrum_rw.execute_sql_query(f"""
+ select id from `{spectrum_rw.db}`.spectrum_supplier where supplier_id = '687'""")[
+ 0
+ ]["id"]
conn = spectrum_rw.make_connection()
c = conn.cursor()
c.executemany(
diff --git a/tests/grliq/models/test_forensic_data.py b/tests/grliq/models/test_forensic_data.py
index 4fbf962..a901dc3 100644
--- a/tests/grliq/models/test_forensic_data.py
+++ b/tests/grliq/models/test_forensic_data.py
@@ -9,16 +9,16 @@ if TYPE_CHECKING:
class TestGrlIqData:
- def test_supported_fonts(self, grliq_data: "GrlIqData"):
+ def test_supported_fonts(self, grliq_data: GrlIqData):
s = grliq_data.supported_fonts_binary
assert len(s) == 1043
assert "Ubuntu" in grliq_data.supported_fonts
- def test_battery(self, grliq_data: "GrlIqData"):
+ def test_battery(self, grliq_data: GrlIqData):
assert not grliq_data.battery_charging
assert grliq_data.battery_level == 0.41
- def test_base(self, grliq_data: "GrlIqData"):
+ def test_base(self, grliq_data: GrlIqData):
from generalresearch.grliq.models.forensic_data import Platform
assert grliq_data.timezone == "America/Los_Angeles"
@@ -41,7 +41,7 @@ class TestGrlIqData:
# Testing things that will cause a validation error, should only be
# because something is "corrupt", not b/c the user is a baddie
- def test_corrupt(self, grliq_data: "GrlIqData"):
+ def test_corrupt(self, grliq_data: GrlIqData):
"""Test for timestamp and timezone offset mismatch validation."""
from generalresearch.grliq.models.forensic_data import GrlIqData
diff --git a/tests/incite/collections/test_df_collection_base.py b/tests/incite/collections/test_df_collection_base.py
index 31d1720..c3c64e4 100644
--- a/tests/incite/collections/test_df_collection_base.py
+++ b/tests/incite/collections/test_df_collection_base.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import TYPE_CHECKING
import pandas as pd
@@ -24,7 +24,7 @@ class TestDFCollectionBase:
"""
- def test_init(self, mnt_filepath: "GRLDatasets", df_coll_type: DFCollectionType):
+ def test_init(self, mnt_filepath: GRLDatasets, df_coll_type: DFCollectionType):
"""Try to initialize the DFCollection with various invalid parameters"""
with pytest.raises(expected_exception=ValueError) as cm:
DFCollection(archive_path=mnt_filepath.data_src)
@@ -46,11 +46,11 @@ class TestDFCollectionBase:
class TestDFCollectionBaseProperties:
@pytest.mark.skip
- def test_df_collection_items(self, mnt_filepath: "GRLDatasets", df_coll_type):
+ def test_df_collection_items(self, mnt_filepath: GRLDatasets, df_coll_type):
instance = DFCollection(
data_type=df_coll_type,
- start=datetime(year=1800, month=1, day=1, tzinfo=timezone.utc),
- finished=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=1800, month=1, day=1, tzinfo=UTC),
+ finished=datetime(year=1900, month=1, day=1, tzinfo=UTC),
offset="100d",
archive_path=mnt_filepath.archive_path(enum_type=df_coll_type),
)
@@ -58,11 +58,11 @@ class TestDFCollectionBaseProperties:
assert len(instance.interval_range) == len(instance.items)
assert len(instance.items) == 366
- def test_df_collection_progress(self, mnt_filepath: "GRLDatasets", df_coll_type):
+ def test_df_collection_progress(self, mnt_filepath: GRLDatasets, df_coll_type):
instance = DFCollection(
data_type=df_coll_type,
- start=datetime(year=1800, month=1, day=1, tzinfo=timezone.utc),
- finished=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=1800, month=1, day=1, tzinfo=UTC),
+ finished=datetime(year=1900, month=1, day=1, tzinfo=UTC),
offset="100d",
archive_path=mnt_filepath.archive_path(enum_type=df_coll_type),
)
@@ -71,7 +71,7 @@ class TestDFCollectionBaseProperties:
assert isinstance(instance.progress, pd.DataFrame)
assert instance.progress.shape == (366, 6)
- def test_df_collection_schema(self, mnt_filepath: "GRLDatasets", df_coll_type):
+ def test_df_collection_schema(self, mnt_filepath: GRLDatasets, df_coll_type):
instance1 = DFCollection(
data_type=DFCollectionType.WALL, archive_path=mnt_filepath.data_src
)
@@ -88,12 +88,12 @@ class TestDFCollectionBaseProperties:
class TestDFCollectionBaseMethods:
@pytest.mark.skip
- def test_initial_load(self, mnt_filepath: "GRLDatasets", thl_web_rr):
+ def test_initial_load(self, mnt_filepath: GRLDatasets, thl_web_rr):
instance = DFCollection(
pg_config=thl_web_rr,
data_type=DFCollectionType.USER,
- start=datetime(year=2022, month=1, day=1, minute=0, tzinfo=timezone.utc),
- finished=datetime(year=2022, month=1, day=1, minute=5, tzinfo=timezone.utc),
+ start=datetime(year=2022, month=1, day=1, minute=0, tzinfo=UTC),
+ finished=datetime(year=2022, month=1, day=1, minute=5, tzinfo=UTC),
offset="2min",
archive_path=mnt_filepath.data_src,
)
diff --git a/tests/incite/collections/test_df_collection_item_base.py b/tests/incite/collections/test_df_collection_item_base.py
index 136d234..8cf719d 100644
--- a/tests/incite/collections/test_df_collection_item_base.py
+++ b/tests/incite/collections/test_df_collection_item_base.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from typing import TYPE_CHECKING
import pytest
@@ -19,12 +19,12 @@ df_collection_types = [e for e in DFCollectionType if e is not DFCollectionType.
@pytest.mark.parametrize("df_coll_type", df_collection_types)
class TestDFCollectionItemBase:
- def test_init(self, mnt_filepath: "GRLDatasets", df_coll_type):
+ def test_init(self, mnt_filepath: GRLDatasets, df_coll_type):
collection = DFCollection(
data_type=df_coll_type,
offset="100d",
- start=datetime(year=1800, month=1, day=1, tzinfo=timezone.utc),
- finished=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=1800, month=1, day=1, tzinfo=UTC),
+ finished=datetime(year=1900, month=1, day=1, tzinfo=UTC),
archive_path=mnt_filepath.archive_path(enum_type=df_coll_type),
)
@@ -45,12 +45,12 @@ class TestDFCollectionItemProperties:
@pytest.mark.parametrize("df_coll_type", df_collection_types)
class TestDFCollectionItemMethods:
- def test_has_mysql_false(self, mnt_filepath: "GRLDatasets", df_coll_type):
+ def test_has_mysql_false(self, mnt_filepath: GRLDatasets, df_coll_type):
collection = DFCollection(
data_type=df_coll_type,
offset="100d",
- start=datetime(year=1800, month=1, day=1, tzinfo=timezone.utc),
- finished=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=1800, month=1, day=1, tzinfo=UTC),
+ finished=datetime(year=1900, month=1, day=1, tzinfo=UTC),
archive_path=mnt_filepath.archive_path(enum_type=df_coll_type),
)
@@ -58,13 +58,13 @@ class TestDFCollectionItemMethods:
assert not instance1.has_mysql()
def test_has_mysql_true(
- self, thl_web_rr: PostgresConfig, mnt_filepath: "GRLDatasets", df_coll_type
+ self, thl_web_rr: PostgresConfig, mnt_filepath: GRLDatasets, df_coll_type
):
collection = DFCollection(
data_type=df_coll_type,
offset="100d",
- start=datetime(year=1800, month=1, day=1, tzinfo=timezone.utc),
- finished=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ start=datetime(year=1800, month=1, day=1, tzinfo=UTC),
+ finished=datetime(year=1900, month=1, day=1, tzinfo=UTC),
archive_path=mnt_filepath.archive_path(enum_type=df_coll_type),
pg_config=thl_web_rr,
)
diff --git a/tests/incite/collections/test_df_collection_item_thl_web.py b/tests/incite/collections/test_df_collection_item_thl_web.py
index 8b8bcbe..062171d 100644
--- a/tests/incite/collections/test_df_collection_item_thl_web.py
+++ b/tests/incite/collections/test_df_collection_item_thl_web.py
@@ -1,11 +1,11 @@
from __future__ import annotations
-from collections.abc import Generator
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable, Generator
+from datetime import UTC, datetime, timedelta, timezone
from itertools import product as iter_product
from os.path import join as pjoin
from pathlib import Path, PurePath
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from uuid import uuid4
import dask.dataframe as dd
@@ -52,7 +52,7 @@ unsupported_mock_types = {
}
-def combo_object() -> Generator[str, None, None]:
+def combo_object() -> Generator[str]:
for x in iter_product(
df_collections,
["15min", "45min", "1H"],
@@ -632,7 +632,7 @@ class TestDFCollectionItemMethodBase:
for item in df_collection.items:
item: DFCollectionItem
- if datetime.now(tz=timezone.utc) > item.finish + aa:
+ if datetime.now(tz=UTC) > item.finish + aa:
assert item.should_archive()
else:
assert not item.should_archive()
diff --git a/tests/incite/collections/test_df_collection_thl_marketplaces.py b/tests/incite/collections/test_df_collection_thl_marketplaces.py
index 981f62e..2597d38 100644
--- a/tests/incite/collections/test_df_collection_thl_marketplaces.py
+++ b/tests/incite/collections/test_df_collection_thl_marketplaces.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from itertools import product
from typing import TYPE_CHECKING
@@ -57,8 +57,8 @@ class TestDFCollection_thl_marketplaces:
archive_path=mnt_filepath.archive_path(enum_type=data_type),
sql_helper=spectrum_rw,
offset=offset,
- start=datetime(year=2023, month=6, day=1, minute=0, tzinfo=timezone.utc),
- finished=datetime(year=2023, month=6, day=1, minute=5, tzinfo=timezone.utc),
+ start=datetime(year=2023, month=6, day=1, minute=0, tzinfo=UTC),
+ finished=datetime(year=2023, month=6, day=1, minute=5, tzinfo=UTC),
)
assert isinstance(instance, DFCollection)
diff --git a/tests/incite/collections/test_df_collection_thl_web.py b/tests/incite/collections/test_df_collection_thl_web.py
index b09d44c..2cb0ba0 100644
--- a/tests/incite/collections/test_df_collection_thl_web.py
+++ b/tests/incite/collections/test_df_collection_thl_web.py
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
)
-def combo_object() -> Generator[tuple, None, None]:
+def combo_object() -> Generator[tuple]:
for x in product(
[
DFCollectionType.USER,
diff --git a/tests/incite/mergers/foundations/test_enriched_session.py b/tests/incite/mergers/foundations/test_enriched_session.py
index 47f243e..a0ae01e 100644
--- a/tests/incite/mergers/foundations/test_enriched_session.py
+++ b/tests/incite/mergers/foundations/test_enriched_session.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from itertools import product
from typing import Optional
@@ -77,15 +77,15 @@ class TestEnrichedSession:
class TestEnrichedSessionAdmin:
@pytest.fixture
- def start(self) -> "datetime":
- return datetime(year=2020, month=3, day=14, tzinfo=timezone.utc)
+ def start(self) -> datetime:
+ return datetime(year=2020, month=3, day=14, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
return "1d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return timedelta(days=5)
def test_to_admin_response(
diff --git a/tests/incite/mergers/foundations/test_enriched_wall.py b/tests/incite/mergers/foundations/test_enriched_wall.py
index 8f4995b..b421df8 100644
--- a/tests/incite/mergers/foundations/test_enriched_wall.py
+++ b/tests/incite/mergers/foundations/test_enriched_wall.py
@@ -1,4 +1,4 @@
-from datetime import timedelta, timezone, datetime
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from itertools import product as iter_product
from typing import Optional
@@ -9,13 +9,13 @@ import pytest
# noinspection PyUnresolvedReferences
from distributed.utils_test import (
- gen_cluster,
+ cleanup,
+ client,
client_no_amm,
+ cluster_fixture,
+ gen_cluster,
loop,
loop_in_thread,
- cleanup,
- cluster_fixture,
- client,
)
from generalresearch.incite.mergers.foundations.enriched_wall import (
@@ -158,15 +158,15 @@ class TestEnrichedWall:
class TestEnrichedWallToAdmin:
@pytest.fixture
- def start(self) -> "datetime":
- return datetime(year=2020, month=3, day=14, tzinfo=timezone.utc)
+ def start(self) -> datetime:
+ return datetime(year=2020, month=3, day=14, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
return "1d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return timedelta(days=5)
def test_empty(self, enriched_wall_merge, client_no_amm, start):
diff --git a/tests/incite/mergers/foundations/test_user_id_product.py b/tests/incite/mergers/foundations/test_user_id_product.py
index f96bfb4..a696b45 100644
--- a/tests/incite/mergers/foundations/test_user_id_product.py
+++ b/tests/incite/mergers/foundations/test_user_id_product.py
@@ -1,4 +1,4 @@
-from datetime import timedelta, datetime, timezone
+from datetime import UTC, datetime, timedelta, timezone
from itertools import product
import pandas as pd
@@ -6,13 +6,13 @@ import pytest
# noinspection PyUnresolvedReferences
from distributed.utils_test import (
- gen_cluster,
+ cleanup,
+ client,
client_no_amm,
+ cluster_fixture,
+ gen_cluster,
loop,
loop_in_thread,
- cleanup,
- cluster_fixture,
- client,
)
from generalresearch.incite.mergers.foundations.user_id_product import (
@@ -27,11 +27,7 @@ from test_utils.incite.mergers.conftest import user_id_product_merge
product(
["12h", "3D"],
[timedelta(days=5)],
- [
- (datetime.now(tz=timezone.utc) - timedelta(days=35)).replace(
- microsecond=0
- )
- ],
+ [(datetime.now(tz=UTC) - timedelta(days=35)).replace(microsecond=0)],
)
),
)
diff --git a/tests/incite/mergers/test_merge_collection.py b/tests/incite/mergers/test_merge_collection.py
index ec507bc..77fa8c7 100644
--- a/tests/incite/mergers/test_merge_collection.py
+++ b/tests/incite/mergers/test_merge_collection.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from itertools import product
import pandas as pd
@@ -21,11 +21,7 @@ merge_types = list(e for e in MergeType if e != MergeType.TEST)
merge_types,
["5min", "6h", "14D"],
[timedelta(days=30)],
- [
- (datetime.now(tz=timezone.utc) - timedelta(days=35)).replace(
- microsecond=0
- )
- ],
+ [(datetime.now(tz=UTC) - timedelta(days=35)).replace(microsecond=0)],
)
),
)
diff --git a/tests/incite/mergers/test_pop_ledger.py b/tests/incite/mergers/test_pop_ledger.py
index 6f96108..7583faf 100644
--- a/tests/incite/mergers/test_pop_ledger.py
+++ b/tests/incite/mergers/test_pop_ledger.py
@@ -1,4 +1,4 @@
-from datetime import timedelta, datetime, timezone
+from datetime import UTC, datetime, timedelta, timezone
from itertools import product as iter_product
from typing import Optional
@@ -10,7 +10,7 @@ from generalresearch.incite.schemas.mergers.pop_ledger import (
numerical_col_names,
)
from test_utils.incite.collections.conftest import ledger_collection
-from test_utils.incite.conftest import mnt_filepath, incite_item_factory
+from test_utils.incite.conftest import incite_item_factory, mnt_filepath
from test_utils.incite.mergers.conftest import pop_ledger_merge
from test_utils.managers.ledger.conftest import create_main_accounts
@@ -27,11 +27,11 @@ from test_utils.managers.ledger.conftest import create_main_accounts
class TestMergePOPLedger:
@pytest.fixture
- def start(self) -> "datetime":
- return datetime(year=2020, month=3, day=14, tzinfo=timezone.utc)
+ def start(self) -> datetime:
+ return datetime(year=2020, month=3, day=14, tzinfo=UTC)
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return timedelta(days=5)
def test_base(
@@ -145,9 +145,9 @@ class TestMergePOPLedger:
delete_ledger_db,
session_collection,
):
+ from generalresearch.models.thl.finance import ProductBalances
from generalresearch.models.thl.ledger import LedgerAccount
from generalresearch.models.thl.product import Product
- from generalresearch.models.thl.finance import ProductBalances
u = user_factory(product=product, created=session_collection.start)
diff --git a/tests/incite/mergers/test_ym_survey_merge.py b/tests/incite/mergers/test_ym_survey_merge.py
index 4c2df6b..9107f21 100644
--- a/tests/incite/mergers/test_ym_survey_merge.py
+++ b/tests/incite/mergers/test_ym_survey_merge.py
@@ -1,4 +1,4 @@
-from datetime import timedelta, timezone, datetime
+from datetime import UTC, datetime, timedelta, timezone
from itertools import product
import pandas as pd
@@ -6,16 +6,16 @@ import pytest
# noinspection PyUnresolvedReferences
from distributed.utils_test import (
- gen_cluster,
+ cleanup,
+ client,
client_no_amm,
+ cluster_fixture,
+ gen_cluster,
loop,
loop_in_thread,
- cleanup,
- cluster_fixture,
- client,
)
-from test_utils.incite.collections.conftest import wall_collection, session_collection
+from test_utils.incite.collections.conftest import session_collection, wall_collection
from test_utils.incite.mergers.conftest import (
enriched_session_merge,
ym_survey_wall_merge,
@@ -28,11 +28,7 @@ from test_utils.incite.mergers.conftest import (
product(
["12h", "3D"],
[timedelta(days=30)],
- [
- (datetime.now(tz=timezone.utc) - timedelta(days=35)).replace(
- microsecond=0
- )
- ],
+ [(datetime.now(tz=UTC) - timedelta(days=35)).replace(microsecond=0)],
)
),
)
diff --git a/tests/incite/schemas/test_admin_responses.py b/tests/incite/schemas/test_admin_responses.py
index 43aa399..29d93fe 100644
--- a/tests/incite/schemas/test_admin_responses.py
+++ b/tests/incite/schemas/test_admin_responses.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from random import sample
from typing import List
@@ -8,8 +8,8 @@ import pytest
from generalresearch.incite.schemas import empty_dataframe_from_schema
from generalresearch.incite.schemas.admin_responses import (
- AdminPOPSchema,
SIX_HOUR_SECONDS,
+ AdminPOPSchema,
)
from generalresearch.locales import Localelator
@@ -72,8 +72,7 @@ class TestAdminPOPSchema:
def test_index_tz_parser(self):
tz_dates = [
- datetime(year=2024, month=1, day=i, tzinfo=timezone.utc)
- for i in range(1, 10)
+ datetime(year=2024, month=1, day=i, tzinfo=UTC) for i in range(1, 10)
]
df = pd.DataFrame(
@@ -85,16 +84,16 @@ class TestAdminPOPSchema:
df = self.assign_valid_vals(df)
# Initially, they're all set with a timezone
- timestmaps: List[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
- assert all([ts.tz == timezone.utc for ts in timestmaps])
+ timestmaps: list[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
+ assert all([ts.tz == UTC for ts in timestmaps])
# After validation, the timezone is removed
df = AdminPOPSchema.validate(df)
- timestmaps: List[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
+ timestmaps: list[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
assert all([ts.tz is None for ts in timestmaps])
def test_index_tz_no_future_beyond_one_year(self):
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
tz_dates = [now + timedelta(days=i * 365) for i in range(1, 10)]
df = pd.DataFrame(
@@ -157,9 +156,7 @@ class TestAdminPOPSchema:
def test_invalid_parsing(self):
# (1) Timezones AND as strings will still parse correctly
tz_str_dates = [
- datetime(
- year=2024, month=1, day=1, minute=i, tzinfo=timezone.utc
- ).isoformat()
+ datetime(year=2024, month=1, day=1, minute=i, tzinfo=UTC).isoformat()
for i in range(1, 10)
]
df = pd.DataFrame(
@@ -173,12 +170,12 @@ class TestAdminPOPSchema:
df = AdminPOPSchema.validate(df, lazy=True)
assert isinstance(df, pd.DataFrame)
- timestmaps: List[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
+ timestmaps: list[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
assert all([ts.tz is None for ts in timestmaps])
# (2) Timezones are removed
dates = [
- datetime(year=2024, month=1, day=1, minute=i, tzinfo=timezone.utc)
+ datetime(year=2024, month=1, day=1, minute=i, tzinfo=UTC)
for i in range(1, 10)
]
df = pd.DataFrame(
@@ -190,12 +187,12 @@ class TestAdminPOPSchema:
df = self.assign_valid_vals(df)
# Has tz before validation, and none after
- timestmaps: List[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
- assert all([ts.tz is timezone.utc for ts in timestmaps])
+ timestmaps: list[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
+ assert all([ts.tz is UTC for ts in timestmaps])
df = AdminPOPSchema.validate(df, lazy=True)
- timestmaps: List[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
+ timestmaps: list[pd.Timestamp] = [i for i in df.index.get_level_values(0)]
assert all([ts.tz is None for ts in timestmaps])
def test_clipping(self):
diff --git a/tests/incite/test_collection_base.py b/tests/incite/test_collection_base.py
index 7e6605f..5a63019 100644
--- a/tests/incite/test_collection_base.py
+++ b/tests/incite/test_collection_base.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from os.path import exists as pexists
from os.path import join as pjoin
from pathlib import Path
@@ -12,11 +12,9 @@ from _pytest._code.code import ExceptionInfo
from generalresearch.incite.base import CollectionBase
from test_utils.incite.conftest import mnt_filepath
-AGO_15min = (datetime.now(tz=timezone.utc) - timedelta(minutes=15)).replace(
- microsecond=0
-)
-AGO_1HR = (datetime.now(tz=timezone.utc) - timedelta(hours=1)).replace(microsecond=0)
-AGO_2HR = (datetime.now(tz=timezone.utc) - timedelta(hours=2)).replace(microsecond=0)
+AGO_15min = (datetime.now(tz=UTC) - timedelta(minutes=15)).replace(microsecond=0)
+AGO_1HR = (datetime.now(tz=UTC) - timedelta(hours=1)).replace(microsecond=0)
+AGO_2HR = (datetime.now(tz=UTC) - timedelta(hours=2)).replace(microsecond=0)
class TestCollectionBase:
@@ -50,7 +48,7 @@ class TestCollectionBase:
with pytest.raises(expected_exception=ValueError) as cm:
cm: ExceptionInfo
CollectionBase(
- start=datetime.now(tz=timezone.utc) - timedelta(days=10),
+ start=datetime.now(tz=UTC) - timedelta(days=10),
archive_path=mnt_filepath.data_src,
)
assert "Collection.start must not have microseconds" in str(cm.value)
@@ -66,9 +64,7 @@ class TestCollectionBase:
assert "Timezone is not UTC" in str(cm.value)
instance = CollectionBase(archive_path=mnt_filepath.data_src)
- assert instance.start == datetime(
- year=2018, month=1, day=1, tzinfo=timezone.utc
- )
+ assert instance.start == datetime(year=2018, month=1, day=1, tzinfo=UTC)
with pytest.raises(expected_exception=ValueError) as cm:
cm: ExceptionInfo
@@ -145,7 +141,7 @@ class TestCollectionBaseProperties:
instance._interval_range(end=datetime.now(tz=tz))
assert "Timezones must match" in str(cm.value)
- res = instance._interval_range(end=datetime.now(tz=timezone.utc))
+ res = instance._interval_range(end=datetime.now(tz=UTC))
assert isinstance(res, pd.IntervalIndex)
assert res.closed_left
assert res.is_non_overlapping_monotonic
@@ -282,7 +278,7 @@ class TestCollectionBaseMethodsSourceTiming:
def test_get_item_start(self, mnt_filepath):
instance = CollectionBase(archive_path=mnt_filepath.data_src)
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
start = pd.Timestamp(dt)
with pytest.raises(expected_exception=NotImplementedError) as cm:
@@ -292,7 +288,7 @@ class TestCollectionBaseMethodsSourceTiming:
def test_get_items(self, mnt_filepath):
instance = CollectionBase(archive_path=mnt_filepath.data_src)
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
with pytest.raises(expected_exception=NotImplementedError) as cm:
instance.get_items(since=dt)
diff --git a/tests/incite/test_collection_base_item.py b/tests/incite/test_collection_base_item.py
index e5d1d02..3f4d023 100644
--- a/tests/incite/test_collection_base_item.py
+++ b/tests/incite/test_collection_base_item.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from os.path import join as pjoin
from pathlib import Path
from uuid import uuid4
@@ -13,7 +13,7 @@ from generalresearch.incite.base import CollectionItemBase
class TestCollectionItemBase:
def test_init(self):
- dt = datetime.now(tz=timezone.utc).replace(microsecond=0)
+ dt = datetime.now(tz=UTC).replace(microsecond=0)
instance = CollectionItemBase()
instance2 = CollectionItemBase(start=dt)
@@ -25,7 +25,7 @@ class TestCollectionItemBase:
assert 0 == instance.start.microsecond == instance2.start.microsecond
def test_init_start(self):
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
with pytest.raises(expected_exception=ValidationError) as cm:
CollectionItemBase(start=dt)
diff --git a/tests/managers/leaderboard.py b/tests/managers/leaderboard.py
index 4d32dd0..149bdbb 100644
--- a/tests/managers/leaderboard.py
+++ b/tests/managers/leaderboard.py
@@ -1,7 +1,7 @@
import os
import time
import zoneinfo
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from uuid import uuid4
@@ -10,9 +10,6 @@ import pytest
from generalresearch.managers.leaderboard.manager import LeaderboardManager
from generalresearch.managers.leaderboard.tasks import hit_leaderboards
from generalresearch.models.thl.definitions import Status
-from generalresearch.models.thl.user import User
-from generalresearch.models.thl.product import Product
-from generalresearch.models.thl.session import Session
from generalresearch.models.thl.leaderboard import (
LeaderboardCode,
LeaderboardFrequency,
@@ -22,7 +19,10 @@ from generalresearch.models.thl.product import (
PayoutConfig,
PayoutTransformation,
PayoutTransformationPercentArgs,
+ Product,
)
+from generalresearch.models.thl.session import Session
+from generalresearch.models.thl.user import User
# random uuid for leaderboard tests
product_id = uuid4().hex
@@ -63,7 +63,7 @@ def _create_session(
)
session = Session(
user=user,
- started=datetime(2025, 2, 5, 6, tzinfo=timezone.utc),
+ started=datetime(2025, 2, 5, 6, tzinfo=UTC),
id=1,
country_iso=country_iso,
status=Status.COMPLETE,
@@ -152,7 +152,7 @@ class TestLeaderboards:
999999,
tzinfo=zoneinfo.ZoneInfo(key="America/New_York"),
)
- assert lb.period_start_utc == datetime(2025, 2, 5, 5, tzinfo=timezone.utc)
+ assert lb.period_start_utc == datetime(2025, 2, 5, 5, tzinfo=UTC)
assert lb.row_count == 7
assert lb.rows == [
LeaderboardRow(bpuid="aaa", rank=1, value=10),
@@ -270,5 +270,5 @@ class TestLeaderboards:
)
assert lb.local_start_time == "2025-02-01T00:00:00+09:00"
assert lb.local_end_time == "2025-02-01T23:59:59.999999+09:00"
- assert lb.period_start_utc == datetime(2025, 1, 31, 15, tzinfo=timezone.utc)
+ assert lb.period_start_utc == datetime(2025, 1, 31, 15, tzinfo=UTC)
print(lb.model_dump(mode="json"))
diff --git a/tests/managers/test_events.py b/tests/managers/test_events.py
index a0fab38..6941c00 100644
--- a/tests/managers/test_events.py
+++ b/tests/managers/test_events.py
@@ -1,22 +1,22 @@
+import math
import random
import time
-from datetime import timedelta, datetime, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from functools import partial
+from math import floor
from typing import Optional
from uuid import uuid4
-import math
import pytest
-from math import floor
from generalresearch.managers.events import EventSubscriber
from generalresearch.models import Source
from generalresearch.models.events import (
- MessageKind,
- EventType,
AggregateBySource,
+ EventType,
MaxGaugeBySource,
+ MessageKind,
)
from generalresearch.models.legacy.bucket import Bucket
from generalresearch.models.thl.definitions import Status, StatusCode1
@@ -41,13 +41,13 @@ def event_subscriber(thl_redis_config, product_id):
def create_dummy(
- product_id: Optional[str] = None, product_user_id: Optional[str] = None
+ product_id: str | None = None, product_user_id: str | None = None
) -> User:
return User(
product_id=product_id,
product_user_id=product_user_id or uuid4().hex,
uuid=uuid4().hex,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
user_id=random.randint(0, floor(2**32 / 2)),
)
@@ -496,7 +496,7 @@ class TestChannelsSubscriptions:
wall.update(
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- finished=datetime.now(tz=timezone.utc),
+ finished=datetime.now(tz=UTC),
cpi=Decimal("1"),
)
event_manager.handle_task_finish(wall, session, user)
diff --git a/tests/managers/thl/test_contest/test_leaderboard.py b/tests/managers/thl/test_contest/test_leaderboard.py
index 80a88a5..1a52f83 100644
--- a/tests/managers/thl/test_contest/test_leaderboard.py
+++ b/tests/managers/thl/test_contest/test_leaderboard.py
@@ -1,10 +1,10 @@
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from zoneinfo import ZoneInfo
from generalresearch.currency import USDCent
from generalresearch.models.thl.contest.definitions import (
- ContestStatus,
ContestEndReason,
+ ContestStatus,
)
from generalresearch.models.thl.contest.leaderboard import (
LeaderboardContest,
@@ -13,9 +13,11 @@ from generalresearch.models.thl.contest.leaderboard import (
from generalresearch.models.thl.product import Product
from generalresearch.models.thl.user import User
from test_utils.managers.contest.conftest import (
- leaderboard_contest_in_db as contest_in_db,
leaderboard_contest_create as contest_create,
)
+from test_utils.managers.contest.conftest import (
+ leaderboard_contest_in_db as contest_in_db,
+)
class TestLeaderboardContestCRUD:
@@ -39,7 +41,7 @@ class TestLeaderboardContestCRUD:
# We have it set in the fixture as the daily contest for 2025-01-01
assert c.end_condition.ends_at == datetime(
2025, 1, 1, 23, 59, 59, 999999, tzinfo=ZoneInfo("America/New_York")
- ).astimezone(tz=timezone.utc) + timedelta(minutes=90)
+ ).astimezone(tz=UTC) + timedelta(minutes=90)
def test_enter(
self,
diff --git a/tests/managers/thl/test_contest/test_milestone.py b/tests/managers/thl/test_contest/test_milestone.py
index 7312a64..66c5dc4 100644
--- a/tests/managers/thl/test_contest/test_milestone.py
+++ b/tests/managers/thl/test_contest/test_milestone.py
@@ -1,23 +1,29 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from generalresearch.models.thl.contest.definitions import (
- ContestStatus,
ContestEndReason,
+ ContestStatus,
)
from generalresearch.models.thl.contest.milestone import (
+ ContestEntryTrigger,
MilestoneContest,
MilestoneContestCreate,
MilestoneUserView,
- ContestEntryTrigger,
)
from generalresearch.models.thl.product import Product
from generalresearch.models.thl.user import User
from test_utils.managers.contest.conftest import (
milestone_contest as contest,
- milestone_contest_in_db as contest_in_db,
+)
+from test_utils.managers.contest.conftest import (
milestone_contest_create as contest_create,
+)
+from test_utils.managers.contest.conftest import (
milestone_contest_factory as contest_factory,
)
+from test_utils.managers.contest.conftest import (
+ milestone_contest_in_db as contest_in_db,
+)
class TestMilestoneContest:
@@ -28,7 +34,7 @@ class TestMilestoneContest:
assert not should, msg
# Change so that the contest ends now
- contest.end_condition.ends_at = datetime.now(tz=timezone.utc)
+ contest.end_condition.ends_at = datetime.now(tz=UTC)
should, msg = contest.should_end()
assert should
assert msg == ContestEndReason.ENDS_AT
diff --git a/tests/managers/thl/test_contest/test_raffle.py b/tests/managers/thl/test_contest/test_raffle.py
index 060055a..5804ea3 100644
--- a/tests/managers/thl/test_contest/test_raffle.py
+++ b/tests/managers/thl/test_contest/test_raffle.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
import pytest
from pydantic import ValidationError
@@ -9,21 +9,19 @@ from generalresearch.managers.thl.ledger_manager.exceptions import (
LedgerTransactionConditionFailedError,
)
from generalresearch.models.thl.contest import (
- ContestPrize,
- ContestEntryRule,
ContestEndCondition,
+ ContestEntryRule,
+ ContestPrize,
)
from generalresearch.models.thl.contest.definitions import (
- ContestStatus,
- ContestPrizeKind,
ContestEndReason,
+ ContestPrizeKind,
+ ContestStatus,
)
from generalresearch.models.thl.contest.exceptions import ContestError
from generalresearch.models.thl.contest.raffle import (
ContestEntry,
ContestEntryType,
-)
-from generalresearch.models.thl.contest.raffle import (
RaffleContest,
RaffleContestCreate,
RaffleUserView,
@@ -32,10 +30,16 @@ from generalresearch.models.thl.product import Product
from generalresearch.models.thl.user import User
from test_utils.managers.contest.conftest import (
raffle_contest as contest,
- raffle_contest_in_db as contest_in_db,
+)
+from test_utils.managers.contest.conftest import (
raffle_contest_create as contest_create,
+)
+from test_utils.managers.contest.conftest import (
raffle_contest_factory as contest_factory,
)
+from test_utils.managers.contest.conftest import (
+ raffle_contest_in_db as contest_in_db,
+)
class TestRaffleContest:
@@ -46,7 +50,7 @@ class TestRaffleContest:
assert not should, msg
# Change so that the contest ends now
- contest.end_condition.ends_at = datetime.now(tz=timezone.utc)
+ contest.end_condition.ends_at = datetime.now(tz=UTC)
should, msg = contest.should_end()
assert should
assert msg == ContestEndReason.ENDS_AT
diff --git a/tests/managers/thl/test_harmonized_uqa.py b/tests/managers/thl/test_harmonized_uqa.py
index 6bbbbe1..3b6df48 100644
--- a/tests/managers/thl/test_harmonized_uqa.py
+++ b/tests/managers/thl/test_harmonized_uqa.py
@@ -1,11 +1,11 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
import pytest
from generalresearch.managers.thl.profiling.uqa import UQAManager
from generalresearch.models.thl.profiling.user_question_answer import (
- UserQuestionAnswer,
DUMMY_UQA,
+ UserQuestionAnswer,
)
from generalresearch.models.thl.user import User
@@ -18,7 +18,7 @@ class TestUQAManager:
assert len(uqas) == 0
def test_create(self, uqa_manager: UQAManager, user: User):
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
uqas = [
UserQuestionAnswer(
user_id=user.user_id,
@@ -38,7 +38,7 @@ class TestUQAManager:
assert res[0] == uqas[0]
# Same question, so this gets updated
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
uqas_update = [
UserQuestionAnswer(
user_id=user.user_id,
@@ -57,7 +57,7 @@ class TestUQAManager:
assert res[0] == uqas_update[0]
# Add a new answer
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
uqas_new = [
UserQuestionAnswer(
user_id=user.user_id,
@@ -103,7 +103,7 @@ class TestUQAManagerCache:
UserQuestionAnswer(
question_id="5d6d9f3c03bb40bf9d0a24f306387d7c",
answer=("1",),
- timestamp=datetime.now(tz=timezone.utc),
+ timestamp=datetime.now(tz=UTC),
country_iso="us",
language_iso="eng",
property_code="gr:gender",
diff --git a/tests/managers/thl/test_ledger/test_lm_accounts.py b/tests/managers/thl/test_ledger/test_lm_accounts.py
index 5cfaac1..faef5fb 100644
--- a/tests/managers/thl/test_ledger/test_lm_accounts.py
+++ b/tests/managers/thl/test_ledger/test_lm_accounts.py
@@ -1,6 +1,7 @@
+from collections.abc import Callable
from itertools import product as iproduct
from random import randint
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
@@ -51,10 +52,10 @@ class TestLedgerAccountManagerNoResults:
def test_get_account_no_results(
self,
- currency: "LedgerCurrency",
+ currency: LedgerCurrency,
kind: str,
- acct_id: "UUIDStr",
- lm: "LedgerManager",
+ acct_id: UUIDStr,
+ lm: LedgerManager,
):
"""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
@@ -74,10 +75,10 @@ class TestLedgerAccountManagerNoResults:
def test_get_account_no_results_many(
self,
- currency: "LedgerCurrency",
+ currency: LedgerCurrency,
kind: str,
- acct_id: "UUIDStr",
- lm: "LedgerManager",
+ acct_id: UUIDStr,
+ lm: LedgerManager,
):
qn = ":".join([currency, kind, acct_id])
@@ -114,10 +115,10 @@ class TestLedgerAccountManagerCreate:
def test_create_account_error_permission(
self,
- currency: "LedgerCurrency",
- account_type: "AccountType",
- direction: "Direction",
- lm: "LedgerManager",
+ currency: LedgerCurrency,
+ account_type: AccountType,
+ direction: Direction,
+ lm: LedgerManager,
):
"""Confirm that the Permission values that are set on the Ledger Manger
allow the Creation action to occur.
@@ -164,10 +165,10 @@ class TestLedgerAccountManagerCreate:
def test_create(
self,
- currency: "LedgerCurrency",
- account_type: "AccountType",
- direction: "Direction",
- lm: "LedgerManager",
+ currency: LedgerCurrency,
+ account_type: AccountType,
+ direction: Direction,
+ lm: LedgerManager,
):
"""Confirm that the Permission values that are set on the Ledger Manger
allow the Creation action to occur.
@@ -194,10 +195,10 @@ class TestLedgerAccountManagerCreate:
def test_get_or_create(
self,
- currency: "LedgerCurrency",
- account_type: "AccountType",
- direction: "Direction",
- lm: "LedgerManager",
+ currency: LedgerCurrency,
+ account_type: AccountType,
+ direction: Direction,
+ lm: LedgerManager,
):
"""Confirm that the Permission values that are set on the Ledger Manger
allow the Creation action to occur.
@@ -225,7 +226,7 @@ class TestLedgerAccountManagerCreate:
class TestLedgerAccountManagerGet:
- def test_get(self, ledger_account: "LedgerAccount", lm: "LedgerManager"):
+ def test_get(self, ledger_account: LedgerAccount, lm: LedgerManager):
res = lm.get_account(qualified_name=ledger_account.qualified_name)
assert res is not None
assert res.uuid == ledger_account.uuid
@@ -243,11 +244,11 @@ class TestLedgerAccountManagerGet:
def test_get_balance_empty(
self,
- ledger_account: "LedgerAccount",
- ledger_account_credit: "LedgerAccount",
- ledger_account_debit: "LedgerAccount",
- ledger_tx: "LedgerTransaction",
- lm: "LedgerManager",
+ ledger_account: LedgerAccount,
+ ledger_account_credit: LedgerAccount,
+ ledger_account_debit: LedgerAccount,
+ ledger_tx: LedgerTransaction,
+ lm: LedgerManager,
):
res = lm.get_account_balance(account=ledger_account)
assert res == 0
@@ -261,12 +262,12 @@ class TestLedgerAccountManagerGet:
@pytest.mark.parametrize("n_times", range(5))
def test_get_account_filtered_balance(
self,
- ledger_account: "LedgerAccount",
- ledger_account_credit: "LedgerAccount",
- ledger_account_debit: "LedgerAccount",
- ledger_tx: "LedgerTransaction",
- n_times: "PositiveInt",
- lm: "LedgerManager",
+ ledger_account: LedgerAccount,
+ ledger_account_credit: LedgerAccount,
+ ledger_account_debit: LedgerAccount,
+ ledger_tx: LedgerTransaction,
+ n_times: PositiveInt,
+ lm: LedgerManager,
):
"""Try searching for random metadata and confirm it's always 0 because
Tx can be found.
@@ -320,7 +321,7 @@ class TestLedgerAccountManagerGet:
)
def test_get_balance_timerange_empty(
- self, ledger_account: "LedgerAccount", lm: "LedgerManager"
+ self, ledger_account: LedgerAccount, lm: LedgerManager
):
res = lm.get_account_balance_timerange(account=ledger_account)
assert res == 0
diff --git a/tests/managers/thl/test_ledger/test_lm_tx_locks.py b/tests/managers/thl/test_ledger/test_lm_tx_locks.py
index df2611b..07c3712 100644
--- a/tests/managers/thl/test_ledger/test_lm_tx_locks.py
+++ b/tests/managers/thl/test_ledger/test_lm_tx_locks.py
@@ -1,7 +1,7 @@
import logging
-from datetime import datetime, timezone, timedelta
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
-from typing import Callable
import pytest
@@ -9,21 +9,21 @@ from generalresearch.managers.thl.ledger_manager.conditions import (
generate_condition_mp_payment,
)
from generalresearch.managers.thl.ledger_manager.exceptions import (
+ LedgerTransactionCreateError,
LedgerTransactionCreateLockError,
LedgerTransactionFlagAlreadyExistsError,
- LedgerTransactionCreateError,
)
from generalresearch.models import Source
from generalresearch.models.thl.ledger import LedgerTransaction
from generalresearch.models.thl.session import (
- Wall,
+ Session,
Status,
StatusCode1,
- Session,
+ Wall,
WallAdjustedStatus,
)
from generalresearch.models.thl.user import User
-from test_utils.models.conftest import user_factory, session, product_user_wallet_no
+from test_utils.models.conftest import product_user_wallet_no, session, user_factory
logger = logging.getLogger("LedgerManager")
@@ -139,7 +139,7 @@ class TestLedgerLocks:
delete_ledger_db()
create_main_accounts()
- now = datetime.now(timezone.utc) - timedelta(hours=1)
+ now = datetime.now(UTC) - timedelta(hours=1)
user: User = user_factory(product=product_user_wallet_no)
# A User does a Wall complete on Session.id=1 and the transaction is
@@ -283,8 +283,8 @@ class TestLedgerLocks:
session_id=3,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
thl_lm.create_tx_task_complete(wall=wall1, user=user, created=wall1.started)
@@ -327,8 +327,8 @@ class TestLedgerLocks:
session_id=3,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
thl_lm.create_tx_task_complete(wall1, user, created=wall1.started)
diff --git a/tests/managers/thl/test_ledger/test_thl_lm_bp_payout.py b/tests/managers/thl/test_ledger/test_thl_lm_bp_payout.py
index 294d092..1fb9c01 100644
--- a/tests/managers/thl/test_ledger/test_thl_lm_bp_payout.py
+++ b/tests/managers/thl/test_ledger/test_thl_lm_bp_payout.py
@@ -1,5 +1,5 @@
import logging
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from random import randint
from uuid import uuid4
@@ -11,22 +11,22 @@ from redis.lock import Lock
from generalresearch.currency import USDCent
from generalresearch.managers.base import Permission
-from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
from generalresearch.managers.thl.ledger_manager.exceptions import (
- LedgerTransactionFlagAlreadyExistsError,
LedgerTransactionConditionFailedError,
- LedgerTransactionReleaseLockError,
LedgerTransactionCreateError,
+ LedgerTransactionFlagAlreadyExistsError,
+ LedgerTransactionReleaseLockError,
)
from generalresearch.managers.thl.ledger_manager.ledger import LedgerTransaction
+from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
from generalresearch.models import Source
from generalresearch.models.thl.definitions import PayoutStatus
from generalresearch.models.thl.ledger import Direction, TransactionType
from generalresearch.models.thl.session import (
- Wall,
+ Session,
Status,
StatusCode1,
- Session,
+ Wall,
)
from generalresearch.models.thl.user import User
from generalresearch.models.thl.wallet import PayoutType
@@ -55,7 +55,7 @@ class TestThlLedgerManagerBPPayout:
delete_ledger_db()
create_main_accounts()
- now = datetime.now(timezone.utc) - timedelta(hours=1)
+ now = datetime.now(UTC) - timedelta(hours=1)
user: User = user_factory(product=product_user_wallet_no)
wall1 = Wall(
@@ -158,7 +158,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
skip_wallet_balance_check=True,
skip_one_per_day_check=True,
skip_flag_check=True,
@@ -189,7 +189,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=uuid4().hex,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
skip_wallet_balance_check=False,
skip_one_per_day_check=False,
skip_flag_check=False,
@@ -199,7 +199,7 @@ class TestThlLedgerManagerBPPayout:
def test_create_tx_redis_failure(self, product, thl_web_rw, thl_lm):
rand_amount: USDCent = USDCent(randint(100, 1_000))
payoutevent_uuid = uuid4().hex
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
thl_lm.create_tx_plug_bp_wallet(
product, rand_amount, now, direction=Direction.CREDIT
@@ -226,7 +226,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
assert e.type is redis.exceptions.TimeoutError
# No txs were created
@@ -238,7 +238,7 @@ class TestThlLedgerManagerBPPayout:
def test_create_tx_multiple_per_day(self, product, thl_lm):
rand_amount: USDCent = USDCent(randint(100, 1_000))
payoutevent_uuid = uuid4().hex
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
thl_lm.create_tx_plug_bp_wallet(
product, rand_amount * USDCent(2), now, direction=Direction.CREDIT
@@ -248,7 +248,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
# Try to create another
@@ -258,7 +258,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
assert e.type is LedgerTransactionFlagAlreadyExistsError
@@ -270,7 +270,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid2,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
assert e.type is LedgerTransactionConditionFailedError
assert str(e.value) == ">1 tx per day"
@@ -280,14 +280,14 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid2,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
skip_one_per_day_check=True,
)
def test_create_tx_redis_lock_release_error(self, product, thl_lm):
rand_amount: USDCent = USDCent(randint(100, 1_000))
payoutevent_uuid = uuid4().hex
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
bp_wallet_account = thl_lm.get_account_or_create_bp_wallet(product=product)
thl_lm.create_tx_plug_bp_wallet(
@@ -304,7 +304,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
assert e.type is LedgerTransactionCreateError
assert str(e.value) == "Redis error: Simulated timeout during acquire"
@@ -321,7 +321,7 @@ class TestThlLedgerManagerBPPayout:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
assert e.type is LedgerTransactionReleaseLockError
assert str(e.value) == "Redis error: Simulated timeout during release"
@@ -337,7 +337,7 @@ class TestPayoutEventManagerBPPayout:
def test_create(self, product, thl_lm, brokerage_product_payout_event_manager):
rand_amount: USDCent = USDCent(randint(100, 1_000))
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
bp_wallet_account = thl_lm.get_account_or_create_bp_wallet(product=product)
assert thl_lm.get_account_balance(bp_wallet_account) == 0
thl_lm.create_tx_plug_bp_wallet(
@@ -369,7 +369,7 @@ class TestPayoutEventManagerBPPayout:
original_release = Lock.release
rand_amount: USDCent = USDCent(randint(100, 1_000))
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
bp_wallet_account = thl_lm.get_account_or_create_bp_wallet(product=product)
assert thl_lm.get_account_balance(bp_wallet_account) == 0
thl_lm.create_tx_plug_bp_wallet(
@@ -435,7 +435,7 @@ class TestPayoutEventManagerBPPayout:
# We wouldn't do this in practice, because this is paying out the BP again, but
# we can if want to.
# Change the timestamp so it'll create a new payout event
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
with pytest.raises(LedgerTransactionConditionFailedError) as e:
pe = brokerage_product_payout_event_manager.create_bp_payout_event(
thl_ledger_manager=thl_lm,
@@ -450,7 +450,7 @@ class TestPayoutEventManagerBPPayout:
assert pe.status == PayoutStatus.FAILED
# And if we really want to, we can make it again
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
pe = brokerage_product_payout_event_manager.create_bp_payout_event(
thl_ledger_manager=thl_lm,
product=product,
@@ -478,7 +478,7 @@ class TestPayoutEventManagerBPPayout:
original_release = Lock.release
rand_amount: USDCent = USDCent(randint(100, 1_000))
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
bp_wallet_account = thl_lm.get_account_or_create_bp_wallet(product=product)
brokerage_product_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
diff --git a/tests/managers/thl/test_ledger/test_thl_lm_tx.py b/tests/managers/thl/test_ledger/test_thl_lm_tx.py
index 31c7107..be988a1 100644
--- a/tests/managers/thl/test_ledger/test_thl_lm_tx.py
+++ b/tests/managers/thl/test_ledger/test_thl_lm_tx.py
@@ -1,5 +1,5 @@
import logging
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from random import randint
from uuid import uuid4
@@ -14,23 +14,22 @@ from generalresearch.models import Source
from generalresearch.models.thl.definitions import (
WALL_ALLOWED_STATUS_STATUS_CODE,
)
-from generalresearch.models.thl.ledger import Direction
-from generalresearch.models.thl.ledger import TransactionType
+from generalresearch.models.thl.ledger import Direction, TransactionType
+from generalresearch.models.thl.payout import UserPayoutEvent
from generalresearch.models.thl.product import (
PayoutConfig,
PayoutTransformation,
UserWalletConfig,
)
from generalresearch.models.thl.session import (
- Wall,
+ Session,
Status,
StatusCode1,
- Session,
+ Wall,
WallAdjustedStatus,
)
from generalresearch.models.thl.user import User
from generalresearch.models.thl.wallet import PayoutType
-from generalresearch.models.thl.payout import UserPayoutEvent
logger = logging.getLogger("LedgerManager")
@@ -82,7 +81,7 @@ class TestThlLedgerTxManager:
session=s1,
status=Status.COMPLETE,
status_code_1=status_code_1,
- finished=datetime.now(tz=timezone.utc) + timedelta(minutes=10),
+ finished=datetime.now(tz=UTC) + timedelta(minutes=10),
payout=bp_pay,
user_payout=user_pay,
)
@@ -127,7 +126,7 @@ class TestThlLedgerTxManager:
session=s1,
status=Status.COMPLETE,
status_code_1=status_code_1,
- finished=datetime.now(tz=timezone.utc) + timedelta(minutes=10),
+ finished=datetime.now(tz=UTC) + timedelta(minutes=10),
payout=bp_pay,
user_payout=user_pay,
)
@@ -209,7 +208,7 @@ class TestThlLedgerTxManager:
# there is no financial changes needed
session.update(
**{
- "finished": datetime.now(tz=timezone.utc) + timedelta(minutes=10),
+ "finished": datetime.now(tz=UTC) + timedelta(minutes=10),
}
)
assert session.finished
@@ -229,7 +228,7 @@ class TestThlLedgerTxManager:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
skip_wallet_balance_check=True,
skip_one_per_day_check=True,
skip_flag_check=True,
@@ -260,7 +259,7 @@ class TestThlLedgerTxManager:
product=product,
amount=rand_amount,
payoutevent_uuid=uuid4().hex,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
skip_wallet_balance_check=False,
skip_one_per_day_check=False,
skip_flag_check=False,
@@ -276,7 +275,7 @@ class TestThlLedgerTxManager:
product=product,
amount=rand_amount,
payoutevent_uuid=payoutevent_uuid,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
)
# Check the basic attributes
@@ -300,7 +299,7 @@ class TestThlLedgerTxManager:
tx = thl_lm.create_tx_plug_bp_wallet(
product=product,
amount=rand_amount,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
direction=Direction.DEBIT,
skip_flag_check=False,
)
@@ -328,7 +327,7 @@ class TestThlLedgerTxManager:
tx = thl_lm.create_tx_plug_bp_wallet_(
product=product,
amount=rand_amount,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
direction=Direction.DEBIT,
)
@@ -345,7 +344,7 @@ class TestThlLedgerTxManager:
thl_lm.create_tx_plug_bp_wallet_(
product=product,
amount=rand_amount + rand_amount,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
direction=Direction.CREDIT,
)
balance = thl_lm.get_account_balance(
@@ -727,8 +726,8 @@ class TestThlLedgerTxManagerFlows:
session_id=1,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
thl_lm.create_tx_task_complete(wall=wall1, user=user, created=wall1.started)
@@ -740,8 +739,8 @@ class TestThlLedgerTxManagerFlows:
session_id=1,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
thl_lm.create_tx_task_complete(wall=wall2, user=user, created=wall2.started)
@@ -793,8 +792,8 @@ class TestThlLedgerTxManagerFlows:
session_id=1,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
tx = thl_lm.create_tx_task_complete(
wall=wall1, user=user, created=wall1.started
@@ -880,8 +879,8 @@ class TestThlLedgerTxManagerFlows:
session_id=3,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
tx = thl_lm.create_tx_task_complete(
@@ -922,8 +921,8 @@ class TestThlLedgerTxManagerFlows:
session_id=3,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
thl_lm.create_tx_task_complete(wall=wall1, user=user, created=wall1.started)
@@ -963,8 +962,8 @@ class TestThlLedgerTxManagerFlows:
session_id=3,
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
thl_lm.create_tx_task_complete(wall=wall1, user=user, created=wall1.started)
@@ -1416,7 +1415,7 @@ class TestThlLedgerManagerAdj:
delete_ledger_db()
create_main_accounts()
- now = datetime.now(timezone.utc) - timedelta(days=1)
+ now = datetime.now(UTC) - timedelta(days=1)
user: User = user_factory(product=product_user_wallet_yes)
# Create 2 Wall completes and create the respective transaction for
diff --git a/tests/managers/thl/test_ledger/test_thl_lm_tx__user_payouts.py b/tests/managers/thl/test_ledger/test_thl_lm_tx__user_payouts.py
index 1e7146a..9253ff0 100644
--- a/tests/managers/thl/test_ledger/test_thl_lm_tx__user_payouts.py
+++ b/tests/managers/thl/test_ledger/test_thl_lm_tx__user_payouts.py
@@ -1,17 +1,17 @@
import logging
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from uuid import uuid4
import pytest
from generalresearch.managers.thl.ledger_manager.exceptions import (
- LedgerTransactionFlagAlreadyExistsError,
LedgerTransactionConditionFailedError,
+ LedgerTransactionFlagAlreadyExistsError,
)
+from generalresearch.models.thl.payout import UserPayoutEvent
from generalresearch.models.thl.user import User
from generalresearch.models.thl.wallet import PayoutType
-from generalresearch.models.thl.payout import UserPayoutEvent
from test_utils.managers.ledger.conftest import create_main_accounts
@@ -243,7 +243,7 @@ class TestLedgerManagerAMT:
delete_ledger_db()
create_main_accounts()
- now = datetime.now(timezone.utc) - timedelta(hours=1)
+ now = datetime.now(UTC) - timedelta(hours=1)
user: User = user_factory(product=product_amt_true)
pe = UserPayoutEvent(
@@ -394,7 +394,7 @@ class TestLedgerManagerPaypal:
delete_ledger_db()
create_main_accounts()
- now = datetime.now(tz=timezone.utc) - timedelta(hours=1)
+ now = datetime.now(tz=UTC) - timedelta(hours=1)
user: User = user_factory(product=product_amt_true)
# debit_account_uuid nothing checks they match the ledger ... todo?
diff --git a/tests/managers/thl/test_ledger/test_user_txs.py b/tests/managers/thl/test_ledger/test_user_txs.py
index ecf146f..b4b0437 100644
--- a/tests/managers/thl/test_ledger/test_user_txs.py
+++ b/tests/managers/thl/test_ledger/test_user_txs.py
@@ -1,6 +1,7 @@
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from uuid import uuid4
from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
@@ -24,8 +25,8 @@ if TYPE_CHECKING:
def test_user_txs(
- user_factory: Callable[..., "User"],
- product_amt_true: "Product",
+ user_factory: Callable[..., User],
+ product_amt_true: Product,
create_main_accounts: Callable[..., None],
thl_lm: ThlLedgerManager,
lm,
@@ -36,7 +37,7 @@ def test_user_txs(
session_factory,
user_payout_event_manager,
utc_now: datetime,
- settings: "GRLSettings",
+ settings: GRLSettings,
):
delete_ledger_db()
create_main_accounts()
@@ -136,13 +137,13 @@ def test_user_txs(
def test_user_txs_pagination(
- user_factory: Callable[..., "User"],
- product_amt_true: "Product",
+ user_factory: Callable[..., User],
+ product_amt_true: Product,
create_main_accounts: Callable[..., None],
- thl_lm: "ThlLedgerManager",
- lm: "LedgerManager",
+ thl_lm: ThlLedgerManager,
+ lm: LedgerManager,
delete_ledger_db: Callable[..., None],
- session_with_tx_factory: Callable[..., "Session"],
+ session_with_tx_factory: Callable[..., Session],
adj_to_fail_with_tx_factory,
user_payout_event_manager,
utc_now: datetime,
@@ -187,7 +188,7 @@ def test_user_txs_pagination(
assert txs.summary.user_bonus.entry_count == 12
# Test filtering. We should pull back only this one
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
user_compensate(
ledger_manager=thl_lm,
user=user,
@@ -203,7 +204,7 @@ def test_user_txs_pagination(
assert txs.summary.user_bonus.entry_count == 1
# And filtering with 0 results
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
txs = thl_lm.get_user_txs(user, page=1, size=5, time_start=now)
assert len(txs.transactions) == 0
assert txs.total == 0
@@ -215,8 +216,8 @@ def test_user_txs_pagination(
def test_user_txs_rolling_balance(
- user_factory: Callable[..., "User"],
- product_amt_true: "Product",
+ user_factory: Callable[..., User],
+ product_amt_true: Product,
create_main_accounts,
thl_lm,
lm,
@@ -224,7 +225,7 @@ def test_user_txs_rolling_balance(
session_with_tx_factory,
adj_to_fail_with_tx_factory,
user_payout_event_manager,
- settings: "GRLSettings",
+ settings: GRLSettings,
):
"""
Creates 3 $1.00 bonuses (postive),
diff --git a/tests/managers/thl/test_maxmind.py b/tests/managers/thl/test_maxmind.py
index c588c58..75bf0e9 100644
--- a/tests/managers/thl/test_maxmind.py
+++ b/tests/managers/thl/test_maxmind.py
@@ -1,17 +1,12 @@
import json
import logging
-from typing import Callable
+from collections.abc import Callable
-import geoip2.models
import pytest
from faker import Faker
from faker.providers.address.en_US import Provider as USAddressProvider
from generalresearch.managers.thl.ipinfo import GeoIpInfoManager
-from generalresearch.managers.thl.maxmind import MaxmindManager
-from generalresearch.managers.thl.maxmind.basic import (
- MaxmindBasicManager,
-)
from generalresearch.models.thl.ipinfo import (
GeoIPInformation,
normalize_ip,
diff --git a/tests/managers/thl/test_profiling/test_user_upk.py b/tests/managers/thl/test_profiling/test_user_upk.py
index 53bb8fe..491e2b1 100644
--- a/tests/managers/thl/test_profiling/test_user_upk.py
+++ b/tests/managers/thl/test_profiling/test_user_upk.py
@@ -1,8 +1,8 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from generalresearch.managers.thl.profiling.user_upk import UserUpkManager
-now = datetime.now(tz=timezone.utc)
+now = datetime.now(tz=UTC)
base = {
"country_iso": "us",
"language_iso": "eng",
diff --git a/tests/managers/thl/test_survey.py b/tests/managers/thl/test_survey.py
index 58c4577..4b4a579 100644
--- a/tests/managers/thl/test_survey.py
+++ b/tests/managers/thl/test_survey.py
@@ -1,24 +1,24 @@
import uuid
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
import pytest
from generalresearch.models import Source
from generalresearch.models.legacy.bucket import (
- SurveyEligibilityCriterion,
- TopNPlusBucket,
DurationSummary,
PayoutSummary,
+ SurveyEligibilityCriterion,
+ TopNPlusBucket,
)
from generalresearch.models.thl.profiling.user_question_answer import (
UserQuestionAnswer,
)
from generalresearch.models.thl.survey.model import (
Survey,
- SurveyStat,
SurveyCategoryModel,
SurveyEligibilityDefinition,
+ SurveyStat,
)
@@ -258,7 +258,7 @@ class TestSurveyStat:
return
# 1,000 of the 20,000 are "new"
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
for s in ss[:1000]:
s.survey__survey_id = "b"
s.updated_at = now
@@ -298,7 +298,7 @@ class TestSurveyStat:
source=source, surveys=surveys, survey_stats=survey_stats
)
# UPDATE -------
- since = datetime.now(tz=timezone.utc)
+ since = datetime.now(tz=UTC)
print(f"{since=}")
# 10 survey disappear
diff --git a/tests/managers/thl/test_task_adjustment.py b/tests/managers/thl/test_task_adjustment.py
index 839bbe1..71e3535 100644
--- a/tests/managers/thl/test_task_adjustment.py
+++ b/tests/managers/thl/test_task_adjustment.py
@@ -1,9 +1,9 @@
import logging
+from datetime import UTC, datetime, timedelta, timezone
+from decimal import Decimal
from random import randint
import pytest
-from datetime import datetime, timezone, timedelta
-from decimal import Decimal
from generalresearch.models import Source
from generalresearch.models.thl.definitions import (
@@ -31,16 +31,14 @@ def session_complete_with_wallet(session_with_tx_factory, user_with_wallet):
@pytest.fixture()
def session_fail(user, session_manager, wall_manager):
- session = session_manager.create_dummy(
- started=datetime.now(timezone.utc), user=user
- )
+ session = session_manager.create_dummy(started=datetime.now(UTC), user=user)
wall1 = wall_manager.create_dummy(
session_id=session.id,
user_id=user.user_id,
source=Source.DYNATA,
req_survey_id="72723",
req_cpi=Decimal("3.22"),
- started=datetime.now(timezone.utc),
+ started=datetime.now(UTC),
)
wall_manager.finish(
wall=wall1,
@@ -109,7 +107,7 @@ class TestHandleRecons:
assert ledger_manager.get_account_balance(commission_account) == 0
# Now, say we get the exact same *adjust to incomplete* msg again. It should do nothing!
- adjusted_timestamp = datetime.now(tz=timezone.utc)
+ adjusted_timestamp = datetime.now(tz=UTC)
wall = wall_manager.get_from_uuid(wall_uuid=wall_uuid)
with pytest.raises(match=" is already "):
wall_manager.adjust_status(
diff --git a/tests/managers/thl/test_task_status.py b/tests/managers/thl/test_task_status.py
index 55c89c0..468fd5e 100644
--- a/tests/managers/thl/test_task_status.py
+++ b/tests/managers/thl/test_task_status.py
@@ -1,31 +1,31 @@
-import pytest
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
+import pytest
+
from generalresearch.managers.thl.session import SessionManager
from generalresearch.models import Source
from generalresearch.models.thl.definitions import (
Status,
- WallAdjustedStatus,
StatusCode1,
+ WallAdjustedStatus,
)
from generalresearch.models.thl.product import (
PayoutConfig,
- UserWalletConfig,
PayoutTransformation,
PayoutTransformationPercentArgs,
+ UserWalletConfig,
)
from generalresearch.models.thl.session import Session, WallOut
from generalresearch.models.thl.task_status import TaskStatusResponse
from generalresearch.models.thl.user import User
-
-start1 = datetime(2023, 2, 1, tzinfo=timezone.utc)
+start1 = datetime(2023, 2, 1, tzinfo=UTC)
finish1 = start1 + timedelta(minutes=5)
recon1 = start1 + timedelta(days=20)
-start2 = datetime(2023, 2, 2, tzinfo=timezone.utc)
+start2 = datetime(2023, 2, 2, tzinfo=UTC)
finish2 = start2 + timedelta(minutes=5)
-start3 = datetime(2023, 2, 3, tzinfo=timezone.utc)
+start3 = datetime(2023, 2, 3, tzinfo=UTC)
finish3 = start3 + timedelta(minutes=5)
diff --git a/tests/managers/thl/test_user_manager/test_base.py b/tests/managers/thl/test_user_manager/test_base.py
index 0d7ffef..2704490 100644
--- a/tests/managers/thl/test_user_manager/test_base.py
+++ b/tests/managers/thl/test_user_manager/test_base.py
@@ -1,5 +1,5 @@
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from random import randint
from uuid import uuid4
@@ -118,7 +118,7 @@ class TestBlockUserManager:
)
assert not user.blocked
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
# Adds user to whitelist
thl_web_rw.execute_write(
"""
diff --git a/tests/managers/thl/test_user_streak.py b/tests/managers/thl/test_user_streak.py
index 7728f9f..ef25e2b 100644
--- a/tests/managers/thl/test_user_streak.py
+++ b/tests/managers/thl/test_user_streak.py
@@ -1,17 +1,17 @@
import copy
-from datetime import datetime, timezone, timedelta, date
+from datetime import UTC, date, datetime, timedelta, timezone
from decimal import Decimal
from zoneinfo import ZoneInfo
import pytest
from generalresearch.managers.thl.user_streak import compute_streaks_from_days
-from generalresearch.models.thl.definitions import StatusCode1, Status
+from generalresearch.models.thl.definitions import Status, StatusCode1
from generalresearch.models.thl.user_streak import (
- UserStreak,
- StreakState,
- StreakPeriod,
StreakFulfillment,
+ StreakPeriod,
+ StreakState,
+ UserStreak,
)
@@ -126,7 +126,7 @@ def test_user_streaks_active_broken(
user_streak_manager, user, session_manager, broken_active_streak
):
# Testing active streak, but broken (not today or yesterday)
- start1 = datetime(2025, 2, 12, tzinfo=timezone.utc)
+ start1 = datetime(2025, 2, 12, tzinfo=UTC)
end1 = start1 + timedelta(minutes=1)
# abandon counts as inactive
@@ -176,7 +176,7 @@ def test_user_streak_complete_active(user_streak_manager, user, session_manager)
# They completed yesterday NY time. Today isn't over so streak is pending
start1 = datetime.now(tz=ZoneInfo("America/New_York")) - timedelta(days=1)
- create_session_complete(session_manager, start1.astimezone(tz=timezone.utc), user)
+ create_session_complete(session_manager, start1.astimezone(tz=UTC), user)
last_complete_day = start1.date()
expected_streak = UserStreak(
@@ -201,7 +201,7 @@ def test_user_streak_complete_active(user_streak_manager, user, session_manager)
# And now they complete today
start2 = datetime.now(tz=ZoneInfo("America/New_York"))
- create_session_complete(session_manager, start2.astimezone(tz=timezone.utc), user)
+ create_session_complete(session_manager, start2.astimezone(tz=UTC), user)
last_complete_day = start2.date()
expected_streak = UserStreak(
longest_streak=2,
diff --git a/tests/managers/thl/test_userhealth.py b/tests/managers/thl/test_userhealth.py
index 1cda8de..e2ea4a8 100644
--- a/tests/managers/thl/test_userhealth.py
+++ b/tests/managers/thl/test_userhealth.py
@@ -1,4 +1,4 @@
-from datetime import timezone, datetime
+from datetime import UTC, datetime, timezone
from uuid import uuid4
import faker
@@ -12,7 +12,7 @@ from generalresearch.models.thl.ipinfo import GeoIPInformation
from generalresearch.models.thl.user_iphistory import (
IPRecord,
)
-from generalresearch.models.thl.userhealth import AuditLogLevel, AuditLog
+from generalresearch.models.thl.userhealth import AuditLog, AuditLogLevel
fake = faker.Faker()
@@ -51,7 +51,7 @@ class TestAuditLog:
res = audit_log_manager.get_by_id(auditlog_id=audit_log.id)
assert isinstance(res, AuditLog)
assert res.id == audit_log.id
- assert res.created.tzinfo == timezone.utc
+ assert res.created.tzinfo == UTC
def test_filter_by_product(
self,
@@ -179,7 +179,7 @@ class TestAuditLog:
res = audit_log_manager.filter_count(
user_ids=[u1.user_id, u2.user_id, u3.user_id],
- created_after=datetime.now(tz=timezone.utc),
+ created_after=datetime.now(tz=UTC),
)
assert isinstance(res, int)
assert res == 0
diff --git a/tests/managers/thl/test_wall_manager.py b/tests/managers/thl/test_wall_manager.py
index ee44e23..46d199f 100644
--- a/tests/managers/thl/test_wall_manager.py
+++ b/tests/managers/thl/test_wall_manager.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone, timedelta
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from uuid import uuid4
@@ -10,7 +10,7 @@ from generalresearch.models.thl.session import (
Status,
StatusCode1,
)
-from test_utils.models.conftest import user, session
+from test_utils.models.conftest import session, user
class TestWallManager:
@@ -88,7 +88,7 @@ class TestWallManager:
session_id=session.id,
user_id=user.user_id,
uuid_id=uuid4().hex,
- started=datetime.now(tz=timezone.utc),
+ started=datetime.now(tz=UTC),
source=Source.DYNATA,
buyer_id="123",
req_survey_id="456",
@@ -217,9 +217,9 @@ class TestWallCacheManager:
def test_get_wall_events(
self, wall_cache_manager, wall_manager, session_manager, user
):
- start1 = datetime.now(timezone.utc) - timedelta(hours=3)
- start2 = datetime.now(timezone.utc) - timedelta(hours=2)
- start3 = datetime.now(timezone.utc) - timedelta(hours=1)
+ start1 = datetime.now(UTC) - timedelta(hours=3)
+ start2 = datetime.now(UTC) - timedelta(hours=2)
+ start3 = datetime.now(UTC) - timedelta(hours=1)
session = session_manager.create_dummy(started=start1, user=user)
wall1 = wall_manager.create_dummy(
diff --git a/tests/models/admin/test_report_request.py b/tests/models/admin/test_report_request.py
index a80afbe..4626ab4 100644
--- a/tests/models/admin/test_report_request.py
+++ b/tests/models/admin/test_report_request.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
import pandas as pd
import pytest
@@ -19,19 +19,19 @@ class TestReportRequest:
assert rr.report_type == ReportType.POP_SESSION
assert rr.start != rr.start_floor, "rr.start != rr.start_floor"
- assert rr.start_floor.tzinfo == timezone.utc, "rr.start_floor.tzinfo not utc"
+ assert rr.start_floor.tzinfo == UTC, "rr.start_floor.tzinfo not utc"
rr1 = ReportRequest.model_validate(
{
"start": datetime(
- year=datetime.now(tz=timezone.utc).year,
+ year=datetime.now(tz=UTC).year,
month=1,
day=1,
hour=0,
minute=30,
second=25,
microsecond=35,
- tzinfo=timezone.utc,
+ tzinfo=UTC,
),
"interval": "1h",
}
@@ -43,14 +43,14 @@ class TestReportRequest:
rr2 = ReportRequest.model_validate(
{
"start": datetime(
- year=datetime.now(tz=timezone.utc).year,
+ year=datetime.now(tz=UTC).year,
month=1,
day=1,
hour=6,
minute=30,
second=25,
microsecond=35,
- tzinfo=timezone.utc,
+ tzinfo=UTC,
),
"interval": "1d",
}
@@ -92,8 +92,8 @@ class TestReportRequest:
with pytest.raises(expected_exception=ValidationError):
ReportRequest.model_validate(
{
- "start": datetime(year=1990, month=1, day=1, tzinfo=timezone.utc),
- "end": datetime(year=1950, month=1, day=1, tzinfo=timezone.utc),
+ "start": datetime(year=1990, month=1, day=1, tzinfo=UTC),
+ "end": datetime(year=1950, month=1, day=1, tzinfo=UTC),
}
)
@@ -156,8 +156,8 @@ class TestReportRequest:
rr = ReportRequest.model_validate(
{
"interval": "1d",
- "start": datetime(year=2000, month=1, day=1, tzinfo=timezone.utc),
- "end": datetime(year=2000, month=1, day=10, tzinfo=timezone.utc),
+ "start": datetime(year=2000, month=1, day=1, tzinfo=UTC),
+ "end": datetime(year=2000, month=1, day=10, tzinfo=UTC),
}
)
diff --git a/tests/models/custom_types/test_aware_datetime.py b/tests/models/custom_types/test_aware_datetime.py
index 530142e..043fba0 100644
--- a/tests/models/custom_types/test_aware_datetime.py
+++ b/tests/models/custom_types/test_aware_datetime.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import logging
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
import pytest
import pytz
@@ -27,14 +27,14 @@ class TestAwareDatetimeISO:
AwareDatetimeISOModel.model_validate_json(t.model_dump_json())
def test_dt(self):
- dt = datetime(2023, 10, 10, 1, 1, 1, tzinfo=timezone.utc)
+ dt = datetime(2023, 10, 10, 1, 1, 1, tzinfo=UTC)
t = AwareDatetimeISOModel(dt=dt, dt_optional=dt)
AwareDatetimeISOModel.model_validate_json(t.model_dump_json())
t = AwareDatetimeISOModel(dt=dt, dt_optional=None)
AwareDatetimeISOModel.model_validate_json(t.model_dump_json())
- dt = datetime(2023, 10, 10, 1, 1, 1, microsecond=123, tzinfo=timezone.utc)
+ dt = datetime(2023, 10, 10, 1, 1, 1, microsecond=123, tzinfo=UTC)
t = AwareDatetimeISOModel(dt=dt, dt_optional=dt)
AwareDatetimeISOModel.model_validate_json(t.model_dump_json())
diff --git a/tests/models/custom_types/test_dsn.py b/tests/models/custom_types/test_dsn.py
index 16e1f83..050976e 100644
--- a/tests/models/custom_types/test_dsn.py
+++ b/tests/models/custom_types/test_dsn.py
@@ -11,9 +11,9 @@ from generalresearch.models.custom_types import DaskDsn, SentryDsn
class SettingsModel(BaseModel):
- dask: Optional["DaskDsn"] = Field(default=None)
- sentry: Optional["SentryDsn"] = Field(default=None)
- db: Optional["MySQLDsn"] = Field(default=None)
+ dask: DaskDsn | None = Field(default=None)
+ sentry: SentryDsn | None = Field(default=None)
+ db: MySQLDsn | None = Field(default=None)
# --- Pytest themselves ---
diff --git a/tests/models/dynata/test_eligbility.py b/tests/models/dynata/test_eligbility.py
index 736c971..16cad26 100644
--- a/tests/models/dynata/test_eligbility.py
+++ b/tests/models/dynata/test_eligbility.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
class TestEligibility:
@@ -40,7 +40,7 @@ class TestEligibility:
"project_id": "p1",
"status": "OPEN",
"project_exclusions": set(),
- "created": datetime.now(tz=timezone.utc),
+ "created": datetime.now(tz=UTC),
"category_exclusions": set(),
"category_ids": set(),
"cpi": 1,
@@ -172,7 +172,7 @@ class TestEligibility:
"project_id": "p1",
"status": "OPEN",
"project_exclusions": set(),
- "created": datetime.now(tz=timezone.utc),
+ "created": datetime.now(tz=UTC),
"category_exclusions": set(),
"category_ids": set(),
"cpi": 1,
diff --git a/tests/models/gr/test_authentication.py b/tests/models/gr/test_authentication.py
index 6c84a5d..51595a7 100644
--- a/tests/models/gr/test_authentication.py
+++ b/tests/models/gr/test_authentication.py
@@ -1,9 +1,9 @@
import binascii
import json
import os
-from datetime import datetime, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timezone
from random import randint
-from typing import Callable
from uuid import uuid4
import pytest
@@ -251,7 +251,7 @@ class TestGRToken:
def gr_token(self, gr_user):
from generalresearch.models.gr.authentication import GRToken
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
token = binascii.hexlify(os.urandom(20)).decode()
gr_token = GRToken(key=token, created=now, user_id=gr_user.id)
diff --git a/tests/models/gr/test_base.py b/tests/models/gr/test_base.py
index a9f01a8..8da28d3 100644
--- a/tests/models/gr/test_base.py
+++ b/tests/models/gr/test_base.py
@@ -1,6 +1,6 @@
import subprocess
+from collections.abc import Callable
from pathlib import Path
-from typing import Callable
import pytest
from pydantic import PostgresDsn
@@ -10,9 +10,11 @@ from generalresearch.pg_helper import PostgresConfig
class TestGRPostgresDjangoCreation:
- def test_git(self, git_key_path: Path, gr_repo: Callable[..., Path]):
+ def test_git(self, gr_repo: Callable[..., Path]):
repo_path = gr_repo()
+ print("test_git.PATH:", repo_path)
+
try:
# Run the git command inside the target directory
result = subprocess.run(
@@ -36,11 +38,13 @@ class TestGRPostgresDjangoCreation:
dsn = django_db_factory("gr")
assert isinstance(dsn, PostgresDsn)
- # def test_django_tables(self, thl_web_rw: PostgresConfig):
- # res = thl_web_rw.execute_sql_query(query="""
- # SELECT COUNT(*)
- # FROM information_schema.tables
- # WHERE table_schema = 'public';
- # """)
- # assert len(res) == 1
- # assert res[0]["count"] == 56
+ def test_django_tables(self, gr_db: PostgresConfig):
+ res = gr_db.execute_sql_query(query="""
+ SELECT COUNT(*)
+ FROM information_schema.tables
+ WHERE table_schema = 'public';
+ """)
+ print(res)
+ assert len(res) == 1
+ assert res[0]["count"] == 56
+ assert True
diff --git a/tests/models/gr/test_business.py b/tests/models/gr/test_business.py
index 7a84f23..716ec75 100644
--- a/tests/models/gr/test_business.py
+++ b/tests/models/gr/test_business.py
@@ -1,5 +1,5 @@
import os
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from typing import Optional
from uuid import uuid4
@@ -82,15 +82,15 @@ class TestBusinessContact:
class TestBusiness:
@pytest.fixture
- def start(self) -> "datetime":
- return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
+ def start(self) -> datetime:
+ return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
return "30d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return None
def test_init(self, business):
@@ -413,15 +413,15 @@ class TestBusiness:
class TestBusinessBalance:
@pytest.fixture
- def start(self) -> "datetime":
- return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
+ def start(self) -> datetime:
+ return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
return "30d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return None
@pytest.mark.skip
@@ -1138,7 +1138,7 @@ class TestBusinessBalance:
class TestBusinessMethods:
@pytest.fixture(scope="function")
- def start(self, utc_90days_ago) -> "datetime":
+ def start(self, utc_90days_ago) -> datetime:
s = utc_90days_ago.replace(microsecond=0)
return s
@@ -1149,7 +1149,7 @@ class TestBusinessMethods:
@pytest.fixture(scope="function")
def duration(
self,
- ) -> Optional["timedelta"]:
+ ) -> timedelta | None:
return None
def test_cache_key(self, business, gr_redis):
@@ -1212,7 +1212,7 @@ class TestBusinessMethods:
# We're going to pull only a specific year, but make sure that
# it's being assigned to the field regardless
- year = datetime.now(tz=timezone.utc).year
+ year = datetime.now(tz=UTC).year
res = Business.from_redis(
uuid=business.uuid,
fields=[f"pop_financial:{year}"],
diff --git a/tests/models/morning/test.py b/tests/models/morning/test.py
index bedf9c2..222cb93 100644
--- a/tests/models/morning/test.py
+++ b/tests/models/morning/test.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from generalresearch.models.morning.question import MorningQuestion
@@ -163,8 +163,8 @@ bid = {
# what gets run in MorningAPI._format_bid
bid["language_isos"] = ("eng",)
bid["country_iso"] = "us"
-bid["end_date"] = datetime(2024, 7, 19, 9, 1, 13, 520243, tzinfo=timezone.utc)
-bid["published_at"] = datetime(2024, 6, 19, 9, 1, 13, 520243, tzinfo=timezone.utc)
+bid["end_date"] = datetime(2024, 7, 19, 9, 1, 13, 520243, tzinfo=UTC)
+bid["published_at"] = datetime(2024, 6, 19, 9, 1, 13, 520243, tzinfo=UTC)
bid.update(bid["statistics"])
bid["qualified_conversion"] /= 100
bid["system_conversion"] /= 100
diff --git a/tests/models/prodege/test_survey_participation.py b/tests/models/prodege/test_survey_participation.py
index 68d7838..3b35d0c 100644
--- a/tests/models/prodege/test_survey_participation.py
+++ b/tests/models/prodege/test_survey_participation.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
class TestProdegeParticipation:
@@ -10,7 +10,7 @@ class TestProdegeParticipation:
ProdegeUserPastParticipation,
)
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
pp = ProdegePastParticipation.from_api(
{
"participation_project_ids": [152677146, 152803285],
@@ -89,7 +89,7 @@ class TestProdegeParticipation:
ProdegeUserPastParticipation,
)
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
pp = ProdegePastParticipation.from_api(
{
"participation_project_ids": [152677146, 152803285],
diff --git a/tests/models/spectrum/test_question.py b/tests/models/spectrum/test_question.py
index ba118d7..4f92961 100644
--- a/tests/models/spectrum/test_question.py
+++ b/tests/models/spectrum/test_question.py
@@ -1,17 +1,17 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from generalresearch.models import Source
from generalresearch.models.spectrum.question import (
- SpectrumQuestionOption,
SpectrumQuestion,
- SpectrumQuestionType,
SpectrumQuestionClass,
+ SpectrumQuestionOption,
+ SpectrumQuestionType,
)
from generalresearch.models.thl.profiling.upk_question import (
UpkQuestion,
+ UpkQuestionChoice,
UpkQuestionSelectorMC,
UpkQuestionType,
- UpkQuestionChoice,
)
@@ -43,7 +43,7 @@ class TestSpectrumQuestion:
tags=None,
options=None,
class_num=SpectrumQuestionClass.CORE,
- created=datetime(2017, 8, 16, 7, 52, 7, 688000, tzinfo=timezone.utc),
+ created=datetime(2017, 8, 16, 7, 52, 7, 688000, tzinfo=UTC),
is_live=True,
source=Source.SPECTRUM,
category_id=None,
@@ -85,7 +85,7 @@ class TestSpectrumQuestion:
SpectrumQuestionOption(id="112", text="Female", order=1),
],
class_num=SpectrumQuestionClass.CORE,
- created=datetime(2017, 8, 16, 7, 52, 7, 688000, tzinfo=timezone.utc),
+ created=datetime(2017, 8, 16, 7, 52, 7, 688000, tzinfo=UTC),
is_live=True,
source=Source.SPECTRUM,
category_id=None,
@@ -160,7 +160,7 @@ class TestSpectrumQuestion:
SpectrumQuestionOption(id="999", text="None of the above", order=3),
],
class_num=SpectrumQuestionClass.EXTENDED,
- created=datetime(2017, 8, 16, 7, 52, 7, 688000, tzinfo=timezone.utc),
+ created=datetime(2017, 8, 16, 7, 52, 7, 688000, tzinfo=UTC),
is_live=True,
source=Source.SPECTRUM,
category_id=None,
diff --git a/tests/models/spectrum/test_survey.py b/tests/models/spectrum/test_survey.py
index b612a63..5e095a3 100644
--- a/tests/models/spectrum/test_survey.py
+++ b/tests/models/spectrum/test_survey.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from decimal import Decimal
@@ -140,11 +140,11 @@ class TestSpectrumSurvey:
"survey_id": 29333264,
"survey_name": "Exciting New Survey #29333264",
"survey_status": 22,
- "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=timezone.utc),
+ "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=UTC),
"category": "Exciting New",
"category_code": 232,
- "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=timezone.utc),
- "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=timezone.utc),
+ "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=UTC),
+ "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=UTC),
"soft_launch": False,
"click_balancing": 0,
"price_type": 1,
@@ -212,7 +212,7 @@ class TestSpectrumSurvey:
survey_id="29333264",
survey_name="Exciting New Survey #29333264",
status=SpectrumStatus.LIVE,
- field_end_date=datetime(2024, 5, 23, 18, 18, 31, tzinfo=timezone.utc),
+ field_end_date=datetime(2024, 5, 23, 18, 18, 31, tzinfo=UTC),
category_code="232",
calculation_type=TaskCalculationType.COMPLETES,
requires_pii=False,
@@ -240,8 +240,8 @@ class TestSpectrumSurvey:
values=["18-64"],
)
},
- created_api=datetime(2024, 5, 20, 17, 48, 13, tzinfo=timezone.utc),
- modified_api=datetime(2024, 5, 20, 18, 18, 31, tzinfo=timezone.utc),
+ created_api=datetime(2024, 5, 20, 17, 48, 13, tzinfo=UTC),
+ modified_api=datetime(2024, 5, 20, 18, 18, 31, tzinfo=UTC),
updated=None,
)
assert expected_survey.model_dump_json() == s.model_dump_json()
@@ -255,11 +255,11 @@ class TestSpectrumSurvey:
"survey_id": 29333264,
"survey_name": "#29333264",
"survey_status": 22,
- "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=timezone.utc),
+ "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=UTC),
"category": "Exciting New",
"category_code": 232,
- "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=timezone.utc),
- "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=timezone.utc),
+ "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=UTC),
+ "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=UTC),
"soft_launch": False,
"click_balancing": 0,
"price_type": 1,
@@ -318,11 +318,11 @@ class TestSpectrumSurvey:
"survey_id": 29333264,
"survey_name": "#29333264",
"survey_status": 22,
- "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=timezone.utc),
+ "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=UTC),
"category": "Exciting New",
"category_code": 232,
- "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=timezone.utc),
- "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=timezone.utc),
+ "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=UTC),
+ "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=UTC),
"soft_launch": False,
"click_balancing": 0,
"price_type": 1,
diff --git a/tests/models/spectrum/test_survey_manager.py b/tests/models/spectrum/test_survey_manager.py
index 582093c..11970bf 100644
--- a/tests/models/spectrum/test_survey_manager.py
+++ b/tests/models/spectrum/test_survey_manager.py
@@ -1,22 +1,21 @@
import copy
import logging
-from datetime import timezone, datetime
+from datetime import UTC, datetime, timezone
from decimal import Decimal
from pymysql import IntegrityError
-
logger = logging.getLogger()
example_survey_api_response = {
"survey_id": 29333264,
"survey_name": "#29333264",
"survey_status": 22,
- "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=timezone.utc),
+ "field_end_date": datetime(2024, 5, 23, 18, 18, 31, tzinfo=UTC),
"category": "Exciting New",
"category_code": 232,
- "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=timezone.utc),
- "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=timezone.utc),
+ "crtd_on": datetime(2024, 5, 20, 17, 48, 13, tzinfo=UTC),
+ "mod_on": datetime(2024, 5, 20, 18, 18, 31, tzinfo=UTC),
"soft_launch": False,
"click_balancing": 0,
"price_type": 1,
@@ -66,7 +65,7 @@ class TestSpectrumSurvey:
assert settings.debug, "CRITICAL: Do not run this on production."
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
spectrum_rw.execute_sql_query(
query=f"""
DELETE FROM `{spectrum_rw.db}`.spectrum_survey
@@ -93,7 +92,7 @@ class TestSpectrumSurvey:
assert settings.debug, "CRITICAL: Do not run this on production."
- now = datetime.now(tz=timezone.utc)
+ now = datetime.now(tz=UTC)
spectrum_rw.execute_sql_query(
query=f"""
DELETE FROM `{spectrum_rw.db}`.spectrum_survey
diff --git a/tests/models/test_finance.py b/tests/models/test_finance.py
index bd548b3..6dcd441 100644
--- a/tests/models/test_finance.py
+++ b/tests/models/test_finance.py
@@ -1,7 +1,7 @@
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from itertools import product as iter_product
from random import randint
-from typing import Callable
from uuid import uuid4
import pandas as pd
@@ -683,7 +683,7 @@ class TestProductFinanceData:
rand_item_time = fake.date_time_between(
start_date=item.start,
end_date=item.finish,
- tzinfo=timezone.utc,
+ tzinfo=UTC,
)
session_with_tx_factory(started=rand_item_time, user=u)
@@ -773,7 +773,7 @@ class TestPOPFinancialData:
rand_item_time = fake.date_time_between(
start_date=item.start,
end_date=item.finish,
- tzinfo=timezone.utc,
+ tzinfo=UTC,
)
session_with_tx_factory(started=rand_item_time, user=u)
@@ -870,7 +870,7 @@ class TestBusinessBalanceData:
item_time = fake.date_time_between(
start_date=item.start,
end_date=item.finish,
- tzinfo=timezone.utc,
+ tzinfo=UTC,
)
session_with_tx_factory(started=item_time, user=u)
item.initial_load(overwrite=True)
diff --git a/tests/models/thl/test_adjustments.py b/tests/models/thl/test_adjustments.py
index 27091bb..c2c035d 100644
--- a/tests/models/thl/test_adjustments.py
+++ b/tests/models/thl/test_adjustments.py
@@ -1,6 +1,6 @@
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
-from typing import Callable
import pytest
@@ -16,14 +16,14 @@ from generalresearch.models.thl.session import (
)
from generalresearch.models.thl.user import User
-started1 = datetime(2023, 1, 1, tzinfo=timezone.utc)
-started2 = datetime(2023, 1, 1, 0, 10, 0, tzinfo=timezone.utc)
+started1 = datetime(2023, 1, 1, tzinfo=UTC)
+started2 = datetime(2023, 1, 1, 0, 10, 0, tzinfo=UTC)
finished1 = started1 + timedelta(minutes=10)
finished2 = started2 + timedelta(minutes=10)
-adj_ts = datetime(2023, 2, 2, tzinfo=timezone.utc)
-adj_ts2 = datetime(2023, 2, 3, tzinfo=timezone.utc)
-adj_ts3 = datetime(2023, 2, 4, tzinfo=timezone.utc)
+adj_ts = datetime(2023, 2, 2, tzinfo=UTC)
+adj_ts2 = datetime(2023, 2, 3, tzinfo=UTC)
+adj_ts3 = datetime(2023, 2, 4, tzinfo=UTC)
class TestProductAdjustments:
diff --git a/tests/models/thl/test_contest/test_contest.py b/tests/models/thl/test_contest/test_contest.py
index 0fbd4cc..acb501c 100644
--- a/tests/models/thl/test_contest/test_contest.py
+++ b/tests/models/thl/test_contest/test_contest.py
@@ -1,4 +1,4 @@
-from typing import Callable
+from collections.abc import Callable
import pytest
diff --git a/tests/models/thl/test_contest/test_leaderboard_contest.py b/tests/models/thl/test_contest/test_leaderboard_contest.py
index 8b714ee..3efcf2f 100644
--- a/tests/models/thl/test_contest/test_leaderboard_contest.py
+++ b/tests/models/thl/test_contest/test_leaderboard_contest.py
@@ -1,4 +1,4 @@
-from datetime import timezone
+from datetime import UTC, timezone
from uuid import uuid4
import pytest
@@ -26,7 +26,7 @@ class TestLeaderboardContest(TestContest):
@pytest.fixture
def leaderboard_contest(
self, product: Product, thl_redis, user_manager
- ) -> "LeaderboardContest":
+ ) -> LeaderboardContest:
board_key = f"leaderboard:{product.uuid}:us:weekly:2025-05-26:complete_count"
c = LeaderboardContest(
@@ -91,7 +91,7 @@ class TestLeaderboardContest(TestContest):
country_iso=model.country_iso,
freq=model.freq,
product_id=leaderboard_contest.product_id,
- within_time=model.period_start_local.astimezone(tz=timezone.utc),
+ within_time=model.period_start_local.astimezone(tz=UTC),
)
lbm.hit_complete_count(product_user_id=user_1.product_user_id)
diff --git a/tests/models/thl/test_ledger.py b/tests/models/thl/test_ledger.py
index 257de3c..5edcc9d 100644
--- a/tests/models/thl/test_ledger.py
+++ b/tests/models/thl/test_ledger.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timezone
+from datetime import UTC, datetime, timezone
from uuid import uuid4
import pytest
@@ -21,7 +21,7 @@ class TestLedgerTransaction:
assert [] == t.entries
assert {} == t.metadata
t = LedgerTransaction(
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
metadata={"a": "b", "user": "1234"},
ext_description="foo",
)
diff --git a/tests/models/thl/test_product.py b/tests/models/thl/test_product.py
index 39469dc..78bc10a 100644
--- a/tests/models/thl/test_product.py
+++ b/tests/models/thl/test_product.py
@@ -2,9 +2,9 @@ from __future__ import annotations
import os
import shutil
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
-from typing import Callable
from uuid import uuid4
import pytest
@@ -586,7 +586,7 @@ class TestProductFinancials:
@pytest.fixture
def start(self) -> datetime:
- return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
+ return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
@@ -769,7 +769,7 @@ class TestProductBalance:
@pytest.fixture
def start(self) -> datetime:
- return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
+ return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
@@ -877,7 +877,7 @@ class TestProductBalance:
product=product,
amount=USDCent(71),
ext_ref_id=uuid4().hex,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
skip_wallet_balance_check=True,
skip_one_per_day_check=True,
)
@@ -892,7 +892,7 @@ class TestProductPOPFinancial:
@pytest.fixture
def start(self) -> datetime:
- return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
+ return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
@@ -965,7 +965,7 @@ class TestProductCache:
@pytest.fixture
def start(self) -> datetime:
- return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
+ return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC)
@pytest.fixture
def offset(self) -> str:
diff --git a/tests/models/thl/test_user.py b/tests/models/thl/test_user.py
index 943ae8e..a4f331a 100644
--- a/tests/models/thl/test_user.py
+++ b/tests/models/thl/test_user.py
@@ -1,5 +1,5 @@
import json
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from random import choice as rand_choice
from random import randint
@@ -383,7 +383,7 @@ class TestUserCreated:
from generalresearch.models.thl.user import User
user = User(user_id=self.user_id)
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
user.created = dt
assert user.created == dt
@@ -419,7 +419,7 @@ class TestUserCreated:
def test_not_in_future(self):
from generalresearch.models.thl.user import User
- the_future = datetime.now(tz=timezone.utc) + timedelta(minutes=1)
+ the_future = datetime.now(tz=UTC) + timedelta(minutes=1)
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, created=the_future)
assert "1 validation error for User" in str(cm.value)
@@ -428,9 +428,9 @@ class TestUserCreated:
def test_after_anno_domini(self):
from generalresearch.models.thl.user import User
- before_ad = datetime(
- year=2015, month=1, day=1, tzinfo=timezone.utc
- ) + timedelta(minutes=1)
+ before_ad = datetime(year=2015, month=1, day=1, tzinfo=UTC) + timedelta(
+ minutes=1
+ )
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, created=before_ad)
assert "1 validation error for User" in str(cm.value)
@@ -444,7 +444,7 @@ class TestUserLastSeen:
from generalresearch.models.thl.user import User
user = User(user_id=self.user_id)
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
user.last_seen = dt
assert user.last_seen == dt
@@ -480,7 +480,7 @@ class TestUserLastSeen:
def test_not_in_future(self):
from generalresearch.models.thl.user import User
- the_future = datetime.now(tz=timezone.utc) + timedelta(minutes=1)
+ the_future = datetime.now(tz=UTC) + timedelta(minutes=1)
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, last_seen=the_future)
assert "1 validation error for User" in str(cm.value)
@@ -489,9 +489,9 @@ class TestUserLastSeen:
def test_after_anno_domini(self):
from generalresearch.models.thl.user import User
- before_ad = datetime(
- year=2015, month=1, day=1, tzinfo=timezone.utc
- ) + timedelta(minutes=1)
+ before_ad = datetime(year=2015, month=1, day=1, tzinfo=UTC) + timedelta(
+ minutes=1
+ )
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, last_seen=before_ad)
assert "1 validation error for User" in str(cm.value)
@@ -549,8 +549,8 @@ class TestUserTiming:
def test_valid(self):
from generalresearch.models.thl.user import User
- created = datetime.now(tz=timezone.utc) - timedelta(minutes=60)
- last_seen = datetime.now(tz=timezone.utc) - timedelta(minutes=59)
+ created = datetime.now(tz=UTC) - timedelta(minutes=60)
+ last_seen = datetime.now(tz=UTC) - timedelta(minutes=59)
user = User(user_id=self.user_id, created=created, last_seen=last_seen)
assert user.created == created
@@ -559,8 +559,8 @@ class TestUserTiming:
def test_created_first(self):
from generalresearch.models.thl.user import User
- created = datetime.now(tz=timezone.utc) - timedelta(minutes=60)
- last_seen = datetime.now(tz=timezone.utc) - timedelta(minutes=59)
+ created = datetime.now(tz=UTC) - timedelta(minutes=60)
+ last_seen = datetime.now(tz=UTC) - timedelta(minutes=59)
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, created=last_seen, last_seen=created)
@@ -602,7 +602,7 @@ class TestUserSerialization:
user = User(
product_id=product_id,
product_user_id=product_user_id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
blocked=False,
)
@@ -623,7 +623,7 @@ class TestUserSerialization:
user = User(
product_id=product_id,
product_user_id=product_user_id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
blocked=False,
)
@@ -633,7 +633,7 @@ class TestUserSerialization:
assert not d.get("blocked")
assert d.get("product") is None
- assert d.get("created").tzinfo == timezone.utc
+ assert d.get("created").tzinfo == UTC
def test_from_json(self):
from generalresearch.models.thl.user import User
@@ -644,14 +644,14 @@ class TestUserSerialization:
user = User(
product_id=product_id,
product_user_id=product_user_id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
blocked=False,
)
u = User.model_validate_json(user.to_json())
assert u.product_id == product_id
assert u.product is None
- assert u.created.tzinfo == timezone.utc
+ assert u.created.tzinfo == UTC
class TestUserMethods:
diff --git a/tests/models/thl/test_user_iphistory.py b/tests/models/thl/test_user_iphistory.py
index 596849c..0f050b0 100644
--- a/tests/models/thl/test_user_iphistory.py
+++ b/tests/models/thl/test_user_iphistory.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from generalresearch.models.thl.user_iphistory import (
UserIPHistory,
@@ -8,7 +8,7 @@ from generalresearch.models.thl.user_iphistory import (
def test_collapse_ip_records():
# This does not exist in a db, so we do not need fixtures/ real user ids, whatever
- now = datetime.now(tz=timezone.utc) - timedelta(days=1)
+ now = datetime.now(tz=UTC) - timedelta(days=1)
# Gets stored most recent first. This is reversed, but the validator will order it
records = [
UserIPRecord(ip="1.2.3.5", created=now + timedelta(minutes=1)),
diff --git a/tests/models/thl/test_wall.py b/tests/models/thl/test_wall.py
index 8398c81..9e9483b 100644
--- a/tests/models/thl/test_wall.py
+++ b/tests/models/thl/test_wall.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from uuid import uuid4
@@ -27,8 +27,8 @@ class TestWall:
ext_status_code_1="1.0",
status=Status.FAIL,
status_code_1=StatusCode1.BUYER_FAIL,
- started=datetime(2023, 1, 1, 0, 0, 1, tzinfo=timezone.utc),
- finished=datetime(2023, 1, 1, 0, 10, 1, tzinfo=timezone.utc),
+ started=datetime(2023, 1, 1, 0, 0, 1, tzinfo=UTC),
+ finished=datetime(2023, 1, 1, 0, 10, 1, tzinfo=UTC),
)
s = w.to_json()
w2 = Wall.from_json(s)
@@ -45,8 +45,8 @@ class TestWall:
survey_id="yyy",
status=Status.FAIL,
status_code_1=StatusCode1.BUYER_FAIL,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
Wall(
user_id=1,
@@ -58,8 +58,8 @@ class TestWall:
status=Status.FAIL,
status_code_1=StatusCode1.MARKETPLACE_FAIL,
status_code_2=WallStatusCode2.COMPLETE_TOO_FAST,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
with pytest.raises(expected_exception=ValidationError) as e:
Wall(
@@ -71,8 +71,8 @@ class TestWall:
survey_id="yyy",
status=Status.FAIL,
status_code_1=StatusCode1.GRS_ABANDON,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
assert "If status is f, status_code_1 should be in" in str(e.value)
@@ -87,8 +87,8 @@ class TestWall:
status=Status.FAIL,
status_code_1=StatusCode1.GRS_ABANDON,
status_code_2=WallStatusCode2.COMPLETE_TOO_FAST,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
assert "If status is f, status_code_1 should be in" in str(e.value)
@@ -104,8 +104,8 @@ class TestWall:
status=Status.FAIL,
status_code_1=StatusCode1.MARKETPLACE_FAIL,
status_code_2=WallStatusCode2.COMPLETE_TOO_FAST,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
Wall(
user_id=1,
@@ -117,8 +117,8 @@ class TestWall:
status=Status.FAIL,
status_code_1=StatusCode1.BUYER_FAIL,
status_code_2=None,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
Wall(
user_id=1,
@@ -130,8 +130,8 @@ class TestWall:
status=Status.COMPLETE,
status_code_1=StatusCode1.COMPLETE,
status_code_2=None,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
with pytest.raises(expected_exception=ValidationError) as e:
@@ -145,8 +145,8 @@ class TestWall:
status=Status.FAIL,
status_code_1=StatusCode1.BUYER_FAIL,
status_code_2=WallStatusCode2.COMPLETE_TOO_FAST,
- started=datetime.now(timezone.utc),
- finished=datetime.now(timezone.utc) + timedelta(seconds=1),
+ started=datetime.now(UTC),
+ finished=datetime.now(UTC) + timedelta(seconds=1),
)
assert "If status_code_1 is 1, status_code_2 should be in" in str(e.value)
diff --git a/tests/models/thl/test_wall_session.py b/tests/models/thl/test_wall_session.py
index 1208c56..10f3cba 100644
--- a/tests/models/thl/test_wall_session.py
+++ b/tests/models/thl/test_wall_session.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
import pytest
@@ -12,7 +12,7 @@ from generalresearch.models.thl.user import User
class TestWallSession:
def test_session_with_no_wall_events(self):
- started = datetime(2023, 1, 1, tzinfo=timezone.utc)
+ started = datetime(2023, 1, 1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
assert s.status is None
assert s.status_code_1 is None
@@ -24,7 +24,7 @@ class TestWallSession:
# assert s.status_code_1 == StatusCode1.SESSION_START_FAIL
def test_session_timeout_with_only_grs(self):
- started = datetime(2023, 1, 1, tzinfo=timezone.utc)
+ started = datetime(2023, 1, 1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
w = Wall(
user_id=1,
@@ -53,7 +53,7 @@ class TestWallSession:
# assert s.status_code_1 == StatusCode1.GRS_FAIL
def test_session_with_only_grs_complete(self):
- started = datetime(year=2023, month=1, day=1, tzinfo=timezone.utc)
+ started = datetime(year=2023, month=1, day=1, tzinfo=UTC)
# A Session is started
s = Session(user=User(user_id=1), started=started)
@@ -98,7 +98,7 @@ class TestWallSession:
# assert s.status_code_1 is None
def test_session_with_only_non_grs_fail(self):
- started = datetime(year=2023, month=1, day=1, tzinfo=timezone.utc)
+ started = datetime(year=2023, month=1, day=1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
w = Wall(
@@ -119,7 +119,7 @@ class TestWallSession:
assert s.payout is None
def test_session_with_only_non_grs_timeout(self):
- started = datetime(year=2023, month=1, day=1, tzinfo=timezone.utc)
+ started = datetime(year=2023, month=1, day=1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
w = Wall(
@@ -139,7 +139,7 @@ class TestWallSession:
assert s.payout is None
def test_session_with_grs_and_external(self):
- started = datetime(year=2023, month=1, day=1, tzinfo=timezone.utc)
+ started = datetime(year=2023, month=1, day=1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
w = Wall(
@@ -168,7 +168,7 @@ class TestWallSession:
s.append_wall_event(w)
w.finish(
status=Status.ABANDON,
- finished=datetime.now(tz=timezone.utc) + timedelta(minutes=10),
+ finished=datetime.now(tz=UTC) + timedelta(minutes=10),
status_code_1=StatusCode1.BUYER_ABANDON,
)
status, status_code_1 = s.determine_session_status()
@@ -206,7 +206,7 @@ class TestWallSession:
assert s.payout is None
def test_session_marketplace_fail(self):
- started = datetime(2023, 1, 1, tzinfo=timezone.utc)
+ started = datetime(2023, 1, 1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
w = Wall(
@@ -229,7 +229,7 @@ class TestWallSession:
assert StatusCode1.SESSION_CONTINUE_QUALITY_FAIL == s.status_code_1
def test_session_unknown(self):
- started = datetime(2023, 1, 1, tzinfo=timezone.utc)
+ started = datetime(2023, 1, 1, tzinfo=UTC)
s = Session(user=User(user_id=1), started=started)
w = Wall(
diff --git a/tests/test_postgres.py b/tests/test_postgres.py
index 3b3ddd0..ed5a7ae 100644
--- a/tests/test_postgres.py
+++ b/tests/test_postgres.py
@@ -1,6 +1,6 @@
import socket
import subprocess
-from typing import Callable
+from collections.abc import Callable
from pydantic import PostgresDsn
@@ -12,7 +12,7 @@ def is_port_open(host: InternalHostname, port: int = 5432, timeout: int = 3):
try:
with socket.create_connection((host, port), timeout=timeout):
return True
- except (socket.timeout, ConnectionRefusedError, OSError):
+ except (TimeoutError, ConnectionRefusedError, OSError):
return False
--
cgit v1.2.3
From e2c5de703be45746bacaea4136f24440ff5a291c Mon Sep 17 00:00:00 2001
From: Max Nanis
Date: Mon, 24 Aug 2026 12:35:35 -0700
Subject: Ruff std replacements
---
generalresearch/__init__.py | 2 +-
generalresearch/config.py | 2 +-
generalresearch/grliq/managers/event_plotter.py | 4 +-
generalresearch/grliq/managers/forensic_data.py | 4 +-
generalresearch/grliq/managers/forensic_events.py | 76 ++++++++++------------
generalresearch/grliq/managers/forensic_results.py | 7 +-
generalresearch/grliq/models/custom_types.py | 3 +-
generalresearch/grliq/models/forensic_data.py | 1 -
generalresearch/grliq/models/forensic_summary.py | 3 +-
generalresearch/grliq/utils.py | 2 +-
generalresearch/grpc.py | 2 +-
generalresearch/incite/base.py | 10 +--
generalresearch/incite/collections/__init__.py | 18 ++---
generalresearch/incite/defaults.py | 2 +-
.../incite/mergers/foundations/__init__.py | 2 +-
.../incite/mergers/foundations/enriched_session.py | 10 +--
.../mergers/foundations/enriched_task_adjust.py | 5 +-
.../incite/mergers/foundations/enriched_wall.py | 8 +--
generalresearch/incite/mergers/ym_survey_wall.py | 10 ++-
generalresearch/incite/mergers/ym_wall_summary.py | 3 +-
generalresearch/incite/schemas/thl_web.py | 2 +-
generalresearch/locales/setup_json.py | 1 +
generalresearch/locales/timezone.py | 1 -
generalresearch/managers/cint/survey.py | 2 +-
generalresearch/managers/criteria.py | 4 +-
generalresearch/managers/dynata/survey.py | 2 +-
generalresearch/managers/events.py | 4 +-
generalresearch/managers/gr/authentication.py | 5 +-
generalresearch/managers/gr/team.py | 2 +-
generalresearch/managers/innovate/survey.py | 2 +-
generalresearch/managers/leaderboard/__init__.py | 3 +-
generalresearch/managers/leaderboard/manager.py | 2 +-
generalresearch/managers/morning/survey.py | 2 +-
generalresearch/managers/network/label.py | 9 ++-
generalresearch/managers/network/tool_run.py | 22 +++----
generalresearch/managers/precision/survey.py | 10 +--
generalresearch/managers/prodege/survey.py | 2 +-
generalresearch/managers/repdata/survey.py | 4 +-
generalresearch/managers/sago/survey.py | 2 +-
generalresearch/managers/spectrum/survey.py | 2 +-
generalresearch/managers/survey.py | 2 -
generalresearch/managers/thl/buyer.py | 2 +-
generalresearch/managers/thl/cashout_method.py | 2 +-
generalresearch/managers/thl/contest_manager.py | 3 +-
.../managers/thl/ledger_manager/conditions.py | 4 +-
.../managers/thl/ledger_manager/exceptions.py | 5 --
.../managers/thl/ledger_manager/ledger.py | 15 ++---
.../managers/thl/ledger_manager/thl_ledger.py | 22 +++----
generalresearch/managers/thl/product.py | 10 +--
generalresearch/managers/thl/profiling/question.py | 2 +-
generalresearch/managers/thl/profiling/uqa.py | 2 +-
generalresearch/managers/thl/profiling/user_upk.py | 2 +-
generalresearch/managers/thl/session.py | 11 +---
generalresearch/managers/thl/survey.py | 25 ++++---
generalresearch/managers/thl/task_adjustment.py | 7 +-
generalresearch/managers/thl/user_compensate.py | 2 +-
.../thl/user_manager/mysql_user_manager.py | 2 +-
.../managers/thl/user_manager/user_manager.py | 1 -
generalresearch/managers/thl/userhealth.py | 2 +-
generalresearch/managers/thl/wall.py | 2 +-
generalresearch/managers/thl/wallet/tango.py | 2 +-
generalresearch/models/admin/request.py | 2 +-
generalresearch/models/custom_types.py | 3 +-
generalresearch/models/dynata/survey.py | 4 +-
generalresearch/models/gr/authentication.py | 5 +-
generalresearch/models/gr/business.py | 6 +-
generalresearch/models/gr/team.py | 7 +-
generalresearch/models/legacy/questions.py | 3 -
generalresearch/models/network/mtr/execute.py | 2 +-
generalresearch/models/network/nmap/parser.py | 2 +-
generalresearch/models/network/rdns/execute.py | 2 +-
generalresearch/models/spectrum/survey.py | 2 +-
generalresearch/models/string_utils.py | 1 -
generalresearch/models/thl/contest/contest.py | 4 +-
.../models/thl/contest/contest_entry.py | 2 +-
generalresearch/models/thl/contest/examples.py | 7 --
generalresearch/models/thl/contest/io.py | 2 +-
generalresearch/models/thl/contest/leaderboard.py | 2 +-
generalresearch/models/thl/contest/milestone.py | 3 +-
generalresearch/models/thl/contest/raffle.py | 2 +-
generalresearch/models/thl/finance.py | 5 +-
generalresearch/models/thl/ipinfo.py | 2 +-
generalresearch/models/thl/ledger_example.py | 2 +-
generalresearch/models/thl/offerwall/cache.py | 2 +-
generalresearch/models/thl/payout_format.py | 12 ++--
generalresearch/models/thl/product.py | 2 -
.../models/thl/profiling/marketplace.py | 2 +-
.../models/thl/profiling/upk_question.py | 2 +-
.../models/thl/profiling/upk_question_answer.py | 2 +-
.../models/thl/profiling/user_question_answer.py | 2 +-
generalresearch/models/thl/session.py | 2 +-
generalresearch/models/thl/survey/__init__.py | 3 -
generalresearch/models/thl/survey/buyer.py | 2 +-
generalresearch/models/thl/survey/model.py | 2 +-
generalresearch/models/thl/survey/penalty.py | 2 +-
generalresearch/models/thl/task_adjustment.py | 2 +-
generalresearch/models/thl/user.py | 2 +-
generalresearch/models/thl/user_iphistory.py | 3 +-
generalresearch/models/thl/wallet/payout.py | 2 +-
generalresearch/pg_helper.py | 12 ++--
generalresearch/schemas/survey_stats.py | 2 +-
generalresearch/sql_helper.py | 19 ++----
generalresearch/thl_django/apps.py | 14 ++--
generalresearch/thl_django/fields.py | 3 +-
.../thl_django/migrations/0001_initial.py | 3 +-
..._live_alter_surveycategory_strength_and_more.py | 2 +-
...rveystat_surveystat_live_survey_idx_and_more.py | 2 +-
...ssion_thl_session_status_d578b7_idx_and_more.py | 2 +-
...p_portscanport_iplabel_mtr_portscan_and_more.py | 5 +-
generalresearch/thl_django/network/models.py | 5 +-
generalresearch/utils/enum.py | 4 +-
generalresearch/wall_status_codes/lucid.py | 2 +-
generalresearch/wall_status_codes/morning.py | 2 +-
generalresearch/wall_status_codes/pollfish.py | 2 +-
generalresearch/wall_status_codes/precision.py | 2 +-
generalresearch/wall_status_codes/repdata.py | 2 +-
test_utils/conftest.py | 3 +-
test_utils/grliq/conftest.py | 2 +-
test_utils/incite/conftest.py | 2 +-
test_utils/managers/conftest.py | 2 -
test_utils/models/conftest.py | 9 +--
test_utils/models/contest/conftest.py | 2 +-
test_utils/models/network/conftest.py | 2 +-
test_utils/models/thl/conftest.py | 2 +-
test_utils/spectrum/conftest.py | 2 +-
.../incite/collections/test_df_collection_base.py | 3 +-
.../collections/test_df_collection_item_base.py | 2 +-
.../collections/test_df_collection_item_thl_web.py | 11 +---
.../test_df_collection_thl_marketplaces.py | 7 +-
.../collections/test_df_collection_thl_web.py | 2 -
.../mergers/foundations/test_enriched_session.py | 7 +-
.../foundations/test_enriched_task_adjust.py | 7 --
.../mergers/foundations/test_enriched_wall.py | 23 +------
.../mergers/foundations/test_user_id_product.py | 15 +----
tests/incite/mergers/test_merge_collection.py | 3 +-
tests/incite/mergers/test_merge_collection_item.py | 9 +--
tests/incite/mergers/test_pop_ledger.py | 8 +--
tests/incite/mergers/test_ym_survey_merge.py | 17 +----
tests/incite/test_collection_base.py | 3 +-
tests/incite/test_collection_base_item.py | 2 +-
tests/incite/test_grl_flow.py | 11 ++--
tests/incite/test_interval_idx.py | 3 +-
tests/managers/gr/test_authentication.py | 3 -
tests/managers/gr/test_business.py | 4 +-
tests/managers/gr/test_team.py | 2 -
tests/managers/leaderboard.py | 2 +-
tests/managers/network/test_label.py | 2 +-
tests/managers/test_events.py | 15 ++---
tests/managers/test_userpid.py | 4 +-
.../managers/thl/test_contest/test_leaderboard.py | 8 +--
tests/managers/thl/test_contest/test_milestone.py | 14 +---
tests/managers/thl/test_contest/test_raffle.py | 14 +---
tests/managers/thl/test_harmonized_uqa.py | 2 +-
tests/managers/thl/test_ipinfo.py | 2 +-
tests/managers/thl/test_ledger/test_lm_accounts.py | 6 --
tests/managers/thl/test_ledger/test_lm_tx_locks.py | 23 ++-----
.../thl/test_ledger/test_thl_lm_accounts.py | 32 ++++-----
.../thl/test_ledger/test_thl_lm_bp_payout.py | 10 +--
tests/managers/thl/test_ledger/test_thl_lm_tx.py | 64 +++---------------
.../test_ledger/test_thl_lm_tx__user_payouts.py | 3 +-
tests/managers/thl/test_ledger/test_thl_pem.py | 7 +-
tests/managers/thl/test_ledger/test_user_txs.py | 3 +-
tests/managers/thl/test_ledger/test_wallet.py | 2 +-
tests/managers/thl/test_product.py | 9 ++-
tests/managers/thl/test_product_prod.py | 2 -
tests/managers/thl/test_profiling/test_user_upk.py | 2 +-
tests/managers/thl/test_session_manager.py | 7 +-
tests/managers/thl/test_survey.py | 2 +-
tests/managers/thl/test_survey_penalty.py | 1 -
tests/managers/thl/test_task_adjustment.py | 2 +-
tests/managers/thl/test_task_status.py | 2 +-
tests/managers/thl/test_user_manager/test_base.py | 4 +-
tests/managers/thl/test_user_manager/test_mysql.py | 1 -
.../thl/test_user_manager/test_user_fetch.py | 1 -
.../thl/test_user_manager/test_user_metadata.py | 1 -
tests/managers/thl/test_user_streak.py | 2 +-
tests/managers/thl/test_userhealth.py | 2 +-
tests/managers/thl/test_wall_manager.py | 13 ++--
tests/models/admin/test_report_request.py | 2 +-
tests/models/custom_types/test_aware_datetime.py | 2 +-
tests/models/custom_types/test_dsn.py | 1 -
tests/models/dynata/test_eligbility.py | 2 +-
tests/models/gr/test_authentication.py | 2 +-
tests/models/gr/test_business.py | 3 +-
tests/models/innovate/test_question.py | 6 +-
.../models/legacy/test_user_question_answer_in.py | 4 +-
tests/models/morning/test.py | 2 +-
tests/models/network/test_mtr.py | 4 +-
tests/models/network/test_nmap_parser.py | 1 +
tests/models/prodege/test_survey_participation.py | 2 +-
tests/models/spectrum/test_question.py | 2 +-
tests/models/spectrum/test_survey.py | 2 +-
tests/models/spectrum/test_survey_manager.py | 2 +-
tests/models/test_finance.py | 2 +-
tests/models/thl/question/test_question_info.py | 2 +-
tests/models/thl/test_adjustments.py | 30 ++-------
.../thl/test_contest/test_leaderboard_contest.py | 2 +-
tests/models/thl/test_ledger.py | 2 +-
tests/models/thl/test_payout.py | 5 +-
tests/models/thl/test_product.py | 2 +-
tests/models/thl/test_upkquestion.py | 12 +---
tests/models/thl/test_user.py | 6 +-
tests/models/thl/test_user_iphistory.py | 2 +-
tests/models/thl/test_user_streak.py | 2 +-
tests/models/thl/test_wall.py | 2 +-
tests/models/thl/test_wall_session.py | 2 +-
tests/sql_helper.py | 4 +-
207 files changed, 398 insertions(+), 725 deletions(-)
(limited to 'test_utils/managers')
diff --git a/generalresearch/__init__.py b/generalresearch/__init__.py
index 604b7e2..3b2ec3d 100644
--- a/generalresearch/__init__.py
+++ b/generalresearch/__init__.py
@@ -129,7 +129,7 @@ def synchronized(wrapped):
if lock is None:
lock = threading.RLock()
- setattr(context, "_synchronized_lock", lock)
+ context._synchronized_lock = lock
return lock
diff --git a/generalresearch/config.py b/generalresearch/config.py
index 76e3995..c6f41e8 100644
--- a/generalresearch/config.py
+++ b/generalresearch/config.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import os
-from datetime import UTC, datetime, timezone
+from datetime import UTC, datetime
from pathlib import Path
from pydantic import DirectoryPath, Field, MariaDBDsn, PostgresDsn, RedisDsn
diff --git a/generalresearch/grliq/managers/event_plotter.py b/generalresearch/grliq/managers/event_plotter.py
index 0bba7c5..94b70ef 100644
--- a/generalresearch/grliq/managers/event_plotter.py
+++ b/generalresearch/grliq/managers/event_plotter.py
@@ -13,7 +13,7 @@ def make_events_svg(
mouse_events: list[MouseEvent], keyboard_events: list[KeyboardEvent]
) -> str:
if len(mouse_events) + len(keyboard_events) == 0:
- return f'"
+ return '"
t = np.array([pm.timeStamp for pm in mouse_events])
t_diff = t.max() - t.min()
@@ -88,7 +88,7 @@ def make_events_svg(
svg_elements.append(svg_multiline_text(text, cx + 5, cy - 5, font_size))
svg = (
- f'