Commit 1e5476fb authored by Stefan Behnel's avatar Stefan Behnel

major cleanup refactoring of the utility code loading support,

simple support for loading requirements (at least from the same utility code type and file),
caching support
parent 0301ebf1
...@@ -748,8 +748,11 @@ def get_type_information_cname(code, dtype, maxdepth=None): ...@@ -748,8 +748,11 @@ def get_type_information_cname(code, dtype, maxdepth=None):
), safe=True) ), safe=True)
return name return name
def load_buffer_utility(util_code_name, **kwargs): def load_buffer_utility(util_code_name, context=None, **kwargs):
return UtilityCode.load(util_code_name, "Buffer.c", **kwargs) if context is None:
return UtilityCode.load(util_code_name, "Buffer.c", **kwargs)
else:
return TempitaUtilityCode.load(util_code_name, "Buffer.c", context=context, **kwargs)
context = dict(max_dims=str(Options.buffer_max_dims)) context = dict(max_dims=str(Options.buffer_max_dims))
buffer_struct_declare_code = load_buffer_utility("BufferStructDeclare", buffer_struct_declare_code = load_buffer_utility("BufferStructDeclare",
......
This diff is collapsed.
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
import cython import cython
cython.declare(error=object, warning=object, warn_once=object, InternalError=object, cython.declare(error=object, warning=object, warn_once=object, InternalError=object,
CompileError=object, UtilityCode=object, StringEncoding=object, operator=object, CompileError=object, UtilityCode=object, TempitaUtilityCode=object,
StringEncoding=object, operator=object,
Naming=object, Nodes=object, PyrexTypes=object, py_object_type=object, Naming=object, Nodes=object, PyrexTypes=object, py_object_type=object,
list_type=object, tuple_type=object, set_type=object, dict_type=object, \ list_type=object, tuple_type=object, set_type=object, dict_type=object, \
unicode_type=object, str_type=object, bytes_type=object, type_type=object, unicode_type=object, str_type=object, bytes_type=object, type_type=object,
...@@ -15,7 +16,7 @@ import operator ...@@ -15,7 +16,7 @@ import operator
from Errors import error, warning, warn_once, InternalError, CompileError from Errors import error, warning, warn_once, InternalError, CompileError
from Errors import hold_errors, release_errors, held_errors, report_error from Errors import hold_errors, release_errors, held_errors, report_error
from Code import UtilityCode from Code import UtilityCode, TempitaUtilityCode
import StringEncoding import StringEncoding
import Naming import Naming
import Nodes import Nodes
...@@ -9967,9 +9968,9 @@ proto=""" ...@@ -9967,9 +9968,9 @@ proto="""
(((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x))) (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x)))
""") """)
binding_cfunc_utility_code = UtilityCode.load("CythonFunction", binding_cfunc_utility_code = TempitaUtilityCode.load(
context=vars(Naming)) "CythonFunction", context=vars(Naming))
fused_function_utility_code = UtilityCode.load( fused_function_utility_code = TempitaUtilityCode.load(
"FusedFunction", "FusedFunction",
"CythonFunction.c", "CythonFunction.c",
context=vars(Naming), context=vars(Naming),
......
...@@ -2,7 +2,7 @@ from Errors import CompileError, error ...@@ -2,7 +2,7 @@ from Errors import CompileError, error
import ExprNodes import ExprNodes
from ExprNodes import IntNode, NameNode, AttributeNode from ExprNodes import IntNode, NameNode, AttributeNode
import Options import Options
from Code import UtilityCode from Code import UtilityCode, TempitaUtilityCode
from UtilityCode import CythonUtilityCode from UtilityCode import CythonUtilityCode
import Buffer import Buffer
import PyrexTypes import PyrexTypes
...@@ -931,8 +931,11 @@ def load_memview_cy_utility(util_code_name, context=None, **kwargs): ...@@ -931,8 +931,11 @@ def load_memview_cy_utility(util_code_name, context=None, **kwargs):
context=context, **kwargs) context=context, **kwargs)
def load_memview_c_utility(util_code_name, context=None, **kwargs): def load_memview_c_utility(util_code_name, context=None, **kwargs):
return UtilityCode.load(util_code_name, "MemoryView_C.c", if context is None:
context=context, **kwargs) return UtilityCode.load(util_code_name, "MemoryView_C.c", **kwargs)
else:
return TempitaUtilityCode.load(util_code_name, "MemoryView_C.c",
context=context, **kwargs)
def use_cython_array_utility_code(env): def use_cython_array_utility_code(env):
env.global_scope().context.cython_scope.lookup('array_cwrapper').used = True env.global_scope().context.cython_scope.lookup('array_cwrapper').used = True
......
...@@ -15,7 +15,7 @@ import Symtab ...@@ -15,7 +15,7 @@ import Symtab
import Options import Options
import Naming import Naming
from Code import UtilityCode, ContentHashingUtilityCode from Code import UtilityCode
from StringEncoding import EncodedString, BytesLiteral from StringEncoding import EncodedString, BytesLiteral
from Errors import error from Errors import error
from ParseTreeTransforms import SkipDeclarations from ParseTreeTransforms import SkipDeclarations
...@@ -32,11 +32,8 @@ try: ...@@ -32,11 +32,8 @@ try:
except ImportError: except ImportError:
basestring = str # Python 3 basestring = str # Python 3
_utility_cache = {}
def load_c_utility(name): def load_c_utility(name):
if name not in _utility_cache: return UtilityCode.load_cached(name, "Optimize.c")
_utility_cache[name] = ContentHashingUtilityCode.load(name, "Optimize.c")
return _utility_cache[name]
class FakePythonEnv(object): class FakePythonEnv(object):
"A fake environment for creating type test nodes etc." "A fake environment for creating type test nodes etc."
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Cython/Python language types # Cython/Python language types
# #
from Code import UtilityCode, LazyUtilityCode, ContentHashingUtilityCode from Code import UtilityCode, LazyUtilityCode, TempitaUtilityCode
import StringEncoding import StringEncoding
import Naming import Naming
import copy import copy
...@@ -610,14 +610,14 @@ class MemoryViewSliceType(PyrexType): ...@@ -610,14 +610,14 @@ class MemoryViewSliceType(PyrexType):
return cname + '.memview' return cname + '.memview'
def create_from_py_utility_code(self, env): def create_from_py_utility_code(self, env):
import MemoryView, Buffer, Code import MemoryView, Buffer
# We don't have 'code', so use a LazyUtilityCode with a callback. # We don't have 'code', so use a LazyUtilityCode with a callback.
def lazy_utility_callback(code): def lazy_utility_callback(code):
context['dtype_typeinfo'] = Buffer.get_type_information_cname( context['dtype_typeinfo'] = Buffer.get_type_information_cname(
code, self.dtype) code, self.dtype)
return ContentHashingUtilityCode.load( return TempitaUtilityCode.load(
"ObjectToMemviewSlice", "MemoryView_C.c", context) "ObjectToMemviewSlice", "MemoryView_C.c", context=context)
env.use_utility_code(Buffer.acquire_utility_code) env.use_utility_code(Buffer.acquire_utility_code)
env.use_utility_code(MemoryView.memviewslice_init_code) env.use_utility_code(MemoryView.memviewslice_init_code)
...@@ -693,7 +693,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -693,7 +693,7 @@ class MemoryViewSliceType(PyrexType):
error_condition = error_condition, error_condition = error_condition,
) )
utility = ContentHashingUtilityCode.load( utility = TempitaUtilityCode.load(
utility_name, "MemoryView_C.c", context=context) utility_name, "MemoryView_C.c", context=context)
env.use_utility_code(utility) env.use_utility_code(utility)
return get_function, set_function return get_function, set_function
...@@ -2796,8 +2796,8 @@ class CStructOrUnionType(CType): ...@@ -2796,8 +2796,8 @@ class CStructOrUnionType(CType):
funcname = self.from_py_function, funcname = self.from_py_function,
init = '%s 0 %s' % ('{' * nesting_depth, '}' * nesting_depth) init = '%s 0 %s' % ('{' * nesting_depth, '}' * nesting_depth)
) )
self._convert_from_py_code = ContentHashingUtilityCode.load( self._convert_from_py_code = TempitaUtilityCode.load(
"FromPyStructUtility", "TypeConversion.c", context) "FromPyStructUtility", "TypeConversion.c", context=context)
env.use_utility_code(self._convert_from_py_code) env.use_utility_code(self._convert_from_py_code)
return True return True
......
...@@ -12,10 +12,8 @@ class TestUtilityLoader(unittest.TestCase): ...@@ -12,10 +12,8 @@ class TestUtilityLoader(unittest.TestCase):
""" """
expected = "test {{loader}} prototype", "test {{loader}} impl" expected = "test {{loader}} prototype", "test {{loader}} impl"
expected_tempita = (expected[0].replace('{{loader}}', 'Loader'),
expected[1].replace('{{loader}}', 'Loader'))
required = "I am a dependency proto", "I am a dependency impl" required = "req {{loader}} proto", "req {{loader}} impl"
context = dict(loader='Loader') context = dict(loader='Loader')
...@@ -30,24 +28,55 @@ class TestUtilityLoader(unittest.TestCase): ...@@ -30,24 +28,55 @@ class TestUtilityLoader(unittest.TestCase):
got = strip_2tup(self.cls.load_as_string(self.name, self.filename)) got = strip_2tup(self.cls.load_as_string(self.name, self.filename))
self.assertEquals(got, self.expected) self.assertEquals(got, self.expected)
got = strip_2tup(self.cls.load_as_string(self.name, context=self.context))
self.assertEquals(got, self.expected_tempita)
def test_load(self): def test_load(self):
utility = self.cls.load(self.name) utility = self.cls.load(self.name)
got = strip_2tup((utility.proto, utility.impl)) got = strip_2tup((utility.proto, utility.impl))
self.assertEquals(got, self.expected) self.assertEquals(got, self.expected)
# Not implemented yet required, = utility.requires
#required, = utility.requires got = strip_2tup((required.proto, required.impl))
#self.assertEquals((required.proto, required.impl), self.required) self.assertEquals(got, self.required)
utility = self.cls.load(self.name, from_file=self.filename) utility = self.cls.load(self.name, from_file=self.filename)
got = strip_2tup((utility.proto, utility.impl)) got = strip_2tup((utility.proto, utility.impl))
self.assertEquals(got, self.expected) self.assertEquals(got, self.expected)
utility = self.cls.load_cached(self.name, from_file=self.filename)
got = strip_2tup((utility.proto, utility.impl))
self.assertEquals(got, self.expected)
class TestCythonUtilityLoader(TestUtilityLoader): class TestTempitaUtilityLoader(TestUtilityLoader):
"""
Test loading UtilityCodes with Tempita substitution
"""
expected_tempita = (TestUtilityLoader.expected[0].replace('{{loader}}', 'Loader'),
TestUtilityLoader.expected[1].replace('{{loader}}', 'Loader'))
required_tempita = (TestUtilityLoader.required[0].replace('{{loader}}', 'Loader'),
TestUtilityLoader.required[1].replace('{{loader}}', 'Loader'))
cls = Code.TempitaUtilityCode
def test_load_as_string(self):
got = strip_2tup(self.cls.load_as_string(self.name, context=self.context))
self.assertEquals(got, self.expected_tempita)
def test_load(self):
utility = self.cls.load(self.name, context=self.context)
got = strip_2tup((utility.proto, utility.impl))
self.assertEquals(got, self.expected_tempita)
required, = utility.requires
got = strip_2tup((required.proto, required.impl))
self.assertEquals(got, self.required_tempita)
utility = self.cls.load(self.name, from_file=self.filename, context=self.context)
got = strip_2tup((utility.proto, utility.impl))
self.assertEquals(got, self.expected_tempita)
class TestCythonUtilityLoader(TestTempitaUtilityLoader):
""" """
Test loading CythonUtilityCodes Test loading CythonUtilityCodes
""" """
...@@ -56,7 +85,8 @@ class TestCythonUtilityLoader(TestUtilityLoader): ...@@ -56,7 +85,8 @@ class TestCythonUtilityLoader(TestUtilityLoader):
expected = None, "test {{cy_loader}} impl" expected = None, "test {{cy_loader}} impl"
expected_tempita = None, "test CyLoader impl" expected_tempita = None, "test CyLoader impl"
required = None, "I am a Cython dependency impl" required = None, "req {{cy_loader}} impl"
required_tempita = None, "req CyLoader impl"
context = dict(cy_loader='CyLoader') context = dict(cy_loader='CyLoader')
...@@ -65,4 +95,7 @@ class TestCythonUtilityLoader(TestUtilityLoader): ...@@ -65,4 +95,7 @@ class TestCythonUtilityLoader(TestUtilityLoader):
cls = UtilityCode.CythonUtilityCode cls = UtilityCode.CythonUtilityCode
# Small hack to pass our tests above # Small hack to pass our tests above
cls.proto = None cls.proto = None
\ No newline at end of file
test_load = TestUtilityLoader.test_load
test_load_tempita = TestTempitaUtilityLoader.test_load
...@@ -66,13 +66,15 @@ class CythonUtilityCode(Code.UtilityCodeBase): ...@@ -66,13 +66,15 @@ class CythonUtilityCode(Code.UtilityCodeBase):
is_cython_utility = True is_cython_utility = True
def __init__(self, impl, name="__pyxutil", prefix="", requires=None, def __init__(self, impl, name="__pyxutil", prefix="", requires=None,
file=None, from_scope=None): file=None, from_scope=None, context=None):
# 1) We need to delay the parsing/processing, so that all modules can be # 1) We need to delay the parsing/processing, so that all modules can be
# imported without import loops # imported without import loops
# 2) The same utility code object can be used for multiple source files; # 2) The same utility code object can be used for multiple source files;
# while the generated node trees can be altered in the compilation of a # while the generated node trees can be altered in the compilation of a
# single file. # single file.
# Hence, delay any processing until later. # Hence, delay any processing until later.
if context is not None:
impl = Code.sub_tempita(impl, context, file, name)
self.impl = impl self.impl = impl
self.name = name self.name = name
self.file = file self.file = file
...@@ -128,6 +130,14 @@ class CythonUtilityCode(Code.UtilityCodeBase): ...@@ -128,6 +130,14 @@ class CythonUtilityCode(Code.UtilityCodeBase):
def put_code(self, output): def put_code(self, output):
pass pass
@classmethod
def load_as_string(cls, util_code_name, from_file=None, **kwargs):
"""
Load a utility code as a string. Returns (proto, implementation)
"""
util = cls.load(util_code_name, from_file, **kwargs)
return util.proto, util.impl # keep line numbers => no lstrip()
def declare_in_scope(self, dest_scope, used=False, cython_scope=None): def declare_in_scope(self, dest_scope, used=False, cython_scope=None):
""" """
Declare all entries from the utility code in dest_scope. Code will only Declare all entries from the utility code in dest_scope. Code will only
......
########## TestCyUtilityLoader ########## ########## TestCyUtilityLoader ##########
#@requires: OtherUtility
test {{cy_loader}} impl test {{cy_loader}} impl
########## OtherUtility ##########
req {{cy_loader}} impl
...@@ -2,4 +2,11 @@ ...@@ -2,4 +2,11 @@
test {{loader}} prototype test {{loader}} prototype
////////// TestUtilityLoader ////////// ////////// TestUtilityLoader //////////
//@requires: OtherUtility
test {{loader}} impl test {{loader}} impl
////////// OtherUtility.proto //////////
req {{loader}} proto
////////// OtherUtility //////////
req {{loader}} impl
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment