Exemplo n.º 1
0
    def test_namespace(self):
        """ There is something pretty subtle about caching and loading ShExJ.py in two different namespaces. The
        test_jsg_files.py test includes a validate function, which dynamically loads all of the generated python
        modules in tests/data/py.  Pretty much no matter how we do it, the module for that dynamic load isn't going
        to be the same as what you get from a straight import.

        We've tried clearing the cache, giving each python file a different name, setting the _ForwardRef
        __forward_evaluated__ to false, but nothing seems to work.  Long and short of it is, you shouldn't
        run test_shexj.py in the same thread as test_jsg_files.

        Update: we removed the _ForwardRef entries and switched to the internal forward typing (x:"Foo") if class Foo
        is further down in the class.  We add a NAMESPACE to the context at the very end of the file and pass it
        through to all of the resolution functions.  BIG HIGH FIVE on this one!
        """
        from pyjsg.parser_impl.generate_python import evaluate

        # # First load done from the testing namespace
        pyfile = os.path.abspath(
            os.path.join(os.path.dirname(__file__), '..', 'test_basics', 'py',
                         'ShExJ.py'))
        evaluate("test_namespace", pyfile, False)
        result = JSGPython(None, pyfile).conforms(json_str)
        self.assertTrue(result.success)

        # Second load from a different file
        pyfile2 = os.path.abspath(
            os.path.join(os.path.dirname(__file__), '..', 'test_jsglib', 'py',
                         'ShExJ.py'))
        copyfile(pyfile, pyfile2)
        result = JSGPython(None, pyfile2).conforms(json_str)
        if not result.success:
            print(result.fail_reason)

        self.assertTrue(result.success)
Exemplo n.º 2
0
    def test_1(self):
        x = JSGPython('''
.IGNORE target;
doc {a:@string}
''')

        rslt = x.conforms('{"a":"hello", "target":"earthling"}')
        self.assertTrue(rslt.success)
Exemplo n.º 3
0
 def test_optional_any(self):
     j = JSGPython('doc { x: .? }', print_python=False)
     rslt = j.conforms('{"x": null}')
     if not rslt.success:
         print(str(rslt))
     self.assertTrue(rslt.success)
     jclass = getattr(j.module, 'doc')
     j2 = jclass()
     self.assertEqual('{}', as_json(j2))
     self.assertTrue(is_valid(j2))
     j2.x = None
     self.assertEqual('{"x": null}', as_json(j2, indent=None))
     self.assertTrue(is_valid(j2))
     j2.x = Empty
     self.assertEqual('{}', as_json(j2))
     self.assertTrue(is_valid(j2))
Exemplo n.º 4
0
 def test_shex_schema(self):
     parser = JSGPython(shexJSGSource)
     log_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'logs', 'test_shex_schema.log')
     validator = FileValidator()
     with open(log_path, 'w') as logf:
         with redirect_stdout(logf):
             self.assertTrue(validate_shex_schemas(parser, validator), f"See {log_path} for reasons")
     print(f"{validator.nvalidated} files validated - {validator.nskipped} skipped")
Exemplo n.º 5
0
 def test_ol(self):
     """ Test that the 'type' variable in the ObjectLiteral is not mistaken as a real, unresolved type.
     """
     shexj_jsg = os.path.join(os.path.dirname(__file__), '..', '..',
                              'tests', 'test_basics', 'jsg', 'ShExJ.jsg')
     rval = JSGPython(shexj_jsg).conforms(json, "1val1DECIMAL")
     self.assertEqual("1val1DECIMAL: Conforms to Schema", str(rval))
     self.assertTrue(rval.success)
Exemplo n.º 6
0
 def test_various_optional_anys(self):
     j = JSGPython('doc {x: .? }')
     for v in ['null', '17', '-22', '-22.0', 'false', '"A string"', '{"x": null}']:
         json = f'{{"x": {v}}}'
         j2 = loads(json, j.module)
         self.assertEqual(json, as_json(j2, indent=None))
     json = '{"x": -17395e-2}'
     self.assertEqual('{"x": -173.95}', as_json(loads(json, j.module), indent=None))
