first commit refactor score
This commit is contained in:
parent
17705e459e
commit
825c07c5f9
|
@ -18,23 +18,6 @@ class SnapshotSoftware(Enum):
|
|||
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_NEGATIVE = -3, 5
|
||||
|
||||
|
@ -126,7 +109,7 @@ class FunctionalityRange(Enum):
|
|||
return self.name
|
||||
|
||||
|
||||
FUNCTIONALITY_RANGE = -0.25, 0.5
|
||||
FUNCTIONALITY_RANGE = -0.3, 0.4
|
||||
|
||||
|
||||
@unique
|
||||
|
@ -142,8 +125,9 @@ class BatteryHealthRange(Enum):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@unique
|
||||
class Bios(Enum):
|
||||
class BiosAccessRange(Enum):
|
||||
"""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'
|
||||
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
|
||||
|
||||
|
||||
# TODO add all grade tables (chassis defects, camera defects, buttons test, connectivity, ..)
|
||||
|
||||
@unique
|
||||
class Orientation(Enum):
|
||||
Vertical = 'vertical'
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from collections import Iterable
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_UP
|
||||
from distutils.version import StrictVersion
|
||||
from typing import Optional, Set, Union
|
||||
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.device.models import Component, Computer, DataStorage, Desktop, \
|
||||
Device, Laptop, Server
|
||||
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, ErasureStandards, \
|
||||
FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
|
||||
RatingRange, RatingSoftware, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \
|
||||
TestDataStorageLength, FUNCTIONALITY_RANGE, FunctionalityRange, AppearanceRange, BatteryHealthRange
|
||||
from ereuse_devicehub.resources.enums import BiosAccessRange, ErasureStandards, \
|
||||
PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
|
||||
RatingRange, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \
|
||||
TestDataStorageLength, FunctionalityRange, AppearanceRange, BatteryHealthRange
|
||||
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
||||
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??
|
||||
"""
|
||||
loudspeaker = Column(BDEnum(LoudspeakerRange))
|
||||
loudspeaker = Column(Boolean)
|
||||
loudspeaker.comment = 'Test to determine if the speaker is working properly and what sound quality it has.'
|
||||
microphone = Column(Boolean)
|
||||
microphone.comment = 'This evaluate if microphone works correctly'
|
||||
|
@ -730,6 +729,7 @@ class TestConnectivity(Test):
|
|||
locked = Column(Boolean)
|
||||
locked.comment = 'Test to check if devices is locked'
|
||||
|
||||
|
||||
class TestBattery(Test):
|
||||
"""
|
||||
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..
|
||||
"""
|
||||
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):
|
||||
|
@ -795,6 +795,12 @@ class TestVisual(ManualRate):
|
|||
functionality_range = Column(DBEnum(FunctionalityRange))
|
||||
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):
|
||||
"""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.comment = """The rating for the content."""
|
||||
software = Column(DBEnum(RatingSoftware))
|
||||
software.comment = """The algorithm used to produce this rating."""
|
||||
version = Column(StrictVersionType)
|
||||
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
|
||||
def rating_range(self) -> RatingRange:
|
||||
|
@ -835,7 +842,15 @@ class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
return args
|
||||
|
||||
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):
|
||||
|
@ -852,332 +867,24 @@ class RateComputer(Rate):
|
|||
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')
|
||||
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))
|
||||
bios_range = Column(DBEnum(Bios))
|
||||
bios_range.comment = Bios.__doc__
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
|
||||
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
|
||||
def data_storage_range(self):
|
||||
if self.data_storage:
|
||||
return RatingRange.from_score(self.data_storage)
|
||||
|
||||
def compute_rate(self):
|
||||
"""
|
||||
The act of compute general computer rate
|
||||
"""
|
||||
pass
|
||||
@property
|
||||
def ram_range(self):
|
||||
if self.ram:
|
||||
return RatingRange.from_score(self.ram)
|
||||
|
||||
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 = [
|
||||
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
|
||||
@property
|
||||
def processor_range(self):
|
||||
if self.processor:
|
||||
return RatingRange.from_score(self.processor)
|
||||
|
||||
|
||||
class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||
|
@ -1205,15 +912,15 @@ class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
|||
"""
|
||||
version = Column(StrictVersionType)
|
||||
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
|
||||
this price, if it has not been set manually."""
|
||||
rating = relationship(FinalRate,
|
||||
rating = relationship(Rate,
|
||||
backref=backref('price',
|
||||
lazy=True,
|
||||
cascade=CASCADE_OWN,
|
||||
uselist=False),
|
||||
primaryjoin=AggregateRate.id == rating_id)
|
||||
primaryjoin=RateComputer.id == rating_id)
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
if 'price' in kwargs:
|
||||
|
@ -1307,7 +1014,7 @@ class EreusePrice(Price):
|
|||
if self.WARRANTY2 in rate:
|
||||
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:
|
||||
raise ValueError('Cannot compute price for Range.VERY_LOW')
|
||||
# We pass ROUND_UP strategy so price is always greater than what refurbisher... amounts
|
||||
|
|
|
@ -123,6 +123,37 @@ class StepRandom(Step):
|
|||
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):
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
|
@ -154,11 +185,124 @@ class SnapshotRequest(Model):
|
|||
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):
|
||||
rating = ... # type: Column
|
||||
appearance = ... # type: Column
|
||||
functionality = ... # type: Column
|
||||
software = ... # type: Column
|
||||
version = ... # type: Column
|
||||
|
||||
def __init__(self, **kwargs) -> None:
|
||||
|
@ -171,118 +315,11 @@ class Rate(EventWithOneDevice):
|
|||
self.rating_range = ... # type: str
|
||||
|
||||
|
||||
class IndividualRate(Rate):
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
self.aggregated_ratings = ... # type: Set[AggregateRate]
|
||||
|
||||
|
||||
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 RateComputer(Rate):
|
||||
id = ...
|
||||
processor = ...
|
||||
ram = ...
|
||||
data_storage = ...
|
||||
|
||||
|
||||
class Price(EventWithOneDevice):
|
||||
|
@ -331,101 +368,6 @@ class EreusePrice(Price):
|
|||
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):
|
||||
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.enums import RatingSoftware
|
||||
from ereuse_devicehub.resources.event.models import AggregateRate, EreusePrice, Rate, \
|
||||
WorkbenchRate
|
||||
from ereuse_devicehub.resources.event.models import RateComputer
|
||||
from ereuse_devicehub.resources.event.rate.workbench import v1_0
|
||||
|
||||
RATE_TYPES = {
|
||||
WorkbenchRate: {
|
||||
RatingSoftware.ECost: {
|
||||
'1.0': v1_0.Rate()
|
||||
},
|
||||
RatingSoftware.EMarket: {
|
||||
}
|
||||
RateComputer: {
|
||||
'1.0': v1_0.Rate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def rate(device: Device, rate: Rate):
|
||||
def rate(device: Device, version):
|
||||
"""
|
||||
Rates the passed-in ``rate`` using values from the rate itself
|
||||
and the ``device``.
|
||||
|
@ -29,50 +19,7 @@ def rate(device: Device, rate: Rate):
|
|||
:param device: The device to use as a model.
|
||||
:param rate: A half-filled rate.
|
||||
"""
|
||||
cls = rate.__class__
|
||||
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][rate.software], \
|
||||
assert str(rate.version) in RATE_TYPES[cls], \
|
||||
'Rate version {} not supported.'.format(rate.version)
|
||||
RATE_TYPES[cls][rate.software][str(rate.version)].compute(device, rate)
|
||||
|
||||
|
||||
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
|
||||
RATE_TYPES[cls][str(rate.version)].compute(device)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import math
|
||||
from typing import Iterable
|
||||
|
||||
import math
|
||||
|
||||
from ereuse_devicehub.resources.device.models import Device
|
||||
from ereuse_devicehub.resources.event.models import WorkbenchRate
|
||||
|
||||
|
||||
class BaseRate:
|
||||
|
@ -20,7 +20,7 @@ class BaseRate:
|
|||
"""Ram has 30% of weight over total score, used in harmonic mean"""
|
||||
RAM_WEIGHT = 0.3
|
||||
|
||||
def compute(self, device: Device, rate: WorkbenchRate):
|
||||
def compute(self, device: Device):
|
||||
raise NotImplementedError()
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -5,13 +5,13 @@ from typing import Iterable
|
|||
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Desktop, Laptop, \
|
||||
Processor, RamModule, Server
|
||||
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
|
||||
WorkbenchRate
|
||||
RateComputer, TestVisual
|
||||
# todo if no return assign then rate_c = 1 is assigned
|
||||
# todo fix corner cases, like components characteristics == None
|
||||
from ereuse_devicehub.resources.event.rate.rate import BaseRate
|
||||
|
||||
|
||||
class Rate(BaseRate):
|
||||
class RateAlgorithm(BaseRate):
|
||||
"""
|
||||
Rate all components in Computer
|
||||
"""
|
||||
|
@ -46,15 +46,16 @@ class Rate(BaseRate):
|
|||
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.
|
||||
|
||||
This mutates "rate".
|
||||
"""
|
||||
assert isinstance(device, (Desktop, Laptop, Server))
|
||||
assert isinstance(rate, WorkbenchRate)
|
||||
|
||||
rate = RateComputer()
|
||||
|
||||
rate.processor = rate.data_storage = rate.ram = 1 # Init
|
||||
|
||||
|
@ -71,8 +72,8 @@ class Rate(BaseRate):
|
|||
setattr(rate, field, result)
|
||||
|
||||
rate_components = self.harmonic_mean_rates(rate.processor, rate.data_storage, rate.ram)
|
||||
rate.appearance = self.Appearance.from_devicehub(rate.appearance_range).value
|
||||
rate.functionality = self.Functionality.from_devicehub(rate.functionality_range).value
|
||||
rate.appearance = self.Appearance.from_devicehub(TestVisual.appearance_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.appearance = round(rate.appearance, 2)
|
||||
|
@ -80,6 +81,8 @@ class Rate(BaseRate):
|
|||
rate.processor = round(rate.processor, 2)
|
||||
rate.ram = round(rate.ram, 2)
|
||||
rate.data_storage = round(rate.data_storage, 2)
|
||||
device.events_one.add(rate)
|
||||
return rate
|
||||
|
||||
|
||||
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.
|
||||
DEFAULT_SCORE = 4000
|
||||
|
||||
def compute(self, processor: Processor, rate: WorkbenchRate):
|
||||
def compute(self, processor: Processor, rate: RateComputer):
|
||||
""" Compute processor rate
|
||||
Obs: cores and speed are possible NULL value
|
||||
:return: result is a rate (score) of Processor characteristics
|
||||
|
@ -139,7 +142,7 @@ class RamRate(BaseRate):
|
|||
# ram.size.weight; ram.speed.weight;
|
||||
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??
|
||||
: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;
|
||||
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
|
||||
:return: result is a rate (score) of all DataStorage devices
|
||||
|
@ -252,3 +255,6 @@ class DataStorageRate(BaseRate):
|
|||
# STEP: Fusion Characteristics
|
||||
return self.harmonic_mean(self.DATA_STORAGE_WEIGHTS,
|
||||
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