Skip to content
This repository has been archived by the owner on Feb 3, 2021. It is now read-only.

Feature: Models v2 #543

Merged
merged 53 commits into from
May 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5ec2a7e
Models 2.0 wip
timotheeguerin May 7, 2018
5787211
More wip
timotheeguerin May 7, 2018
908cbb8
Models
timotheeguerin May 7, 2018
290716e
Models
timotheeguerin May 7, 2018
1ad23fe
More
timotheeguerin May 7, 2018
4834da8
More tests
timotheeguerin May 7, 2018
f7d5a56
Tweaks
timotheeguerin May 7, 2018
be4bb84
tweaks
timotheeguerin May 7, 2018
636feb0
Merge beginning
timotheeguerin May 7, 2018
48b326e
Merge wip
timotheeguerin May 7, 2018
dc62fe7
Fix tests
timotheeguerin May 8, 2018
bea0c5a
More for merging
timotheeguerin May 8, 2018
2295159
Merge
timotheeguerin May 8, 2018
2ad46eb
List works
timotheeguerin May 8, 2018
5b4c55a
Test inheritance
timotheeguerin May 8, 2018
7828145
update Cluster configuration
timotheeguerin May 8, 2018
f262204
update Cluster configuration
timotheeguerin May 8, 2018
04ffd6c
Secrets use new models
timotheeguerin May 8, 2018
af72e5f
more
timotheeguerin May 8, 2018
30923f9
Fix print
timotheeguerin May 8, 2018
dfbc815
Fix more issues
timotheeguerin May 8, 2018
0c275c5
rename vm_count
timotheeguerin May 8, 2018
0646007
more Tests
timotheeguerin May 8, 2018
acf9ea9
Style
timotheeguerin May 9, 2018
07b1874
fix issues
timotheeguerin May 9, 2018
9817a32
Fix yaml dump
timotheeguerin May 9, 2018
a4d3435
Added serialization tests
timotheeguerin May 9, 2018
04036c8
Remove prints
timotheeguerin May 9, 2018
417af1d
remove eunused code
timotheeguerin May 9, 2018
daa7210
Merge branch 'master' into feature/models2
timotheeguerin May 9, 2018
9d7e37c
More
timotheeguerin May 9, 2018
46916a3
Merge branch 'feature/models2' of https://github.com/Azure/aztk into …
timotheeguerin May 9, 2018
69cc064
Plugin configuration wip
timotheeguerin May 9, 2018
c926e31
Updated writing models docs
timotheeguerin May 9, 2018
5c9e8b1
Fix pylint
timotheeguerin May 9, 2018
d8e6f66
Fix tests
timotheeguerin May 9, 2018
2731e53
fix pylint issue
timotheeguerin May 9, 2018
eabd77d
More plugin as functions
timotheeguerin May 10, 2018
9c1f9d1
Subnet not required
timotheeguerin May 21, 2018
9c19d11
Added more test and fix
timotheeguerin May 21, 2018
359558e
update docs
timotheeguerin May 21, 2018
5bb1e2e
Added more test and fix
timotheeguerin May 21, 2018
c819eed
Fix
timotheeguerin May 21, 2018
c4aa186
update tempalte
timotheeguerin May 21, 2018
e328299
merge
jafreck May 24, 2018
e7c851f
Merge branch 'master' into feature/models2
jafreck May 24, 2018
1936111
Make user configuration optional
timotheeguerin May 24, 2018
b94f832
Merge branch 'feature/models2' of https://github.com/Azure/aztk into …
timotheeguerin May 24, 2018
db21d2f
Size 0 handled
timotheeguerin May 29, 2018
7fb9423
Tweak models
timotheeguerin May 29, 2018
90e79fb
rename size_low_pri to size_low_priority
timotheeguerin May 29, 2018
116d0c7
tweaks
timotheeguerin May 29, 2018
751030c
spark config default none
timotheeguerin May 29, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ tmp/

# Built docs
docs/_build/

# PyCharm
.idea/
2 changes: 1 addition & 1 deletion .style.yapf
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true
indent_width = 4
column_limit = 120
column_limit = 140
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
"--style=.style.yapf"
],
"python.venvPath": "${workspaceFolder}/.venv/",
"python.pythonPath": "${workspaceFolder}/.venv/Scripts/python.exe"
"python.pythonPath": "${workspaceFolder}/.venv/Scripts/python.exe",
"python.unitTest.pyTestEnabled": true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is true the production value?

Copy link
Member Author

@timotheeguerin timotheeguerin May 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setting is to have option to run/debug the test one by one in vscode instead of using the cli, this is just for development
image

}
4 changes: 2 additions & 2 deletions aztk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def __create_pool_and_job(self, cluster_conf: models.ClusterConfiguration, softw
network_conf = batch_models.NetworkConfiguration(
subnet_id=cluster_conf.subnet_id)
auto_scale_formula = "$TargetDedicatedNodes={0}; $TargetLowPriorityNodes={1}".format(
cluster_conf.vm_count, cluster_conf.vm_low_pri_count)
cluster_conf.size, cluster_conf.size_low_priority)

# Confiure the pool
pool = batch_models.PoolAddParameter(
Expand All @@ -110,7 +110,7 @@ def __create_pool_and_job(self, cluster_conf: models.ClusterConfiguration, softw
batch_models.MetadataItem(
name=constants.AZTK_SOFTWARE_METADATA_KEY, value=software_metadata_key),
batch_models.MetadataItem(
name=constants.AZTK_MODE_METADATA_KEY, value=constants.AZTK_CLUSTER_MODE_METADATA)
name=constants.AZTK_MODE_METADATA_KEY, value=constants.AZTK_CLUSTER_MODE_METADATA)
])

