first commit rate v2; adding Quality, Functionality Rates class
This commit is contained in:
parent
15f705dd50
commit
ddb1877133
|
@ -119,6 +119,21 @@ class FunctionalityRange(Enum):
|
|||
return self.name
|
||||
|
||||
|
||||
FUNCTIONALITY_RANGE = -0.25, 0.5
|
||||
|
||||
|
||||
@unique
|
||||
class FunctionalityRangev2(Enum):
|
||||
"""Grade the buttons and chassis that affect its usage, like screen defect or camera defects"""
|
||||
A = 'A. All the buttons works perfectly, no screen/camera defects and chassis without issues'
|
||||
B = 'B. There is a button difficult to press or unstable it, a screen/camera defect or chassis problem'
|
||||
C = 'C. Multiple buttons don\'t work; broken or unusable it, some screen/camera defects and chassis problems'
|
||||
D = 'D. All buttons. screen or chassis don\'t work; broken or unusable it, difficult to usage.'
|
||||
NONE = 'NA. Grade doesn’t exists'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@unique
|
||||
class Bios(Enum):
|
||||
"""How difficult it has been to set the bios to boot from the network."""
|
||||
|
@ -132,6 +147,8 @@ class Bios(Enum):
|
|||
return self.name
|
||||
|
||||
|
||||
# TODO add all grade tables (chassis defects, camera defects, buttons test, connectivity, ..)
|
||||
|
||||
@unique
|
||||
class Orientation(Enum):
|
||||
Vertical = 'vertical'
|
||||
|
|
|
@ -31,7 +31,8 @@ from ereuse_devicehub.resources.device.models import Component, Computer, DataSt
|
|||
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, ErasureStandards, \
|
||||
FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
|
||||
RatingRange, RatingSoftware, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \
|
||||
TestDataStorageLength
|
||||
TestDataStorageLength, FUNCTIONALITY_RANGE, FunctionalityRangev2
|
||||
from ereuse_devicehub.resources.event.rate.workbench.v2_0 import QualityRate, FunctionalityRate
|
||||
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
|
||||
|
@ -650,7 +651,7 @@ class ManualRate(IndividualRate):
|
|||
raise NotImplementedError()
|
||||
|
||||
|
||||
class WorkbenchRate(ManualRate):
|
||||
class WorkbenchComputerRate(ManualRate):
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id), primary_key=True)
|
||||
processor = Column(Float(decimal_return_scale=2), check_range('processor', *RATE_POSITIVE))
|
||||
ram = Column(Float(decimal_return_scale=2), check_range('ram', *RATE_POSITIVE))
|
||||
|
@ -696,6 +697,172 @@ class WorkbenchRate(ManualRate):
|
|||
return RatingRange.from_score(self.graphic_card)
|
||||
|
||||
|
||||
""" QUALITY RATE CODE START HERE """
|
||||
|
||||
|
||||
class QualityRate(Rate):
|
||||
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.')
|
||||
|
||||
@property
|
||||
def ram_range(self):
|
||||
return self.workbench.ram_range
|
||||
|
||||
@property
|
||||
def processor_range(self):
|
||||
return self.workbench.processor_range
|
||||
|
||||
@property
|
||||
def display_range(self):
|
||||
return self.workbench.data_storage_range
|
||||
|
||||
@property
|
||||
def data_storage_range(self):
|
||||
return self.workbench.data_storage_range
|
||||
|
||||
@property
|
||||
def battery_range(self):
|
||||
return self.workbench.ram_range
|
||||
|
||||
@property
|
||||
def camera_range(self):
|
||||
return self.workbench_mobile.camera_range
|
||||
|
||||
@property
|
||||
def graphic_card_range(self):
|
||||
return self.workbench_mobil.graphic_card_range
|
||||
|
||||
|
||||
class QualityRateComputer(QualityRate):
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(QualityRate.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')
|
||||
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__
|
||||
|
||||
# todo ensure for WorkbenchRate version and software are not None when inserting them
|
||||
|
||||
def ratings(self):
|
||||
"""
|
||||
#Computes all the possible rates taking this rating as a model.
|
||||
|
||||
#Returns a set of ratings, including this one, which is mutated,
|
||||
#and the final :class:`.AggregateRate`.
|
||||
"""
|
||||
from ereuse_devicehub.resources.event.rate.main import main
|
||||
return main(self, **app.config.get_namespace('WORKBENCH_RATE_'))
|
||||
|
||||
@property
|
||||
def graphic_card_range(self):
|
||||
if self.graphic_card:
|
||||
return RatingRange.from_score(self.graphic_card)
|
||||
|
||||
@property
|
||||
def network_adapter_range(self):
|
||||
return self.workbench_mobil.network_adapter_range
|
||||
|
||||
@property
|
||||
def bios_range(self):
|
||||
return self.workbench_mobil.bios_range
|
||||
|
||||
|
||||
class QualityRateMobile(QualityRate):
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(QualityRate.id), primary_key=True)
|
||||
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')
|
||||
|
||||
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__
|
||||
|
||||
# todo ensure for WorkbenchRate version and software are not None when inserting them
|
||||
|
||||
def ratings(self):
|
||||
"""
|
||||
#Computes all the possible rates taking this rating as a model.
|
||||
"""
|
||||
from ereuse_devicehub.resources.event.rate.main import main
|
||||
return main(self, **app.config.get_namespace('WORKBENCH_RATE_'))
|
||||
|
||||
@property
|
||||
def display_range(self):
|
||||
if self.data_storage:
|
||||
return RatingRange.from_score(self.data_storage)
|
||||
|
||||
@property
|
||||
def battery_range(self):
|
||||
if self.ram:
|
||||
return RatingRange.from_score(self.ram)
|
||||
|
||||
@property
|
||||
def camera_range(self):
|
||||
if self.processor:
|
||||
return RatingRange.from_score(self.processor)
|
||||
|
||||
@property
|
||||
def graphic_card_range(self):
|
||||
if self.graphic_card:
|
||||
return RatingRange.from_score(self.graphic_card)
|
||||
|
||||
|
||||
class FunctionalityRate(Rate):
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
|
||||
functionality = Column(Float(decimal_return_scale=2), check_range('functionality', *FUNCTIONALITY_RANGE))
|
||||
functionality.comment = 'Functionality rate of a device'
|
||||
|
||||
functionality_range = Column(DBEnum(FunctionalityRangev2))
|
||||
functionality_range.comment = FunctionalityRangev2.__doc__
|
||||
|
||||
connectivity = Column(Float(decimal_return_scale=2),
|
||||
comment='This punctuation covers a series of aspects related to connectivity.')
|
||||
audio = Column(Float(decimal_return_scale=2), comment='Take into account loudspeaker and microphone')
|
||||
|
||||
@property
|
||||
def connectivity_rate(self):
|
||||
yield
|
||||
|
||||
@property
|
||||
def audio_rate(self):
|
||||
yield
|
||||
|
||||
@property
|
||||
def test_buttonse(self):
|
||||
yield
|
||||
|
||||
@classmethod
|
||||
def test_camera_defects(self):
|
||||
yield
|
||||
|
||||
|
||||
class FinalRate(Rate):
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
|
||||
|
||||
|
||||
class AggregateRate(Rate):
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
|
||||
manual_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id))
|
||||
|
@ -711,16 +878,16 @@ class AggregateRate(Rate):
|
|||
order_by=lambda: AggregateRate.created,
|
||||
collection_class=OrderedSet),
|
||||
primaryjoin=manual_id == ManualRate.id)
|
||||
workbench_id = Column(UUID(as_uuid=True), ForeignKey(WorkbenchRate.id))
|
||||
workbench_id = Column(UUID(as_uuid=True), ForeignKey(QualityRateComputer.id))
|
||||
workbench_id.comment = """The WorkbenchRate used to generate
|
||||
this aggregation, or None if none used.
|
||||
"""
|
||||
workbench = relationship(WorkbenchRate,
|
||||
workbench = relationship(QualityRateComputer,
|
||||
backref=backref('aggregate_rate_workbench',
|
||||
lazy=True,
|
||||
order_by=lambda: AggregateRate.created,
|
||||
collection_class=OrderedSet),
|
||||
primaryjoin=workbench_id == WorkbenchRate.id)
|
||||
primaryjoin=workbench_id == QualityRateComputer.id)
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
kwargs.setdefault('version', StrictVersion('1.0'))
|
||||
|
@ -781,7 +948,198 @@ class AggregateRate(Rate):
|
|||
return self.workbench.labelling
|
||||
|
||||
@classmethod
|
||||
def from_workbench_rate(cls, rate: WorkbenchRate):
|
||||
def from_workbench_rate(cls, rate: QualityRateComputer):
|
||||
aggregate = cls()
|
||||
aggregate.rating = rate.rating
|
||||
aggregate.software = rate.software
|
||||
aggregate.appearance = rate.appearance
|
||||
aggregate.functionality = rate.functionality
|
||||
aggregate.device = rate.device
|
||||
aggregate.workbench = rate
|
||||
return aggregate
|
||||
|
||||
|
||||
####################################################################################
|
||||
|
||||
|
||||
class ResultRate(Rate):
|
||||
"""The act of grading the appearance, quality (performance), and functionality
|
||||
of a device.
|
||||
|
||||
There are five categories of ``Rate``:
|
||||
1. ``Quality``. How good is the machine, in terms of performance.
|
||||
2. ``Functionality``.
|
||||
3. ``Appearance``.
|
||||
4. ``Market value``.
|
||||
5. ``Cost of repair``.
|
||||
|
||||
|
||||
There are types of rating a device:
|
||||
|
||||
1. Rate Quality
|
||||
2. Rate Functionality
|
||||
3. Rate Final
|
||||
|
||||
|
||||
List of source where can input information of rating a device:
|
||||
|
||||
1. When processing the device with Workbench Computer/Mobile.
|
||||
2. Using the Android App (through Scan).
|
||||
3.
|
||||
4. Anytime after manually written in a form in the website.
|
||||
"""
|
||||
|
||||
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
|
||||
quality_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id))
|
||||
quality_id.comment = """The Quality Rate used to generate this
|
||||
aggregation, or None if none used.
|
||||
"""
|
||||
|
||||
func_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id))
|
||||
func_id.comment = """The Functionality Rate used to generate this
|
||||
aggregation, or None if none used.
|
||||
"""
|
||||
|
||||
final_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id))
|
||||
final_id.comment = """The Final Rate used to generate this
|
||||
aggregation, or None if none used.
|
||||
"""
|
||||
|
||||
""" MANUAL INPUT """
|
||||
manual_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id))
|
||||
manual_id.comment = """The ManualEvent used to generate this
|
||||
aggregation, or None if none used.
|
||||
|
||||
An example of ManualEvent is using the web or the Android app
|
||||
to rate a device.
|
||||
"""
|
||||
manual = relationship(ManualRate,
|
||||
backref=backref('aggregate_rate_manual',
|
||||
lazy=True,
|
||||
order_by=lambda: ResultRate.created,
|
||||
collection_class=OrderedSet),
|
||||
primaryjoin=manual_id == ManualRate.id)
|
||||
|
||||
""" WORKBENCH COMPUTER """
|
||||
workbench_computer_id = Column(UUID(as_uuid=True), ForeignKey(QualityRateComputer.id))
|
||||
workbench_computer_id.comment = """The WorkbenchRate used to generate
|
||||
this aggregation, or None if none used.
|
||||
"""
|
||||
workbench_computer = relationship(QualityRateComputer,
|
||||
backref=backref('aggregate_rate_workbench',
|
||||
lazy=True,
|
||||
order_by=lambda: ResultRate.created,
|
||||
collection_class=OrderedSet),
|
||||
primaryjoin=workbench_computer_id == QualityRateComputer.id)
|
||||
|
||||
""" WORKBENCH MOBILE """
|
||||
|
||||
workbench_mobile_id = Column(UUID(as_uuid=True), ForeignKey(QualityRateMobile.id))
|
||||
workbench_mobile_id.comment = """The WorkbenchRate used to generate
|
||||
this aggregation, or None if none used.
|
||||
"""
|
||||
workbench_mobile = relationship(QualityRateMobile,
|
||||
backref=backref('aggregate_rate_workbench',
|
||||
lazy=True,
|
||||
order_by=lambda: ResultRate.created,
|
||||
collection_class=OrderedSet),
|
||||
primaryjoin=workbench_mobile_id == QualityRateMobile.id)
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
kwargs.setdefault('version', StrictVersion('1.0'))
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def quality_rate(cls, quality: QualityRate):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def functionality_rate(cls, func: FunctionalityRate):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def final_rate(cls, rate: Rate):
|
||||
pass
|
||||
|
||||
# Categories
|
||||
|
||||
@classmethod
|
||||
def quality_category(cls, quality: QualityRate):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def functionality_category(cls, quality: QualityRate):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def appearance_category(cls, quality: QualityRate):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def maket_value_category(cls, quality: QualityRate):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def cost_of_repair_category(cls, quality: QualityRate):
|
||||
pass
|
||||
|
||||
|
||||
# todo take value from LAST event (manual or workbench)
|
||||
|
||||
@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 data_storage_range(self):
|
||||
return self.workbench.data_storage_range
|
||||
|
||||
@property
|
||||
def ram_range(self):
|
||||
return self.workbench.ram_range
|
||||
|
||||
@property
|
||||
def processor_range(self):
|
||||
return self.workbench.processor_range
|
||||
|
||||
@property
|
||||
def graphic_card_range(self):
|
||||
return self.workbench.graphic_card_range
|
||||
|
||||
@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: QualityRateComputer):
|
||||
aggregate = cls()
|
||||
aggregate.rating = rate.rating
|
||||
aggregate.software = rate.software
|
||||
|
|
|
@ -0,0 +1,301 @@
|
|||
from enum import Enum
|
||||
from typing import Iterable
|
||||
|
||||
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Desktop, Laptop, \
|
||||
Processor, RamModule, Server, Device
|
||||
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
|
||||
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
|
||||
|
||||
def compute(self, FunctionalityDevice: FunctionalityRate):
|
||||
"""
|
||||
|
||||
:param FunctionalityDevice: List[Boolean]
|
||||
:return:
|
||||
"""
|
||||
# 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]
|
||||
"""
|
||||
|
||||
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
|
|
@ -14,7 +14,7 @@ from ereuse_devicehub.resources.agent import schemas as s_agent
|
|||
from ereuse_devicehub.resources.device import schemas as s_device
|
||||
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, FunctionalityRange, \
|
||||
PhysicalErasureMethod, PriceSoftware, RATE_POSITIVE, RatingRange, RatingSoftware, ReceiverRole, \
|
||||
Severity, SnapshotExpectedEvents, SnapshotSoftware, TestDataStorageLength
|
||||
Severity, SnapshotExpectedEvents, SnapshotSoftware, TestDataStorageLength, FunctionalityRangev2
|
||||
from ereuse_devicehub.resources.event import models as m
|
||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
|
@ -109,6 +109,7 @@ class StepRandom(Step):
|
|||
__doc__ = m.StepRandom.__doc__
|
||||
|
||||
|
||||
|
||||
class Rate(EventWithOneDevice):
|
||||
__doc__ = m.Rate.__doc__
|
||||
rating = Integer(validate=Range(*RATE_POSITIVE),
|
||||
|
@ -157,6 +158,28 @@ class WorkbenchRate(ManualRate):
|
|||
graphic_card_range = EnumField(RatingRange, dump_only=True, data_key='graphicCardRange')
|
||||
|
||||
|
||||
"""
|
||||
WORKBENCH RATE COMPUTER
|
||||
Adaptation of old class WorkbenchRate
|
||||
"""
|
||||
|
||||
|
||||
class WorkbenchRateComputer(ManualRate):
|
||||
__doc__ = m.WorkbenchRate.__doc__
|
||||
processor = Float()
|
||||
ram = Float()
|
||||
data_storage = Float()
|
||||
graphic_card = Float()
|
||||
bios = Float()
|
||||
bios_range = EnumField(Bios,
|
||||
description=m.WorkbenchComputerRate.bios_range.comment,
|
||||
data_key='biosRange')
|
||||
data_storage_range = EnumField(RatingRange, dump_only=True, data_key='dataStorageRange')
|
||||
ram_range = EnumField(RatingRange, dump_only=True, data_key='ramRange')
|
||||
processor_range = EnumField(RatingRange, dump_only=True, data_key='processorRange')
|
||||
graphic_card_range = EnumField(RatingRange, dump_only=True, data_key='graphicCardRange')
|
||||
|
||||
|
||||
class AggregateRate(Rate):
|
||||
__doc__ = m.AggregateRate.__doc__
|
||||
workbench = NestedOn(WorkbenchRate, dump_only=True,
|
||||
|
@ -187,6 +210,106 @@ class AggregateRate(Rate):
|
|||
graphic_card_range = EnumField(RatingRange, dump_only=True, data_key='graphicCardRange')
|
||||
|
||||
|
||||
class QualityRate(Rate):
|
||||
__doc__ = m.QualityRate.__doc__
|
||||
|
||||
ram = Float(dump_only=True, description=m.QualityRate.ram.comment)
|
||||
processor = Float(dump_only=True, description=m.QualityRate.processor.comment)
|
||||
data_storage = Float(dump_only=True, description=m.QualityRate.data_storage.comment)
|
||||
|
||||
|
||||
""" New class for WorkbenchRate in Rate v2"""
|
||||
|
||||
|
||||
class QualityRateComputer(Rate):
|
||||
__doc__ = m.QualityRateComputer.__doc__
|
||||
|
||||
""" List of components appears in general quality rate a device
|
||||
|
||||
ram = Float(dump_only=True, description=m.QualityRateComputer.ram.comment)
|
||||
processor = Float(dump_only=True, description=m.QualityRateComputer.processor.comment)
|
||||
data_storage = Float(dump_only=True, description=m.QualityRateComputer.data_storage.comment)
|
||||
"""
|
||||
|
||||
graphic_card = Float(dump_only=True, description=m.QualityRateComputer.processor.comment)
|
||||
network_adapter = Float(dump_only=True, description=m.QualityRateComputer.network_adapter.comment)
|
||||
|
||||
|
||||
class QualityRateMobile(Rate):
|
||||
__doc__ = m.QualityRateMobile.__doc__
|
||||
|
||||
""" List of components appears in general quality rate a device
|
||||
|
||||
ram = Float(dump_only=True, description=m.QualityRateMobile.ram.comment)
|
||||
processor = Float(dump_only=True, description=m.QualityRateMobile.processor.comment)
|
||||
data_storage = Float(dump_only=True, description=m.QualityRateMobile.data_storage.comment)
|
||||
"""
|
||||
|
||||
display = Float(dump_only=True, description=m.QualityRateMobile.display.comment)
|
||||
battery = Float(dump_only=True, description=m.QualityRateMobile.batter.comment)
|
||||
camera = Float(dump_only=True, description=m.QualityRateMobile.camera.comment)
|
||||
|
||||
|
||||
class FunctionalityRate(Rate):
|
||||
__doc__ = m.FunctionalityRate.__doc__
|
||||
|
||||
functionality = EnumField(dump_only=True, description=m.FunctionalityRate.functionality.comment)
|
||||
functionality_range = EnumField(dump_only=True, description=m.FunctionalityRate.functionality_range.comment)
|
||||
connectivity_rate = EnumField(dump_only=True, description=m.FunctionalityRate.connectivity_rate.comment)
|
||||
audio_rate = EnumField(dump_only=True, description=m.FunctionalityRate.audio_rate.comment)
|
||||
|
||||
|
||||
class FinalRate(Rate):
|
||||
__doc__ = m.FinalRate.__doc__
|
||||
workbench_computer = NestedOn(WorkbenchComputer, dump_only=True,
|
||||
description=m.ResultRate.workbench_computer_id.comment)
|
||||
workbench_mobile = NestedOn(WorkbenchMobile, dump_only=True,
|
||||
description=m.ResultRate.workbench_mobile_id.comment)
|
||||
bios = EnumField(Bios, dump_only=True)
|
||||
bios_range = EnumField(Bios,
|
||||
description=m.WorkbenchRate.bios_range.comment,
|
||||
data_key='biosRange')
|
||||
|
||||
|
||||
# TODO Finish input rates (internal and external sources) - Whats really interesting to save in BD?? Whichs aspects?
|
||||
class ResultRate(Rate):
|
||||
__doc__ = m.ResultRate.__doc__
|
||||
# TODO ask for what to do NestedOn??
|
||||
workbench_computer = NestedOn(WorkbenchRateComputer, dump_only=True,
|
||||
description=m.ResultRate.workbench_computer_id.comment)
|
||||
workbench_mobile = NestedOn(WorkbenchRateMobile, dump_only=True,
|
||||
description=m.ResultRate.workbench_mobile_id.comment)
|
||||
manual_computer = NestedOn(ManualRateComputer,
|
||||
dump_only=True,
|
||||
description=m.ResultRate.manual_computer_id.comment)
|
||||
|
||||
processor = Float(dump_only=True)
|
||||
ram = Float(dump_only=True)
|
||||
data_storage = Float(dump_only=True)
|
||||
graphic_card = Float(dump_only=True)
|
||||
bios = EnumField(Bios, dump_only=True)
|
||||
bios_range = EnumField(Bios,
|
||||
description=m.WorkbenchRate.bios_range.comment,
|
||||
data_key='biosRange')
|
||||
appearance_range = EnumField(AppearanceRange,
|
||||
required=True,
|
||||
data_key='appearanceRange',
|
||||
description=m.ManualRate.appearance_range.comment)
|
||||
functionality_range = EnumField(FunctionalityRange,
|
||||
required=True,
|
||||
data_key='functionalityRange',
|
||||
description=m.ManualRate.functionality_range.comment)
|
||||
labelling = Boolean(description=m.ManualRate.labelling.comment)
|
||||
data_storage_range = EnumField(RatingRange, dump_only=True, data_key='dataStorageRange')
|
||||
ram_range = EnumField(RatingRange, dump_only=True, data_key='ramRange')
|
||||
processor_range = EnumField(RatingRange, dump_only=True, data_key='processorRange')
|
||||
graphic_card_range = EnumField(RatingRange, dump_only=True, data_key='graphicCardRange')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Price(EventWithOneDevice):
|
||||
__doc__ = m.Price.__doc__
|
||||
currency = EnumField(Currency, required=True, description=m.Price.currency.comment)
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import math
|
||||
|
||||
from ereuse_devicehub.resources.device.models import HardDrive, Processor, RamModule, Device
|
||||
from ereuse_devicehub.resources.event.rate.workbench.v2_0 import Rate
|
||||
|
||||
|
||||
def test_ratev2_general():
|
||||
"""
|
||||
Test to check if compute all aspects (quality, functionality and appearance) correctly
|
||||
|
||||
Quality rate aspects:
|
||||
Display (screen)
|
||||
Processor
|
||||
RAM
|
||||
Data Storage
|
||||
Battery
|
||||
Camera
|
||||
|
||||
Functionality rate aspects on mobile devices
|
||||
SIM
|
||||
USB/ Charger plug
|
||||
Wi-Fi
|
||||
Bluetooth
|
||||
Fingerprint sensor
|
||||
Loudspeaker
|
||||
Microphone
|
||||
|
||||
|
||||
"""
|
||||
device_test = Device()
|
||||
device_test.components |= {
|
||||
Processor(cores=2, speed=3.4), # CPU
|
||||
HardDrive(size=476940), # HDD
|
||||
RamModule(size=4096, speed=1600), # RAM
|
||||
RamModule(size=2048, speed=1067), # RAM
|
||||
Display(size=5.5, resolutionH=1080, resolutionW=1920), # Screen
|
||||
Battery(capacity=3000), # Mobile devices
|
||||
Camera(resolution=16)
|
||||
}
|
||||
|
||||
rate_device = Rate().compute(device_test)
|
||||
|
||||
assert math.isclose(rate_device, 2.2, rel_tol=0.001)
|
||||
|
||||
|
||||
def test_quality_rate():
|
||||
""" Test to check all quality aspects
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def test_functionality_rate():
|
||||
"""
|
||||
Test to check all functionality aspects
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def test_component_rate_equal_to_zero():
|
||||
"""
|
||||
Test to check all functionality aspects
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def tes_component_rate_is_null():
|
||||
"""
|
||||
Test to check all functionality aspects
|
||||
:return:
|
||||
"""
|
||||
pass
|
Reference in New Issue