mirror of
https://github.com/openSUSE/osc.git
synced 2025-02-13 06:00:37 +01:00
Limit model attributes to predefined fields by forbidding creating new attributes on fly
This commit is contained in:
parent
3c733387af
commit
587c094f61
@ -126,7 +126,9 @@ HttpHeader = NewType("HttpHeader", Tuple[str, str])
|
|||||||
class OscOptions(BaseModel):
|
class OscOptions(BaseModel):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.extra_fields = {}
|
self._allow_new_attributes = True
|
||||||
|
self._extra_fields = {}
|
||||||
|
self._allow_new_attributes = False
|
||||||
|
|
||||||
# compat function with the config dict
|
# compat function with the config dict
|
||||||
def _get_field_name(self, name):
|
def _get_field_name(self, name):
|
||||||
@ -145,7 +147,7 @@ class OscOptions(BaseModel):
|
|||||||
field_name = self._get_field_name(name)
|
field_name = self._get_field_name(name)
|
||||||
|
|
||||||
if field_name is None and not hasattr(self, name):
|
if field_name is None and not hasattr(self, name):
|
||||||
return self.extra_fields[name]
|
return self._extra_fields[name]
|
||||||
|
|
||||||
field_name = field_name or name
|
field_name = field_name or name
|
||||||
try:
|
try:
|
||||||
@ -158,7 +160,7 @@ class OscOptions(BaseModel):
|
|||||||
field_name = self._get_field_name(name)
|
field_name = self._get_field_name(name)
|
||||||
|
|
||||||
if field_name is None and not hasattr(self, name):
|
if field_name is None and not hasattr(self, name):
|
||||||
self.extra_fields[name] = value
|
self._extra_fields[name] = value
|
||||||
return
|
return
|
||||||
|
|
||||||
field_name = field_name or name
|
field_name = field_name or name
|
||||||
|
@ -280,6 +280,13 @@ class ModelMeta(type):
|
|||||||
class BaseModel(metaclass=ModelMeta):
|
class BaseModel(metaclass=ModelMeta):
|
||||||
__fields__: Dict[str, Field]
|
__fields__: Dict[str, Field]
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if getattr(self, "_allow_new_attributes", True) or hasattr(self.__class__, name) or hasattr(self, name):
|
||||||
|
# allow setting properties - test if they exist in the class
|
||||||
|
# also allow setting existing attributes that were previously initialized via __dict__
|
||||||
|
return super().__setattr__(name, value)
|
||||||
|
raise AttributeError(f"Setting attribute '{self.__class__.__name__}.{name}' is not allowed")
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self._values = {}
|
self._values = {}
|
||||||
self._parent = kwargs.pop("_parent", None)
|
self._parent = kwargs.pop("_parent", None)
|
||||||
@ -307,6 +314,8 @@ class BaseModel(metaclass=ModelMeta):
|
|||||||
for name, field in self.__fields__.items():
|
for name, field in self.__fields__.items():
|
||||||
field.validate_type(getattr(self, name))
|
field.validate_type(getattr(self, name))
|
||||||
|
|
||||||
|
self._allow_new_attributes = False
|
||||||
|
|
||||||
def dict(self, exclude_unset=False):
|
def dict(self, exclude_unset=False):
|
||||||
result = {}
|
result = {}
|
||||||
for name, field in self.__fields__.items():
|
for name, field in self.__fields__.items():
|
||||||
|
@ -116,6 +116,9 @@ class TestExampleConfig(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.tmpdir)
|
shutil.rmtree(self.tmpdir)
|
||||||
|
|
||||||
|
def test_invalid_attribute(self):
|
||||||
|
self.assertRaises(AttributeError, setattr, self.config, "new_attribute", "123")
|
||||||
|
|
||||||
def test_apiurl(self):
|
def test_apiurl(self):
|
||||||
self.assertEqual(self.config["apiurl"], "https://api.opensuse.org")
|
self.assertEqual(self.config["apiurl"], "https://api.opensuse.org")
|
||||||
|
|
||||||
@ -407,26 +410,19 @@ class TestExampleConfig(unittest.TestCase):
|
|||||||
|
|
||||||
def test_extra_fields(self):
|
def test_extra_fields(self):
|
||||||
self.assertEqual(self.config["plugin-option"], "plugin-general-option")
|
self.assertEqual(self.config["plugin-option"], "plugin-general-option")
|
||||||
self.assertEqual(self.config.extra_fields, {"plugin-option": "plugin-general-option"})
|
self.assertEqual(self.config._extra_fields, {"plugin-option": "plugin-general-option"})
|
||||||
|
|
||||||
# write to an existing attribute instead of extra_fields
|
|
||||||
self.config.attrib = 123
|
|
||||||
self.assertEqual(self.config["attrib"], 123)
|
|
||||||
self.config["attrib"] = 456
|
|
||||||
self.assertEqual(self.config["attrib"], 456)
|
|
||||||
self.assertEqual(self.config.extra_fields, {"plugin-option": "plugin-general-option"})
|
|
||||||
|
|
||||||
self.config["new-option"] = "value"
|
self.config["new-option"] = "value"
|
||||||
self.assertEqual(self.config["new-option"], "value")
|
self.assertEqual(self.config["new-option"], "value")
|
||||||
self.assertEqual(self.config.extra_fields, {"plugin-option": "plugin-general-option", "new-option": "value"})
|
self.assertEqual(self.config._extra_fields, {"plugin-option": "plugin-general-option", "new-option": "value"})
|
||||||
|
|
||||||
host_options = self.config["api_host_options"][self.config["apiurl"]]
|
host_options = self.config["api_host_options"][self.config["apiurl"]]
|
||||||
self.assertEqual(host_options["plugin-option"], "plugin-host-option")
|
self.assertEqual(host_options["plugin-option"], "plugin-host-option")
|
||||||
self.assertEqual(host_options.extra_fields, {"plugin-option": "plugin-host-option"})
|
self.assertEqual(host_options._extra_fields, {"plugin-option": "plugin-host-option"})
|
||||||
|
|
||||||
host_options["new-option"] = "value"
|
host_options["new-option"] = "value"
|
||||||
self.assertEqual(host_options["new-option"], "value")
|
self.assertEqual(host_options["new-option"], "value")
|
||||||
self.assertEqual(host_options.extra_fields, {"plugin-option": "plugin-host-option", "new-option": "value"})
|
self.assertEqual(host_options._extra_fields, {"plugin-option": "plugin-host-option", "new-option": "value"})
|
||||||
|
|
||||||
def test_apiurl_aliases(self):
|
def test_apiurl_aliases(self):
|
||||||
expected = {"https://api.opensuse.org": "https://api.opensuse.org", "osc": "https://api.opensuse.org"}
|
expected = {"https://api.opensuse.org": "https://api.opensuse.org", "osc": "https://api.opensuse.org"}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user