# Create the pool + create user for the pool
Expand Down
Empty file added aztk/core/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions aztk/core/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .model import Model
from .fields import String, Integer, Boolean, Float, List, ModelMergeStrategy, ListMergeStrategy
241 changes: 241 additions & 0 deletions aztk/core/models/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import collections
import enum

from aztk.error import InvalidModelFieldError
from . import validators as aztk_validators

class ModelMergeStrategy(enum.Enum):
Override = 1
"""
Override the value with the other value
"""
Merge = 2
"""
Try to merge value nested
"""

class ListMergeStrategy(enum.Enum):
Replace = 1
"""
Override the value with the other value
"""
Append = 2
"""
Append all the values of the new list
"""

# pylint: disable=W0212
class Field:
"""
Base class for all model fields
"""
def __init__(self, *validators, **kwargs):
self.default = kwargs.get('default')
self.required = 'default' not in kwargs
self.validators = []

if self.required:
self.validators.append(aztk_validators.Required())

self.validators.extend(validators)

choices = kwargs.get('choices')
if choices:
self.validators.append(aztk_validators.In(choices))

def validate(self, value):
for validator in self.validators:
validator(value)

def __get__(self, instance, owner):
if instance is not None:
value = instance._data.get(self)
if value is None:
return instance._defaults.setdefault(self, self._default(instance))
return value

return self

def __set__(self, instance, value):
instance._data[self] = value

def merge(self, instance, value):
"""
Method called when merging 2 model together.
This is overriden in some of the fields where merge can be handled differently
"""
if value is not None:
instance._data[self] = value

def serialize(self, instance):
return self.__get__(instance, None)

def _default(self, model):
if callable(self.default):
return self.__call_default(model)

return self.default

def __call_default(self, *args):
try:
return self.default()
except TypeError as error:
try:
return self.default(*args)
except TypeError:
raise error


class String(Field):
"""
Model String field
"""

def __init__(self, *args, **kwargs):
super().__init__(aztk_validators.String(), *args, **kwargs)


class Integer(Field):
"""
Model Integer field
"""
def __init__(self, *args, **kwargs):
super().__init__(aztk_validators.Integer(), *args, **kwargs)


class Float(Field):
"""
Model Float field
"""

def __init__(self, *args, **kwargs):
super().__init__(aztk_validators.Float(), *args, **kwargs)


class Boolean(Field):
"""
Model Boolean field
"""

def __init__(self, *args, **kwargs):
super().__init__(aztk_validators.Boolean(), *args, **kwargs)


class List(Field):
"""
Field that should be a list
"""

def __init__(self, model=None, **kwargs):
self.model = model
kwargs.setdefault('default', list)
self.merge_strategy = kwargs.get('merge_strategy', ListMergeStrategy.Append)
self.skip_none = kwargs.get('skip_none', True)

super().__init__(
aztk_validators.List(*kwargs.get('inner_validators', [])), **kwargs)

def __set__(self, instance, value):
if isinstance(value, collections.MutableSequence):
value = self._resolve(value)
if value is None:
value = []
super().__set__(instance, value)

def _resolve(self, value):
result = []
for item in value:
if item is None and self.skip_none: # Skip none values
continue

if self.model and isinstance(item, collections.MutableMapping):
item = self.model(**item)
result.append(item)
return result

def merge(self, instance, value):
if value is None:
value = []

if self.merge_strategy == ListMergeStrategy.Append:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we have implementations for all defined types of ListMergeStrategy?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other one is replace which is the default

current = instance._data.get(self)
if current is None:
current = []
value = current + value

instance._data[self] = value

def serialize(self, instance):
items = super().serialize(instance)
output = []
if items is not None:
for item in items:
if hasattr(item, 'to_dict'):
output.append(item.to_dict())
else:
output.append(item)
return output

class Model(Field):
"""
Field is another model

Args:
model (aztk.core.models.Model): Model object that field should be
merge_strategy (ModelMergeStrategy): When merging models how should the nested model be merged.
Default: `ModelMergeStrategy.merge`
"""

def __init__(self, model, *args, **kwargs):
super().__init__(aztk_validators.Model(model), *args, **kwargs)

self.model = model
self.merge_strategy = kwargs.get('merge_strategy', ModelMergeStrategy.Merge)

def __set__(self, instance, value):
if isinstance(value, collections.MutableMapping):
value = self.model(**value)

super().__set__(instance, value)

def merge(self, instance, value):
if self.merge_strategy == ModelMergeStrategy.Merge:
current = instance._data.get(self)
if current is not None:
current.merge(value)
value = current

instance._data[self] = value

def serialize(self, instance):
val = super().serialize(instance)
if val is not None:
return val.to_dict()
else:
return None

class Enum(Field):
"""
Field that should be an enum
"""
def __init__(self, model, *args, **kwargs):
super().__init__(aztk_validators.InstanceOf(model), *args, **kwargs)

self.model = model

def __set__(self, instance, value):
if value is not None and not isinstance(value, self.model):
try:
value = self.model(value)
except ValueError:
available = [e.value for e in self.model]
raise InvalidModelFieldError("{0} is not a valid option. Use one of {1}".format(value, available))
super().__set__(instance, value)


def serialize(self, instance):
val = super().serialize(instance)
if val is not None:
return val.value
else:
return None
Loading