【问题标题】:How to correctly call jsonnet with imports from Python如何正确调用来自 Python 的导入的 jsonnet
【发布时间】:2018-04-20 20:40:34
【问题描述】:

我正在使用 jsonnet 构建 Python 代码将使用的 json 对象,使用 bindings 从 Python 调用 jsonnet。我想设置我的目录结构,以便 jsonnet 文件位于相对于 Python 代码运行位置的一个或多个子目录中,例如:

foo.py jsonnet/ jsonnet/bar.jsonnet jsonnet/baz.libsonnet

运行foo.py 然后应该能够对从jsonnet/ 中的文件读取的字符串使用_jsonnet.evaluate_snippet(),这些文件从jsonnet/ 导入其他文件。最好的方法是什么?

【问题讨论】:

    标签: python python-import jsonnet


    【解决方案1】:

    默认导入器使用相对于导入它们的文件的路径。如果是evaluate_snippet,您需要手动传递路径。这样 jsonnet 就知道在哪里查找导入的文件。

    如果您打算处理文件,您可以使用自定义导入器。 (题外话:jsonnet尽量避免对源文件进行预处理,所以可能有更好的方法或者jsonnet中缺少的特性。)

    以下是有关如何在 Python 中使用自定义导入器的完整工作示例(已根据提供的目录结构进行调整):

    import os
    import unittest
    
    import _jsonnet
    
    
    #  Returns content if worked, None if file not found, or throws an exception
    def try_path(dir, rel):
        if not rel:
            raise RuntimeError('Got invalid filename (empty string).')
        if rel[0] == '/':
            full_path = rel
        else:
            full_path = dir + rel
        if full_path[-1] == '/':
            raise RuntimeError('Attempted to import a directory')
    
        if not os.path.isfile(full_path):
            return full_path, None
        with open(full_path) as f:
            return full_path, f.read()
    
    
    def import_callback(dir, rel):
        full_path, content = try_path(dir, rel)
        if content:
            return full_path, content
        raise RuntimeError('File not found')
    
    
    class JsonnetTests(unittest.TestCase):
        def setUp(self):
            self.input_filename = os.path.join(
                "jsonnet",
                "bar.jsonnet",
            )
            self.expected_str = '{\n   "num": 42,\n   "str": "The answer to life ..."\n}\n'
            with open(self.input_filename, "r") as infile:
                self.input_snippet = infile.read()
    
        def test_evaluate_file(self):
            json_str = _jsonnet.evaluate_file(
                self.input_filename,
                import_callback=import_callback,
            )
            self.assertEqual(json_str, self.expected_str)
    
        def test_evaluate_snippet(self):
            json_str = _jsonnet.evaluate_snippet(
                "jsonnet/bar.jsonnet",
                self.input_snippet,
                import_callback=import_callback,
            )
            self.assertEqual(json_str, self.expected_str)
    
    if __name__ == '__main__':
        unittest.main()
    

    注意:这是an example from jsonnet repo的修改版。

    【讨论】:

      【解决方案2】:

      我不完全明白你为什么要使用evaluate_snippet()(也许通过将它们从python加载到字符串中来掩盖实际的文件名+evaluate_snippet("blah", str)?),而不是evaluate_file() - 在任何情况下,该结构都应该可以工作好的。

      例子:

      jsonnet_test.py:

      import json:
      import _jsonnet
      
      jsonnet_file = "jsonnet/bar.jsonnet"
      data = json.loads(_jsonnet.evaluate_file(jsonnet_file))
      print("{str} => {num}".format(**data))
      

      jsonnet/bar.jsonnet

      local baz = import "baz.libsonnet";
      {
        str: "The answer to life ...",
        num: baz.mult(6, 7),
      }
      

      jsonnet/baz.libsonnet

      {
        mult(a, b):: (
          a * b
        ),
      }
      

      输出:

      $ python jsonnet_test.py
      The answer to life ... => 42
      

      【讨论】:

      • 我需要修改jsonnet代码,然后才能传递给_jsonnet。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-18
      • 1970-01-01
      • 1970-01-01
      • 2016-03-19
      • 2020-08-04
      相关资源
      最近更新 更多