iwa 0.1.3__py3-none-any.whl → 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,204 @@
1
+ """Tests for wallet injection in web dependencies."""
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+
6
+ class TestWalletInjection:
7
+ """Tests for get_wallet, set_wallet, and _WalletProxy."""
8
+
9
+ def setup_method(self):
10
+ """Reset the global wallet state before each test."""
11
+ # Import fresh to reset state
12
+ import iwa.web.dependencies as deps
13
+
14
+ deps._wallet = None
15
+
16
+ def test_get_wallet_lazy_initialization(self):
17
+ """get_wallet() creates a Wallet on first call if none injected."""
18
+ import iwa.web.dependencies as deps
19
+
20
+ deps._wallet = None
21
+
22
+ with patch.object(deps, "Wallet") as mock_wallet_cls:
23
+ mock_wallet_cls.return_value = MagicMock(name="LazyWallet")
24
+
25
+ result = deps.get_wallet()
26
+
27
+ mock_wallet_cls.assert_called_once()
28
+ assert result == mock_wallet_cls.return_value
29
+
30
+ def test_get_wallet_returns_same_instance(self):
31
+ """get_wallet() returns the same instance on subsequent calls."""
32
+ import iwa.web.dependencies as deps
33
+
34
+ deps._wallet = None
35
+
36
+ with patch.object(deps, "Wallet") as mock_wallet_cls:
37
+ mock_wallet_cls.return_value = MagicMock(name="SingletonWallet")
38
+
39
+ first = deps.get_wallet()
40
+ second = deps.get_wallet()
41
+
42
+ # Should only create once
43
+ mock_wallet_cls.assert_called_once()
44
+ assert first is second
45
+
46
+ def test_set_wallet_injects_external_wallet(self):
47
+ """set_wallet() allows injecting an external wallet instance."""
48
+ import iwa.web.dependencies as deps
49
+
50
+ deps._wallet = None
51
+
52
+ external_wallet = MagicMock(name="ExternalWallet")
53
+ deps.set_wallet(external_wallet)
54
+
55
+ result = deps.get_wallet()
56
+
57
+ assert result is external_wallet
58
+
59
+ def test_set_wallet_prevents_lazy_init(self):
60
+ """set_wallet() prevents Wallet() from being called."""
61
+ import iwa.web.dependencies as deps
62
+
63
+ deps._wallet = None
64
+
65
+ with patch.object(deps, "Wallet") as mock_wallet_cls:
66
+ external_wallet = MagicMock(name="InjectedWallet")
67
+ deps.set_wallet(external_wallet)
68
+
69
+ result = deps.get_wallet()
70
+
71
+ # Wallet() should NOT be called
72
+ mock_wallet_cls.assert_not_called()
73
+ assert result is external_wallet
74
+
75
+ def test_set_wallet_overrides_existing(self):
76
+ """set_wallet() can override a previously set wallet."""
77
+ import iwa.web.dependencies as deps
78
+
79
+ deps._wallet = None
80
+
81
+ wallet1 = MagicMock(name="Wallet1")
82
+ wallet2 = MagicMock(name="Wallet2")
83
+
84
+ deps.set_wallet(wallet1)
85
+ assert deps.get_wallet() is wallet1
86
+
87
+ deps.set_wallet(wallet2)
88
+ assert deps.get_wallet() is wallet2
89
+
90
+
91
+ class TestWalletProxy:
92
+ """Tests for _WalletProxy backwards compatibility."""
93
+
94
+ def setup_method(self):
95
+ """Reset the global wallet state before each test."""
96
+ import iwa.web.dependencies as deps
97
+
98
+ deps._wallet = None
99
+
100
+ def test_wallet_proxy_forwards_attribute_access(self):
101
+ """wallet.attribute forwards to get_wallet().attribute."""
102
+ import iwa.web.dependencies as deps
103
+
104
+ deps._wallet = None
105
+
106
+ mock_wallet = MagicMock()
107
+ mock_wallet.balance_service = MagicMock(name="BalanceService")
108
+ deps.set_wallet(mock_wallet)
109
+
110
+ # Access through the proxy
111
+ result = deps.wallet.balance_service
112
+
113
+ assert result is mock_wallet.balance_service
114
+
115
+ def test_wallet_proxy_forwards_method_calls(self):
116
+ """wallet.method() forwards to get_wallet().method()."""
117
+ import iwa.web.dependencies as deps
118
+
119
+ deps._wallet = None
120
+
121
+ mock_wallet = MagicMock()
122
+ mock_wallet.get_accounts_balances.return_value = ({"0x1": {}}, {"0x1": {}})
123
+ deps.set_wallet(mock_wallet)
124
+
125
+ # Call method through proxy
126
+ result = deps.wallet.get_accounts_balances("gnosis", ["native"])
127
+
128
+ mock_wallet.get_accounts_balances.assert_called_once_with("gnosis", ["native"])
129
+ assert result == ({"0x1": {}}, {"0x1": {}})
130
+
131
+ def test_wallet_proxy_triggers_lazy_init(self):
132
+ """Accessing wallet.attr when no wallet set triggers lazy init."""
133
+ import iwa.web.dependencies as deps
134
+
135
+ deps._wallet = None
136
+
137
+ with patch.object(deps, "Wallet") as mock_wallet_cls:
138
+ mock_instance = MagicMock()
139
+ mock_instance.key_storage = MagicMock(name="KeyStorage")
140
+ mock_wallet_cls.return_value = mock_instance
141
+
142
+ # Access through proxy should trigger lazy init
143
+ result = deps.wallet.key_storage
144
+
145
+ mock_wallet_cls.assert_called_once()
146
+ assert result is mock_instance.key_storage
147
+
148
+
149
+ class TestIntegrationWithRouters:
150
+ """Integration tests for wallet injection with routers."""
151
+
152
+ def setup_method(self):
153
+ """Reset the global wallet state before each test."""
154
+ import iwa.web.dependencies as deps
155
+
156
+ deps._wallet = None
157
+
158
+ def test_injected_wallet_used_by_routers(self):
159
+ """Routers using 'wallet' get the injected instance."""
160
+ import iwa.web.dependencies as deps
161
+
162
+ # Inject a mock wallet BEFORE routers access it
163
+ mock_wallet = MagicMock()
164
+ mock_wallet.key_storage = MagicMock()
165
+ mock_wallet.key_storage.accounts = {}
166
+ deps.set_wallet(mock_wallet)
167
+
168
+ # Simulate what a router does
169
+ from iwa.web.dependencies import wallet
170
+
171
+ # Access through the module-level wallet (proxy)
172
+ accounts = wallet.key_storage.accounts
173
+
174
+ assert accounts == {}
175
+ # Verify it's using our injected wallet
176
+ assert deps.get_wallet() is mock_wallet
177
+
178
+
179
+ class TestServerAsync:
180
+ """Tests for run_server_async function."""
181
+
182
+ def test_run_server_async_source_has_localhost_default(self):
183
+ """run_server_async defaults to localhost for security (source check)."""
184
+ import pathlib
185
+
186
+ # Read the source file directly to verify default
187
+ server_path = pathlib.Path(__file__).parent.parent / "server.py"
188
+ source = server_path.read_text()
189
+
190
+ # Verify the function signature has localhost default
191
+ assert 'async def run_server_async(host: str = "127.0.0.1"' in source
192
+
193
+ def test_run_server_source_has_async_function(self):
194
+ """run_server_async function exists in server.py source."""
195
+ import pathlib
196
+
197
+ server_path = pathlib.Path(__file__).parent.parent / "server.py"
198
+ source = server_path.read_text()
199
+
200
+ # Verify the async function exists
201
+ assert "async def run_server_async" in source
202
+ assert "uvicorn.Config" in source
203
+ assert "uvicorn.Server" in source
204
+ assert "await server.serve()" in source
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.1.3
3
+ Version: 0.1.6
4
4
  Summary: A secure, modular, and plugin-based framework for crypto agents and ops
5
5
  Requires-Python: <4.0,>=3.12
6
6
  Description-Content-Type: text/markdown
@@ -92,11 +92,11 @@ iwa/plugins/olas/contracts/abis/staking_token.json,sha256=cuUOmi1s4Z6VSIX0an_IxK
92
92
  iwa/plugins/olas/scripts/test_full_mech_flow.py,sha256=Fqoq5bn7Z_3YyRrnuqNAZy9cwQDLiXP6Vf3EIeWPo2I,9024
93
93
  iwa/plugins/olas/scripts/test_simple_lifecycle.py,sha256=8T50tOZx3afeECSfCNAb0rAHNtYOsBaeXlMwKXElCk8,2099
94
94
  iwa/plugins/olas/service_manager/__init__.py,sha256=GXiThMEY3nPgHUl1i-DLrF4h96z9jPxxI8Jepo2E1PM,1926
95
- iwa/plugins/olas/service_manager/base.py,sha256=EBPg0ymqgtAb7ZvVSfTt31QYgv_6gp4UAc6je00NLAg,5009
96
- iwa/plugins/olas/service_manager/drain.py,sha256=tJLqvMEPOymxukFuxt-AdgOB4bIIciKcXoxOPx9j-LM,13983
97
- iwa/plugins/olas/service_manager/lifecycle.py,sha256=Jz2WTsBE_kGjFnsnpQlUBmMM2csOuqEfYdvj4cLrNuU,50586
95
+ iwa/plugins/olas/service_manager/base.py,sha256=1a5qzG02mCYoUFxNRUVRf6HZ-HuUuXatQGJesqr14vQ,5736
96
+ iwa/plugins/olas/service_manager/drain.py,sha256=67BRhIPjaCDqS4kUI7yVYCMAHjmvAk96hjuNLNJ35Zc,14480
97
+ iwa/plugins/olas/service_manager/lifecycle.py,sha256=1RRlRl0bZhcdQ53SS7TVpUQL75JJcwhpjWD1pgfwW1g,50995
98
98
  iwa/plugins/olas/service_manager/mech.py,sha256=NVzVbEmyOe3wK92VEzCCOSuy3HDkEP1MSoVt7Av8Psk,27949
