From 54111deda7a90b153ffdabaab65883b5e1e76be7 Mon Sep 17 00:00:00 2001 From: Kenichi Maehashi Date: Sat, 19 Jun 2021 23:45:20 +0900 Subject: [PATCH] wip --- example/example_builder.py | 30 ++++++++++++++++++ pypict/builder/_constraint.py | 57 +++++++++++++++++++++++++---------- pypict/builder/_export.py | 14 --------- pypict/builder/_model.py | 2 +- pypict/builder/_parameter.py | 11 ++++--- 5 files changed, 79 insertions(+), 35 deletions(-) create mode 100644 example/example_builder.py diff --git a/example/example_builder.py b/example/example_builder.py new file mode 100644 index 0000000..34e453a --- /dev/null +++ b/example/example_builder.py @@ -0,0 +1,30 @@ +from ast import Param +from pypict.builder import Model, Parameter, IF, AND, OR, NOT + + +type = Parameter('Type', ['Single', 'Span', 'Stripe', 'Mirror', 'RAID-5']) +size = Parameter('Size', [10, 100, 500, 1000, 5000, 10000, 40000]) +method = Parameter('Format method', ['Quick', 'Slow']) +filesys = Parameter('File System', ['FAT', 'FAT32', 'NTFS']) +cluster = Parameter('Cluster size', [512, 1024, 2048, 4096, 8192, 16384, 32768, 65536]) +compression = Parameter('Compression', ['On', 'Off']) + +model = Model().parameters( + type, size, method, filesys, cluster, compression +).constraints( + IF(filesys == 'FAT').THEN(size <= 4096), + IF(filesys == 'FAT32').THEN(size <= 32000), + size < 10000, + compression == 'OFF', + filesys.like('FAT*'), + IF(cluster.in_(512, 1024, 2048)).THEN(compression == 'off'), + IF(filesys.in_('FAT', 'FAT32')).THEN(compression == 'off'), + + IF( + OR( + filesys != 'NTFS', + AND(filesys == 'NTFS', cluster > 4096), + ) + ).THEN(compression == 'Off') +) +print(model.to_string()) \ No newline at end of file diff --git a/pypict/builder/_constraint.py b/pypict/builder/_constraint.py index 02b594b..dcc1d2b 100644 --- a/pypict/builder/_constraint.py +++ b/pypict/builder/_constraint.py @@ -1,15 +1,15 @@ -from pypict.builder._export import _literal +import pypict.builder class _Constraint: - def to_string(self): + def to_string(self) -> str: raise NotImplemented - def __str__(self): + def __str__(self) -> str: return self.to_string() - def __repr__(self): + def __repr__(self) -> str: return f'' @@ -19,17 +19,20 @@ def __init__(self, param, op, value_or_param): self._op = op self._value_or_param = value_or_param - def to_string(self): + def to_string(self) -> str: return f'{_literal(self._param)} {self._op} {_literal(self._value_or_param)}' class _LogicalOp(_Constraint): - _op = None + _op: str = None # to be overridden - def __init__(self, consts): + def __init__(self, *consts: _Constraint): + for const in consts: + if not isinstance(const, _Constraint): + raise ValueError self._consts = consts - def to_string(self): + def to_string(self) -> str: return '(' + f' {self._op} '.join([str(x) for x in self._consts]) + ')' @@ -42,38 +45,60 @@ class OR(_LogicalOp): class NOT(_Constraint): - def __init__(self, const): + def __init__(self, const: _Constraint): + if not isinstance(const, _Constraint): + raise ValueError self._const = const - def to_string(self): + def to_string(self) -> str: return f'NOT {self._const}' class IF(_Constraint): - def __init__(self, const): + def __init__(self, const: _Constraint): + if not isinstance(const, _Constraint): + raise ValueError self._const = const self._then = None self._else = None - def THEN(self, const): + def THEN(self, const: _Constraint) -> 'IF': if self._then is not None: raise ValueError self._then = const return self - def ELSE(self, const): + def ELSE(self, const: _Constraint) -> 'IF': if self._then is None: raise ValueError if self._else is None: raise ValueError self._else = const - def to_string(self): + def to_string(self) -> str: if self._then is None: raise ValueError return ( f'IF {self._const}' + f'\nTHEN {self._then}' + - (f'\nELSE {self._else}' if self._else else '') + - ';' + (f'\nELSE {self._else}' if self._else else '') ) + + +class _ValueSet: + def __init__(self, values): + self._values = values + + def to_string(self) -> str: + return '{ ' + ', '.join([_literal(x) for x in self._values]) + ' }' + + +def _literal(v): + if isinstance(v, pypict.builder.Parameter): + return f'[{v._name}]' + elif isinstance(v, _ValueSet): + return v.to_string() + elif isinstance(v, str): + return f'"{v}"' # TODO check? + else: + return str(v) \ No newline at end of file diff --git a/pypict/builder/_export.py b/pypict/builder/_export.py index 81117cc..e69de29 100644 --- a/pypict/builder/_export.py +++ b/pypict/builder/_export.py @@ -1,14 +0,0 @@ -from pypict import builder - - -def _literal(v): - if isinstance(v, builder.Parameter): - return f'[{v._name}]' - elif isinstance(v, str): - return f'"{v}"' # TODO check? - else: - return str(v) - - -def _ValueSet(values): - return '{ ' + ','.join([_literal(x) for x in values]) + ' }' diff --git a/pypict/builder/_model.py b/pypict/builder/_model.py index 98c76c0..374d656 100644 --- a/pypict/builder/_model.py +++ b/pypict/builder/_model.py @@ -41,7 +41,7 @@ def to_string(self): # Constraint definitions if len(self._constraints) != 0: for c in self._constraints: - lines.append(c.to_string()) + lines.append(c.to_string() + ';') return '\n'.join(lines) diff --git a/pypict/builder/_parameter.py b/pypict/builder/_parameter.py index 81ca3b0..905da10 100644 --- a/pypict/builder/_parameter.py +++ b/pypict/builder/_parameter.py @@ -1,8 +1,7 @@ import numbers from typing import Iterable, Iterator, List, Optional, Tuple, Type, Union -from pypict.builder._constraint import _Relation -from pypict.builder._export import _literal, _ValueSet +from pypict.builder._constraint import _Relation, _ValueSet NumericType = numbers.Real @@ -104,10 +103,14 @@ def __le__(self, other: Union[DataTypes, 'Parameter']): self._check_operand(other) return _Relation(self, '<=', other) - def __in__(self, values: Iterable[DataTypes]): + def in_(self, *values: DataTypes): + for x in values: + self._check_operand(x, allow_string=True) return _Relation(self, 'IN', _ValueSet(values)) def like(self, value): - if self._dtype != str: + if self._numeric: + raise ValueError + if not isinstance(value, StringType): raise ValueError return _Relation(self, 'LIKE', value)