Exemplo n.º 7
0
    def test_1(self):
        x = JSGPython('''
doc {
    sequences: [(RNASEQ|DNASEQ)]
}

@terminals
RNASEQ: [ACGU]+ ;
DNASEQ: [ACGT]+ ;
''')

        rslt = x.conforms('''
{ "sequences": [
    "GCUACGGAGCUUGGAGCUAG",
    "ATTTTGCGAGGTCCC"
   ]
}''')
        self.assertTrue(rslt.success)
Exemplo n.º 8
0
 def test_required_null(self):
     j = JSGPython('doc { x: @null }', print_python=False)
     rslt = j.conforms('{"x": null}')
     if not rslt.success:
         print(str(rslt))
     self.assertTrue(rslt.success)
     jclass = getattr(j.module, 'doc')
     j2 = jclass()
     self.assertEqual('{}', as_json(j2))
     self.assertFalse(is_valid(j2))
     j2.x = None
     self.assertEqual('{"x": null}', as_json(j2, indent=None))
     self.assertTrue(is_valid(j2))
     j2.x = Empty
     self.assertEqual('{}', as_json(j2))
     self.assertFalse(is_valid(j2))
     with self.assertRaises(ValueError):
         j2.x = 17
Exemplo n.º 9
0
    def test_1(self):
        x = JSGPython('''doc {
    v1: @string,
    v2: @number,
    v3: @int,
    v4: @bool,
    v5: @null,
    v6: @array,
    v7: @object 
}
obj {a: . , }''')

        rslt = x.conforms('''
        { "v1": "This is text!",
          "v2": -117.432e+2,
          "v3": -100173,
          "v4": false,
          "v5": null,
          "v6": [12, "text", null],
          "v7": {"q": "life", "a": 42}
        }''')
        self.assertTrue(rslt.success)
Exemplo n.º 10
0
    def do_test(self,
                jsg: str,
                test_file: str,
                module,
                passing_json: List[str],
                failing_vars: Dict[str, Any],
                failing_json: List[str] = None,
                print_python: bool = False) -> None:
        x = JSGPython(jsg, print_python=print_python)
        py_file = os.path.join(self.cwd, test_file + '.py')
        with open(py_file) as f:
            expected = self._strip_details(f.read())
        actual = self._strip_details(x.python)
        if expected != actual:
            if self.save_output_files or self.save_all_output_files:
                with open(py_file, 'w') as f:
                    f.write(x.python)
                    print(f"***** {py_file} updated *****")
            self.maxDiff = None
            self.assertEqual(expected, actual)

        for p in passing_json:
            json_doc = loads(p, module)
            log = logger()
            doc_is_valid = is_valid(json_doc, log)
            self.assertTrue(doc_is_valid, log.getvalue())

        for f in failing_json if failing_json else []:
            doc_is_valid = True
            json_doc = None
            error = ""
            try:
                json_doc = loads(f, module)
            except ValueError as e:
                doc_is_valid = False
                error = e
            if doc_is_valid:
                log = logger()
                doc_is_valid = is_valid(json_doc, log)
                error = log.getvalue()
            self.assertFalse(doc_is_valid, f)

        for k, v in failing_vars.items():
            with self.assertRaises(ValueError):
                vv = f'"{v}"' if isinstance(v, str) else str(v)
                loads(f'{{"{k}": {vv}}}', module)
Exemplo n.º 11
0
def validate_shexj_json(json_str: str, input_fname: str, parser: JSGPython) -> bool:
    """Validate json_str against ShEx Schema

    :param json_str: String to validate
    :param input_fname: Name of source file for error reporting
    :param parser: JSGPython parser
    :return: True if pass
    """
    rslt = parser.conforms(json_str, input_fname)
    if not rslt.success:
        print("File: {} - ".format(input_fname))
        print(str(rslt.fail_reason))
        return False
    else:
        log = StringIO()
        if not compare_json(json_str, as_json(parser.json_obj), cast(TextIO, log)):
            print("File: {} - ".format(input_fname))
            print(log.getvalue())
            print(as_json(parser.json_obj))
            return False
    return True
Exemplo n.º 12
0
 def test_extra(self):
     x = JSGPython('doc {a:@string}')
     self.assertFalse(x.conforms('{"a":"hello", "target":"earthling"}').success)
