예제 #1
0
    def __init__(self,
                 schema: Union[str, TextIO, SchemaDefinition, "Generator"],
                 fmt: Optional[str] = None,
                 emit_metadata: bool = False) -> None:
        """
        Constructor

        :param schema: metamodel compliant schema.  Can be URI, file name, actual schema, another generator, an
        open file or a pre-parsed schema.
        :param fmt: expected output format
        :param emit_metadata: True means include date, generator, etc. information in source header if appropriate
        """
        if fmt is None:
            fmt = self.valid_formats[0]
        assert fmt in self.valid_formats, f"Unrecognized format: {fmt}"
        self.format = fmt
        self.emit_metadata = emit_metadata
        if isinstance(schema, Generator):
            gen = schema
            self.schema = gen.schema
            self.synopsis = gen.synopsis
            self.namespaces = gen.namespaces
            self.base_dir = gen.base_dir
            self.schema_location = gen.schema_location
        else:
            loader = SchemaLoader(schema, self.base_dir)
            loader.resolve()
            self.schema = loader.schema
            self.synopsis = loader.synopsis
            self.namespaces = loader.namespaces
            self.base_dir = loader.base_dir
            self.schema_location = loader.schema_location
예제 #2
0
    def test_error_paths(self):
        """ Test various loader error situations"""

        fn = env.input_path('loadererror1.yaml')
        with self.assertRaises(ValueError,
                               msg="Unknown slot domain should fail") as e:
            SchemaLoader(fn).resolve()
        self.assertIn('loadererror1.yaml", line 11, col 13', str(e.exception))

        fn = env.input_path('loadererror2.yaml')
        with self.assertRaises(ValueError, msg="No Type URI") as e:
            SchemaLoader(fn).resolve()
        self.assertIn('type "string" does not declare a URI', str(e.exception))

        fn = env.input_path('loadererror2a.yaml')
        with self.assertRaises(ValueError,
                               msg="Optional key slot should fail") as e:
            SchemaLoader(fn).resolve()
        self.assertIn('slot: s1 - key and identifier slots cannot be optional',
                      str(e.exception))

        fn = env.input_path('loadertest1.yaml')
        schema = SchemaLoader(fn).resolve()
        self.assertEqual('string', schema.slots['s1'].range)

        fn = env.input_path('loadererror4.yaml')
        with self.assertRaises(ValueError,
                               msg="Default prefix is not defined") as e:
            SchemaLoader(fn).resolve()
        self.assertIn('loadererror4.yaml", line 6, col 17', str(e.exception))
예제 #3
0
 def __init__(self, schema: Union[str, TextIO, SchemaDefinition],
              **kwargs) -> None:
     super().__init__(schema, **kwargs)
     self.graph: Optional[Graph] = None
     self.metamodel = SchemaLoader(LOCAL_METAMODEL_YAML_FILE) if os.path.exists(LOCAL_METAMODEL_YAML_FILE) else\
         SchemaLoader(METAMODEL_YAML_URI, base_dir=META_BASE_URI)
     self.metamodel.resolve()
     self.top_value_uri: Optional[URIRef] = None
예제 #4
0
 def __init__(self,
              schema: Union[str, TextIO, SchemaDefinition],
              fmt: str = 'ttl') -> None:
     super().__init__(schema, fmt)
     self.graph: Graph = None
     self.metamodel = SchemaLoader(LOCAL_YAML_PATH)
     self.metamodel.resolve()
     self.top_value_uri: URIRef = None
예제 #5
0
 def test_missing_type_uri(self):
     """ A type with neither a typeof or uri is an error """
     fn = os.path.join(datadir, 'loadererror10.yaml')
     with self.assertRaises(ValueError,
                            msg="A non-typeof type has to have a URI"):
         _ = SchemaLoader(fn).resolve()
     fn = os.path.join(datadir, 'loaderpass11.yaml')
     _ = SchemaLoader(fn).resolve()
예제 #6
0
    def __init__(self,
                 schema: Union[str, TextIO, SchemaDefinition, "Generator"],
                 format: Optional[str] = None,
                 emit_metadata: bool = False,
                 useuris: Optional[bool] = None,
                 importmap: Optional[str] = None,
                 log_level: int = DEFAULT_LOG_LEVEL_INT,
                 **kwargs) -> None:
        """
        Constructor

        :param schema: metamodel compliant schema.  Can be URI, file name, actual schema, another generator, an
        open file or a pre-parsed schema.
        :param format: expected output format
        :param emit_metadata: True means include date, generator, etc. information in source header if appropriate
        :param useuris: True means declared class slot uri's are used.  False means use model uris
        :param importmap: File name of import mapping file -- maps import name/uri to target
        :param log_level: Logging level
        :param logger: pre-set logger (hidden in kwargs)
        """
        if 'logger' in kwargs:
            self.logger = kwargs.pop('logger')
        else:
            logging.basicConfig()
            self.logger = logging.getLogger(self.__class__.__name__)
            self.logger.setLevel(log_level)

        if format is None:
            format = self.valid_formats[0]
        assert format in self.valid_formats, f"Unrecognized format: {format}"
        self.format = format
        self.emit_metadata = emit_metadata
        if isinstance(schema, Generator):
            gen = schema
            self.schema = gen.schema
            self.synopsis = gen.synopsis
            self.loaded = gen.loaded
            self.namespaces = gen.namespaces
            self.base_dir = gen.base_dir
            self.importmap = gen.importmap
            self.schema_location = gen.schema_location
            self.schema_defaults = gen.schema_defaults
            self.logger = gen.logger
        else:
            loader = SchemaLoader(schema,
                                  self.base_dir,
                                  useuris=useuris,
                                  importmap=importmap,
                                  logger=self.logger)
            loader.resolve()
            self.schema = loader.schema
            self.synopsis = loader.synopsis
            self.loaded = loader.loaded
            self.namespaces = loader.namespaces
            self.base_dir = loader.base_dir
            self.importmap = loader.importmap
            self.schema_location = loader.schema_location
            self.schema_defaults = loader.schema_defaults
예제 #7
0
 def test_missing_type_uri(self):
     """ A type with neither a typeof or uri is an error """
     fn = env.input_path('loadererror10.yaml')
     with self.assertRaises(ValueError,
                            msg="A non-typeof type has to have a URI") as e:
         _ = SchemaLoader(fn).resolve()
     self.assertIn('loadererror10.yaml", line 12, col 3', str(e.exception))
     fn = env.input_path('loaderpass11.yaml')
     _ = SchemaLoader(fn).resolve()
예제 #8
0
 def test_biolink_model(self):
     """ Make sure the biolink model is valid """
     schema = SchemaLoader(BIOLINK_MODEL_YAML)
     errors = []
     try:
         schema.resolve()
     except ValueError as e:
         errors.append(str(e))
     if not errors:
         errors = schema.synopsis.errors()
     self.assertEqual([], errors, "biolink-model.yaml - errors detected")
예제 #9
0
    def test_key_and_id(self):
        """ A slot cannot be both a key and an identifier """
        fn = os.path.join(datadir, 'loadererror8.yaml')
        with self.assertRaises(
                ValueError, msg="A slot cannot be both a key and identifier"):
            _ = SchemaLoader(fn).resolve()

        fn = os.path.join(datadir, 'loadererror9.yaml')
        with self.assertRaises(
                ValueError, msg="A slot cannot be both a key and identifier"):
            _ = SchemaLoader(fn).resolve()
예제 #10
0
    def test_multi_key(self):
        """ Multiple keys are not supported """
        fn = os.path.join(datadir, 'loadererror6.yaml')
        with self.assertRaises(ValueError,
                               msg="Two or more keys are not allowed"):
            _ = SchemaLoader(fn).resolve()

        fn = os.path.join(datadir, 'loadererror7.yaml')
        with self.assertRaises(ValueError,
                               msg="Two or more keys are not allowed"):
            _ = SchemaLoader(fn).resolve()
예제 #11
0
 def eval_loader(self,
                 base_name: str,
                 is_sourcedir: bool = False,
                 source: Optional[str] = None) -> None:
     fn = os.path.join(sourcedir if is_sourcedir else datadir, base_name +
                       '.yaml') if not source else source
     loader = SchemaLoader(fn)
     schema = as_json(self.fix_schema_metadata(loader.resolve()))
     self.eval_output(schema, base_name + '.json', loads)
     errors = '\n'.join(loader.synopsis.errors())
     self.eval_output(errors, base_name + '.errs')
     self.assertFalse(update_all_files, "Updating base files -- rerun")
예제 #12
0
 def test_default_range(self):
     """ Validate default slot range settings """
     schema = SchemaLoader(env.input_path('resolver1.yaml')).resolve()
     self.assertEqual({
         's1': 't1',
         's2': 't2'
     }, {slot.name: slot.range
         for slot in schema.slots.values()})
     schema = SchemaLoader(env.input_path('resolver2.yaml')).resolve()
     self.assertEqual({
         's1': 'string',
         's2': 't2'
     }, {slot.name: slot.range
         for slot in schema.slots.values()})
