kuhl-haus-mdp 0.1.5__tar.gz → 0.1.6__tar.gz
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.
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/PKG-INFO +2 -2
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/README.md +1 -1
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/pyproject.toml +1 -1
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/analyzers/analyzer.py +5 -4
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/analyzers/top_stocks.py +8 -9
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/market_data_scanner.py +21 -5
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/analyzers/test_top_stocks_rehydrate.py +18 -9
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/components/test_market_data_scanner.py +8 -18
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/LICENSE.txt +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/analyzers/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/analyzers/massive_data_analyzer.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/market_data_cache.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/widget_data_service.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/helpers/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/helpers/process_manager.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/helpers/queue_name_resolver.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/helpers/utils.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/massive_data_listener.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/massive_data_processor.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/massive_data_queues.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/web_socket_message_serde.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_analyzer_result.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_cache_keys.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_cache_ttl.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_pubsub_keys.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_scanner_names.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/massive_data_queue.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/top_stocks_cache_item.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/analyzers/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/analyzers/test_massive_data_analyzer.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/components/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/components/test_market_data_cache.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/components/test_widget_data_service.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/helpers/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/helpers/test_process_manager.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/helpers/test_queue_name_resolver.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/helpers/test_utils.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/integ/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/integ/test_web_socket_message_serde.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/models/__init__.py +0 -0
- {kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/tests/models/test_top_stocks_cache_item.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kuhl-haus-mdp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Market data processing pipeline for stock market scanner
|
|
5
5
|
Author-Email: Tom Pounders <git@oldschool.engineer>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -68,7 +68,7 @@ Description-Content-Type: text/markdown
|
|
|
68
68
|
[](https://codecov.io/gh/kuhl-haus/kuhl-haus-mdp)
|
|
69
69
|
[](https://github.com/kuhl-haus/kuhl-haus-mdp/issues)
|
|
70
70
|
[](https://github.com/kuhl-haus/kuhl-haus-mdp/pulls)
|
|
71
|
-
|
|
71
|
+
[](https://kuhl-haus-mdp.readthedocs.io/en/latest/)
|
|
72
72
|
|
|
73
73
|
# kuhl-haus-mdp
|
|
74
74
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
[](https://codecov.io/gh/kuhl-haus/kuhl-haus-mdp)
|
|
16
16
|
[](https://github.com/kuhl-haus/kuhl-haus-mdp/issues)
|
|
17
17
|
[](https://github.com/kuhl-haus/kuhl-haus-mdp/pulls)
|
|
18
|
-
|
|
18
|
+
[](https://kuhl-haus-mdp.readthedocs.io/en/latest/)
|
|
19
19
|
|
|
20
20
|
# kuhl-haus-mdp
|
|
21
21
|
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from typing import Optional, List
|
|
2
2
|
from kuhl_haus.mdp.models.market_data_analyzer_result import MarketDataAnalyzerResult
|
|
3
|
+
from kuhl_haus.mdp.components.market_data_cache import MarketDataCache
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class Analyzer:
|
|
6
|
-
|
|
7
|
+
cache: MarketDataCache
|
|
7
8
|
|
|
8
|
-
def __init__(self,
|
|
9
|
-
self.
|
|
9
|
+
def __init__(self, cache: MarketDataCache, **kwargs):
|
|
10
|
+
self.cache = cache
|
|
10
11
|
|
|
11
|
-
async def rehydrate(self
|
|
12
|
+
async def rehydrate(self):
|
|
12
13
|
pass
|
|
13
14
|
|
|
14
15
|
async def analyze_data(self, data: dict) -> Optional[List[MarketDataAnalyzerResult]]:
|
|
@@ -26,21 +26,15 @@ from kuhl_haus.mdp.models.top_stocks_cache_item import TopStocksCacheItem
|
|
|
26
26
|
class TopStocksAnalyzer(Analyzer):
|
|
27
27
|
|
|
28
28
|
def __init__(self, cache: MarketDataCache, **kwargs):
|
|
29
|
-
|
|
30
|
-
kwargs["cache_key"] = MarketDataCacheKeys.TOP_STOCKS_SCANNER.value
|
|
31
|
-
super().__init__(**kwargs)
|
|
29
|
+
super().__init__(cache=cache, **kwargs)
|
|
32
30
|
self.cache = cache
|
|
31
|
+
self.cache_key = MarketDataCacheKeys.TOP_STOCKS_SCANNER.value
|
|
33
32
|
self.logger = logging.getLogger(__name__)
|
|
34
33
|
self.cache_item = TopStocksCacheItem()
|
|
35
34
|
self.last_update_time = 0
|
|
36
35
|
self.pre_market_reset = False
|
|
37
36
|
|
|
38
|
-
async def rehydrate(self
|
|
39
|
-
if not data:
|
|
40
|
-
self.cache_item = TopStocksCacheItem()
|
|
41
|
-
self.logger.info("No data to rehydrate TopStocksCacheItem.")
|
|
42
|
-
return
|
|
43
|
-
|
|
37
|
+
async def rehydrate(self):
|
|
44
38
|
# Get current time in UTC, then convert to Eastern Time
|
|
45
39
|
utc_now = datetime.now(timezone.utc)
|
|
46
40
|
et_now = utc_now.astimezone(ZoneInfo("America/New_York"))
|
|
@@ -52,6 +46,11 @@ class TopStocksAnalyzer(Analyzer):
|
|
|
52
46
|
self.cache_item = TopStocksCacheItem()
|
|
53
47
|
self.logger.info(f"Outside market hours ({et_now.strftime('%H:%M:%S %Z')}), clearing cache.")
|
|
54
48
|
return
|
|
49
|
+
data = await self.cache.get_cache(self.cache_key)
|
|
50
|
+
if not data:
|
|
51
|
+
self.cache_item = TopStocksCacheItem()
|
|
52
|
+
self.logger.info("No data to rehydrate TopStocksCacheItem.")
|
|
53
|
+
return
|
|
55
54
|
self.cache_item = TopStocksCacheItem(**data)
|
|
56
55
|
self.logger.info("Rehydrated TopStocksCacheItem")
|
|
57
56
|
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/market_data_scanner.py
RENAMED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Union, Optional, List
|
|
4
|
+
from typing import Any, Union, Optional, List
|
|
5
5
|
|
|
6
6
|
import redis.asyncio as aioredis
|
|
7
7
|
from redis.exceptions import ConnectionError
|
|
8
8
|
|
|
9
|
+
from massive.rest import RESTClient
|
|
10
|
+
|
|
9
11
|
from kuhl_haus.mdp.analyzers.analyzer import Analyzer
|
|
10
12
|
from kuhl_haus.mdp.models.market_data_analyzer_result import MarketDataAnalyzerResult
|
|
13
|
+
from kuhl_haus.mdp.components.market_data_cache import MarketDataCache
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
class MarketDataScanner:
|
|
@@ -18,11 +21,14 @@ class MarketDataScanner:
|
|
|
18
21
|
error: int
|
|
19
22
|
restarts: int
|
|
20
23
|
|
|
21
|
-
def __init__(self, redis_url: str,
|
|
24
|
+
def __init__(self, redis_url: str, massive_api_key: str, subscriptions: List[str], analyzer_class: Any):
|
|
22
25
|
self.redis_url = redis_url
|
|
23
|
-
self.
|
|
26
|
+
self.massive_api_key = massive_api_key
|
|
24
27
|
self.logger = logging.getLogger(__name__)
|
|
25
28
|
|
|
29
|
+
self.analyzer: Analyzer = None
|
|
30
|
+
self.analyzer_class = analyzer_class
|
|
31
|
+
|
|
26
32
|
# Connection objects
|
|
27
33
|
self.redis_client = None # : aioredis.Redis = None
|
|
28
34
|
self.pubsub_client: Optional[aioredis.client.PubSub] = None
|
|
@@ -30,6 +36,7 @@ class MarketDataScanner:
|
|
|
30
36
|
# State
|
|
31
37
|
self.mdc_connected = False
|
|
32
38
|
self.running = False
|
|
39
|
+
self.mdc: Optional[MarketDataCache] = None
|
|
33
40
|
|
|
34
41
|
self.subscriptions: List[str] = subscriptions
|
|
35
42
|
self._pubsub_task: Union[asyncio.Task, None] = None
|
|
@@ -48,9 +55,9 @@ class MarketDataScanner:
|
|
|
48
55
|
await self.connect()
|
|
49
56
|
self.pubsub_client = self.redis_client.pubsub()
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
self.analyzer = self.analyzer_class(cache=self.mdc)
|
|
52
59
|
self.logger.info(f"mds rehydrating from cache")
|
|
53
|
-
await self.analyzer.rehydrate(
|
|
60
|
+
await self.analyzer.rehydrate()
|
|
54
61
|
self.logger.info("mds rehydration complete")
|
|
55
62
|
|
|
56
63
|
for subscription in self.subscriptions:
|
|
@@ -73,6 +80,10 @@ class MarketDataScanner:
|
|
|
73
80
|
pass
|
|
74
81
|
self._pubsub_task = None
|
|
75
82
|
|
|
83
|
+
if self.mdc:
|
|
84
|
+
await self.mdc.close()
|
|
85
|
+
self.mdc = None
|
|
86
|
+
|
|
76
87
|
if self.pubsub_client:
|
|
77
88
|
for subscription in self.subscriptions:
|
|
78
89
|
if subscription.endswith("*"):
|
|
@@ -104,6 +115,11 @@ class MarketDataScanner:
|
|
|
104
115
|
|
|
105
116
|
# Test Redis connection
|
|
106
117
|
await self.redis_client.ping()
|
|
118
|
+
self.mdc = MarketDataCache(
|
|
119
|
+
rest_client=RESTClient(api_key=self.massive_api_key),
|
|
120
|
+
redis_client=self.redis_client,
|
|
121
|
+
massive_api_key=self.massive_api_key
|
|
122
|
+
)
|
|
107
123
|
self.mdc_connected = True
|
|
108
124
|
self.logger.debug(f"Connected to Redis: {self.redis_url}")
|
|
109
125
|
except Exception as e:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
|
|
1
2
|
from datetime import datetime, timezone
|
|
2
|
-
from unittest.mock import patch, MagicMock
|
|
3
|
+
from unittest.mock import patch, MagicMock, AsyncMock
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
5
6
|
|
|
@@ -10,7 +11,9 @@ from kuhl_haus.mdp.components.market_data_cache import MarketDataCache
|
|
|
10
11
|
|
|
11
12
|
@pytest.fixture
|
|
12
13
|
def mock_market_data_cache():
|
|
13
|
-
|
|
14
|
+
mock = MagicMock(spec=MarketDataCache)
|
|
15
|
+
mock.get_cache = AsyncMock()
|
|
16
|
+
return mock
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
@pytest.fixture
|
|
@@ -56,13 +59,16 @@ def outside_trading_hour_patch():
|
|
|
56
59
|
|
|
57
60
|
@pytest.mark.asyncio
|
|
58
61
|
@patch("kuhl_haus.mdp.analyzers.top_stocks.ZoneInfo")
|
|
59
|
-
async def test_rehydrate_no_data(mock_zoneinfo, top_stocks_analyzer, mock_logger):
|
|
62
|
+
async def test_rehydrate_no_data(mock_zoneinfo, top_stocks_analyzer, mock_logger, trading_hour_patch, mock_market_data_cache):
|
|
60
63
|
"""Test rehydrate when no data is passed."""
|
|
61
64
|
# Arrange
|
|
65
|
+
# Configure ZoneInfo mock to return timezone.utc so astimezone works properly
|
|
66
|
+
mock_zoneinfo.return_value = timezone.utc
|
|
62
67
|
top_stocks_analyzer.logger = mock_logger
|
|
68
|
+
top_stocks_analyzer.cache.get_cache.return_value = None
|
|
63
69
|
|
|
64
70
|
# Act
|
|
65
|
-
await top_stocks_analyzer.rehydrate(
|
|
71
|
+
_ = await top_stocks_analyzer.rehydrate()
|
|
66
72
|
|
|
67
73
|
# Assert
|
|
68
74
|
assert isinstance(top_stocks_analyzer.cache_item, TopStocksCacheItem)
|
|
@@ -71,15 +77,17 @@ async def test_rehydrate_no_data(mock_zoneinfo, top_stocks_analyzer, mock_logger
|
|
|
71
77
|
|
|
72
78
|
@pytest.mark.asyncio
|
|
73
79
|
@patch("kuhl_haus.mdp.analyzers.top_stocks.ZoneInfo")
|
|
74
|
-
async def test_rehydrate_outside_trading_hours(mock_zoneinfo, top_stocks_analyzer, outside_trading_hour_patch, mock_logger):
|
|
80
|
+
async def test_rehydrate_outside_trading_hours(mock_zoneinfo, top_stocks_analyzer, outside_trading_hour_patch, mock_logger, mock_market_data_cache):
|
|
75
81
|
"""Test rehydrate outside trading hours."""
|
|
76
82
|
# Arrange
|
|
77
83
|
# Configure ZoneInfo mock to return timezone.utc so astimezone works properly
|
|
78
84
|
mock_zoneinfo.return_value = timezone.utc
|
|
79
85
|
top_stocks_analyzer.logger = mock_logger
|
|
86
|
+
data = {"day_start_time": 1672531200}
|
|
87
|
+
top_stocks_analyzer.cache.get_cache.return_value = data
|
|
80
88
|
|
|
81
89
|
# Act
|
|
82
|
-
await top_stocks_analyzer.rehydrate(
|
|
90
|
+
await top_stocks_analyzer.rehydrate()
|
|
83
91
|
|
|
84
92
|
# Assert
|
|
85
93
|
assert isinstance(top_stocks_analyzer.cache_item, TopStocksCacheItem)
|
|
@@ -91,18 +99,19 @@ async def test_rehydrate_outside_trading_hours(mock_zoneinfo, top_stocks_analyze
|
|
|
91
99
|
|
|
92
100
|
@pytest.mark.asyncio
|
|
93
101
|
@patch("kuhl_haus.mdp.analyzers.top_stocks.ZoneInfo")
|
|
94
|
-
async def test_rehydrate_within_trading_hours(mock_zoneinfo, top_stocks_analyzer, trading_hour_patch, mock_logger):
|
|
102
|
+
async def test_rehydrate_within_trading_hours(mock_zoneinfo, top_stocks_analyzer, trading_hour_patch, mock_logger, mock_market_data_cache):
|
|
95
103
|
"""Test rehydrate within trading hours with valid data."""
|
|
96
104
|
# Arrange
|
|
97
105
|
# Configure ZoneInfo mock to return timezone.utc so astimezone works properly
|
|
98
106
|
mock_zoneinfo.return_value = timezone.utc
|
|
99
107
|
data = {"day_start_time": 1672531200}
|
|
108
|
+
top_stocks_analyzer.cache.get_cache.return_value = data
|
|
100
109
|
top_stocks_analyzer.logger = mock_logger
|
|
101
110
|
|
|
102
111
|
# Act
|
|
103
|
-
await top_stocks_analyzer.rehydrate(
|
|
112
|
+
await top_stocks_analyzer.rehydrate()
|
|
104
113
|
|
|
105
114
|
# Assert
|
|
106
115
|
assert isinstance(top_stocks_analyzer.cache_item, TopStocksCacheItem)
|
|
107
116
|
assert top_stocks_analyzer.cache_item.day_start_time == 1672531200
|
|
108
|
-
mock_logger.info.assert_called_once_with("Rehydrated TopStocksCacheItem")
|
|
117
|
+
mock_logger.info.assert_called_once_with("Rehydrated TopStocksCacheItem")
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# tests/test_market_data_scanner.py
|
|
2
|
-
import asyncio
|
|
3
|
-
import json
|
|
4
2
|
import unittest
|
|
5
3
|
from unittest.mock import AsyncMock, patch, MagicMock
|
|
6
4
|
|
|
7
5
|
from kuhl_haus.mdp.analyzers.analyzer import Analyzer
|
|
6
|
+
from kuhl_haus.mdp.analyzers.top_stocks import TopStocksAnalyzer
|
|
8
7
|
from kuhl_haus.mdp.components.market_data_scanner import MarketDataScanner
|
|
9
8
|
|
|
10
9
|
|
|
@@ -14,22 +13,26 @@ class TestMarketDataScanner(unittest.IsolatedAsyncioTestCase):
|
|
|
14
13
|
def setUp(self):
|
|
15
14
|
"""Set up a MarketDataScanner instance for testing."""
|
|
16
15
|
self.redis_url = "redis://localhost:6379/0"
|
|
17
|
-
self.analyzer = MagicMock(spec=
|
|
16
|
+
self.analyzer = MagicMock(spec=TopStocksAnalyzer)
|
|
18
17
|
self.analyzer.cache_key = MagicMock()
|
|
19
18
|
self.analyzer.rehydrate = AsyncMock()
|
|
20
19
|
self.analyzer.analyze_data = AsyncMock()
|
|
21
20
|
self.subscriptions = ["channel_1"]
|
|
22
21
|
self.scanner = MarketDataScanner(
|
|
23
22
|
redis_url=self.redis_url,
|
|
24
|
-
|
|
23
|
+
massive_api_key="test_key",
|
|
25
24
|
subscriptions=self.subscriptions,
|
|
25
|
+
analyzer_class=Analyzer
|
|
26
26
|
)
|
|
27
|
+
self.scanner.start()
|
|
27
28
|
|
|
29
|
+
@patch("kuhl_haus.mdp.analyzers.analyzer.Analyzer")
|
|
28
30
|
@patch("kuhl_haus.mdp.components.market_data_scanner.asyncio.sleep", new_callable=AsyncMock)
|
|
29
31
|
@patch("kuhl_haus.mdp.components.market_data_scanner.MarketDataScanner.start", new_callable=AsyncMock)
|
|
30
32
|
@patch("kuhl_haus.mdp.components.market_data_scanner.MarketDataScanner.stop", new_callable=AsyncMock)
|
|
31
|
-
async def test_restart(self, mock_stop, mock_start, mock_sleep):
|
|
33
|
+
async def test_restart(self, mock_stop, mock_start, mock_sleep, mock_analyzer):
|
|
32
34
|
"""Test the restart method stops and starts the scanner."""
|
|
35
|
+
self.analyzer.return_value = mock_analyzer
|
|
33
36
|
self.scanner.start = mock_start
|
|
34
37
|
self.scanner.stop = mock_stop
|
|
35
38
|
mock_stop.return_value = None
|
|
@@ -40,16 +43,3 @@ class TestMarketDataScanner(unittest.IsolatedAsyncioTestCase):
|
|
|
40
43
|
mock_start.assert_called_once()
|
|
41
44
|
self.assertEqual(self.scanner.restarts, 1)
|
|
42
45
|
|
|
43
|
-
async def test_process_message_success(self):
|
|
44
|
-
"""Test _process_message handles and processes valid data."""
|
|
45
|
-
valid_data = {"key": "value"}
|
|
46
|
-
analyzer_results = [MagicMock(), MagicMock()]
|
|
47
|
-
self.analyzer.analyze_data = AsyncMock(return_value=analyzer_results)
|
|
48
|
-
self.scanner.cache_result = AsyncMock()
|
|
49
|
-
|
|
50
|
-
await self.scanner._process_message(valid_data)
|
|
51
|
-
|
|
52
|
-
self.analyzer.analyze_data.assert_called_once_with(valid_data)
|
|
53
|
-
self.scanner.cache_result.assert_any_call(analyzer_results[0])
|
|
54
|
-
self.scanner.cache_result.assert_any_call(analyzer_results[1])
|
|
55
|
-
self.assertEqual(self.scanner.processed, 1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/analyzers/massive_data_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/market_data_cache.py
RENAMED
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/components/widget_data_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/helpers/queue_name_resolver.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/massive_data_listener.py
RENAMED
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/massive_data_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/integ/web_socket_message_serde.py
RENAMED
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_analyzer_result.py
RENAMED
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_cache_keys.py
RENAMED
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_cache_ttl.py
RENAMED
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_pubsub_keys.py
RENAMED
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/market_data_scanner_names.py
RENAMED
|
File without changes
|
|
File without changes
|
{kuhl_haus_mdp-0.1.5 → kuhl_haus_mdp-0.1.6}/src/kuhl_haus/mdp/models/top_stocks_cache_item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|