Browse Source

Factor out schema type comparion in config generation and get several tests passing (#303).

Dan Helfman 2 months ago
parent
commit
57721937a3

+ 1 - 0
borgmatic/commands/arguments.py

@@ -297,6 +297,7 @@ def make_argument_description(schema, flag_name):
     an example or additional information as appropriate based on its type. Return the updated
     an example or additional information as appropriate based on its type. Return the updated
     description for use in a command-line argument.
     description for use in a command-line argument.
     '''
     '''
+    # FIXME: Argument descriptions are apparently broken right now.
     description = schema.get('description')
     description = schema.get('description')
     schema_type = schema.get('type')
     schema_type = schema.get('type')
 
 

+ 4 - 8
borgmatic/config/generate.py

@@ -36,10 +36,10 @@ def schema_to_sample_configuration(schema, source_config=None, level=0, parent_i
     schema_type = schema.get('type')
     schema_type = schema.get('type')
     example = schema.get('example')
     example = schema.get('example')
 
 
-    if schema_type == 'array' or (isinstance(schema_type, list) and 'array' in schema_type):
+    if borgmatic.config.schema.compare_types(schema_type, {'array'}):
         config = ruamel.yaml.comments.CommentedSeq(
         config = ruamel.yaml.comments.CommentedSeq(
             example
             example
-            if schema['items'].get('type') in SCALAR_SCHEMA_TYPES
+            if borgmatic.config.schema.compare_types(schema['items'].get('type'), SCALAR_SCHEMA_TYPES)
             else [
             else [
                 schema_to_sample_configuration(
                 schema_to_sample_configuration(
                     schema['items'], source_config, level, parent_is_sequence=True
                     schema['items'], source_config, level, parent_is_sequence=True
@@ -47,7 +47,7 @@ def schema_to_sample_configuration(schema, source_config=None, level=0, parent_i
             ]
             ]
         )
         )
         add_comments_to_configuration_sequence(config, schema, indent=(level * INDENT))
         add_comments_to_configuration_sequence(config, schema, indent=(level * INDENT))
-    elif schema_type == 'object' or (isinstance(schema_type, list) and 'object' in schema_type):
+    elif borgmatic.config.schema.compare_types(schema_type, {'object'}):
         if source_config and isinstance(source_config, list) and isinstance(source_config[0], dict):
         if source_config and isinstance(source_config, list) and isinstance(source_config[0], dict):
             source_config = dict(collections.ChainMap(*source_config))
             source_config = dict(collections.ChainMap(*source_config))
 
 
@@ -66,11 +66,7 @@ def schema_to_sample_configuration(schema, source_config=None, level=0, parent_i
         add_comments_to_configuration_object(
         add_comments_to_configuration_object(
             config, schema, source_config, indent=indent, skip_first=parent_is_sequence
             config, schema, source_config, indent=indent, skip_first=parent_is_sequence
         )
         )
-    elif isinstance(schema_type, list) and all(
-        element_schema_type in SCALAR_SCHEMA_TYPES for element_schema_type in schema_type
-    ):
-        return example
-    elif schema_type in SCALAR_SCHEMA_TYPES:
+    elif borgmatic.config.schema.compare_types(schema_type, SCALAR_SCHEMA_TYPES, match=all):
         return example
         return example
     else:
     else:
         raise ValueError(f'Schema at level {level} is unsupported: {schema}')
         raise ValueError(f'Schema at level {level} is unsupported: {schema}')

+ 22 - 0
borgmatic/config/schema.py

@@ -39,3 +39,25 @@ def parse_type(schema_type):
         }[schema_type]
         }[schema_type]
     except KeyError:
     except KeyError:
         raise ValueError(f'Unknown type in configuration schema: {schema_type}')
         raise ValueError(f'Unknown type in configuration schema: {schema_type}')
+
+
+def compare_types(schema_type, target_types, match=any):
+    '''
+    Given a schema type as a string or a list of strings (representing multiple types) and a set of
+    target type strings, return whether every schema type is in the set of target types.
+
+    If the schema type is a list of strings, use the given match function (such as any or all) to
+    compare elements.
+    '''
+    if isinstance(schema_type, list):
+        if match(
+            element_schema_type in target_types for element_schema_type in schema_type
+        ):
+            return True
+
+        return False
+
+    if schema_type in target_types:
+        return True
+
+    return False

+ 20 - 8
tests/unit/config/test_generate.py

@@ -2,6 +2,7 @@ import pytest
 from flexmock import flexmock
 from flexmock import flexmock
 
 
 from borgmatic.config import generate as module
 from borgmatic.config import generate as module
+import borgmatic.config.schema
 
 
 
 
 def test_schema_to_sample_configuration_generates_config_map_with_examples():
 def test_schema_to_sample_configuration_generates_config_map_with_examples():
@@ -9,13 +10,16 @@ def test_schema_to_sample_configuration_generates_config_map_with_examples():
         'type': 'object',
         'type': 'object',
         'properties': dict(
         'properties': dict(
             [
             [
-                ('field1', {'example': 'Example 1'}),
-                ('field2', {'example': 'Example 2'}),
-                ('field3', {'example': 'Example 3'}),
+                ('field1', {'type': 'string', 'example': 'Example 1'}),
+                ('field2', {'type': 'string', 'example': 'Example 2'}),
+                ('field3', {'type': 'string', 'example': 'Example 3'}),
             ]
             ]
         ),
         ),
     }
     }
-    flexmock(module).should_receive('get_properties').and_return(schema['properties'])
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').and_return(False)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('object', {'object'}).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('string', module.SCALAR_SCHEMA_TYPES, match=all).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('get_properties').and_return(schema['properties'])
     flexmock(module.ruamel.yaml.comments).should_receive('CommentedMap').replace_with(dict)
     flexmock(module.ruamel.yaml.comments).should_receive('CommentedMap').replace_with(dict)
     flexmock(module).should_receive('add_comments_to_configuration_object')
     flexmock(module).should_receive('add_comments_to_configuration_object')
 
 
@@ -46,11 +50,15 @@ def test_schema_to_sample_configuration_generates_config_sequence_of_maps_with_e
         'items': {
         'items': {
             'type': 'object',
             'type': 'object',
             'properties': dict(
             'properties': dict(
-                [('field1', {'example': 'Example 1'}), ('field2', {'example': 'Example 2'})]
+                [('field1', {'type': 'string', 'example': 'Example 1'}), ('field2', {'type': 'string', 'example': 'Example 2'})]
             ),
             ),
         },
         },
     }
     }