예제 #13
0
 def test_representation_errors(self):
     """ Test misformed schema elements """
     fn = env.input_path('typeerror1.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
     fn = env.input_path('typeerror2.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
     fn = env.input_path('typeerror3.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
     fn = env.input_path('typeerror4.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
예제 #14
0
 def test_representation_errors(self):
     """ Test misformed schema elements """
     fn = os.path.join(datadir, 'typeerror1.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
     fn = os.path.join(datadir, 'typeerror2.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
     fn = os.path.join(datadir, 'typeerror3.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
     fn = os.path.join(datadir, 'typeerror4.yaml')
     with self.assertRaises(ValueError):
         SchemaLoader(fn)
예제 #15
0
    def test_multi_key(self):
        """ Multiple keys are not supported """
        fn = env.input_path('loadererror6.yaml')
        with self.assertRaises(
                ValueError, msg='Multiple keys/identifiers not allowed') as e:
            _ = SchemaLoader(fn).resolve()
        self.assertIn('multiple keys/identifiers not allowed',
                      str(e.exception))

        fn = env.input_path('loadererror7.yaml')
        with self.assertRaises(ValueError,
                               msg="Two or more keys are not allowed") as e:
            _ = SchemaLoader(fn).resolve()
        self.assertIn('multiple keys/identifiers not allowed',
                      str(e.exception))
예제 #16
0
 def test_no_inverse_domain(self):
     with self.assertRaises(ValueError) as e:
         env.generate_single_file('issue_18_error3.yaml',
                                  lambda: as_yaml(SchemaLoader(env.input_path('issue_18_error3.yaml')).resolve()),
                                  value_is_returned=True)
     self.assertEqual("Unable to determine the range of slot `s1'. Its inverse (s2) has no declared domain",
                      str(e.exception).strip())
예제 #17
0
 def test_inverse_mismatch(self):
     """ Test error detection when inverses don't match """
     with self.assertRaises(ValueError) as e:
         env.generate_single_file('issue_18_error1.yaml',
                                  lambda: as_yaml(SchemaLoader(env.input_path('issue_18_error1.yaml')).resolve()),
                                  value_is_returned=True)
     self.assertEqual('Slot s1.inverse (s2) does not match slot s2.inverse (s3)', str(e.exception).strip())
예제 #18
0
    def eval_synopsis(self,
                      base_name: str,
                      source: Optional[str] = None) -> None:
        schema = SchemaLoader(source if source else env.input_path(base_name +
                                                                   '.yaml'),
                              importmap=env.import_map)
        schema.resolve()
        self.summary = schema.synopsis.summary()

        self.env.generate_single_file(
            base_name + '.errs',
            lambda: '\n'.join(schema.synopsis.errors()),
            value_is_returned=True)
        self.env.generate_single_file(base_name + '.synopsis',
                                      lambda: self.summary,
                                      value_is_returned=True)
예제 #19
0
 def test_undefined_subset(self):
     """ Throw an error on an undefined subset reference """
     fn = env.input_path('loadererror11.yaml')
     with self.assertRaises(ValueError,
                            msg="Subset references must be valid") as e:
         _ = SchemaLoader(fn).resolve()
     self.assertIn('loadererror11.yaml", line 22, col 16', str(e.exception))
예제 #20
0
 def eval_loader(self,
                 base_name: str,
                 logger: Optional[logging.Logger] = None,
                 source: Optional[str] = None) -> None:
     loader = SchemaLoader(source
                           or self.env.input_path(base_name + '.yaml'),
                           logger=logger)
     self.env.generate_single_file(base_name + '.json',
                                   lambda: as_json(loader.resolve()),
                                   filtr=json_metadata_filter,
                                   value_is_returned=True)
     self.env.generate_single_file(
         base_name + '.errs',
         lambda: '\n'.join(loader.synopsis.errors()),
         filtr=json_metadata_filter,
         value_is_returned=True)
예제 #21
0
 def test_empty_range(self):
     """ A type must have either a base or a parent """
     fn = env.input_path('loadererror5.yaml')
     with self.assertRaises(ValueError,
                            msg="Range error should be raised") as e:
         _ = SchemaLoader(fn).resolve()
     self.assertIn('loadererror5.yaml", line 9, col 3', str(e.exception))
예제 #22
0
class SchemaSynopsisTestCase(Base):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.loader: SchemaLoader = None

    def loadit(self, source: str) -> None:
        self.loader = SchemaLoader(source)
        self.loader.resolve()

    """ Tests for various parts of the schema synopsis file """

    def eval_synopsis(self,
                      base_name: str,
                      *,
                      is_sourcedir: bool = False,
                      source: Optional[str] = None) -> None:
        fn = os.path.join(sourcedir if is_sourcedir else inputdir, base_name +
                          '.yaml') if not source else source
        self.loadit(fn)
        errors = '\n'.join(self.loader.synopsis.errors())
        self.eval_output(errors, base_name + '.errs')

        synopsis = self.loader.synopsis.summary()
        self.eval_output(synopsis, base_name + '.synopsis')
        self.assertFalse(update_all_files, "Updating base files -- rerun")

    def assert_warning(self, text: str) -> bool:
        return f'* {text}' in self.loader.synopsis.summary()

    def assert_error(self, text: Union[str, List[str]]) -> None:
        if isinstance(text, str):
            text = [text]
        self.assertEqual(text,
                         [e.strip() for e in self.loader.synopsis.errors()])

    def test_meta_synopsis(self):
        """ Raise a flag if the number of classes, slots, types or other elements change in the model  """
        self.eval_synopsis('meta', source=LOCAL_METAMODEL_YAML_FILE)

    def test_unitialized_domain(self):
        self.loadit(os.path.join(inputdir, 'synopsis1.yaml'))
        # Owners check no longer occurs
        # self.assert_error('Slot s1 has no owners')
        self.assert_warning('Unspecified domain: s1')

    def test_applyto(self):
        self.eval_synopsis('synopsis2')
예제 #23
0
 def test_multi_domains(self):
     with self.redirect_logstream() as logger:
         env.generate_single_file('issue_18_warning1.yaml',
                                  lambda: as_yaml(SchemaLoader(env.input_path('issue_18_warning1.yaml'),
                                                               logger=logger).resolve()),
                                  filtr=yaml_filter, value_is_returned=True)
     self.assertIn('Slot s2.inverse (s1), has multi domains (c1, c2)  Multi ranges not yet implemented',
                   logger.result)
예제 #24
0
 def test_issue_167(self):
     """ Test extensions to the four basic types """
     env.generate_single_file(
         'issue_167.yaml',
         lambda: as_yaml(
             SchemaLoader(env.input_path('issue_167.yaml')).resolve()),
         value_is_returned=True,
         filtr=yaml_filter)
예제 #25
0
 def test_multi_usages_2(self):
     """ Slot usage chain with starting alias """
     schema = SchemaLoader(env.input_path('multi_usages_2.yaml')).resolve()
     self._eval_expected(schema, 's1', 'value', 'root_class', None, None, 'string')
     self._eval_expected(schema, 'child_class1_s1', 'value', 'child_class1', 's1', 's1', 'boolean')
     self._eval_expected(schema, 'child_class2_s1', 'value', 'child_class2', 'child_class1_s1', 's1', 'integer')
     self._eval_expected(schema, 'child_class3_s1', 'value', 'child_class3', 'child_class2_s1', 's1', 'integer')
     env.eval_single_file(env.expected_path('multi_usages_2.yaml'), as_yaml(schema), filtr=yaml_filter)
예제 #26
0
 def test_mergeerror1(self):
     """ Test conflicting definitions path """
     fn = env.input_path('mergeerror1.yaml')
     with self.assertRaises(ValueError) as ve:
         SchemaLoader(fn)
     self.assertEqual(
         "Conflicting URIs (http://example.org/schema2, http://example.org/schema1) for item: c1",
         str(ve.exception))
예제 #27
0
 def test_issue_177_dup(self):
     env.generate_single_file(
         'issue_177_error.yaml',
         lambda: as_yaml(
             SchemaLoader(env.input_path('issue_177_error.yaml')).resolve()
         ),
         value_is_returned=True,
         filtr=yaml_filter)
예제 #28
0
 def test_issue_167b_yaml(self):
     """ Annotations yaml example """
     env.generate_single_file(
         'issue_167b.yaml',
         lambda: as_yaml(
             SchemaLoader(env.input_path('issue_167b.yaml'),
                          importmap=env.import_map).resolve()),
         value_is_returned=True,
         filtr=yaml_filter)
예제 #29
0
    def test_key_and_id(self):
        """ A slot cannot be both a key and an identifier """
        fn = env.input_path('loadererror8.yaml')
        with self.assertRaises(
                ValueError,
                msg="A slot cannot be both a key and identifier") as e:
            _ = SchemaLoader(fn).resolve()
        self.assertIn(
            'A slot cannot be both a key and identifier at the same time',
            str(e.exception))

        fn = env.input_path('loadererror9.yaml')
        with self.assertRaises(
                ValueError,
                msg="A slot cannot be both a key and identifier") as e:
            _ = SchemaLoader(fn).resolve()
        self.assertIn(
            'A slot cannot be both a key and identifier at the same time',
            str(e.exception))
예제 #30
0
 def test_issue_58(self):
     """ Reject non NSNAME model names"""
     with self.assertRaises(ValueError) as ve:
         env.generate_single_file(
             'issue_58_error1.yaml',
             lambda: as_yaml(
                 SchemaLoader(env.input_path('issue_58_error1.yaml')).
                 resolve()),
             value_is_returned=True)
     self.assertIn('issue 58: Not a valid NCName', str(ve.exception))