99
- iwa/plugins/olas/service_manager/staking.py,sha256=Vl7NGzxfNhlajec1kUvqODiq-DBXyd86at5jKrwHDuc,29808
99
+ iwa/plugins/olas/service_manager/staking.py,sha256=qhZB5yM4YMJulfmFoX6zTAukbZxBw8xtcik7bu8dGjE,31264
100
100
  iwa/plugins/olas/tests/conftest.py,sha256=4vM7EI00SrTGyeP0hNzsGSQHEj2-iznVgzlNh2_OGfo,739
101
101
  iwa/plugins/olas/tests/test_importer.py,sha256=i9LKov7kNRECB3hmRnhKBwcfx3uxtjWe4BB77bOOpeo,4282
102
102
  iwa/plugins/olas/tests/test_importer_error_handling.py,sha256=GeXu4Par3_FAUL9hT6Sn5PdRg2_EU2gf3iaL73atoYo,12256
@@ -112,12 +112,12 @@ iwa/plugins/olas/tests/test_plugin.py,sha256=RVgU-Cq6t_3mOh90xFAGwlJOV7ZIgp0VNaK
112
112
  iwa/plugins/olas/tests/test_plugin_full.py,sha256=55EBa07JhJLVG3IMi6QKlR_ivWLYCdLQTySP66qbEXo,8584
113
113
  iwa/plugins/olas/tests/test_service_lifecycle.py,sha256=sOCtpz8T9s55AZe9AoqP1h3XrXw5NDSjDqwLgYThvU4,5559
114
114
  iwa/plugins/olas/tests/test_service_manager.py,sha256=_mFRptssimITHhjvZA5jUPU2bInUIPCKll5wlj9elcA,40905
115
- iwa/plugins/olas/tests/test_service_manager_errors.py,sha256=-qpLmU4Uiqqtre59L2wXpO4WPMs4ej_K_gAL3naEvRg,8554
115
+ iwa/plugins/olas/tests/test_service_manager_errors.py,sha256=1rgM-gUrpo0y3IHMVhsiAC2JMRH5YrOpzRqTP5NPwfg,8608
116
116
  iwa/plugins/olas/tests/test_service_manager_flows.py,sha256=ZSmBJNa18d_MyAaLQRoPpfFYRwzmk9k-5AhSAGd7WeI,20737
117
117
  iwa/plugins/olas/tests/test_service_manager_mech.py,sha256=qG6qu5IPRNypXUsblU2OEkuiuwDJ0TH8RXZbibmTFcQ,4937
118
118
  iwa/plugins/olas/tests/test_service_manager_rewards.py,sha256=2YCrXBU5bEkPuhBoGBhjnO1nA2qwHxn5Ivrror18FHM,12248
119
119
  iwa/plugins/olas/tests/test_service_manager_validation.py,sha256=ajlfH5uc4mAHf8A7GLE5cW7X8utM2vUilM0JdGDdlVg,5382
120
- iwa/plugins/olas/tests/test_service_staking.py,sha256=exxWsile_wG_0rz_cGbCPG-_Ubq01Ofl4D_pi0plj5Y,18332
120
+ iwa/plugins/olas/tests/test_service_staking.py,sha256=BZW0bpBmekP2tkD64K-DM9Xd2jATrF6QcY7byjDQf0U,18350
121
121
  iwa/plugins/olas/tests/test_staking_integration.py,sha256=q7zLQLrUyhtcnZf6MMymx2cX0Gmqaa7i1mRh1clnyj4,30198