Exemplo n.º 13
0
    def test_nested_objects(self):
        """ The issue being tested here is that we appear to be issuing anonymous identifiers for
        inner objects twice -- once when referenced and a second time when publishing.  As an example, the
        'entry' in 'directory' is typed as '_Anon1', while the ArrayFactory names it as '_Anon6'
        """
        jsg = """
        directory {
            entries: {
                id: ID,
                name: {
                    first: @string,
                    middle: [@string]?,
                    last: @string
                },
                address: {
                    city: @string,
                    state: @string,
                    zip: @int?
                }*
            }*
        }

        @terminals
        ID: [1-9][0-9]{7} @int;
        """

        p1 = '''
          {
            "entries": [
                {"id": 11725433,
                  "name": {
                      "first": "Sam",
                      "last": "Sneed"
                  },
                  "address": [
                    {
                      "city": "Southwark",
                      "state": "Bliss"
                    }
                  ]
                },
                {"id": 10000001,
                  "name": {
                      "first": "Julie",
                      "middle": ["Mary", "Elizabeth"],
                      "last": "Sneed"
                  },
                  "address": [
                    {
                      "city": "Southwark",
                      "state": "Agony"
                    }
                  ]
                }
            ]
          }  
        '''

        x = JSGPython(jsg, print_python=False)
        rslt = x.conforms(p1, 'p1')
        if not rslt.success:
            print(str(rslt))

        self.assertTrue(rslt.success)
Exemplo n.º 14
0
 def test_name_valuetype(self):
     x = JSGPython('''doc {
         last_name : @string,       # exactly one last name of type string
         "first name" : @string+      # array or one or more first names
         age : @int?,               # optional age of type int
         weight : @number*,         # array of zero or more weights
         rating : @int{2,},         # at least two ratings
         spin: [@bool{0, 2}]?
     }
     ''',
                   print_python=False)
     r = x.conforms('''
     { "last_name" : "snooter",
       "first name" : ["grunt", "peter"],
       "weight" : [],
       "rating" : [10, 10]
     }''')
     self.assertTrue(r.success, str(r))
     r = x.conforms('''
     { 
       "first name" : ["grunt", "peter"],
       "weight" : [],
       "rating" : [10, 10]
     }''')
     self.assertFalse(r.success)
     self.assertEqual("FAIL - doc: Missing required field: 'last_name'",
                      str(r))
     r = x.conforms('''
     { "last_name" : "snooter",
       "first name" : [],
       "weight" : [],
       "rating" : [9, 9]
     }''')
     self.assertFalse(r.success)
     self.assertEqual(
         "FAIL - Wrong type for first name: [] - expected: <class 'pyjsg.jsglib.jsg_array.first name'> got list",
         str(r))
     r = x.conforms('''
        { "last_name" : "snooter",
          "first name" : "jim",
          "weight" : [],
          "rating" : [1, 2]
        }''')
     self.assertFalse(r.success)
     self.assertEqual(
         "FAIL - Wrong type for first name: 'jim' - expected: <class 'pyjsg.jsglib.jsg_array.first name'> got str",
         str(r))
     r = x.conforms('''
       { "last_name" : "snooter",
         "first name" : [17, 12.3, false],
         "weight" : [],
         "rating" : [1, 1]
       }''')
     self.assertFalse(r.success)
     # TODO: Get these error messages up and running
     print(f"TODO: first name element 0: 17 is not a String\n"
           f"first name element 1: 12.3 is not a String\n"
           f"first name element 2: False is not a String !=  {str(r)}")
     # self.assertEqual("FAIL - first name element 0: 17 is not a String\n")
     #                  "first name element 1: 12.3 is not a String\n"
     #                  "first name element 2: False is not a String", str(r))
     r = x.conforms('''
        { "last_name" : "snooter",
          "first name" : ["jim"],
          "weight" : [],
          "rating" : [1]
        }''')
     self.assertFalse(r.success)
     # TODO: Fix this
     print(
         f"TODO - rating: at least 2 values required - element has 1 != {str(r)}"
     )
     # self.assertEqual("FAIL - rating: at least 2 values required - element has 1", str(r))
     r = x.conforms('''
        { "last_name" : "snooter",
          "first name" : ["jim"],
          "weight" : [],
          "rating" : [1, 10],
          "spin" : [false, true, false]
        }''')
     self.assertFalse(r.success)
     # TODO: Fix this
     print(
         f"TODO - spin: no more than 2 values permitted - element has 3 != {str(r)}"
     )