first commit refactor score
This commit is contained in:
parent
17705e459e
commit
825c07c5f9
|
@ -18,23 +18,6 @@ class SnapshotSoftware(Enum):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@unique
|
|
||||||
class RatingSoftware(Enum):
|
|
||||||
"""The software used to compute the Score."""
|
|
||||||
ECost = 'ECost'
|
|
||||||
"""
|
|
||||||
The eReuse.org rate algorithm that focuses maximizing refurbishment
|
|
||||||
of devices in general, specially penalizing very low and very high
|
|
||||||
devices in order to stimulate medium-range devices.
|
|
||||||
|
|
||||||
This model is cost-oriented.
|
|
||||||
"""
|
|
||||||
EMarket = 'EMarket'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
RATE_POSITIVE = 0, 10
|
RATE_POSITIVE = 0, 10
|
||||||
RATE_NEGATIVE = -3, 5
|
RATE_NEGATIVE = -3, 5
|
||||||
|
|
||||||
|
@ -126,7 +109,7 @@ class FunctionalityRange(Enum):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
FUNCTIONALITY_RANGE = -0.25, 0.5
|
FUNCTIONALITY_RANGE = -0.3, 0.4
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
|
@ -142,8 +125,9 @@ class BatteryHealthRange(Enum):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class Bios(Enum):
|
class BiosAccessRange(Enum):
|
||||||
"""How difficult it has been to set the bios to boot from the network."""
|
"""How difficult it has been to set the bios to boot from the network."""
|
||||||
A = 'A. If by pressing a key you could access a boot menu with the network boot'
|
A = 'A. If by pressing a key you could access a boot menu with the network boot'
|
||||||
B = 'B. You had to get into the BIOS, and in less than 5 steps you could set the network boot'
|
B = 'B. You had to get into the BIOS, and in less than 5 steps you could set the network boot'
|
||||||
|
@ -155,8 +139,6 @@ class Bios(Enum):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
# TODO add all grade tables (chassis defects, camera defects, buttons test, connectivity, ..)
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class Orientation(Enum):
|
class Orientation(Enum):
|
||||||
Vertical = 'vertical'
|
Vertical = 'vertical'
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from collections import Iterable
|
from collections import Iterable
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_UP
|
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_UP
|
||||||
from distutils.version import StrictVersion
|
|
||||||
from typing import Optional, Set, Union
|
from typing import Optional, Set, Union
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
|
@ -28,10 +27,10 @@ from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.agent.models import Agent
|
from ereuse_devicehub.resources.agent.models import Agent
|
||||||
from ereuse_devicehub.resources.device.models import Component, Computer, DataStorage, Desktop, \
|
from ereuse_devicehub.resources.device.models import Component, Computer, DataStorage, Desktop, \
|
||||||
Device, Laptop, Server
|
Device, Laptop, Server
|
||||||
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, ErasureStandards, \
|
from ereuse_devicehub.resources.enums import BiosAccessRange, ErasureStandards, \
|
||||||
FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
|
PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
|
||||||
RatingRange, RatingSoftware, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \
|
RatingRange, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \
|
||||||
TestDataStorageLength, FUNCTIONALITY_RANGE, FunctionalityRange, AppearanceRange, BatteryHealthRange
|
TestDataStorageLength, FunctionalityRange, AppearanceRange, BatteryHealthRange
|
||||||
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
||||||
from ereuse_devicehub.resources.user.models import User
|
from ereuse_devicehub.resources.user.models import User
|
||||||
|
|
||||||
|
@ -708,7 +707,7 @@ class TestAudio(Test):
|
||||||
"""
|
"""
|
||||||
Test to check all this aspects related with audio functions, Manual Tests??
|
Test to check all this aspects related with audio functions, Manual Tests??
|
||||||
"""
|
"""
|
||||||
loudspeaker = Column(BDEnum(LoudspeakerRange))
|
loudspeaker = Column(Boolean)
|
||||||
loudspeaker.comment = 'Test to determine if the speaker is working properly and what sound quality it has.'
|
loudspeaker.comment = 'Test to determine if the speaker is working properly and what sound quality it has.'
|
||||||
microphone = Column(Boolean)
|
microphone = Column(Boolean)
|
||||||
microphone.comment = 'This evaluate if microphone works correctly'
|
microphone.comment = 'This evaluate if microphone works correctly'
|
||||||
|
@ -730,6 +729,7 @@ class TestConnectivity(Test):
|
||||||
locked = Column(Boolean)
|
locked = Column(Boolean)
|
||||||
locked.comment = 'Test to check if devices is locked'
|
locked.comment = 'Test to check if devices is locked'
|
||||||
|
|
||||||
|
|
||||||
class TestBattery(Test):
|
class TestBattery(Test):
|
||||||
"""
|
"""
|
||||||
Test battery health, status and length of charge. Minimum X minutes discharging the device
|
Test battery health, status and length of charge. Minimum X minutes discharging the device
|
||||||
|
@ -781,7 +781,7 @@ class TestBiosDifficulty:
|
||||||
Test to determinate a grade to reflect some possibles difficult to access or modify setting in the BIOS, like password protection..
|
Test to determinate a grade to reflect some possibles difficult to access or modify setting in the BIOS, like password protection..
|
||||||
"""
|
"""
|
||||||
bios_access_range = Column(BDEnum(BiosAccessRange))
|
bios_access_range = Column(BDEnum(BiosAccessRange))
|
||||||
bios_access_range.comment = 'Range of difficult to acces BIOS'
|
bios_access_range.comment = 'Range of difficult to access BIOS'
|
||||||
|
|
||||||
|
|
||||||
class TestVisual(ManualRate):
|
class TestVisual(ManualRate):
|
||||||
|
@ -795,6 +795,12 @@ class TestVisual(ManualRate):
|
||||||
functionality_range = Column(DBEnum(FunctionalityRange))
|
functionality_range = Column(DBEnum(FunctionalityRange))
|
||||||
functionality_range.comment = FunctionalityRange.__doc__
|
functionality_range.comment = FunctionalityRange.__doc__
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return super().__str__() + '. Appearance {} and functionality {}'.format(
|
||||||
|
self.appearance_range,
|
||||||
|
self.functionality_range
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
"""The act of computing a rate based on different categories:
|
"""The act of computing a rate based on different categories:
|
||||||
|
@ -810,10 +816,11 @@ class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
|
||||||
rating = Column(Float(decimal_return_scale=2), check_range('rating', *RATE_POSITIVE))
|
rating = Column(Float(decimal_return_scale=2), check_range('rating', *RATE_POSITIVE))
|
||||||
rating.comment = """The rating for the content."""
|
rating.comment = """The rating for the content."""
|
||||||
software = Column(DBEnum(RatingSoftware))
|
|
||||||
software.comment = """The algorithm used to produce this rating."""
|
|
||||||
version = Column(StrictVersionType)
|
version = Column(StrictVersionType)
|
||||||
version.comment = """The version of the software."""
|
version.comment = """The version of the software."""
|
||||||
|
appearance = Column(Float(decimal_return_scale=2), check_range('appearance', *RATE_NEGATIVE))
|
||||||
|
functionality = Column(Float(decimal_return_scale=2),
|
||||||
|
check_range('functionality', *RATE_NEGATIVE))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rating_range(self) -> RatingRange:
|
def rating_range(self) -> RatingRange:
|
||||||
|
@ -835,7 +842,15 @@ class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return '{} ({} v.{})'.format(self.rating_range, self.software, self.version)
|
return '{} (v.{})'.format(self.rating_range, self.version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def compute(cls, device) -> 'RateComputer':
|
||||||
|
"""
|
||||||
|
The act of compute general computer rate
|
||||||
|
"""
|
||||||
|
from ereuse_devicehub.resources.event.rate.workbench.v1_0 import rate_algorithm
|
||||||
|
return rate_algorithm.compute(device)
|
||||||
|
|
||||||
|
|
||||||
class RateComputer(Rate):
|
class RateComputer(Rate):
|
||||||
|
@ -852,332 +867,24 @@ class RateComputer(Rate):
|
||||||
comment='RAM memory rate.')
|
comment='RAM memory rate.')
|
||||||
data_storage = Column(Float(decimal_return_scale=2), check_range('data_storage', *RATE_POSITIVE),
|
data_storage = Column(Float(decimal_return_scale=2), check_range('data_storage', *RATE_POSITIVE),
|
||||||
comment='Data storage rate, like HHD, SSD.')
|
comment='Data storage rate, like HHD, SSD.')
|
||||||
graphic_card = Column(Float(decimal_return_scale=2), check_range('graphic_card', *RATE_POSITIVE),
|
|
||||||
comment='Graphic card score in performance, amount of memory and benchmark result')
|
|
||||||
network_adapter = Column(Float(decimal_return_scale=2), check_range('network_adapter', *RATE_POSITIVE),
|
|
||||||
comment='Network adapter rate, take it speed limit')
|
|
||||||
|
|
||||||
bios = Column(Float(decimal_return_scale=2), check_range('bios', *RATE_POSITIVE))
|
def __init__(self, **kwargs) -> None:
|
||||||
bios_range = Column(DBEnum(Bios))
|
super().__init__(**kwargs)
|
||||||
bios_range.comment = Bios.__doc__
|
|
||||||
|
|
||||||
appearance = Column(Float(decimal_return_scale=2), check_range('appearance', *RATE_NEGATIVE))
|
@property
|
||||||
functionality = Column(Float(decimal_return_scale=2),
|
def data_storage_range(self):
|
||||||
check_range('functionality', *RATE_NEGATIVE))
|
if self.data_storage:
|
||||||
|
return RatingRange.from_score(self.data_storage)
|
||||||
|
|
||||||
def compute_rate(self):
|
@property
|
||||||
"""
|
def ram_range(self):
|
||||||
The act of compute general computer rate
|
if self.ram:
|
||||||
"""
|
return RatingRange.from_score(self.ram)
|
||||||
pass
|
|
||||||
|
|
||||||
def compute_features(self, device):
|
@property
|
||||||
"""
|
def processor_range(self):
|
||||||
The act of compute rate about features (quality) aspects of a device
|
if self.processor:
|
||||||
"""
|
return RatingRange.from_score(self.processor)
|
||||||
# norm = (x - xMin) / (xMax – xMin)
|
|
||||||
# harmonic_mean = sum(x.weights)/sum(x.char_weight/x.char_norm)
|
|
||||||
|
|
||||||
CHARACTERISTIC_WEIGHTS = [
|
|
||||||
CPU_CHAR_WEIGHTS = 0.2, 0.4, 0.4 # cores, speed, benchmark
|
|
||||||
RAM_CHAR_WEIGHT = 0.3, 0.3, 0.4 # size, benchmark
|
|
||||||
DATA_STORAGE_CHAR_WEIGHT = 0.2, 0.4, 0.4 # size, speed, benchmark
|
|
||||||
GRAPHIC_CARD_CHAR_WEIGHT = 0.5, 0.5 # size, benchmark
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
self.processor = harmonic_mean(device.cpu.cores, device.cpu.speed, device.cpu.benchmarkCPUSysbench.rate,
|
|
||||||
PROCESSOR_CHAR_WEIGHTS)
|
|
||||||
self.ram = harmonic_mean(device.ram.size, device.ram.speed, device.ram.benchmarkRAMSysbench.rate,
|
|
||||||
RAM_CHAR_WEIGHT)
|
|
||||||
self.data_storage = harmonic_mean(device.data_storage.size, device.data_storage.speed,
|
|
||||||
device.data_storage.benchmarkDataStorage.rate, DATA_STORAGE_CHAR_WEIGHT)
|
|
||||||
self.graphic_card = harmonic_mean(device.graphic_card.size, device.graphic_card.benchmarkGraphicCard.rate,
|
|
||||||
GRAPHIC_CARD_CHAR_WEIGHT)
|
|
||||||
# self.network_adapter = device.network_adapter.rate
|
|
||||||
...
|
|
||||||
|
|
||||||
COMPONENTS_WEIGHTS..
|
|
||||||
|
|
||||||
return harmonic_mean(self.processor, self.ram, self.data_storage, self.graphic_card, ..., COMPONENTS_WEIGHTS)
|
|
||||||
|
|
||||||
def compute_functionality(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute functionality characteristics of a device.
|
|
||||||
Two functionality variables, functionality rate (float) and functionality range (Enum)
|
|
||||||
"""
|
|
||||||
DATA_STORAGE_WEIGHT = 0.1
|
|
||||||
STRESS_WEIGHT = 0.2
|
|
||||||
BIOS_WEIGHT = 0.2
|
|
||||||
...
|
|
||||||
|
|
||||||
test_data_storage = device.last_event_of(TestDataStorage)
|
|
||||||
test_data_storage = int(test_data_storage) * DATA_STORAGE_WEIGHT
|
|
||||||
|
|
||||||
test_stress = device.last_event_of(StressTest)
|
|
||||||
test_stress = int(test_stress) * STRESS_WEIGHT
|
|
||||||
|
|
||||||
test_bios_power_on = device.last_event_of(TestBios).bios_power_on # type: bool
|
|
||||||
test_bios_power_on = int(test_bios_power_on) * BIOS_WEIGHT
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
functionality_tests = harmonic_mean(test_data_storage, test_stress, test_bios_power_on, ...)
|
|
||||||
|
|
||||||
functionality_range = device.last_event_of(TestVisual).functionality_range
|
|
||||||
|
|
||||||
self.functionality = functionality_range + functionality_tests
|
|
||||||
|
|
||||||
def compute_appearance(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute appearance of a device.
|
|
||||||
"""
|
|
||||||
test_visual_appearance = device.last_event_of(TestVisual).appearance_range
|
|
||||||
self.appearance = test_visual_appearance
|
|
||||||
|
|
||||||
|
|
||||||
class RateDesktop(RateComputer):
|
|
||||||
"""
|
|
||||||
Rate class for device type: Desktop
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class RateLaptop(RateComputer):
|
|
||||||
"""
|
|
||||||
Rate class for device type: Laptop
|
|
||||||
"""
|
|
||||||
|
|
||||||
display = Column(Float(decimal_return_scale=2), check_range('display', *RATE_POSITIVE))
|
|
||||||
display.comment = 'Display rate, screen resolution and size to calculate PPI and convert in score'
|
|
||||||
battery = Column(Float(decimal_return_scale=2), check_range('battery', *RATE_POSITIVE),
|
|
||||||
comment='Battery rate is related with capacity and its health')
|
|
||||||
camera = Column(Float(decimal_return_scale=2), check_range('camera', *RATE_POSITIVE),
|
|
||||||
comment='Camera rate take into account resolution')
|
|
||||||
|
|
||||||
def compute_features(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute rate about features (quality) aspects of a device
|
|
||||||
"""
|
|
||||||
# norm = (x - xMin) / (xMax – xMin)
|
|
||||||
# harmonic_mean = sum(x.weights)/sum(x.char_weight/x.char_norm)
|
|
||||||
|
|
||||||
CHARACTERISTIC_WEIGHTS = [
|
|
||||||
PROCESSOR_CHAR_WEIGHTS = 0.2, 0.4, 0.4 # cores, speed, benchmark
|
|
||||||
RAM_CHAR_WEIGHT = 0.3, 0.3, 0.4 # size, benchmark
|
|
||||||
DATA_STORAGE_CHAR_WEIGHT = 0.2, 0.4, 0.4 # size, speed, benchmark
|
|
||||||
GRAPHIC_CARD_CHAR_WEIGHT = 0.5, 0.5 # size, benchmark
|
|
||||||
DISPLAY_CHAR_WEIGHT = 0.4, 0.6 # size, resolution
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
self.processor = harmonic_mean(device.cpu.cores, device.cpu.speed, device.cpu.benchmarkCPUSysbench.rate,
|
|
||||||
PROCESSOR_CHAR_WEIGHTS)
|
|
||||||
self.ram = harmonic_mean(device.ram.size, device.ram.speed, device.ram.benchmarkRAMSysbench.rate,
|
|
||||||
RAM_CHAR_WEIGHT)
|
|
||||||
self.data_storage = harmonic_mean(device.data_storage.size, device.data_storage.speed,
|
|
||||||
device.data_storage.benchmarkDataStorage.rate, DATA_STORAGE_CHAR_WEIGHT)
|
|
||||||
self.graphic_card = harmonic_mean(device.graphic_card.size, device.graphic_card.benchmarkGraphicCard.rate,
|
|
||||||
GRAPHIC_CARD_CHAR_WEIGHT)
|
|
||||||
self.display = harmonic_mean(device.display.size, device.display.resolution, DISPLAY_CHAR_WEIGHT)
|
|
||||||
...
|
|
||||||
|
|
||||||
COMPONENTS_WEIGHTS = [
|
|
||||||
PROCESSOR_WEIGHT: 0.1,
|
|
||||||
RAM_WEIGHT: 0.25,
|
|
||||||
DATA_STORAGE_WEIGHT: 0.05,
|
|
||||||
GRAPHIC_CARD_WEIGHT: 0.1,
|
|
||||||
DISPLAY_WEIGHT: 0.3,
|
|
||||||
BATTERY_WEIGHT: 0.25,
|
|
||||||
CAMERA_WEIGHT: 0.1,
|
|
||||||
... ...
|
|
||||||
]
|
|
||||||
|
|
||||||
return harmonic_mean(self.processor, self.ram, self.data_storage, self.graphic_card, self.display,
|
|
||||||
self.battery, self.camera, ..., COMPONENTS_WEIGHTS)
|
|
||||||
|
|
||||||
def compute_functionality(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute functionality characteristics of a device.
|
|
||||||
Two functionality variables, functionality rate (float) and functionality range (Enum)
|
|
||||||
"""
|
|
||||||
DATA_STORAGE_WEIGHT = 0.1
|
|
||||||
STRESS_WEIGHT = 0.2
|
|
||||||
CONNECTIVITY_WEIGHT = 0.2
|
|
||||||
BIOS_WEIGHT = 0.25
|
|
||||||
BATTERY_WEIGHT = 0.05
|
|
||||||
AUDIO_WEIGHT = 0.05
|
|
||||||
CAMERA_WEIGHT = 0.05
|
|
||||||
...
|
|
||||||
|
|
||||||
test_data_storage = device.last_event_of(TestDataStorage)
|
|
||||||
test_data_storage = int(test_data_storage) * DATA_STORAGE_WEIGHT
|
|
||||||
|
|
||||||
test_stress = device.last_event_of(StressTest)
|
|
||||||
test_stress = int(test_stress) * STRESS_WEIGHT
|
|
||||||
|
|
||||||
test_connectivity = device.last_event_of(TestConnectivity)
|
|
||||||
test_connectivity = int(test_connectivity) * CONNECTIVITY_WEIGHT
|
|
||||||
|
|
||||||
test_bios_power_on = device.last_event_of(TestBios).bios_power_on # type: bool
|
|
||||||
test_bios_power_on = int(test_bios_power_on) * BIOS_WEIGHT
|
|
||||||
|
|
||||||
test_battery = device.last_event_of(TestBattery)
|
|
||||||
test_battery = int(test_battery) * BATTERY_WEIGHT
|
|
||||||
|
|
||||||
test_audio = int(device.last_event_of(TestAudio)) * AUDIO_WEIGHT
|
|
||||||
|
|
||||||
test_camera = device.last_event_of(TestCamera)
|
|
||||||
test_camera = int(test_camera) * CAMERA_WEIGHT
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
functionality_tests = harmonic_mean(test_data_storage, test_stress, test_connectivity, test_bios_power_on,
|
|
||||||
test_battery, test_audio, test_camera, ...)
|
|
||||||
|
|
||||||
functionality_range = device.last_event_of(TestVisual).functionality_range
|
|
||||||
|
|
||||||
self.functionality = functionality_range + functionality_tests
|
|
||||||
|
|
||||||
|
|
||||||
class RateServer(RateComputer):
|
|
||||||
"""
|
|
||||||
Rate class for device type: Desktop
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class RateMobile(Rate):
|
|
||||||
"""
|
|
||||||
Main class to group by device type: Mobile
|
|
||||||
Computer is broadly extended by ``Smartphone``, ``Tablet``, and
|
|
||||||
``Cellphone``.
|
|
||||||
"""
|
|
||||||
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
|
|
||||||
|
|
||||||
processor = Column(Float(decimal_return_scale=2), check_range('processor', *RATE_POSITIVE),
|
|
||||||
comment='Is a test explain cpu component.')
|
|
||||||
ram = Column(Float(decimal_return_scale=2), check_range('ram', *RATE_POSITIVE),
|
|
||||||
comment='RAM memory rate.')
|
|
||||||
data_storage = Column(Float(decimal_return_scale=2), check_range('data_storage', *RATE_POSITIVE),
|
|
||||||
comment='Data storage rate, like HHD, SSD.')
|
|
||||||
graphic_card = Column(Float(decimal_return_scale=2), check_range('graphic_card', *RATE_POSITIVE),
|
|
||||||
comment='Graphic card score in performance, amount of memory and benchmark result')
|
|
||||||
display = Column(Float(decimal_return_scale=2), check_range('display', *RATE_POSITIVE))
|
|
||||||
display.comment = 'Display rate, screen resolution and size to calculate PPI and convert in score'
|
|
||||||
battery = Column(Float(decimal_return_scale=2), check_range('battery', *RATE_POSITIVE),
|
|
||||||
comment='Battery rate is related with capacity and its health')
|
|
||||||
camera = Column(Float(decimal_return_scale=2), check_range('camera', *RATE_POSITIVE),
|
|
||||||
comment='Camera rate take into account resolution')
|
|
||||||
|
|
||||||
def compute_rate(self):
|
|
||||||
"""
|
|
||||||
The act of compute general computer rate
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def compute_features(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute rate about features (quality) aspects of a device
|
|
||||||
"""
|
|
||||||
# norm = (x - xMin) / (xMax – xMin)
|
|
||||||
# harmonic_mean = sum(x.weights)/sum(x.char_weight/x.char_norm)
|
|
||||||
|
|
||||||
CHARACTERISTIC_WEIGHTS = [
|
|
||||||
PROCESSOR_CHAR_WEIGHTS = 0.2, 0.4, 0.4 # cores, speed, benchmark
|
|
||||||
RAM_CHAR_WEIGHT = 0.3, 0.3, 0.4 # size, benchmark
|
|
||||||
DATA_STORAGE_CHAR_WEIGHT = 0.2, 0.4, 0.4 # size, speed, benchmark
|
|
||||||
GRAPHIC_CARD_CHAR_WEIGHT = 0.5, 0.5 # size, benchmark
|
|
||||||
DISPLAY_CHAR_WEIGHT = 0.4, 0.6 # size, resolution
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
self.processor = harmonic_mean(device.cpu.cores, device.cpu.speed, device.cpu.benchmarkCPUSysbench.rate,
|
|
||||||
PROCESSOR_CHAR_WEIGHTS)
|
|
||||||
self.ram = harmonic_mean(device.ram.size, device.ram.speed, device.ram.benchmarkRAMSysbench.rate,
|
|
||||||
RAM_CHAR_WEIGHT)
|
|
||||||
self.data_storage = harmonic_mean(device.data_storage.size, device.data_storage.speed,
|
|
||||||
device.data_storage.benchmarkDataStorage.rate, DATA_STORAGE_CHAR_WEIGHT)
|
|
||||||
self.graphic_card = harmonic_mean(device.graphic_card.size, device.graphic_card.benchmarkGraphicCard.rate,
|
|
||||||
GRAPHIC_CARD_CHAR_WEIGHT)
|
|
||||||
self.display = harmonic_mean(device.display.size, device.display.resolution, DISPLAY_CHAR_WEIGHT)
|
|
||||||
...
|
|
||||||
|
|
||||||
COMPONENTS_WEIGHTS = [
|
|
||||||
PROCESSOR_WEIGHT: 0.1,
|
|
||||||
RAM_WEIGHT: 0.25,
|
|
||||||
DATA_STORAGE_WEIGHT: 0.05,
|
|
||||||
GRAPHIC_CARD_WEIGHT: 0.1,
|
|
||||||
DISPLAY_WEIGHT: 0.3,
|
|
||||||
BATTERY_WEIGHT: 0.25,
|
|
||||||
CAMERA_WEIGHT: 0.1,
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
return harmonic_mean(self.processor, self.ram, self.data_storage, self.graphic_card, self.display,
|
|
||||||
self.battery, self.camera, ..., COMPONENTS_WEIGHTS)
|
|
||||||
|
|
||||||
def compute_functionality(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute functionality characteristics of a device.
|
|
||||||
Two functionality variables, functionality rate (float) and functionality range (Enum)
|
|
||||||
"""
|
|
||||||
DATA_STORAGE_WEIGHT = 0.1
|
|
||||||
STRESS_WEIGHT = 0.2
|
|
||||||
CONNECTIVITY_WEIGHT = 0.2
|
|
||||||
BIOS_WEIGHT = 0.25
|
|
||||||
BATTERY_WEIGHT = 0.05
|
|
||||||
AUDIO_WEIGHT = 0.05
|
|
||||||
CAMERA_WEIGHT = 0.05
|
|
||||||
...
|
|
||||||
|
|
||||||
test_data_storage = device.last_event_of(TestDataStorage)
|
|
||||||
test_data_storage = int(test_data_storage) * DATA_STORAGE_WEIGHT
|
|
||||||
|
|
||||||
test_stress = device.last_event_of(StressTest)
|
|
||||||
test_stress = int(test_stress) * STRESS_WEIGHT
|
|
||||||
|
|
||||||
test_connectivity = device.last_event_of(TestConnectivity)
|
|
||||||
test_connectivity = int(test_connectivity) * CONNECTIVITY_WEIGHT
|
|
||||||
|
|
||||||
test_bios_power_on = device.last_event_of(TestBios).bios_power_on # type: bool
|
|
||||||
test_bios_power_on = int(test_bios_power_on) * BIOS_WEIGHT
|
|
||||||
|
|
||||||
test_battery = device.last_event_of(TestBattery)
|
|
||||||
test_battery = int(test_battery) * BATTERY_WEIGHT
|
|
||||||
|
|
||||||
test_audio = int(device.last_event_of(TestAudio)) * AUDIO_WEIGHT
|
|
||||||
|
|
||||||
test_camera = device.last_event_of(TestCamera)
|
|
||||||
test_camera = int(test_camera) * CAMERA_WEIGHT
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
functionality_tests = harmonic_mean(test_data_storage, test_stress, test_connectivity, test_bios_power_on,
|
|
||||||
test_battery, test_audio, test_camera, ...)
|
|
||||||
|
|
||||||
functionality_range = device.last_event_of(TestVisual).functionality_range
|
|
||||||
|
|
||||||
self.functionality = functionality_range + functionality_tests
|
|
||||||
|
|
||||||
def compute_appearance(self, device):
|
|
||||||
"""
|
|
||||||
The act of compute appearance of a device.
|
|
||||||
"""
|
|
||||||
test_visual_appearance = device.last_event_of(TestVisual).appearance_range
|
|
||||||
self.appearance = test_visual_appearance
|
|
||||||
|
|
||||||
|
|
||||||
class RateMonitor(Rate):
|
|
||||||
"""
|
|
||||||
Main class to group by device type: Monitor
|
|
||||||
Computer is broadly extended by ``ComputerMonitor``, ``TelevisionSet``, and
|
|
||||||
`` Projector``.
|
|
||||||
Important: Aspect ratio is an important variable in screen features
|
|
||||||
"""
|
|
||||||
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
|
|
||||||
|
|
||||||
# TODO determinate which variables must take into account to compute monitor score
|
|
||||||
|
|
||||||
|
|
||||||
class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
@ -1205,15 +912,15 @@ class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
"""
|
"""
|
||||||
version = Column(StrictVersionType)
|
version = Column(StrictVersionType)
|
||||||
version.comment = """The version of the software, or None."""
|
version.comment = """The version of the software, or None."""
|
||||||
rating_id = Column(UUID(as_uuid=True), ForeignKey(AggregateRate.id))
|
rating_id = Column(UUID(as_uuid=True), ForeignKey(RateComputer.id))
|
||||||
rating_id.comment = """The AggregateRate used to auto-compute
|
rating_id.comment = """The AggregateRate used to auto-compute
|
||||||
this price, if it has not been set manually."""
|
this price, if it has not been set manually."""
|
||||||
rating = relationship(FinalRate,
|
rating = relationship(Rate,
|
||||||
backref=backref('price',
|
backref=backref('price',
|
||||||
lazy=True,
|
lazy=True,
|
||||||
cascade=CASCADE_OWN,
|
cascade=CASCADE_OWN,
|
||||||
uselist=False),
|
uselist=False),
|
||||||
primaryjoin=AggregateRate.id == rating_id)
|
primaryjoin=RateComputer.id == rating_id)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
if 'price' in kwargs:
|
if 'price' in kwargs:
|
||||||
|
@ -1307,7 +1014,7 @@ class EreusePrice(Price):
|
||||||
if self.WARRANTY2 in rate:
|
if self.WARRANTY2 in rate:
|
||||||
self.warranty2 = EreusePrice.Type(rate[self.WARRANTY2][role], price)
|
self.warranty2 = EreusePrice.Type(rate[self.WARRANTY2][role], price)
|
||||||
|
|
||||||
def __init__(self, rating: AggregateRate, **kwargs) -> None:
|
def __init__(self, rating: RateComputer, **kwargs) -> None:
|
||||||
if rating.rating_range == RatingRange.VERY_LOW:
|
if rating.rating_range == RatingRange.VERY_LOW:
|
||||||
raise ValueError('Cannot compute price for Range.VERY_LOW')
|
raise ValueError('Cannot compute price for Range.VERY_LOW')
|
||||||
# We pass ROUND_UP strategy so price is always greater than what refurbisher... amounts
|
# We pass ROUND_UP strategy so price is always greater than what refurbisher... amounts
|
||||||
|
|
|
@ -123,6 +123,37 @@ class StepRandom(Step):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EraseBasic(EventWithOneDevice):
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.start_time = ... # type: datetime
|
||||||
|
self.end_time = ... # type: datetime
|
||||||
|
self.steps = ... # type: List[Step]
|
||||||
|
self.zeros = ... # type: bool
|
||||||
|
self.success = ... # type: bool
|
||||||
|
|
||||||
|
@property
|
||||||
|
def standards(self) -> Set[ErasureStandards]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def certificate(self) -> urlutils.URL:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EraseSectors(EraseBasic):
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ErasePhysical(EraseBasic):
|
||||||
|
method = ... # type: Column
|
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.method = ... # type: PhysicalErasureMethod
|
||||||
|
|
||||||
|
|
||||||
class Snapshot(EventWithOneDevice):
|
class Snapshot(EventWithOneDevice):
|
||||||
def __init__(self, **kwargs) -> None:
|
def __init__(self, **kwargs) -> None:
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
@ -154,11 +185,124 @@ class SnapshotRequest(Model):
|
||||||
self.snapshot = ... # type: Snapshot
|
self.snapshot = ... # type: Snapshot
|
||||||
|
|
||||||
|
|
||||||
|
class Benchmark(EventWithOneDevice):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkDataStorage(Benchmark):
|
||||||
|
read_speed = ... # type: Column
|
||||||
|
write_speed = ... # type: Column
|
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.read_speed = ... # type: float
|
||||||
|
self.write_speed = ... # type: float
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkWithRate(Benchmark):
|
||||||
|
rate = ... # type: Column
|
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.rate = ... # type: int
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkProcessor(BenchmarkWithRate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkProcessorSysbench(BenchmarkProcessor):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkRamSysbench(BenchmarkWithRate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkGraphicCard(BenchmarkWithRate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Test(EventWithOneDevice):
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.elapsed = ... # type: timedelta
|
||||||
|
self.success = ... # type: bool
|
||||||
|
|
||||||
|
|
||||||
|
class TestDataStorage(Test):
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.id = ... # type: UUID
|
||||||
|
self.length = ... # type: TestDataStorageLength
|
||||||
|
self.status = ... # type: str
|
||||||
|
self.lifetime = ... # type: timedelta
|
||||||
|
self.first_error = ... # type: int
|
||||||
|
self.passed_lifetime = ... # type: timedelta
|
||||||
|
self.assessment = ... # type: int
|
||||||
|
self.reallocated_sector_count = ... # type: int
|
||||||
|
self.power_cycle_count = ... # type: int
|
||||||
|
self.reported_uncorrectable_errors = ... # type: int
|
||||||
|
self.command_timeout = ... # type: int
|
||||||
|
self.current_pending_sector_count = ... # type: int
|
||||||
|
self.offline_uncorrectable = ... # type: int
|
||||||
|
self.remaining_lifetime_percentage = ... # type: int
|
||||||
|
|
||||||
|
|
||||||
|
class StressTest(Test):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestAudio(Test):
|
||||||
|
"""
|
||||||
|
Test to check all this aspects related with audio functions, Manual Tests??
|
||||||
|
"""
|
||||||
|
loudspeaker = ... # type: Column
|
||||||
|
microphone = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestConnectivity(Test):
|
||||||
|
cellular_network = ... # type: Column
|
||||||
|
wifi = ... # type: Column
|
||||||
|
bluetooth = ... # type: Column
|
||||||
|
usb_port = ... # type: Column
|
||||||
|
locked = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestBattery(Test):
|
||||||
|
battery_stat = ... # type: Column
|
||||||
|
battery_health = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestCamera(Test):
|
||||||
|
camera = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestKeyboard(Test):
|
||||||
|
keyboard = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestTrackpad(Test):
|
||||||
|
trackpad = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestBios(Test):
|
||||||
|
bios_power_on = ... # type: Column
|
||||||
|
|
||||||
|
|
||||||
|
class TestBiosDifficulty:
|
||||||
|
bios_access_range = ... # type: BiosAccessRange
|
||||||
|
|
||||||
|
|
||||||
|
class TestVisual(ManualRate):
|
||||||
|
appearance_range = ... # type: AppearanceRange
|
||||||
|
functionality_range = ... # type: FunctionalityRange
|
||||||
|
|
||||||
|
|
||||||
class Rate(EventWithOneDevice):
|
class Rate(EventWithOneDevice):
|
||||||
rating = ... # type: Column
|
rating = ... # type: Column
|
||||||
appearance = ... # type: Column
|
appearance = ... # type: Column
|
||||||
functionality = ... # type: Column
|
functionality = ... # type: Column
|
||||||
software = ... # type: Column
|
|
||||||
version = ... # type: Column
|
version = ... # type: Column
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
def __init__(self, **kwargs) -> None:
|
||||||
|
@ -171,118 +315,11 @@ class Rate(EventWithOneDevice):
|
||||||
self.rating_range = ... # type: str
|
self.rating_range = ... # type: str
|
||||||
|
|
||||||
|
|
||||||
class IndividualRate(Rate):
|
class RateComputer(Rate):
|
||||||
def __init__(self, **kwargs) -> None:
|
id = ...
|
||||||
super().__init__(**kwargs)
|
processor = ...
|
||||||
self.aggregated_ratings = ... # type: Set[AggregateRate]
|
ram = ...
|
||||||
|
data_storage = ...
|
||||||
|
|
||||||
class AggregateRate(Rate):
|
|
||||||
manual_id = ... # type: Column
|
|
||||||
manual = ... # type: relationship
|
|
||||||
workbench = ... # type: relationship
|
|
||||||
workbench_id = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.manual_id = ... # type: UUID
|
|
||||||
self.manual = ... # type: ManualRate
|
|
||||||
self.workbench = ... # type: WorkbenchRate
|
|
||||||
self.workbench_id = ... # type: UUID
|
|
||||||
self.price = ... # type: Price
|
|
||||||
|
|
||||||
@property
|
|
||||||
def processor(self):
|
|
||||||
return self.workbench.processor
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ram(self):
|
|
||||||
return self.workbench.ram
|
|
||||||
|
|
||||||
@property
|
|
||||||
def data_storage(self):
|
|
||||||
return self.workbench.data_storage
|
|
||||||
|
|
||||||
@property
|
|
||||||
def graphic_card(self):
|
|
||||||
return self.workbench.graphic_card
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bios(self):
|
|
||||||
return self.workbench.bios
|
|
||||||
|
|
||||||
@property
|
|
||||||
def functionality_range(self):
|
|
||||||
return self.workbench.functionality_range
|
|
||||||
|
|
||||||
@property
|
|
||||||
def appearance_range(self):
|
|
||||||
return self.workbench.appearance_range
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bios_range(self):
|
|
||||||
return self.workbench.bios_range
|
|
||||||
|
|
||||||
@property
|
|
||||||
def labelling(self):
|
|
||||||
return self.workbench.labelling
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_workbench_rate(cls, rate: WorkbenchRate) -> AggregateRate:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ManualRate(IndividualRate):
|
|
||||||
labelling = ... # type: Column
|
|
||||||
appearance_range = ... # type: Column
|
|
||||||
functionality_range = ... # type: Column
|
|
||||||
aggregate_rate_manual = ... #type: relationship
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.labelling = ... # type: bool
|
|
||||||
self.appearance_range = ... # type: AppearanceRange
|
|
||||||
self.functionality_range = ... # type: FunctionalityRange
|
|
||||||
self.aggregate_rate_manual = ... #type: AggregateRate
|
|
||||||
|
|
||||||
def ratings(self) -> Set[Rate]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class WorkbenchRate(ManualRate):
|
|
||||||
processor = ... # type: Column
|
|
||||||
ram = ... # type: Column
|
|
||||||
data_storage = ... # type: Column
|
|
||||||
graphic_card = ... # type: Column
|
|
||||||
bios_range = ... # type: Column
|
|
||||||
bios = ... # type: Column
|
|
||||||
aggregate_rate_workbench = ... #type: Column
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.processor = ... # type: float
|
|
||||||
self.ram = ... # type: float
|
|
||||||
self.data_storage = ... # type: float
|
|
||||||
self.graphic_card = ... # type: float
|
|
||||||
self.bios_range = ... # type: Bios
|
|
||||||
self.bios = ... # type: float
|
|
||||||
self.aggregate_rate_workbench = ... #type: AggregateRate
|
|
||||||
|
|
||||||
@property
|
|
||||||
def data_storage_range(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ram_range(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
|
||||||
def processor_range(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
|
||||||
def graphic_card_range(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Price(EventWithOneDevice):
|
class Price(EventWithOneDevice):
|
||||||
|
@ -331,101 +368,6 @@ class EreusePrice(Price):
|
||||||
self.warranty2 = ... # type: float
|
self.warranty2 = ... # type: float
|
||||||
|
|
||||||
|
|
||||||
class Test(EventWithOneDevice):
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.elapsed = ... # type: timedelta
|
|
||||||
self.success = ... # type: bool
|
|
||||||
|
|
||||||
|
|
||||||
class TestDataStorage(Test):
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.id = ... # type: UUID
|
|
||||||
self.length = ... # type: TestDataStorageLength
|
|
||||||
self.status = ... # type: str
|
|
||||||
self.lifetime = ... # type: timedelta
|
|
||||||
self.first_error = ... # type: int
|
|
||||||
self.passed_lifetime = ... # type: timedelta
|
|
||||||
self.assessment = ... # type: int
|
|
||||||
self.reallocated_sector_count = ... # type: int
|
|
||||||
self.power_cycle_count = ... # type: int
|
|
||||||
self.reported_uncorrectable_errors = ... # type: int
|
|
||||||
self.command_timeout = ... # type: int
|
|
||||||
self.current_pending_sector_count = ... # type: int
|
|
||||||
self.offline_uncorrectable = ... # type: int
|
|
||||||
self.remaining_lifetime_percentage = ... # type: int
|
|
||||||
|
|
||||||
|
|
||||||
class StressTest(Test):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class EraseBasic(EventWithOneDevice):
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.start_time = ... # type: datetime
|
|
||||||
self.end_time = ... # type: datetime
|
|
||||||
self.steps = ... # type: List[Step]
|
|
||||||
self.zeros = ... # type: bool
|
|
||||||
self.success = ... # type: bool
|
|
||||||
|
|
||||||
@property
|
|
||||||
def standards(self) -> Set[ErasureStandards]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
|
||||||
def certificate(self) -> urlutils.URL:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class EraseSectors(EraseBasic):
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ErasePhysical(EraseBasic):
|
|
||||||
method = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.method = ... # type: PhysicalErasureMethod
|
|
||||||
|
|
||||||
|
|
||||||
class Benchmark(EventWithOneDevice):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkDataStorage(Benchmark):
|
|
||||||
read_speed = ... # type: Column
|
|
||||||
write_speed = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.read_speed = ... # type: float
|
|
||||||
self.write_speed = ... # type: float
|
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkWithRate(Benchmark):
|
|
||||||
rate = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.rate = ... # type: int
|
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkProcessor(BenchmarkWithRate):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkProcessorSysbench(BenchmarkProcessor):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkRamSysbench(BenchmarkWithRate):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ToRepair(EventWithMultipleDevices):
|
class ToRepair(EventWithMultipleDevices):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,15 @@
|
||||||
from contextlib import suppress
|
|
||||||
from distutils.version import StrictVersion
|
|
||||||
from typing import Set, Union
|
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
from ereuse_devicehub.resources.enums import RatingSoftware
|
from ereuse_devicehub.resources.event.models import RateComputer
|
||||||
from ereuse_devicehub.resources.event.models import AggregateRate, EreusePrice, Rate, \
|
|
||||||
WorkbenchRate
|
|
||||||
from ereuse_devicehub.resources.event.rate.workbench import v1_0
|
from ereuse_devicehub.resources.event.rate.workbench import v1_0
|
||||||
|
|
||||||
RATE_TYPES = {
|
RATE_TYPES = {
|
||||||
WorkbenchRate: {
|
RateComputer: {
|
||||||
RatingSoftware.ECost: {
|
|
||||||
'1.0': v1_0.Rate()
|
'1.0': v1_0.Rate()
|
||||||
},
|
|
||||||
RatingSoftware.EMarket: {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def rate(device: Device, rate: Rate):
|
def rate(device: Device, version):
|
||||||
"""
|
"""
|
||||||
Rates the passed-in ``rate`` using values from the rate itself
|
Rates the passed-in ``rate`` using values from the rate itself
|
||||||
and the ``device``.
|
and the ``device``.
|
||||||
|
@ -29,50 +19,7 @@ def rate(device: Device, rate: Rate):
|
||||||
:param device: The device to use as a model.
|
:param device: The device to use as a model.
|
||||||
:param rate: A half-filled rate.
|
:param rate: A half-filled rate.
|
||||||
"""
|
"""
|
||||||
cls = rate.__class__
|
|
||||||
assert cls in RATE_TYPES, 'Rate type {} not supported.'.format(cls)
|
assert cls in RATE_TYPES, 'Rate type {} not supported.'.format(cls)
|
||||||
assert rate.software in RATE_TYPES[cls], 'Rate soft {} not supported.'.format(rate.software)
|
assert str(rate.version) in RATE_TYPES[cls], \
|
||||||
assert str(rate.version) in RATE_TYPES[cls][rate.software], \
|
|
||||||
'Rate version {} not supported.'.format(rate.version)
|
'Rate version {} not supported.'.format(rate.version)
|
||||||
RATE_TYPES[cls][rate.software][str(rate.version)].compute(device, rate)
|
RATE_TYPES[cls][str(rate.version)].compute(device)
|
||||||
|
|
||||||
|
|
||||||
def main(rating_model: WorkbenchRate,
|
|
||||||
software: RatingSoftware,
|
|
||||||
version: StrictVersion) -> Set[Union[WorkbenchRate, AggregateRate, EreusePrice]]:
|
|
||||||
"""
|
|
||||||
Generates all the rates (per software and version) for a given
|
|
||||||
half-filled rate acting as a model, and finally it generates
|
|
||||||
an ``AggregateRating`` with the rate that matches the
|
|
||||||
``software`` and ``version``.
|
|
||||||
|
|
||||||
This method mutates ``rating_model`` by fulfilling it and
|
|
||||||
``rating_model.device`` by adding the new rates.
|
|
||||||
|
|
||||||
:return: A set of rates with the ``rate`` value computed, where
|
|
||||||
the first rate is the ``rating_model``.
|
|
||||||
"""
|
|
||||||
assert rating_model.device
|
|
||||||
events = set()
|
|
||||||
for soft, value in RATE_TYPES[rating_model.__class__].items():
|
|
||||||
for vers, func in value.items():
|
|
||||||
if not rating_model.rating: # Fill the rating before creating another rate
|
|
||||||
rating = rating_model
|
|
||||||
else: # original rating was filled already; use a new one
|
|
||||||
rating = WorkbenchRate(
|
|
||||||
labelling=rating_model.labelling,
|
|
||||||
appearance_range=rating_model.appearance_range,
|
|
||||||
functionality_range=rating_model.functionality_range,
|
|
||||||
device=rating_model.device,
|
|
||||||
)
|
|
||||||
rating.software = soft
|
|
||||||
rating.version = vers
|
|
||||||
rate(rating_model.device, rating)
|
|
||||||
events.add(rating)
|
|
||||||
if soft == software and vers == version:
|
|
||||||
aggregation = AggregateRate.from_workbench_rate(rating)
|
|
||||||
events.add(aggregation)
|
|
||||||
with suppress(ValueError):
|
|
||||||
# We will have exception if range == VERY_LOW
|
|
||||||
events.add(EreusePrice(aggregation))
|
|
||||||
return events
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import math
|
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
from ereuse_devicehub.resources.event.models import WorkbenchRate
|
|
||||||
|
|
||||||
|
|
||||||
class BaseRate:
|
class BaseRate:
|
||||||
|
@ -20,7 +20,7 @@ class BaseRate:
|
||||||
"""Ram has 30% of weight over total score, used in harmonic mean"""
|
"""Ram has 30% of weight over total score, used in harmonic mean"""
|
||||||
RAM_WEIGHT = 0.3
|
RAM_WEIGHT = 0.3
|
||||||
|
|
||||||
def compute(self, device: Device, rate: WorkbenchRate):
|
def compute(self, device: Device):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -5,13 +5,13 @@ from typing import Iterable
|
||||||
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Desktop, Laptop, \
|
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Desktop, Laptop, \
|
||||||
Processor, RamModule, Server
|
Processor, RamModule, Server
|
||||||
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
|
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
|
||||||
WorkbenchRate
|
RateComputer, TestVisual
|
||||||
# todo if no return assign then rate_c = 1 is assigned
|
# todo if no return assign then rate_c = 1 is assigned
|
||||||
# todo fix corner cases, like components characteristics == None
|
# todo fix corner cases, like components characteristics == None
|
||||||
from ereuse_devicehub.resources.event.rate.rate import BaseRate
|
from ereuse_devicehub.resources.event.rate.rate import BaseRate
|
||||||
|
|
||||||
|
|
||||||
class Rate(BaseRate):
|
class RateAlgorithm(BaseRate):
|
||||||
"""
|
"""
|
||||||
Rate all components in Computer
|
Rate all components in Computer
|
||||||
"""
|
"""
|
||||||
|
@ -46,15 +46,16 @@ class Rate(BaseRate):
|
||||||
DataStorage.t: ('data_storage', DataStorageRate())
|
DataStorage.t: ('data_storage', DataStorageRate())
|
||||||
}
|
}
|
||||||
|
|
||||||
def compute(self, device: Computer, rate: WorkbenchRate):
|
def compute(self, device: Computer):
|
||||||
"""
|
"""
|
||||||
Compute 'Workbench'Rate computer is a rate (score) ranging from 0 to 4.7
|
Compute RateComputer is a rate (score) ranging from 0 to 4.7
|
||||||
that represents estimating value of use of desktop and laptop computer components.
|
that represents estimating value of use of desktop and laptop computer components.
|
||||||
|
|
||||||
This mutates "rate".
|
This mutates "rate".
|
||||||
"""
|
"""
|
||||||
assert isinstance(device, (Desktop, Laptop, Server))
|
assert isinstance(device, (Desktop, Laptop, Server))
|
||||||
assert isinstance(rate, WorkbenchRate)
|
|
||||||
|
rate = RateComputer()
|
||||||
|
|
||||||
rate.processor = rate.data_storage = rate.ram = 1 # Init
|
rate.processor = rate.data_storage = rate.ram = 1 # Init
|
||||||
|
|
||||||
|
@ -71,8 +72,8 @@ class Rate(BaseRate):
|
||||||
setattr(rate, field, result)
|
setattr(rate, field, result)
|
||||||
|
|
||||||
rate_components = self.harmonic_mean_rates(rate.processor, rate.data_storage, rate.ram)
|
rate_components = self.harmonic_mean_rates(rate.processor, rate.data_storage, rate.ram)
|
||||||
rate.appearance = self.Appearance.from_devicehub(rate.appearance_range).value
|
rate.appearance = self.Appearance.from_devicehub(TestVisual.appearance_range).value
|
||||||
rate.functionality = self.Functionality.from_devicehub(rate.functionality_range).value
|
rate.functionality = self.Functionality.from_devicehub(TestVisual.functionality_range).value
|
||||||
|
|
||||||
rate.rating = round(max(rate_components + rate.functionality + rate.appearance, 0), 2)
|
rate.rating = round(max(rate_components + rate.functionality + rate.appearance, 0), 2)
|
||||||
rate.appearance = round(rate.appearance, 2)
|
rate.appearance = round(rate.appearance, 2)
|
||||||
|
@ -80,6 +81,8 @@ class Rate(BaseRate):
|
||||||
rate.processor = round(rate.processor, 2)
|
rate.processor = round(rate.processor, 2)
|
||||||
rate.ram = round(rate.ram, 2)
|
rate.ram = round(rate.ram, 2)
|
||||||
rate.data_storage = round(rate.data_storage, 2)
|
rate.data_storage = round(rate.data_storage, 2)
|
||||||
|
device.events_one.add(rate)
|
||||||
|
return rate
|
||||||
|
|
||||||
|
|
||||||
class ProcessorRate(BaseRate):
|
class ProcessorRate(BaseRate):
|
||||||
|
@ -95,7 +98,7 @@ class ProcessorRate(BaseRate):
|
||||||
# Intel(R) Core(TM) i3 CPU 530 @ 2.93GHz, score = 23406.92 but results inan score of 17503.
|
# Intel(R) Core(TM) i3 CPU 530 @ 2.93GHz, score = 23406.92 but results inan score of 17503.
|
||||||
DEFAULT_SCORE = 4000
|
DEFAULT_SCORE = 4000
|
||||||
|
|
||||||
def compute(self, processor: Processor, rate: WorkbenchRate):
|
def compute(self, processor: Processor, rate: RateComputer):
|
||||||
""" Compute processor rate
|
""" Compute processor rate
|
||||||
Obs: cores and speed are possible NULL value
|
Obs: cores and speed are possible NULL value
|
||||||
:return: result is a rate (score) of Processor characteristics
|
:return: result is a rate (score) of Processor characteristics
|
||||||
|
@ -139,7 +142,7 @@ class RamRate(BaseRate):
|
||||||
# ram.size.weight; ram.speed.weight;
|
# ram.size.weight; ram.speed.weight;
|
||||||
RAM_WEIGHTS = 0.7, 0.3
|
RAM_WEIGHTS = 0.7, 0.3
|
||||||
|
|
||||||
def compute(self, ram_devices: Iterable[RamModule], rate: WorkbenchRate):
|
def compute(self, ram_devices: Iterable[RamModule], rate: RateComputer):
|
||||||
"""
|
"""
|
||||||
Obs: RamModule.speed is possible NULL value & size != NULL or NOT??
|
Obs: RamModule.speed is possible NULL value & size != NULL or NOT??
|
||||||
:return: result is a rate (score) of all RamModule components
|
:return: result is a rate (score) of all RamModule components
|
||||||
|
@ -196,7 +199,7 @@ class DataStorageRate(BaseRate):
|
||||||
# drive.size.weight; drive.readingSpeed.weight; drive.writingSpeed.weight;
|
# drive.size.weight; drive.readingSpeed.weight; drive.writingSpeed.weight;
|
||||||
DATA_STORAGE_WEIGHTS = 0.5, 0.25, 0.25
|
DATA_STORAGE_WEIGHTS = 0.5, 0.25, 0.25
|
||||||
|
|
||||||
def compute(self, data_storage_devices: Iterable[DataStorage], rate: WorkbenchRate):
|
def compute(self, data_storage_devices: Iterable[DataStorage], rate: RateComputer):
|
||||||
"""
|
"""
|
||||||
Obs: size != NULL and 0 value & read_speed and write_speed != NULL
|
Obs: size != NULL and 0 value & read_speed and write_speed != NULL
|
||||||
:return: result is a rate (score) of all DataStorage devices
|
:return: result is a rate (score) of all DataStorage devices
|
||||||
|
@ -252,3 +255,6 @@ class DataStorageRate(BaseRate):
|
||||||
# STEP: Fusion Characteristics
|
# STEP: Fusion Characteristics
|
||||||
return self.harmonic_mean(self.DATA_STORAGE_WEIGHTS,
|
return self.harmonic_mean(self.DATA_STORAGE_WEIGHTS,
|
||||||
rates=(size_rate, read_speed_rate, write_speed_rate))
|
rates=(size_rate, read_speed_rate, write_speed_rate))
|
||||||
|
|
||||||
|
|
||||||
|
rate_algorithm = RateAlgorithm()
|
||||||
|
|
|
@ -1,313 +0,0 @@
|
||||||
from enum import Enum
|
|
||||||
from typing import Iterable
|
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.models import DataStorage, Processor, RamModule, Device
|
|
||||||
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, WorkbenchRate
|
|
||||||
from ereuse_devicehub.resources.event.rate.rate import BaseRate
|
|
||||||
|
|
||||||
|
|
||||||
class Rate(BaseRate):
|
|
||||||
"""
|
|
||||||
Rate all the categories of a device
|
|
||||||
RATE = Quality Rate + Functionality Rate + Appearance Rate
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Range(Enum):
|
|
||||||
@classmethod
|
|
||||||
def from_devicehub(cls, r: Enum):
|
|
||||||
return getattr(cls, r.name) if r else cls.NONE
|
|
||||||
|
|
||||||
def compute(self, device: Device):
|
|
||||||
rate_quality = QualityRate.compute()
|
|
||||||
rate_functionality = FunctionalityRate.compute()
|
|
||||||
rate_appearance = self.Appearance.from_devicehub(rate.appearance_range).value
|
|
||||||
|
|
||||||
# Final result
|
|
||||||
return round(max(rate_quality + rate_functionality + rate_appearance, 0), 2)
|
|
||||||
|
|
||||||
|
|
||||||
class QualityRate(BaseRate):
|
|
||||||
"""
|
|
||||||
Rate Quality aspect
|
|
||||||
Display (screen)
|
|
||||||
Processor
|
|
||||||
RAM
|
|
||||||
Data Storage
|
|
||||||
Battery
|
|
||||||
Camera
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
List components wieghts
|
|
||||||
total_weights = 1
|
|
||||||
"""
|
|
||||||
DISPLAY_WEIGHT = 0.25
|
|
||||||
PROCESSOR_WEIGHT = 0.1
|
|
||||||
RAM_WEIGHT = 0.25
|
|
||||||
DATA_STORAGE_WEIGHT = 0.05
|
|
||||||
BATTERY_WEIGHT = 0.25
|
|
||||||
CAMERA_WEIGHT = 0.1
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
super().__init__()
|
|
||||||
# TODO Check if component exists before rate it.
|
|
||||||
self.RATES = {
|
|
||||||
# composition: type: (field, compute class)
|
|
||||||
Display.t: ('display', DisplayRate()),
|
|
||||||
Processor.t: ('processor', ProcessorRate()),
|
|
||||||
RamModule.t: ('ram', RamRate()),
|
|
||||||
DataStorage.t: ('data_storage', DataStorageRate()),
|
|
||||||
Battery.t: ('battery', BatteryRate()),
|
|
||||||
Camera.t: ('camera', CameraRate())
|
|
||||||
}
|
|
||||||
|
|
||||||
def compute(self, device: Device):
|
|
||||||
rate = self.RATES
|
|
||||||
# TODO Assign only the weight of existing components.
|
|
||||||
weights = (
|
|
||||||
self.DISPLAY_WEIGHT, self.PROCESSOR_WEIGHT, self.RAM_WEIGHT, self.DATA_STORAGE_WEIGHT, self.BATTERY_WEIGHT,
|
|
||||||
self.CAMERA_WEIGHT)
|
|
||||||
|
|
||||||
return self.harmonic_mean(weights, rate)
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionalityRate(BaseRate):
|
|
||||||
"""
|
|
||||||
Rate Functionality aspects on mobile devices
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Functionality Range v2
|
|
||||||
A = 0, 5
|
|
||||||
B = 0
|
|
||||||
C = -0, 25
|
|
||||||
D = -0, 5
|
|
||||||
NONE = -0, 3
|
|
||||||
|
|
||||||
# SUM(weights) = 1
|
|
||||||
SIM_WEIGHT = 0.2
|
|
||||||
USB_WEIGHT = 0.25
|
|
||||||
WIFI_WEIGHT = 0.05
|
|
||||||
BLUETOOTH_WEIGHT = 0.05
|
|
||||||
FINGERPRINT_WEIGHT = 0.05
|
|
||||||
LOUDSPEAKER_WEIGHT = 0.15
|
|
||||||
MICROPHONE_WEIGHT = 0.15
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def compute(cls, device: Device):
|
|
||||||
"""
|
|
||||||
|
|
||||||
:param FunctionalityDevice: List[Boolean]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
test_bios_power_on = device.last_event_of(TestBios).bios_power_on # type: bool
|
|
||||||
test_bios_power_on = int(test_bios_power_on)
|
|
||||||
|
|
||||||
|
|
||||||
test_battery = device.last_event_of(TestBattery)
|
|
||||||
test_audio
|
|
||||||
test_data_storage
|
|
||||||
|
|
||||||
functionality = test_bios.bios_power_on * self.BIOS_WEIGHT + ...
|
|
||||||
return cls(funcionality=functionality)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TODO Check if funcionality aspect is != NULL
|
|
||||||
sim = FunctionalityDevice.sim * self.SIM_WEIGHT
|
|
||||||
usb = FunctionalityDevice.usb * self.USB_WEIGHT
|
|
||||||
wifi = FunctionalityDevice.wifi * self.WIFI_WEIGHT
|
|
||||||
bt = FunctionalityDevice.bt * self.BLUETOOTH_WEIGHT
|
|
||||||
fingerprint = FunctionalityDevice.fingerprint * self.FINGERPRINT_WEIGHT
|
|
||||||
loudspeaker = FunctionalityDevice.loudspeaker * self.LOUDSPEAKER_WEIGHT
|
|
||||||
microphone = FunctionalityDevice.microphone * self.MICROPHONE_WEIGHT
|
|
||||||
|
|
||||||
functionality_rate = (sim + usb + wifi + bt + fingerprint + loudspeaker + microphone)
|
|
||||||
# TODO Add functionality range (buttons, chassis, display defects, camera defects)
|
|
||||||
return functionality_rate
|
|
||||||
|
|
||||||
|
|
||||||
class Appearance(Range):
|
|
||||||
"""
|
|
||||||
APPEARANCE GRADE [0.5,-0.5]
|
|
||||||
Enum(AppearanceRangev2)
|
|
||||||
"""
|
|
||||||
|
|
||||||
Z = 0.5
|
|
||||||
A = 0.4
|
|
||||||
B = 0.1
|
|
||||||
C = -0.1
|
|
||||||
D = -0.25
|
|
||||||
E = -0.5
|
|
||||||
NONE = -0.3
|
|
||||||
|
|
||||||
|
|
||||||
class DisplayRate(QualityRate):
|
|
||||||
"""
|
|
||||||
Calculate a DisplayRate
|
|
||||||
"""
|
|
||||||
SIZE_NORM = 3.5, 7.24
|
|
||||||
RESOLUTION_H_NORM = 440, 1080
|
|
||||||
RESOLUTION_W_NORM = 720, 2048
|
|
||||||
|
|
||||||
DISPLAY_WEIGHTS = 0.6, 0.2, 0.2
|
|
||||||
|
|
||||||
def compute(self, display: Display):
|
|
||||||
size = display.size or self.DEFAULT_SIZE
|
|
||||||
resolution_h = display.resolution_h or 0
|
|
||||||
resolution_w = display.resolution_w or 0
|
|
||||||
|
|
||||||
# STEP: Normalize values
|
|
||||||
size_norm = max(self.norm(size, *self.SIZE_NORM), 0)
|
|
||||||
resolution_h_norm = max(self.norm(resolution_h, *self.RESOLUTION_H_NORM), 0)
|
|
||||||
resolution_w_norm = max(self.norm(resolution_w, *self.RESOLUTION_W_NORM), 0)
|
|
||||||
|
|
||||||
# STEP: Fusion Characteristics
|
|
||||||
return self.harmonic_mean(self.DISPLAY_WEIGHTS, rates=(size_norm, resolution_h_norm, resolution_w_norm))
|
|
||||||
|
|
||||||
|
|
||||||
# COMPONENTS RATE V1 (PROCESSOR,RAM,HHD)
|
|
||||||
|
|
||||||
# TODO quality components rate qualityrate class??
|
|
||||||
|
|
||||||
class ProcessorRate(QualityRate):
|
|
||||||
"""
|
|
||||||
Calculate a ProcessorRate
|
|
||||||
"""
|
|
||||||
# processor.xMin, processor.xMax
|
|
||||||
PROCESSOR_NORM = 3196.17, 17503.81
|
|
||||||
CORES_NORM = 1, 6
|
|
||||||
|
|
||||||
DEFAULT_CORES = 1
|
|
||||||
DEFAULT_SPEED = 1.6
|
|
||||||
DEFAULT_SCORE = 4000
|
|
||||||
|
|
||||||
PROCESSOR_WEIGHTS = 0.5, 0.5
|
|
||||||
|
|
||||||
def compute(self, processor: Processor):
|
|
||||||
""" Compute processor rate
|
|
||||||
Obs: cores and speed are possible NULL value
|
|
||||||
:return: result is a rate (score) of Processor characteristics
|
|
||||||
"""
|
|
||||||
cores = processor.cores or self.DEFAULT_CORES
|
|
||||||
speed = processor.speed or self.DEFAULT_SPEED
|
|
||||||
|
|
||||||
# STEP: Normalize values
|
|
||||||
cores_norm = max(self.norm(cores, *self.PROCESSOR_NORM), 0)
|
|
||||||
cpu_speed_norm = max(self.norm(speed, *self.CORES_NORM), 0)
|
|
||||||
|
|
||||||
# STEP: Fusion Characteristics
|
|
||||||
return self.harmonic_mean(self.PROCESSOR_WEIGHTS, rates=(cores_norm, cpu_speed_norm))
|
|
||||||
|
|
||||||
|
|
||||||
class RamRate(QualityRate):
|
|
||||||
"""
|
|
||||||
Calculate a RamRate of all RamModule devices
|
|
||||||
"""
|
|
||||||
# ram.size.xMin; ram.size.xMax
|
|
||||||
SIZE_NORM = 256, 8192
|
|
||||||
RAM_SPEED_NORM = 133, 1333
|
|
||||||
# ram.speed.factor
|
|
||||||
RAM_SPEED_FACTOR = 3.7
|
|
||||||
# ram.size.weight; ram.speed.weight;
|
|
||||||
RAM_WEIGHTS = 0.7, 0.3
|
|
||||||
|
|
||||||
def compute(self, ram_devices: Iterable[RamModule]):
|
|
||||||
"""
|
|
||||||
Obs: RamModule.speed is possible NULL value & size != NULL or NOT??
|
|
||||||
:return: result is a rate (score) of all RamModule components
|
|
||||||
"""
|
|
||||||
size = 0.0
|
|
||||||
speed = 0.0
|
|
||||||
|
|
||||||
# STEP: Filtering, data cleaning and merging of component parts
|
|
||||||
for ram in ram_devices:
|
|
||||||
_size = ram.size or 0
|
|
||||||
size += _size
|
|
||||||
|
|
||||||
_speed = ram.speed or 0
|
|
||||||
speed += _speed
|
|
||||||
|
|
||||||
# STEP: Normalize values
|
|
||||||
size_norm = max(self.norm(size, *self.SIZE_NORM), 0)
|
|
||||||
ram_speed_norm = max(self.norm(speed, *self.RAM_SPEED_NORM), 0)
|
|
||||||
|
|
||||||
# STEP: Fusion Characteristics
|
|
||||||
return self.harmonic_mean(self.RAM_WEIGHTS, rates=(size_norm, ram_speed_norm))
|
|
||||||
|
|
||||||
|
|
||||||
class DataStorageRate(QualityRate):
|
|
||||||
"""
|
|
||||||
Calculate the rate of all DataStorage devices
|
|
||||||
"""
|
|
||||||
# drive.size.xMin; drive.size.xMax
|
|
||||||
SIZE_NORM = 4096, 265000
|
|
||||||
READ_SPEED_NORM = 2.7, 109.5
|
|
||||||
WRITE_SPEED_NORM = 2, 27.35
|
|
||||||
# drive.size.weight; drive.readingSpeed.weight; drive.writingSpeed.weight;
|
|
||||||
DATA_STORAGE_WEIGHTS = 0.5, 0.25, 0.25
|
|
||||||
|
|
||||||
def compute(self, data_storage_devices: Iterable[DataStorage], rate: WorkbenchRate):
|
|
||||||
"""
|
|
||||||
Obs: size != NULL and 0 value & read_speed and write_speed != NULL
|
|
||||||
:return: result is a rate (score) of all DataStorage devices
|
|
||||||
"""
|
|
||||||
size = 0
|
|
||||||
read_speed = 0
|
|
||||||
write_speed = 0
|
|
||||||
|
|
||||||
# STEP: Filtering, data cleaning and merging of component parts
|
|
||||||
for storage in data_storage_devices:
|
|
||||||
# todo fix StopIteration if don't exists BenchmarkDataStorage
|
|
||||||
benchmark = next(e for e in storage.events if isinstance(e, BenchmarkDataStorage))
|
|
||||||
# prevent NULL values
|
|
||||||
_size = storage.size or 0
|
|
||||||
size += _size
|
|
||||||
read_speed += benchmark.read_speed * _size
|
|
||||||
write_speed += benchmark.write_speed * _size
|
|
||||||
|
|
||||||
# STEP: Fusion components
|
|
||||||
# Check almost one storage have size, try catch exception 0/0
|
|
||||||
if size:
|
|
||||||
read_speed /= size
|
|
||||||
write_speed /= size
|
|
||||||
|
|
||||||
# STEP: Normalize values
|
|
||||||
size_norm = max(self.norm(size, *self.SIZE_NORM), 0)
|
|
||||||
read_speed_norm = max(self.norm(read_speed, *self.READ_SPEED_NORM), 0)
|
|
||||||
write_speed_norm = max(self.norm(write_speed, *self.WRITE_SPEED_NORM), 0)
|
|
||||||
|
|
||||||
# STEP: Fusion Characteristics
|
|
||||||
return self.harmonic_mean(self.DATA_STORAGE_WEIGHTS,
|
|
||||||
rates=(size_norm, read_speed_norm, write_speed_norm))
|
|
||||||
|
|
||||||
|
|
||||||
class BatteryRate(QualityRate):
|
|
||||||
"""
|
|
||||||
Rate Battery component if device Type = {Mobile Devices}
|
|
||||||
"""
|
|
||||||
CAPACITY_NORM = 2200, 6000
|
|
||||||
DEFAULT_CAPACITY = 3000
|
|
||||||
|
|
||||||
def compute(self, display: Display):
|
|
||||||
capacity = battery.capacity or self.DEFAULT_CAPACITY
|
|
||||||
|
|
||||||
# STEP: Normalize values
|
|
||||||
capacity_norm = max(self.norm(capacity, *self.CAPACITY_NORM), 0)
|
|
||||||
|
|
||||||
return capacity_norm
|
|
||||||
|
|
||||||
|
|
||||||
class CameraRate(QualityRate):
|
|
||||||
"""
|
|
||||||
Rate camera component if exist on device
|
|
||||||
"""
|
|
||||||
RESOLUTION_NORM = 2200, 6000
|
|
||||||
DEFAULT_RESOLUTION = 16
|
|
||||||
|
|
||||||
def compute(self, display: Display):
|
|
||||||
resolution = camera.resolution or self.DEFAULT_RESOLUTION
|
|
||||||
|
|
||||||
# STEP: Normalize values
|
|
||||||
resolution_norm = max(self.norm(resolution, *self.RESOLUTION_NORM), 0)
|
|
||||||
|
|
||||||
return resolution_norm
|
|
Reference in a new issue