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 FootprintImage(PKDataClass): type: str filename: str originalFilename: str mimetype: str size: int extension: str description: str replacement: str
[docs]@dataclass class FootprintAttachment(PKDataClass): type: str filename: str originalFilename: str mimetype: str size: int extension: str description: str replacement: str
[docs]@dataclass class FootprintCategory(PKDataClass): parent: Any # FootprintCategory children: List[Any] # List[FootprintCategory] categoryPath: str expanded: bool name: str description: 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 Footprint(PKDataClass): name: str description: str category: FootprintCategory image: FootprintImage attachments: List[FootprintAttachment] categoryPath: str
[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 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 MetaPartParameterCriteria(PKDataClass): partParameterName: str operator: str value: float siPrefix: SiPrefix stringValue: str valueType: str unit: Unit
[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