kuon.watcher.condition_checker   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 109
Duplicated Lines 26.61 %

Test Coverage

Coverage 42.86%

Importance

Changes 0
Metric Value
wmc 12
eloc 48
dl 29
loc 109
ccs 18
cts 42
cp 0.4286
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A ConditionChecker._check_below_value() 0 9 1
A ConditionChecker.clear_sold_history_cache() 0 6 1
A ConditionChecker.get_sold_history() 0 17 3
A ConditionChecker.__init__() 0 10 1
A ConditionChecker._check_below_cheapest_last_sold() 15 15 2
A ConditionChecker.check_condition() 0 11 2
A ConditionChecker._check_below_average_last_sold() 14 14 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3 1
from json.decoder import JSONDecodeError
4 1
from typing import Type
5
6 1
from requests.exceptions import ConnectionError as RequestsConnectionError
7 1
from selenium.common.exceptions import TimeoutException
8
9 1
from kuon.api_response import LockedDict
10 1
from kuon.exceptions import InvalidApiResponseType
11 1
from kuon.watcher.adapters import SalesAdapterBase
12 1
from kuon.watcher.tracker import TrackConditions
13
14
15 1
class ConditionChecker(object):
16
    """Class for checking if the given conditions match the item"""
17
18 1
    _cache = {}
19
20 1
    def __init__(self, adapter: Type[SalesAdapterBase], *args, **kwargs) -> None:
21
        """Initializing function
22
23
        :type adapter: Type[SalesAdapterBase]
24
        """
25
        self.sales_interface = adapter(*args, **kwargs)
26
        self.condition_mapping = {
27
            TrackConditions.BELOW_VALUE: self._check_below_value,
28
            TrackConditions.BELOW_AVERAGE_LAST_SOLD: self._check_below_average_last_sold,
29
            TrackConditions.BELOW_CHEAPEST_LAST_SOLD: self._check_below_cheapest_last_sold,
30
        }
31
32 1
    @staticmethod
33 1
    def _check_below_value(item: LockedDict, condition: LockedDict) -> bool:
34
        """Check if the value of the item is below the specified search value
35
36
        :type item: LockedDict
37
        :type condition: LockedDict
38
        :return:
39
        """
40
        return item[condition.key] >= 0 and (item[condition.key] < condition.value)
41
42 1 View Code Duplication
    def _check_below_average_last_sold(self, item: LockedDict, condition: LockedDict) -> bool:
43
        """Check if the value of the item is below the average of the last 20 sold items
44
45
        :type item: LockedDict
46
        :type condition: LockedDict
47
        :return:
48
        """
49
        last_sold = self.get_sold_history(market_name=item.market_name, no_delay=True)
50
        avg_value = sum([sold_item[condition.key] for sold_item in last_sold.data.sales]) / len(last_sold.data.sales)
51
52
        if condition.unit == "%":
53
            return item[condition.key] >= 0 and (item[condition.key] < avg_value * (1 + condition.value))
54
        else:
55
            return item[condition.key] >= 0 and (item[condition.key] < avg_value + condition.value)
56
57 1 View Code Duplication
    def _check_below_cheapest_last_sold(self, item: LockedDict, condition: LockedDict) -> bool:
58
        """Check if the value of the item is below the average of the cheapest sold items
59
        of the last 20 purchases
60
61
        :type item: LockedDict
62
        :type condition: LockedDict
63
        :return:
64
        """
65
        last_sold = self.get_sold_history(market_name=item.market_name, no_delay=True)
66
        lowest_value = min([sold_item[condition.key] for sold_item in last_sold.data.sales])
67
68
        if condition.unit == "%":
69
            return item[condition.key] >= 0 and (item[condition.key] < lowest_value * (1 + condition.value))
70
        else:
71
            return item[condition.key] >= 0 and (item[condition.key] < lowest_value + condition.value)
72
73 1
    def check_condition(self, item: LockedDict, settings: LockedDict) -> bool:
74
        """Check if the set condition matches on the passed item
75
76
        :type item: LockedDict
77
        :type settings: LockedDict
78
        :return:
79
        """
80
        try:
81
            return all([self.condition_mapping[cond.condition](item, cond) for cond in settings.conditions])
82
        except (InvalidApiResponseType, JSONDecodeError, RequestsConnectionError, TimeoutException):
83
            return False
84
85 1
    def get_sold_history(self, market_name: str, no_delay: bool = False) -> LockedDict:
86
        """Cache the sold history entries to execute less queries
87
88
        :type market_name: str
89
        :type no_delay: bool
90
        :return:
91
        """
92
        if market_name not in self._cache:
93
            self._cache[market_name] = {}
94
95
        if no_delay not in self._cache[market_name]:
96
            last_sold = self.sales_interface.get_sold_history(
97
                market_name=market_name,
98
                no_delay=True
99
            )
100
            self._cache[market_name][no_delay] = last_sold
101
        return self._cache[market_name][no_delay]
102
103 1
    def clear_sold_history_cache(self) -> None:
104
        """Clear the sold history cache
105
106
        :return:
107
        """
108
        self._cache = {}
109