122
122
  iwa/plugins/olas/tests/test_staking_validation.py,sha256=uug64jFcXYJ3Nw_lNa3O4fnhNr5wAWHHIrchSbR2MVE,4020
123
123
  iwa/plugins/olas/tui/__init__.py,sha256=5ZRsbC7J3z1xfkZRiwr4bLEklf78rNVjdswe2p7SlS8,28
@@ -146,10 +146,11 @@ iwa/tui/tests/test_wallets_refactor.py,sha256=71G3HLbhTtgDy3ffVbYv0MFYRgdYd-NWGB
146
146
  iwa/tui/tests/test_widgets.py,sha256=C9UgIGeWRaQ459JygFEQx-7hOi9mWrSUDDIMZH1ge50,3994
147
147
  iwa/tui/widgets/__init__.py,sha256=UzD6nJbwv9hOtkWl9I7faXm1a-rcu4xFRxrf4KBwwY4,161
148
148
  iwa/tui/widgets/base.py,sha256=Z8FigMhsfD76PkFVERqMaotd-xwXfuFZm_8TmCMOsl4,3381
149
- iwa/web/dependencies.py,sha256=0_dAJlRh6gKrUDRPKUe92eshFsg572yx_H0lQgSqGDA,2103
149
+ iwa/web/cache.py,sha256=cRrt0uy2bbSL3qBXzZqx3u3S6rRYCduy9FqpfNnzgTI,4149
150
+ iwa/web/dependencies.py,sha256=iTvdCSuETFLeQPtFydi21s1EKA_a80rbA57s-994fMQ,2980
150
151
  iwa/web/models.py,sha256=MSD9WPy_Nz_amWgoo2KSDTn4ZLv_AV0o0amuNtSf-68,3035
151
- iwa/web/server.py,sha256=4ZLVFEKoGs_NoCcXMeyYzDNdxUXazjwHQaX7CR1pwHE,5239
152
- iwa/web/routers/accounts.py,sha256=VhCHrwzRWqZcSW-tTEqFWT5hFl-IYEWpqXeuN8xM3-4,3922
152
+ iwa/web/server.py,sha256=kqQrZhuc3sr_CBnC6xdyeFUu-2QKGCIbWul-sdjJ5xM,5787
153
+ iwa/web/routers/accounts.py,sha256=zCkRDCIfL6PjVNtEmsU2GSL5Hmk8abebugisShgHoCU,4894
153
154
  iwa/web/routers/state.py,sha256=wsBAOIWZeMWjMwLiiWVhuEXHAceI0IIq6CPpmh7SbIc,2469
154
155
  iwa/web/routers/swap.py,sha256=8xycAytquR29ELxW3vx428W8s9bI_w_x2kpRhhJ0KXY,22630
155
156
  iwa/web/routers/transactions.py,sha256=bRjfD7zcuX3orVIHzOMVsIkEtcE_pM_KCom4cdAKV6Q,5602
@@ -157,16 +158,18 @@ iwa/web/routers/olas/__init__.py,sha256=Jo6Dm1e8fHafCD800fbxsxeFz3tvuEEKXEf5-9tj
157
158
  iwa/web/routers/olas/admin.py,sha256=PMRdNelqYgQ1xbqh3floFV5xrVtBRQiwZPd8J9_ffxg,5785
158
159
  iwa/web/routers/olas/funding.py,sha256=f8fADNtbZEBFl-vuVKfas6os38Vot6K5tJBTenZmCD0,4832
159
160
  iwa/web/routers/olas/general.py,sha256=dPsBQppTGoQY1RztliUhseOHOZGeeCR10lhThD9kyXo,803
160
- iwa/web/routers/olas/services.py,sha256=jDbxLUJBN48vs2-fXrIpxhPSM6quqYxggmMOkUVEIaI,18200
161
- iwa/web/routers/olas/staking.py,sha256=jktJ2C1Q9X4aC0tWJByN3sHpEXY0EIvr3rr4N0MtXXc,14081
161
+ iwa/web/routers/olas/services.py,sha256=cKMjy7jExgu_X7idVF--l4o_sYc3ve-aNs0aONFHFcQ,19883
162
+ iwa/web/routers/olas/staking.py,sha256=RCoYCzIfVuhjUckfbC_eZLKEYTw1VToaU6jMWPN-6MI,14369
162
163
  iwa/web/static/app.js,sha256=VCm9zPJERb9pX6zbFQ_7D47UnztGdibrkZ1dmwhsvdc,114949
