mirror of
https://github.com/openSUSE/osc.git
synced 2025-02-02 17:56:15 +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):
|
||||
def __init__(self, *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
|
||||
def _get_field_name(self, name):
|
||||
@ -145,7 +147,7 @@ class OscOptions(BaseModel):
|
||||
field_name = self._get_field_name(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
|
||||
try:
|
||||
@ -158,7 +160,7 @@ class OscOptions(BaseModel):
|
||||
field_name = self._get_field_name(name)
|
||||
|
||||
if field_name is None and not hasattr(self, name):
|
||||
self.extra_fields[name] = value
|
||||
self._extra_fields[name] = value
|
||||
return
|
||||
|
||||
field_name = field_name or name
|
||||
|
@ -280,6 +280,13 @@ class ModelMeta(type):
|
||||
class BaseModel(metaclass=ModelMeta):
|
||||
__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):
|
||||
self._values = {}
|
||||
self._parent = kwargs.pop("_parent", None)
|
||||
@ -307,6 +314,8 @@ class BaseModel(metaclass=ModelMeta):
|
||||
for name, field in self.__fields__.items():
|
||||
field.validate_type(getattr(self, name))
|
||||
|
||||
self._allow_new_attributes = False
|
||||
|
||||
def dict(self, exclude_unset=False):
|
||||
result = {}
|
||||
for name, field in self.__fields__.items():
|
||||
|
@ -116,6 +116,9 @@ class TestExampleConfig(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
def test_invalid_attribute(self):
|
||||
self.assertRaises(AttributeError, setattr, self.config, "new_attribute", "123")
|
||||
|
||||
def test_apiurl(self):
|
||||
self.assertEqual(self.config["apiurl"], "https://api.opensuse.org")
|
||||
|
||||
@ -407,26 +410,19 @@ class TestExampleConfig(unittest.TestCase):
|
||||
|
||||
def test_extra_fields(self):
|
||||
self.assertEqual(self.config["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.assertEqual(self.config._extra_fields, {"plugin-option": "plugin-general-option"})
|
||||
|
||||
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"]]
|
||||
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"
|
||||
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):
|
||||
expected = {"https://api.opensuse.org": "https://api.opensuse.org", "osc": "https://api.opensuse.org"}
|
||||
|
Loading…
Reference in New Issue
Block a user