Giuseppe Lavagetto has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/405303 )
Change subject: Refactor conftool.action
......................................................................
Refactor conftool.action
Split the Action class, which had grown out of proportion, to a separate
list of smaller Action classes.
Change-Id: I6cccb9e62887aa9151ac2ede50e923689cfe57b2
---
M conftool/action.py
M conftool/cli/tool.py
M conftool/tests/unit/test_action.py
3 files changed, 77 insertions(+), 63 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/operations/software/conftool
refs/changes/03/405303/1
diff --git a/conftool/action.py b/conftool/action.py
index 1870435..76d3c84 100644
--- a/conftool/action.py
+++ b/conftool/action.py
@@ -12,30 +12,60 @@
pass
-class Action(object):
+def get_action(obj, act):
+ prefix = act[:3]
+ if prefix == 'get':
+ return GetAction(obj)
+ elif act == 'delete':
+ return DelAction(obj)
+ elif prefix == 'set':
+ return SetAction(obj, act[4:])
+ else:
+ raise ActionError("Could not parse action %s" % act)
+
+
+class GetAction(object):
+ """Action to perform when a get request is involved"""
+ def __init__(self, obj):
+ self.entity = obj
+
+ def run(self):
+ self.entity.fetch()
+ if self.entity.exists:
+ return str(self.entity)
+ else:
+ return "%s not found" % self.entity.name
+
+
+class DelAction(GetAction):
+ """Action to perform when deleting an object"""
+ def run(self):
+ self.entity.delete()
+ entity_type = self.entity.__class__.__name__,
+ return "Deleted %s %s." % (entity_type,
+ self.entity.name)
+
+
+class SetAction(object):
def __init__(self, obj, act):
+ """Action to perform when editing an object"""
self.entity = obj
- self.action, self.args = self._parse_action(act)
+ if not self.entity.exists:
+ raise ActionError("Entity %s doesn't exist" % self.entity.name)
+
+ self.args = self._parse_action(act)
self.description = ""
- def _parse_action(self, act):
- # TODO: Move this to the cli.tool submodule
+ def _parse_action(self, arg):
# TODO: make the parsing of the argument a bit more formal
- if act.startswith('get'):
- return ('get', None)
- elif act.startswith('delete'):
- return ('delete', None)
- elif not act.startswith('set/'):
- raise ActionError("Cannot parse action %s" % act)
- set_arg = act.replace('set/', '', 1)
- if set_arg.startswith('@'):
- return ('set', self._from_file(set_arg))
+ if arg.startswith('@'):
+ return self._from_file(arg)
try:
- values = dict((el.strip().split('=')) for el in set_arg.split(':'))
+ values = dict((el.strip().split('=')) for el in arg.split(':'))
except Exception:
- raise ActionError("Could not parse set instructions: %s" % set_arg)
- return ('set', self._from_cli(values))
+ raise ActionError("Could not parse set instructions: %s" % arg)
+ return self._from_cli(values)
def _from_cli(self, values):
for k, v in values.items():
@@ -70,33 +100,19 @@
return values
def run(self):
- if self.action == 'get':
- self.entity.fetch()
- if self.entity.exists:
- return str(self.entity)
- else:
- return "%s not found" % self.entity.name
- elif self.action == 'delete':
- self.entity.delete()
- entity_type = self.entity.__class__.__name__,
- return "Deleted %s %s." % (entity_type,
- self.entity.name)
- elif self.action == 'set':
- if not self.entity.exists:
- raise ActionError("Entity %s doesn't exist" % self.entity.name)
- # Validate the new data *before* updating the object
- try:
- self.entity.validate(self.args)
- except Exception as e:
- raise ActionValidationError("The provided data is not valid:
%s" % e)
+ # Validate the new data *before* updating the object
+ try:
+ self.entity.validate(self.args)
+ except Exception as e:
+ raise ActionValidationError("The provided data is not valid: %s" %
e)
- desc = []
- for (k, v) in self.args.items():
- curval = getattr(self.entity, k)
- if v != curval:
- msg = "%s: %s changed %s => %s" % (
- self.entity.name, k,
- curval, v)
- desc.append(msg)
- self.entity.update(self.args)
- return "\n".join(desc)
+ desc = []
+ for (k, v) in self.args.items():
+ curval = getattr(self.entity, k)
+ if v != curval:
+ msg = "%s: %s changed %s => %s" % (
+ self.entity.name, k,
+ curval, v)
+ desc.append(msg)
+ self.entity.update(self.args)
+ return "\n".join(desc)
diff --git a/conftool/cli/tool.py b/conftool/cli/tool.py
index 32abf34..056437d 100644
--- a/conftool/cli/tool.py
+++ b/conftool/cli/tool.py
@@ -64,7 +64,7 @@
fail = False
for obj in self.host_list():
try:
- a = action.Action(obj, self._action)
+ a = action.get_action(obj, self._action)
msg = a.run()
except action.ActionError as e:
fail = True
diff --git a/conftool/tests/unit/test_action.py
b/conftool/tests/unit/test_action.py
index 7a68c3a..05ace73 100644
--- a/conftool/tests/unit/test_action.py
+++ b/conftool/tests/unit/test_action.py
@@ -2,7 +2,7 @@
import unittest
from conftool import configuration
-from conftool.action import Action, ActionError
+from conftool.action import get_action, ActionError, GetAction, DelAction,
SetAction
from conftool.kvobject import KVObject
from conftool.tests.unit import MockBackend, MockEntity
from conftool.types import get_validator
@@ -13,41 +13,39 @@
KVObject.backend = MockBackend({})
KVObject.config = configuration.Config(driver="")
self.entity = MockEntity('Foo', 'Bar', 'test')
-
+ self.entity.exists = True
def test_init(self):
"""
Test initialization of the Action object
"""
# Get action
- a = Action(self.entity, 'get')
+ a = get_action(self.entity, 'get')
self.assertEqual(a.entity, self.entity)
- self.assertEqual(a.action, 'get')
- self.assertIsNone(a.args)
+ self.assertEqual(a.__class__, GetAction)
# Delete action
- a = Action(self.entity, 'delete')
- self.assertEqual(a.action, 'delete')
- self.assertIsNone(a.args)
+ a = get_action(self.entity, 'delete')
+ self.assertEqual(a.__class__, DelAction)
# Set from file
- with mock.patch('conftool.action.Action._from_file') as mocker:
+ with mock.patch('conftool.action.SetAction._from_file') as mocker:
values = {'a': 10, 'b': 'test test'}
mocker.return_value = values
- a = Action(self.entity, 'set/@filename.yaml')
- self.assertEqual(a.action, 'set')
+ a = get_action(self.entity, 'set/@filename.yaml')
+ self.assertEqual(a.__class__, SetAction)
self.assertEqual(a.args, values)
# Set from cli
- a = Action(self.entity, 'set/a=10:b=test test')
- self.assertEqual(a.action, 'set')
+ a = get_action(self.entity, 'set/a=10:b=test test')
+ self.assertEqual(a.__class__, SetAction)
self.assertEqual(a.args, {'a': '10', 'b': 'test test'})
- self.assertRaises(ActionError, Action, self.entity, 'set/a=1:')
- a = Action(self.entity, 'set/a=true:b=a,foo,bar')
+ self.assertRaises(ActionError, get_action, self.entity, 'set/a=1:')
+ a = get_action(self.entity, 'set/a=true:b=a,foo,bar')
self.assertEqual(a.args, {'a': 'true', 'b': 'a,foo,bar'})
def test_from_cli(self):
"""
Test parsing of cli-provided arguments
"""
- a = Action(self.entity, 'get')
+ a = get_action(self.entity, 'set/bar=ac')
a.entity._schema['bar'] = get_validator('list')
self.assertEqual(a._from_cli({'bar': 'abc,def,ghi'}),
{'bar': ['abc', 'def', 'ghi']})
@@ -57,7 +55,7 @@
del a.entity._schema['bar']
def test_run(self):
- a = Action(self.entity, 'get')
+ a = get_action(self.entity, 'get')
a.entity.fetch = mock.Mock()
a.entity.exists = False
self.assertEqual(a.run(), "test not found")
--
To view, visit https://gerrit.wikimedia.org/r/405303
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6cccb9e62887aa9151ac2ede50e923689cfe57b2
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/conftool
Gerrit-Branch: master
Gerrit-Owner: Giuseppe Lavagetto <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits