Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/config system #350

Merged
merged 23 commits into from
Oct 25, 2016
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d1dc75d
feat: Add basic config system
giulioungaretti Sep 28, 2016
6320d05
feat: Add user schema validation
giulioungaretti Oct 2, 2016
9cc174d
fix: Bugs in user specified schema validation
giulioungaretti Oct 3, 2016
c4bf199
feat: Add module logger
giulioungaretti Oct 3, 2016
5993432
feat: Add possibility to update and validate custom fields
giulioungaretti Oct 3, 2016
d16f599
feat: Add saving
giulioungaretti Oct 4, 2016
13230eb
feat: Add config first use case.
giulioungaretti Oct 4, 2016
9f0480e
feat: Add default to schema
giulioungaretti Oct 5, 2016
66a1cb4
feat: add dot access to config items
giulioungaretti Oct 9, 2016
71f9144
fix: Refactor API.
giulioungaretti Oct 9, 2016
d531dd4
docs: add notebook
giulioungaretti Oct 9, 2016
0b8e248
fix: use better name
giulioungaretti Oct 10, 2016
ccab458
fix: Polish docs
giulioungaretti Oct 21, 2016
6f276d1
fix: Rename config file
giulioungaretti Oct 21, 2016
3d4b850
fix: Improve example notebook
giulioungaretti Oct 21, 2016
3403eb0
fix: update path in rst doc
giulioungaretti Oct 23, 2016
f2a4a24
fix: Add json-schema requirements
giulioungaretti Oct 23, 2016
ec7ad59
fix: indend schema and udpate name
giulioungaretti Oct 24, 2016
cb05e45
Merge branch 'master' into feature/config_system
giulioungaretti Oct 24, 2016
a4d4906
fix: Update also schema name
giulioungaretti Oct 24, 2016
84f77a3
Merge branch 'master' into feature/config_system
giulioungaretti Oct 24, 2016
173e866
docs: Polish notebook
giulioungaretti Oct 24, 2016
7efab7f
Merge branch 'master' into feature/config_system
giulioungaretti Oct 25, 2016
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
Prev Previous commit
Next Next commit
feat: Add possibility to update and validate custom fields
  • Loading branch information
giulioungaretti committed Oct 23, 2016
commit 5993432171fa8c2f703f429a3cf85b9f28696080
79 changes: 78 additions & 1 deletion qcodes/config/config.py
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ class Config():
schema = json.load(fp)

# home dir, os independent
home_file_name = expanduser(config_file_name)
home_file_name = expanduser("~/{}".format(config_file_name))
schema_home_file_name = home_file_name.replace(config_file_name,
schema_file_name)

@@ -89,6 +89,59 @@ def validate(self, json_config, schema, extra_schema_path=None):
else:
jsonschema.validate(json_config, schema)

def add(self, key, value, value_type=None, description=None):
""" Add custom config value
Add key, value with optional value_type to user cofnig and schema.
If value_type is specified then the new value is validated.
Args:
key(str): key to be added under user config
value (any): value to add to config
value_type(Optional(string)): type of value
allowed are string, boolean, integer
description (str): description of key to add to schema
example:
>>> defaults.add("trace_color", "blue", "string", "description")
will update the config:
`...
"user": { "trace_color": "blue"}
...`
and the schema:
`...
"user":{
"type" : "object",
"description": "controls user settings of qcodes"
"properties" : {
"trace_color": {
"description" : "description",
"type": "string"
}
}
}
...`

Todo:
- Add enum support for value_type
"""
self.current_config["user"].update({key: value})

if value_type is None:
if description is not None:
logger.warning(""" Passing a description without a type does
not make sense. Description is ignored """)
else:
# update schema!
schema_entry = {key: {"type": value_type}}
if description is not None:
schema_entry = {key: {
"type": value_type,
"description": description}
}
self.schema['properties']["user"]["properties"].update(schema_entry)
self.validate(self.current_config, self.schema)

# TODO(giulioungaretti) to store just the user schema
# or the entire thing ?

def load_config(self, path):
"""Load a config JSON file

@@ -103,6 +156,30 @@ def load_config(self, path):
config = json.load(fp)
return config

def save_config(self, path):
""" Save config file
Args:
path (string): path of new config file
"""
raise NotImplementedError
with open(path, "w") as fp:
json.dump(fp, self.current_config)

def save_home_config(self):
""" Save config file to home dir
"""
raise NotImplementedError

def save_env_config(self):
""" Save config file to env path
"""
raise NotImplementedError

def save_cwd_config(self):
""" Save config file to current working dir
"""
raise NotImplementedError

def __getitem__(self, name):
val = self.current_config
for key in name.split('.'):
58 changes: 56 additions & 2 deletions qcodes/tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import json
import copy
import jsonschema

from functools import partial
@@ -63,6 +63,42 @@
]
}

# schema updaed by adding custom fileds by the
UPDATED_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"a": {
"type": "integer"
},
"b": {
"type": "integer"
},
"z": {
"type": "integer"
},
"c": {
"type": "integer"
},
"bar": {
"type": "boolean"
},
"user": {
"type": "object",
"properties": {
"foo":
{
"type": "string",
"description": "foo"
}
}
}
},
"required": [
"z"
]
}

USER_SCHEMA = """ {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
@@ -76,7 +112,6 @@
"description": "foo"
}
}
}
}
}
} """
@@ -152,3 +187,22 @@ def test_bad_user_schema(self, isfile, load_config, env, schema):
with self.assertRaises(jsonschema.exceptions.ValidationError):
self.conf.load_default()

@patch.object(Config, "current_config", new_callable=PropertyMock)
def test_update_user_config(self, config):
# deep copy because we mutate state
config.return_value = copy.deepcopy(CONFIG)
self.conf.add("foo", "bar")
self.assertEqual(self.conf.current_config, UPDATED_CONFIG)

@patch.object(Config, 'schema', new_callable=PropertyMock)
@patch.object(Config, "current_config", new_callable=PropertyMock)
def test_update_and_validate_user_config(self, config, schema):
self.maxDiff = None
schema.return_value = copy.deepcopy(SCHEMA)
# deep copy because we mutate state
config.return_value = copy.deepcopy(CONFIG)
# import pdb
# pdb.set_trace()
self.conf.add("foo", "bar", "string", "foo")
self.assertEqual(self.conf.current_config, UPDATED_CONFIG)
self.assertEqual(self.conf.schema, UPDATED_SCHEMA)