Source code for pypartkeepr.dataclasses
# -*- mode: python; mode: elpy; coding: utf-8 -*-
#
# Copyright 2018-2019 Luc Chouinard lumostor@3X0.ca
#
# This file is part of pypartkeepr.
#
# pypartkeepr is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pypartkeepr is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pypartkeepr. If not, see <https://www.gnu.org/licenses/>.
#
import re
import collections
from dataclasses import dataclass, fields
from typing import ClassVar, List, Any
from decimal import Decimal
import logging
import yaml
from pypartkeepr.utils import log_with, logger_border, set_logger
module_logger = logging.getLogger(__name__)
[docs]@dataclass
class pyPKConfig(yaml.YAMLObject):
protocol: str
servername: str
port: int
username: str
log_level: str
octopart_api_key: str
yaml_tag: ClassVar = '!pyPKConfig'
yaml_loader: ClassVar = yaml.SafeLoader
id_pat = re.compile('(.+/)([0-9]+)')
[docs]class PKDataClassBase:
@set_logger
def __init__(self):
pass
[docs] @staticmethod
def is_of_type(objtype, matchtype):
if (hasattr(objtype, '__origin__')
and isinstance(objtype.__origin__(), matchtype)):
return True
else:
return False
[docs] @classmethod
def from_dict(cls, dictarg):
if '@type' in dictarg:
logger = logging.getLogger(__name__+'.'+dictarg['@type'])
else:
logger = logging.getLogger(__name__+'.PKDataClassBase')
logger.debug('({})'.format(dictarg))
attrs_repl = {'id': '@id', 'type': '@type'}
attributes_name = {}
attributes_type = {}
for n, t in [(f.name, f.type) for f in fields(cls)]:
if n in attrs_repl:
attributes_name[attrs_repl[n]] = n
attributes_type[attrs_repl[n]] = t
else:
attributes_name[n] = n
attributes_type[n] = t
if not isinstance(dictarg, collections.Mapping):
logger.error('(): Type {} is not a dict like.'.format(type(dictarg)))
raise TypeError('Type {} is not a dict like.'.format(type(dictarg)))
clsargs = []
for attribute in attributes_name:
logger.debug('(): attribute_type: {}'.format(attributes_type[attribute]))
logger.debug('(): attribute: {}'.format(attribute))
arg = dictarg.get(attribute, None)
# print('from_dict():', attribute, attributes_type[attribute], type(arg))
if arg is None and PKDataClassBase.is_of_type(attributes_type[attribute], List):
arg = list()
elif arg is None:
pass
elif attribute == 'children':
if attributes_type[attribute] == List[Any]:
argl = []
for ai in arg:
if isinstance(ai, collections.Mapping):
argl.append(globals()[ai['@type']].from_dict(ai))
else:
argl.append(ai)
arg = argl
elif attribute == 'parent':
if isinstance(arg, collections.Mapping):
arg = globals()[arg['@type']].from_dict(arg)
elif attributes_type[attribute] == Any:
arg = globals()[arg['@type']].from_dict(arg)
elif isinstance(arg, Decimal):
arg = str(arg)
elif PKDataClassBase.is_of_type(attributes_type[attribute], List):
logger.debug('(): List'.format())
argl = []
for ai in arg:
if attributes_type[attribute] == 'Any':
argl.append(globals()[arg[0]['@type']].from_dict(ai))
else:
logger.debug('(): List[{}]'.format(ai))
argl.append(globals()[
attributes_type[attribute].__args__].from_dict(ai))
arg = argl
elif issubclass(attributes_type[attribute], PKDataClassBase):
arg = attributes_type[attribute].from_dict(arg)
clsargs.append(arg)
return cls(*clsargs)
@logger_border
def asdict(self, *, dict_factory=dict):
attrs_repl = {'id': '@id', 'type': '@type'}
attributes_name = {}
for k in [f.name for f in fields(self)]:
if k in attrs_repl:
attributes_name[k] = attrs_repl[k]
else:
attributes_name[k] = k
d = dict_factory()
for k in attributes_name:
attr = getattr(self, k)
if attr is not None:
if isinstance(attr, PKDataClassBase):
attr = attr.asdict()
elif isinstance(attr, list):
for i, v in enumerate(attr):
if attr[i] and isinstance(attr[i], PKDataClassBase):
attr[i] = attr[i].asdict()
d[attributes_name[k]] = attr
return d
[docs]@dataclass
class PKDataClass(PKDataClassBase):
id: int
type: str
def __post_init__(self):
self.logger = logging.getLogger(__name__+self.__class__.__name__)
[docs]@dataclass
class Distributor(PKDataClass):
name: str
address: str
url: str
phone: str
fax: str
email: str
comment: str
skuurl: str
enabledForReports: bool
[docs]@dataclass
class BatchJobQueryField(PKDataClass):
property: str
operator: str
value: str
description: str
dynamic: bool
[docs]@dataclass
class BatchJobUpdateField(PKDataClass):
property: str
value: str
description: str
dynamic: bool
[docs]@dataclass
class BatchJob(PKDataClass):
name: str
batchJobQueryFields: List[BatchJobQueryField]
batchJobUpdateFields: List[BatchJobUpdateField]
baseEntity: str
[docs]@dataclass
class ImportPreset(PKDataClass):
baseEntity: str
name: str
configuration: str
[docs]@dataclass
class GridPreset(PKDataClass):
grid: str
name: str
configuration: str
gridDefault: bool
[docs]@dataclass
class SiPrefix(PKDataClass):
prefix: str
symbol: str
exponent: int
base: int
[docs]@dataclass
class PartAttachment(PKDataClass):
isImage: bool
type: str
filename: str
originalFilename: str
mimetype: str
size: int
extension: str
description: str
replacement: str
[docs]@dataclass
class PartCategory(PKDataClass):
parent: Any # PartCategory
children: List[Any] # List[PartCategory]
categoryPath: str
expanded: bool
name: str
description: str
[docs]@dataclass
class PartDistributor(PKDataClass):
distributor: Distributor
orderNumber: str
packagingUnit: int
price: float
currency: str
sku: str
ignoreForReports: bool
[docs]@dataclass
class ManufacturerICLogo(PKDataClass):
type: str
filename: str
originalFilename: str
mimetype: str
size: int
extension: str
description: str
replacement: str
[docs]@dataclass
class Manufacturer(PKDataClass):
name: str
address: str
url: str
email: str
comment: str
phone: str
fax: str
icLogos: List[ManufacturerICLogo]
[docs]@dataclass
class PartManufacturer(PKDataClass):
manufacturer: Manufacturer
partNumber: str
[docs]@dataclass
class Unit(PKDataClass):
name: str
symbol: str
prefixes: SiPrefix
[docs]@dataclass
class PartMeasurementUnit(PKDataClass):
name: str
shortName: str
default: bool
[docs]@dataclass
class StorageLocationCategory(PKDataClass):
parent: Any # StorageLocationCategory
children: List[Any] # List[StorageLocationCategory]
categoryPath: str
expanded: bool
name: str
description: str
[docs]@dataclass
class StorageLocationImage(PKDataClass):
type: str
filename: str
originalFilename: str
mimetype: str
size: int
extension: str
description: str
replacement: str
[docs]@dataclass
class StorageLocation(PKDataClass):
name: str
image: StorageLocationImage
category: StorageLocationCategory
categoryPath: str
[docs]@dataclass
class StockEntry(PKDataClass):
stockLevel: int
part: Any # Part
user: Any # User
price: float
dateTime: str
correction: bool
comment: str
[docs]@dataclass
class PartStock(PKDataClass):
quantity: int
price: float
comment: str
[docs]@dataclass
class PartParameter(PKDataClass):
name: str
description: str
unit: Unit
value: float
maxValue: float
minValue: float
stringValue: str
valueType: str
siPrefix: SiPrefix
minSiPrefix: SiPrefix
maxSiPrefix: SiPrefix
[docs]@dataclass
class Part(PKDataClass):
category: PartCategory
name: str
description: str
footprint: Footprint
partUnit: PartMeasurementUnit
storageLocation: StorageLocation
manufacturers: List[PartManufacturer]
distributors: List[PartDistributor]
attachments: List[PartAttachment]
comment: str
stockLevel: int
minStockLevel: int
averagePrice: float
stockLevels: List[StockEntry]
parameters: List[PartParameter]
metaPartParameterCriterias: List[MetaPartParameterCriteria]
status: str
needsReview: bool
partCondition: str
productionRemarks: str
createDate: str
internalPartNumber: str
removals: bool
lowStock: bool
metaPart: bool
metaPartMatches: str
categoryPath: str
projectNames: str
[docs]@dataclass
class TempImage(PKDataClass):
created: str
replacement: str
originalFilename: str
size: int
type: str
description: str
fullFilename: str
filename: str
extension: str
legacyExtension: str
mimeType: str
[docs]@dataclass
class TempUploadedFile(PKDataClass):
created: str
replacement: str
originalFilename: str
size: int
type: str
description: str
fullFilename: str
filename: str
extension: str
legacyExtension: str
mimeType: str
[docs]@dataclass
class UserProvider(PKDataClass):
type: str
editable: bool
[docs]@dataclass
class User(PKDataClass):
username: str
password: str
newPassword: str
email: str
legacy: bool
provider: UserProvider
initialUserPreferences: str
active: bool
protected: bool
[docs]@dataclass
class TipOfTheDay(PKDataClass):
name: str
[docs]@dataclass
class TipOfTheDayHistory(PKDataClass):
name: str
user: User
[docs]@dataclass
class FOSUser(PKDataClass):
email: str
[docs]@dataclass
class ProjectPart(PKDataClass):
part: Part
quantity: int
remarks: str
overageType: str
overage: int
lotNumber: str
totalQuantity: int
[docs]@dataclass
class ProjectAttachment(PKDataClass):
type: str
filename: str
originalFilename: str
mimetype: str
size: int
extension: str
description: str
replacement: str
[docs]@dataclass
class Project(PKDataClass):
name: str
parts: List[ProjectPart]
description: str
attachments: List[ProjectAttachment]
[docs]@dataclass
class ReportProject(PKDataClass):
project: Project
quantity: int
[docs]@dataclass
class ReportPart(PKDataClass):
report: Any # Report
part: Part
quantity: int
distributor: Distributor
distributorOrderNumber: str
itemPrice: str
orderSum: str
metaPart: bool
subParts: Part
projectParts: List[ProjectPart]
itemSum: str
missing: int
[docs]@dataclass
class Report(PKDataClass):
name: str
createDateTime: str
reportProjects: List[ReportProject]
reportParts: List[ReportPart]
[docs]@dataclass
class ProjectRunPart(PKDataClass):
projectRun: Any # ProjectRun
part: Part
quantity: int
lotNumber: str
[docs]@dataclass
class ProjectRun(PKDataClass):
runDateTime: str
project: Project
quantity: int
parts: List[ProjectRunPart]
[docs]@dataclass
class SystemNotice(PKDataClass):
date: str
title: str
description: str
acknowledged: bool
type: str
[docs]@dataclass
class SystemPreference(PKDataClass):
preferenceKey: str
preferenceValue: str