-    flexmock(module).should_receive('get_properties').and_return(schema['items']['properties'])
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').and_return(False)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('array', {'array'}).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('object', {'object'}).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('string', module.SCALAR_SCHEMA_TYPES, match=all).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('get_properties').and_return(schema['items']['properties'])
     flexmock(module.ruamel.yaml.comments).should_receive('CommentedSeq').replace_with(list)
     flexmock(module.ruamel.yaml.comments).should_receive('CommentedSeq').replace_with(list)
     flexmock(module).should_receive('add_comments_to_configuration_sequence')
     flexmock(module).should_receive('add_comments_to_configuration_sequence')
     flexmock(module).should_receive('add_comments_to_configuration_object')
     flexmock(module).should_receive('add_comments_to_configuration_object')
@@ -66,11 +74,15 @@ def test_schema_to_sample_configuration_generates_config_sequence_of_maps_with_m
         'items': {
         'items': {
             'type': ['object', 'null'],
             'type': ['object', 'null'],
             'properties': dict(
             'properties': dict(
-                [('field1', {'example': 'Example 1'}), ('field2', {'example': 'Example 2'})]
+                [('field1', {'type': 'string', 'example': 'Example 1'}), ('field2', {'type': 'string', 'example': 'Example 2'})]
             ),
             ),
         },
         },
     }
     }
-    flexmock(module).should_receive('get_properties').and_return(schema['items']['properties'])
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').and_return(False)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('array', {'array'}).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args(['object', 'null'], {'object'}).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('compare_types').with_args('string', module.SCALAR_SCHEMA_TYPES, match=all).and_return(True)
+    flexmock(module.borgmatic.config.schema).should_receive('get_properties').and_return(schema['items']['properties'])
     flexmock(module.ruamel.yaml.comments).should_receive('CommentedSeq').replace_with(list)
     flexmock(module.ruamel.yaml.comments).should_receive('CommentedSeq').replace_with(list)
     flexmock(module).should_receive('add_comments_to_configuration_sequence')
     flexmock(module).should_receive('add_comments_to_configuration_sequence')
     flexmock(module).should_receive('add_comments_to_configuration_object')
     flexmock(module).should_receive('add_comments_to_configuration_object')