first commit rate v2; adding Quality, Functionality Rates class

This commit is contained in:
nad 2019-02-27 23:36:26 +01:00
parent 15f705dd50
commit ddb1877133
6 changed files with 879 additions and 7 deletions

View file

View file

@ -119,6 +119,21 @@ class FunctionalityRange(Enum):
return self.name 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 doesnt exists'
def __str__(self):
return self.name
@unique @unique
class Bios(Enum): class Bios(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."""
@ -132,6 +147,8 @@ 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'

View file

@ -31,7 +31,8 @@ from ereuse_devicehub.resources.device.models import Component, Computer, DataSt
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, ErasureStandards, \ from ereuse_devicehub.resources.enums import AppearanceRange, Bios, ErasureStandards, \
FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \ FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
RatingRange, RatingSoftware, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \ 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.models import STR_SM_SIZE, Thing
from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.user.models import User
@ -650,7 +651,7 @@ class ManualRate(IndividualRate):
raise NotImplementedError() raise NotImplementedError()
class WorkbenchRate(ManualRate): class WorkbenchComputerRate(ManualRate):
id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id), primary_key=True) id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id), primary_key=True)
processor = Column(Float(decimal_return_scale=2), check_range('processor', *RATE_POSITIVE)) processor = Column(Float(decimal_return_scale=2), check_range('processor', *RATE_POSITIVE))
ram = Column(Float(decimal_return_scale=2), check_range('ram', *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) 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): class AggregateRate(Rate):
id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True) id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
manual_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id)) manual_id = Column(UUID(as_uuid=True), ForeignKey(ManualRate.id))
@ -711,16 +878,16 @@ class AggregateRate(Rate):
order_by=lambda: AggregateRate.created, order_by=lambda: AggregateRate.created,
collection_class=OrderedSet), collection_class=OrderedSet),
primaryjoin=manual_id == ManualRate.id) 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 workbench_id.comment = """The WorkbenchRate used to generate
this aggregation, or None if none used. this aggregation, or None if none used.
""" """
workbench = relationship(WorkbenchRate, workbench = relationship(QualityRateComputer,
backref=backref('aggregate_rate_workbench', backref=backref('aggregate_rate_workbench',
lazy=True, lazy=True,
order_by=lambda: AggregateRate.created, order_by=lambda: AggregateRate.created,
collection_class=OrderedSet), collection_class=OrderedSet),
primaryjoin=workbench_id == WorkbenchRate.id) primaryjoin=workbench_id == QualityRateComputer.id)
def __init__(self, *args, **kwargs) -> None: def __init__(self, *args, **kwargs) -> None:
kwargs.setdefault('version', StrictVersion('1.0')) kwargs.setdefault('version', StrictVersion('1.0'))
@ -781,7 +948,198 @@ class AggregateRate(Rate):
return self.workbench.labelling return self.workbench.labelling
@classmethod @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 = cls()
aggregate.rating = rate.rating aggregate.rating = rate.rating
aggregate.software = rate.software aggregate.software = rate.software

View file

@ -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

View file

@ -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.device import schemas as s_device
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, FunctionalityRange, \ from ereuse_devicehub.resources.enums import AppearanceRange, Bios, FunctionalityRange, \
PhysicalErasureMethod, PriceSoftware, RATE_POSITIVE, RatingRange, RatingSoftware, ReceiverRole, \ 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.event import models as m
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.schemas import Thing from ereuse_devicehub.resources.schemas import Thing
@ -109,6 +109,7 @@ class StepRandom(Step):
__doc__ = m.StepRandom.__doc__ __doc__ = m.StepRandom.__doc__
class Rate(EventWithOneDevice): class Rate(EventWithOneDevice):
__doc__ = m.Rate.__doc__ __doc__ = m.Rate.__doc__
rating = Integer(validate=Range(*RATE_POSITIVE), rating = Integer(validate=Range(*RATE_POSITIVE),
@ -157,6 +158,28 @@ class WorkbenchRate(ManualRate):
graphic_card_range = EnumField(RatingRange, dump_only=True, data_key='graphicCardRange') 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): class AggregateRate(Rate):
__doc__ = m.AggregateRate.__doc__ __doc__ = m.AggregateRate.__doc__
workbench = NestedOn(WorkbenchRate, dump_only=True, workbench = NestedOn(WorkbenchRate, dump_only=True,
@ -187,6 +210,106 @@ class AggregateRate(Rate):
graphic_card_range = EnumField(RatingRange, dump_only=True, data_key='graphicCardRange') 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): class Price(EventWithOneDevice):
__doc__ = m.Price.__doc__ __doc__ = m.Price.__doc__
currency = EnumField(Currency, required=True, description=m.Price.currency.comment) currency = EnumField(Currency, required=True, description=m.Price.currency.comment)

73
tests/test_rate_v2.py Normal file
View file

@ -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