163
164
  iwa/web/static/index.html,sha256=Qg06MFK__2KxwWTr8hhjX_GwsoN53QsLCTypu4fBR-Q,28516
164
165
  iwa/web/static/style.css,sha256=7i6T96pS7gXSLDZfyp_87gRlyB9rpsFWJEHJ-dRY1ug,24371
166
+ iwa/web/tests/test_response_cache.py,sha256=o1s4shq4N72xjMBawx_mhnqDTY1GbNy6FTgulY2nvM4,25435
167
+ iwa/web/tests/test_wallet_injection.py,sha256=YjoQh1FMwroswF6O_XZOwYXzanv-JYElNTDNKxAS77g,6751
165
168
  iwa/web/tests/test_web_endpoints.py,sha256=vA25YghHNB23sbmhD4ciesn_f_okSq0tjlkrSiKZ0rs,24007
166
169
  iwa/web/tests/test_web_olas.py,sha256=GunKEAzcbzL7FoUGMtEl8wqiqwYwA5lB9sOhfCNj0TA,16312
167
170
  iwa/web/tests/test_web_swap.py,sha256=7A4gBJFL01kIXPtW1E1J17SCsVc_0DmUn-R8kKrnnVA,2974
168
171
  iwa/web/tests/test_web_swap_coverage.py,sha256=zGNrzlhZ_vWDCvWmLcoUwFgqxnrp_ACbo49AtWBS_Kw,5584
169
- iwa-0.1.3.dist-info/licenses/LICENSE,sha256=eIubm_IlBHPYRQlLNZKbBNKhJUUP3JH0A2miZUhAVfI,1078
172
+ iwa-0.1.6.dist-info/licenses/LICENSE,sha256=eIubm_IlBHPYRQlLNZKbBNKhJUUP3JH0A2miZUhAVfI,1078
170
173
  tests/legacy_cow.py,sha256=oOkZvIxL70ReEoD9oHQbOD5GpjIr6AGNHcOCgfPlerU,8389
171
174
  tests/legacy_safe.py,sha256=AssM2g13E74dNGODu_H0Q0y412lgqsrYnEzI97nm_Ts,2972
172
175
  tests/legacy_transaction_retry_logic.py,sha256=D9RqZ7DBu61Xr2djBAodU2p9UE939LL-DnQXswX5iQk,1497
@@ -224,8 +227,8 @@ tests/test_utils.py,sha256=vkP49rYNI8BRzLpWR3WnKdDr8upeZjZcs7Rx0pjbQMo,1292
224
227
  tests/test_workers.py,sha256=MInwdkFY5LdmFB3o1odIaSD7AQZb3263hNafO1De5PE,2793
225
228
  tools/create_and_stake_service.py,sha256=1xwy_bJQI1j9yIQ968Oc9Db_F6mk1659LuuZntTASDE,3742
226
229
  tools/verify_drain.py,sha256=PkMjblyOOAuQge88FwfEzRtCYeEtJxXhPBmtQYCoQ-8,6743
227
- iwa-0.1.3.dist-info/METADATA,sha256=uKemLrcWBfz_raFNxn3okTiQWiwF-lLQok838PpZXtI,7336
228
- iwa-0.1.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
229
- iwa-0.1.3.dist-info/entry_points.txt,sha256=nwB6kscrfA7M00pYmL2j-sBH6eF6h2ga9IK1BZxdiyQ,241
230
- iwa-0.1.3.dist-info/top_level.txt,sha256=kedS9cRUbm4JE2wYeabIXilhHjN8KCw0IGbqqqsw0Bs,16
231
- iwa-0.1.3.dist-info/RECORD,,
230
+ iwa-0.1.6.dist-info/METADATA,sha256=KUGGOVmGvGxhLDLF4tbDcu73WjStPOe_FCRiOqmf-nI,7336
231
+ iwa-0.1.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
232
+ iwa-0.1.6.dist-info/entry_points.txt,sha256=nwB6kscrfA7M00pYmL2j-sBH6eF6h2ga9IK1BZxdiyQ,241
233
+ iwa-0.1.6.dist-info/top_level.txt,sha256=kedS9cRUbm4JE2wYeabIXilhHjN8KCw0IGbqqqsw0Bs,16
234
+ iwa-0.1.6.dist-info/RECORD,,
File without changes