Revision: 1495
http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1495&view=rev
Author: roman_yakovenko
Date: 2008-12-24 20:57:21 +0000 (Wed, 24 Dec 2008)
Log Message:
-----------
making more room for new module builder
Modified Paths:
--------------
pyplusplus_dev/pyplusplus/module_builder/__init__.py
Added Paths:
-----------
pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py
pyplusplus_dev/pyplusplus/module_builder/module_builder.py
Removed Paths:
-------------
pyplusplus_dev/pyplusplus/module_builder/builder.py
pyplusplus_dev/pyplusplus/module_builder/extension_builder.py
Modified: pyplusplus_dev/pyplusplus/module_builder/__init__.py
===================================================================
--- pyplusplus_dev/pyplusplus/module_builder/__init__.py 2008-12-24 20:47:08 UTC (rev 1494)
+++ pyplusplus_dev/pyplusplus/module_builder/__init__.py 2008-12-24 20:57:21 UTC (rev 1495)
@@ -12,7 +12,7 @@
U{web site<http://www.language-binding.net>}
"""
-from extension_builder import extension_module_builder_t as module_builder_t
+from boost_python_builder import builder_t as module_builder_t
from ctypes_builder import ctypes_module_builder_t
#aliases for functionality located in pygccxml.parser module
Copied: pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py (from rev 1494, pyplusplus_dev/pyplusplus/module_builder/extension_builder.py)
===================================================================
--- pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py (rev 0)
+++ pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py 2008-12-24 20:57:21 UTC (rev 1495)
@@ -0,0 +1,418 @@
+# Copyright 2004-2008 Roman Yakovenko.
+# Distributed under the Boost Software License, Version 1.0. (See
+# accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import os
+import sys
+import time
+import types
+import warnings
+import module_builder
+
+from pygccxml import parser
+from pygccxml import declarations as decls_package
+
+from pyplusplus import utils
+from pyplusplus import _logging_
+from pyplusplus import decl_wrappers
+from pyplusplus import file_writers
+from pyplusplus import code_creators
+from pyplusplus import module_creator as mcreator_package
+
+class builder_t(module_builder.module_builder_t):
+ """
+ This class provides users with simple and intuitive interface to Py++
+ and/or pygccxml functionality. If this is your first attempt to use Py++
+ consider to read tutorials. You can find them on U{web site<http://www.language-binding.net>}.
+ """
+
+ def __init__( self
+ , files
+ , gccxml_path=''
+ , working_directory='.'
+ , include_paths=None
+ , define_symbols=None
+ , undefine_symbols=None
+ , start_with_declarations=None
+ , compilation_mode=None
+ , cache=None
+ , optimize_queries=True
+ , ignore_gccxml_output=False
+ , indexing_suite_version=1
+ , cflags=""
+ , encoding='ascii'
+ , compiler=None):
+ """
+ @param files: list of files, declarations from them you want to export
+ @type files: list of strings or L{file_configuration_t} instances
+
+ @param gccxml_path: path to gccxml binary. If you don't pass this argument,
+ pygccxml parser will try to locate it using you environment PATH variable
+ @type gccxml_path: str
+
+ @param include_paths: additional header files location. You don't have to
+ specify system and standard directories.
+ @type include_paths: list of strings
+
+ @param define_symbols: list of symbols to be defined for preprocessor.
+ @param define_symbols: list of strings
+
+ @param undefine_symbols: list of symbols to be undefined for preprocessor.
+ @param undefine_symbols: list of strings
+
+ @param cflags: Raw string to be added to gccxml command line.
+ """
+ module_builder.module_builder_t.__init__( self, global_ns=None, encoding=encoding )
+
+ gccxml_config = parser.config_t( gccxml_path=gccxml_path
+ , working_directory=working_directory
+ , include_paths=include_paths
+ , define_symbols=define_symbols
+ , undefine_symbols=undefine_symbols
+ , start_with_declarations=start_with_declarations
+ , ignore_gccxml_output=ignore_gccxml_output
+ , cflags=cflags
+ , compiler=compiler)
+
+ #may be in future I will add those directories to user_defined_directories to self.__code_creator.
+ self.__parsed_files = map( decls_package.filtering.normalize_path
+ , parser.project_reader_t.get_os_file_names( files ) )
+ tmp = map( lambda file_: os.path.split( file_ )[0], self.__parsed_files )
+ self.__parsed_dirs = filter( None, tmp )
+
+ self.global_ns = self.__parse_declarations( files
+ , gccxml_config
+ , compilation_mode
+ , cache
+ , indexing_suite_version)
+ self.__code_creator = None
+ if optimize_queries:
+ self.run_query_optimizer()
+
+ self.__declarations_code_head = []
+ self.__declarations_code_tail = []
+
+ self.__registrations_code_head = []
+ self.__registrations_code_tail = []
+
+
+
+ def register_module_dependency( self, other_module_generated_code_dir ):
+ """``already_exposed`` solution is pretty good when you mix hand-written
+ modules with Py++ generated. It doesn't work/scale for "true"
+ multi-module development. This is exactly the reason why ``Py++``_
+ offers "semi automatic" solution.
+
+ For every exposed module, ``Py++``_ generates "exposed_decl.pypp.txt" file.
+ This file contains the list of all parsed declarations and whether they
+ were included or excluded. Later, when you work on another module, you
+ can tell ``Py++``_ that the current module depends on the previously
+ generated one. ``Py++``_ will load "exposed_decl.pypp.txt" file and
+ update the declarations.
+ """
+
+ db = utils.exposed_decls_db_t()
+ db.load( other_module_generated_code_dir )
+ db.update_decls( self.global_ns )
+
+
+ def __parse_declarations( self, files, gccxml_config, compilation_mode, cache, indexing_suite_version ):
+ if None is gccxml_config:
+ gccxml_config = parser.config_t()
+ if None is compilation_mode:
+ compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE
+ start_time = time.clock()
+ self.logger.debug( 'parsing files - started' )
+ reader = parser.project_reader_t( gccxml_config, cache, decl_wrappers.dwfactory_t() )
+ decls = reader.read_files( files, compilation_mode )
+
+ self.logger.debug( 'parsing files - done( %f seconds )' % ( time.clock() - start_time ) )
+ self.logger.debug( 'settings declarations defaults - started' )
+
+ global_ns = decls_package.matcher.get_single(
+ decls_package.namespace_matcher_t( name='::' )
+ , decls )
+ if indexing_suite_version != 1:
+ for cls in global_ns.classes():
+ cls.indexing_suite_version = indexing_suite_version
+ for cls in global_ns.decls(decl_type=decls_package.class_declaration_t):
+ cls.indexing_suite_version = indexing_suite_version
+
+ start_time = time.clock()
+ self.__apply_decls_defaults(decls)
+ self.logger.debug( 'settings declarations defaults - done( %f seconds )'
+ % ( time.clock() - start_time ) )
+ return global_ns
+
+ def __filter_by_location( self, flatten_decls ):
+ for decl in flatten_decls:
+ if not decl.location:
+ continue
+ fpath = decls_package.filtering.normalize_path( decl.location.file_name )
+ if decls_package.filtering.contains_parent_dir( fpath, self.__parsed_dirs ):
+ continue
+ if fpath in self.__parsed_files:
+ continue
+ found = False
+ for pfile in self.__parsed_files:
+ if fpath.endswith( pfile ):
+ found = True
+ break
+ if not found:
+ decl.exclude()
+
+ def __apply_decls_defaults(self, decls):
+ flatten_decls = decls_package.make_flatten( decls )
+ self.__filter_by_location( flatten_decls )
+ call_policies_resolver = mcreator_package.built_in_resolver_t()
+ calldefs = filter( lambda decl: isinstance( decl, decls_package.calldef_t )
+ , flatten_decls )
+ map( lambda calldef: calldef.set_call_policies( call_policies_resolver( calldef ) )
+ , calldefs )
+ mem_vars = filter( lambda decl: isinstance( decl, decls_package.variable_t )
+ and isinstance( decl.parent, decls_package.class_t )
+ , flatten_decls )
+ map( lambda mem_var: mem_var.set_getter_call_policies( call_policies_resolver( mem_var, 'get' ) )
+ , mem_vars )
+ map( lambda mem_var: mem_var.set_setter_call_policies( call_policies_resolver( mem_var, 'set' ) )
+ , mem_vars )
+
+ @property
+ def declarations_code_head( self ):
+ "List of user code, that will be added to the head of the declarations section."
+ return self.__declarations_code_head
+
+ @property
+ def declarations_code_tail( self ):
+ "List of user code, that will be added to the tail of the declarations section."
+ return self.__declarations_code_tail
+
+ @property
+ def registrations_code_head( self ):
+ "List of user code, that will be added to the head of the registrations section."
+ return self.__registrations_code_head
+
+ @property
+ def registrations_code_tail( self ):
+ "List of user code, that will be added to the tail of the registrations section."
+ return self.__registrations_code_tail
+
+ def build_code_creator( self
+ , module_name
+ , boost_python_ns_name='bp'
+ , create_casting_constructor=True
+ , call_policies_resolver_=None
+ , types_db=None
+ , target_configuration=None
+ , enable_indexing_suite=True
+ , doc_extractor=None):
+ """
+ Creates L{module_t} code creator.
+
+ @param module_name: module name
+ @type module_name: string
+
+ @param boost_python_ns_name: boost::python namespace alias, by default
+ it is 'bp'
+ @type boost_python_ns_name: string
+
+ @param call_policies_resolver_: callable, that will be invoked on every
+ calldef object. It should return call policies.
+ @type call_policies_resolver_: callable
+ @param doc_extractor: callable, that takes as argument reference to declaration
+ and returns documentation string
+ @type doc_extractor: callable or None
+ """
+ if not create_casting_constructor:
+ msg = os.linesep.join([
+ "create_casting_constructor argument is deprecated."
+ , "If want to disable boost::python::implicitly_convertible code generation, consider to use allow_implicit_conversion constructor property"
+ , ">>> mb = module_builder_t(...)"
+ , ">>> mb.constructors().allow_implicit_conversion = False"])
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
+
+ self.global_ns.constructors(allow_empty=True).allow_implicit_conversion = False
+
+ creator = mcreator_package.creator_t( self.global_ns
+ , module_name
+ , boost_python_ns_name
+ , call_policies_resolver_
+ , types_db
+ , target_configuration
+ , enable_indexing_suite
+ , doc_extractor)
+ self.__code_creator = creator.create()
+ self.__code_creator.replace_included_headers(self.__parsed_files)
+ return self.__code_creator
+
+ @property
+ def code_creator( self ):
+ "reference to L{code_creators.module_t} instance"
+ if not self.__code_creator:
+ raise RuntimeError( "self.module is equal to None. Did you forget to call build_code_creator function?" )
+ return self.__code_creator
+
+ def has_code_creator( self ):
+ """
+ Function, that will return True if build_code_creator function has been
+ called and False otherwise
+ """
+ return not ( None is self.__code_creator )
+
+ def add_declaration_code( self, code, tail=True ):
+ if tail:
+ self.__declarations_code_tail.append( code )
+ else:
+ self.__declarations_code_head.append( code )
+
+ def add_registration_code( self, code, tail=True ):
+ if tail:
+ self.__registrations_code_tail.append( code )
+ else:
+ self.__registrations_code_head.append( code )
+
+ def add_constants( self, **keywds ):
+ """adds code that exposes some constants to Python.
+
+ For example:
+ mb.add_constants( version='"1.2.3"' )
+ or
+ mb.add_constants( **{ version:'"1.2.3"' } )
+ will generate next code:
+ boost::python::scope().attr("version") = "1.2.3";
+ """
+ tmpl = 'boost::python::scope().attr("%(name)s") = %(value)s;'
+ for name, value in keywds.items():
+ if not isinstance( value, types.StringTypes ):
+ value = str( value )
+ self.add_registration_code( tmpl % dict( name=name, value=value) )
+
+
+ def __merge_user_code( self ):
+ for code in self.__declarations_code_tail:
+ self.code_creator.add_declaration_code( code, -1 )
+
+ for code in self.__declarations_code_head:
+ self.code_creator.add_declaration_code( code, 0 )
+
+ body = self.code_creator.body
+
+ for code in self.__registrations_code_tail:
+ body.adopt_creator( code_creators.custom_text_t( code ), -1 )
+
+ for code in self.__registrations_code_head:
+ body.adopt_creator( code_creators.custom_text_t( code ), 0 )
+
+
+ def write_module( self, file_name ):
+ """
+ Writes module to single file
+ @param file_name: file name
+ @type file_name: string
+ """
+ self.__merge_user_code()
+ file_writers.write_file( self.code_creator, file_name, encoding=self.encoding )
+
+ def __work_on_unused_files( self, dir_name, written_files, on_unused_file_found ):
+ all_files = os.listdir( dir_name )
+ all_files = map( lambda fname: os.path.join( dir_name, fname ), all_files )
+ all_files = filter( file_writers.has_pypp_extenstion, all_files )
+
+ unused_files = set( all_files ).difference( set( written_files ) )
+ for fpath in unused_files:
+ try:
+ if on_unused_file_found is os.remove:
+ self.logger.info( 'removing file "%s"' % fpath )
+ on_unused_file_found( fpath )
+ except Exception, error:
+ self.logger.exception( "Exception was catched, while executing 'on_unused_file_found' function." )
+
+ def split_module( self
+ , dir_name
+ , huge_classes=None
+ , on_unused_file_found=os.remove
+ , use_files_sum_repository=False):
+ """
+ Writes module to multiple files
+
+ @param dir_name: directory name
+ @type dir_name: string
+
+ @param huge_classes: list that contains reference to classes, that should be split
+
+ @param on_unused_file_found: callable object that represents the action that should be taken on
+ file, which is no more in use
+
+ @use_files_sum_repository: Py++ can generate file, which will contain md5 sum of every generated file.
+ Next time you generate code, md5sum will be loaded from the file and compared.
+ This could speed-up code generation process by 10-15%.
+ """
+ self.__merge_user_code()
+
+ files_sum_repository = None
+ if use_files_sum_repository:
+ cache_file = os.path.join( dir_name, self.code_creator.body.name + '.md5.sum' )
+ files_sum_repository = file_writers.cached_repository_t( cache_file )
+
+ written_files = []
+ if None is huge_classes:
+ written_files = file_writers.write_multiple_files(
+ self.code_creator
+ , dir_name
+ , files_sum_repository=files_sum_repository
+ , encoding=self.encoding)
+ else:
+ written_files = file_writers.write_class_multiple_files(
+ self.code_creator
+ , dir_name
+ , huge_classes
+ , files_sum_repository=files_sum_repository
+ , encoding=self.encoding)
+ self.__work_on_unused_files( dir_name, written_files, on_unused_file_found )
+
+ return written_files
+
+ def balanced_split_module( self
+ , dir_name
+ , number_of_files
+ , on_unused_file_found=os.remove
+ , use_files_sum_repository=False):
+ """
+ Writes module to fixed number of multiple cpp files
+
+ @param number_of_files: the desired number of generated cpp files
+ @type number_of_files: int
+
+ @param dir_name: directory name
+ @type dir_name: string
+
+ @param on_unused_file_found: callable object that represents the action that should be taken on
+ file, which is no more in use
+
+ @use_files_sum_repository: Py++ can generate file, which will contain md5 sum of every generated file.
+ Next time you generate code, md5sum will be loaded from the file and compared.
+ This could speed-up code generation process by 10-15%.
+ """
+ self.__merge_user_code()
+
+ files_sum_repository = None
+ if use_files_sum_repository:
+ cache_file = os.path.join( dir_name, self.code_creator.body.name + '.md5.sum' )
+ files_sum_repository = file_writers.cached_repository_t( cache_file )
+
+ written_files = file_writers.write_balanced_files( self.code_creator
+ , dir_name
+ , number_of_buckets=number_of_files
+ , files_sum_repository=files_sum_repository
+ , encoding=self.encoding)
+
+ self.__work_on_unused_files( dir_name, written_files, on_unused_file_found )
+
+ return written_files
+
+ def _get_BOOST_PYTHON_MAX_ARITY( self ):
+ return decl_wrappers.calldef_t.BOOST_PYTHON_MAX_ARITY
+ def _set_BOOST_PYTHON_MAX_ARITY( self, value ):
+ decl_wrappers.calldef_t.BOOST_PYTHON_MAX_ARITY = value
+ BOOST_PYTHON_MAX_ARITY = property( _get_BOOST_PYTHON_MAX_ARITY, _set_BOOST_PYTHON_MAX_ARITY )
Deleted: pyplusplus_dev/pyplusplus/module_builder/builder.py
===================================================================
--- pyplusplus_dev/pyplusplus/module_builder/builder.py 2008-12-24 20:47:08 UTC (rev 1494)
+++ pyplusplus_dev/pyplusplus/module_builder/builder.py 2008-12-24 20:57:21 UTC (rev 1495)
@@ -1,311 +0,0 @@
-# Copyright 2004-2008 Roman Yakovenko.
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
-# http://www.boost.org/LICENSE_1_0.txt)
-
-import os
-import sys
-
-from pyplusplus import _logging_
-from pyplusplus import decl_wrappers
-
-class base_builder_t(object):
- """
- """
-
- def __init__( self, global_ns=None, encoding='ascii' ):
- """
- """
- object.__init__( self )
- self.logger = _logging_.loggers.module_builder
- self.__encoding = encoding
- self.__global_ns = global_ns
-
- def __get_global_ns( self ):
- if not self.__global_ns:
- raise RuntimeError( "Reference to global namespace declaration was not set." )
- return self.__global_ns
- def __set_global_ns( self, global_ns ):
- self.__global_ns = global_ns
-
- global_ns = property( __get_global_ns, __set_global_ns
- , doc="""reference to global namespace""" )
-
- @property
- def encoding( self ):
- return self.__encoding
-
- def run_query_optimizer(self):
- """
- It is possible to optimze time that takes to execute queries. In most cases
- this is done from __init__ method. But there are use-case, when you need
- to disable optimizer at __init__ and run it later.
- """
- self.global_ns.init_optimizer()
-
- def print_declarations(self, decl=None, detailed=True, recursive=True, writer=sys.stdout.write):
- """
- This function will print detailed description of all declarations or
- some specific one.
-
- @param decl: optional, if passed, then only it will be printed
- @type decl: instance of L{decl_wrappers.decl_wrapper_t} class
- """
- if None is decl:
- decl = self.global_ns
- decl_wrappers.print_declarations( decl, detailed, recursive, writer )
-
- #select decl(s) interfaces
- def decl( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.decl( name=name
- , function=function
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def decls( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.decls( name=name
- , function=function
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def class_( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.class_( name=name
- , function=function
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def classes( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.classes( name=name
- , function=function
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def variable( self, name=None, function=None, type=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.variable( name=name
- , function=function
- , type=type
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
- var = variable
-
- def variables( self, name=None, function=None, type=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.variables( name=name
- , function=function
- , type=type
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
- vars = variables
-
- def calldef( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.calldef( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def calldefs( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.calldefs( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def operator( self, name=None, symbol=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.operator( name=name
- , symbol=symbol
- , decl_type=decl_type
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def operators( self, name=None, symbol=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.operators( name=name
- , symbol=symbol
- , decl_type=decl_type
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def member_function( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.member_function( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
- mem_fun = member_function
-
- def member_functions( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.member_functions( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- mem_funs = member_functions
-
- def constructor( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.constructor( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def constructors( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.constructors( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def member_operator( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.member_operator( name=name
- , symbol=symbol
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def member_operators( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.member_operators( name=name
- , symbol=symbol
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def casting_operator( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.casting_operator( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def casting_operators( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.casting_operators( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- def enumeration( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.enumeration( name=name
- , function=function
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
- enum = enumeration
-
- def enumerations( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.scopedef_t} class documentation"""
- return self.global_ns.enumerations( name=name
- , function=function
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
-
- enums = enumerations
-
- def namespace( self, name=None, function=None, recursive=None ):
- """Please see L{decl_wrappers.namespace_t} class documentation"""
- return self.global_ns.namespace( name=name
- , function=function
- , recursive=recursive )
-
- def namespaces( self, name=None, function=None, recursive=None ):
- """Please see L{decl_wrappers.namespace_t} class documentation"""
- return self.global_ns.namespaces( name=name
- , function=function
- , recursive=recursive )
-
- def free_function( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.namespace_t} class documentation"""
- return self.global_ns.free_function( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
- free_fun = free_function
-
- def free_functions( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.namespace_t} class documentation"""
- return self.global_ns.free_functions( name=name
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive)
- free_funs = free_functions
-
- def free_operator( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.namespace_t} class documentation"""
- return self.global_ns.free_operator( name=name
- , symbol=symbol
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
-
- def free_operators( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ):
- """Please see L{decl_wrappers.namespace_t} class documentation"""
- return self.global_ns.free_operators( name=name
- , symbol=symbol
- , function=function
- , return_type=return_type
- , arg_types=arg_types
- , header_dir=header_dir
- , header_file=header_file
- , recursive=recursive )
Deleted: pyplusplus_dev/pyplusplus/module_builder/extension_builder.py
===================================================================
--- pyplusplus_dev/pyplusplus/module_builder/extension_builder.py 2008-12-24 20:47:08 UTC (rev 1494)
+++ pyplusplus_dev/pyplusplus/module_builder/extension_builder.py 2008-12-24 20:57:21 UTC (rev 1495)
@@ -1,418 +0,0 @@
-# Copyright 2004-2008 Roman Yakovenko.
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
-# http://www.boost.org/LICENSE_1_0.txt)
-
-import os
-import sys
-import time
-import types
-import builder
-import warnings
-
-from pygccxml import parser
-from pygccxml import declarations as decls_package
-
-from pyplusplus import utils
-from pyplusplus import _logging_
-from pyplusplus import decl_wrappers
-from pyplusplus import file_writers
-from pyplusplus import code_creators
-from pyplusplus import module_creator as mcreator_package
-
-class extension_module_builder_t(builder.base_builder_t):
- """
- This class provides users with simple and intuitive interface to Py++
- and/or pygccxml functionality. If this is your first attempt to use Py++
- consider to read tutorials. You can find them on U{web site<http://www.language-binding.net>}.
- """
-
- def __init__( self
- , files
- , gccxml_path=''
- , working_directory='.'
- , include_paths=None
- , define_symbols=None
- , undefine_symbols=None
- , start_with_declarations=None
- , compilation_mode=None
- , cache=None
- , optimize_queries=True
- , ignore_gccxml_output=False
- , indexing_suite_version=1
- , cflags=""
- , encoding='ascii'
- , compiler=None):
- """
- @param files: list of files, declarations from them you want to export
- @type files: list of strings or L{file_configuration_t} instances
-
- @param gccxml_path: path to gccxml binary. If you don't pass this argument,
- pygccxml parser will try to locate it using you environment PATH variable
- @type gccxml_path: str
-
- @param include_paths: additional header files location. You don't have to
- specify system and standard directories.
- @type include_paths: list of strings
-
- @param define_symbols: list of symbols to be defined for preprocessor.
- @param define_symbols: list of strings
-
- @param undefine_symbols: list of symbols to be undefined for preprocessor.
- @param undefine_symbols: list of strings
-
- @param cflags: Raw string to be added to gccxml command line.
- """
- builder.base_builder_t.__init__( self, global_ns=None, encoding=encoding )
-
- gccxml_config = parser.config_t( gccxml_path=gccxml_path
- , working_directory=working_directory
- , include_paths=include_paths
- , define_symbols=define_symbols
- , undefine_symbols=undefine_symbols
- , start_with_declarations=start_with_declarations
- , ignore_gccxml_output=ignore_gccxml_output
- , cflags=cflags
- , compiler=compiler)
-
- #may be in future I will add those directories to user_defined_directories to self.__code_creator.
- self.__parsed_files = map( decls_package.filtering.normalize_path
- , parser.project_reader_t.get_os_file_names( files ) )
- tmp = map( lambda file_: os.path.split( file_ )[0], self.__parsed_files )
- self.__parsed_dirs = filter( None, tmp )
-
- self.global_ns = self.__parse_declarations( files
- , gccxml_config
- , compilation_mode
- , cache
- , indexing_suite_version)
- self.__code_creator = None
- if optimize_queries:
- self.run_query_optimizer()
-
- self.__declarations_code_head = []
- self.__declarations_code_tail = []
-
- self.__registrations_code_head = []
- self.__registrations_code_tail = []
-
-
-
- def register_module_dependency( self, other_module_generated_code_dir ):
- """``already_exposed`` solution is pretty good when you mix hand-written
- modules with Py++ generated. It doesn't work/scale for "true"
- multi-module development. This is exactly the reason why ``Py++``_
- offers "semi automatic" solution.
-
- For every exposed module, ``Py++``_ generates "exposed_decl.pypp.txt" file.
- This file contains the list of all parsed declarations and whether they
- were included or excluded. Later, when you work on another module, you
- can tell ``Py++``_ that the current module depends on the previously
- generated one. ``Py++``_ will load "exposed_decl.pypp.txt" file and
- update the declarations.
- """
-
- db = utils.exposed_decls_db_t()
- db.load( other_module_generated_code_dir )
- db.update_decls( self.global_ns )
-
-
- def __parse_declarations( self, files, gccxml_config, compilation_mode, cache, indexing_suite_version ):
- if None is gccxml_config:
- gccxml_config = parser.config_t()
- if None is compilation_mode:
- compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE
- start_time = time.clock()
- self.logger.debug( 'parsing files - started' )
- reader = parser.project_reader_t( gccxml_config, cache, decl_wrappers.dwfactory_t() )
- decls = reader.read_files( files, compilation_mode )
-
- self.logger.debug( 'parsing files - done( %f seconds )' % ( time.clock() - start_time ) )
- self.logger.debug( 'settings declarations defaults - started' )
-
- global_ns = decls_package.matcher.get_single(
- decls_package.namespace_matcher_t( name='::' )
- , decls )
- if indexing_suite_version != 1:
- for cls in global_ns.classes():
- cls.indexing_suite_version = indexing_suite_version
- for cls in global_ns.decls(decl_type=decls_package.class_declaration_t):
- cls.indexing_suite_version = indexing_suite_version
-
- start_time = time.clock()
- self.__apply_decls_defaults(decls)
- self.logger.debug( 'settings declarations defaults - done( %f seconds )'
- % ( time.clock() - start_time ) )
- return global_ns
-
- def __filter_by_location( self, flatten_decls ):
- for decl in flatten_decls:
- if not decl.location:
- continue
- fpath = decls_package.filtering.normalize_path( decl.location.file_name )
- if decls_package.filtering.contains_parent_dir( fpath, self.__parsed_dirs ):
- continue
- if fpath in self.__parsed_files:
- continue
- found = False
- for pfile in self.__parsed_files:
- if fpath.endswith( pfile ):
- found = True
- break
- if not found:
- decl.exclude()
-
- def __apply_decls_defaults(self, decls):
- flatten_decls = decls_package.make_flatten( decls )
- self.__filter_by_location( flatten_decls )
- call_policies_resolver = mcreator_package.built_in_resolver_t()
- calldefs = filter( lambda decl: isinstance( decl, decls_package.calldef_t )
- , flatten_decls )
- map( lambda calldef: calldef.set_call_policies( call_policies_resolver( calldef ) )
- , calldefs )
- mem_vars = filter( lambda decl: isinstance( decl, decls_package.variable_t )
- and isinstance( decl.parent, decls_package.class_t )
- , flatten_decls )
- map( lambda mem_var: mem_var.set_getter_call_policies( call_policies_resolver( mem_var, 'get' ) )
- , mem_vars )
- map( lambda mem_var: mem_var.set_setter_call_policies( call_policies_resolver( mem_var, 'set' ) )
- , mem_vars )
-
- @property
- def declarations_code_head( self ):
- "List of user code, that will be added to the head of the declarations section."
- return self.__declarations_code_head
-
- @property
- def declarations_code_tail( self ):
- "List of user code, that will be added to the tail of the declarations section."
- return self.__declarations_code_tail
-
- @property
- def registrations_code_head( self ):
- "List of user code, that will be added to the head of the registrations section."
- return self.__registrations_code_head
-
- @property
- def registrations_code_tail( self ):
- "List of user code, that will be added to the tail of the registrations section."
- return self.__registrations_code_tail
-
- def build_code_creator( self
- , module_name
- , boost_python_ns_name='bp'
- , create_casting_constructor=True
- , call_policies_resolver_=None
- , types_db=None
- , target_configuration=None
- , enable_indexing_suite=True
- , doc_extractor=None):
- """
- Creates L{module_t} code creator.
-
- @param module_name: module name
- @type module_name: string
-
- @param boost_python_ns_name: boost::python namespace alias, by default
- it is 'bp'
- @type boost_python_ns_name: string
-
- @param call_policies_resolver_: callable, that will be invoked on every
- calldef object. It should return call policies.
- @type call_policies_resolver_: callable
- @param doc_extractor: callable, that takes as argument reference to declaration
- and returns documentation string
- @type doc_extractor: callable or None
- """
- if not create_casting_constructor:
- msg = os.linesep.join([
- "create_casting_constructor argument is deprecated."
- , "If want to disable boost::python::implicitly_convertible code generation, consider to use allow_implicit_conversion constructor property"
- , ">>> mb = module_builder_t(...)"
- , ">>> mb.constructors().allow_implicit_conversion = False"])
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
-
- self.global_ns.constructors(allow_empty=True).allow_implicit_conversion = False
-
- creator = mcreator_package.creator_t( self.global_ns
- , module_name
- , boost_python_ns_name
- , call_policies_resolver_
- , types_db
- , target_configuration
- , enable_indexing_suite
- , doc_extractor)
- self.__code_creator = creator.create()
- self.__code_creator.replace_included_headers(self.__parsed_files)
- return self.__code_creator
-
- @property
- def code_creator( self ):
- "reference to L{code_creators.module_t} instance"
- if not self.__code_creator:
- raise RuntimeError( "self.module is equal to None. Did you forget to call build_code_creator function?" )
- return self.__code_creator
-
- def has_code_creator( self ):
- """
- Function, that will return True if build_code_creator function has been
- called and False otherwise
- """
- return not ( None is self.__code_creator )
-
- def add_declaration_code( self, code, tail=True ):
- if tail:
- self.__declarations_code_tail.append( code )
- else:
- self.__declarations_code_head.append( code )
-
- def add_registration_code( self, code, tail=True ):
- if tail:
- self.__registrations_code_tail.append( code )
- else:
- self.__registrations_code_head.append( code )
-
- def add_constants( self, **keywds ):
- """adds code that exposes some constants to Python.
-
- For example:
- mb.add_constants( version='"1.2.3"' )
- or
- mb.add_constants( **{ version:'"1.2.3"' } )
- will generate next code:
- boost::python::scope().attr("version") = "1.2.3";
- """
- tmpl = 'boost::python::scope().attr("%(name)s") = %(value)s;'
- for name, value in keywds.items():
- if not isinstance( value, types.StringTypes ):
- value = str( value )
- self.add_registration_code( tmpl % dict( name=name, value=value) )
-
-
- def __merge_user_code( self ):
- for code in self.__declarations_code_tail:
- self.code_creator.add_declaration_code( code, -1 )
-
- for code in self.__declarations_code_head:
- self.code_creator.add_declaration_code( code, 0 )
-
- body = self.code_creator.body
-
- for code in self.__registrations_code_tail:
- body.adopt_creator( code_creators.custom_text_t( code ), -1 )
-
- for code in self.__registrations_code_head:
- body.adopt_creator( code_creators.custom_text_t( code ), 0 )
-
-
- def write_module( self, file_name ):
- """
- Writes module to single file
- @param file_name: file name
- @type file_name: string
- """
- self.__merge_user_code()
- file_writers.write_file( self.code_creator, file_name, encoding=self.encoding )
-
- def __work_on_unused_files( self, dir_name, written_files, on_unused_file_found ):
- all_files = os.listdir( dir_name )
- all_files = map( lambda fname: os.path.join( dir_name, fname ), all_files )
- all_files = filter( file_writers.has_pypp_extenstion, all_files )
-
- unused_files = set( all_files ).difference( set( written_files ) )
- for fpath in unused_files:
- try:
- if on_unused_file_found is os.remove:
- self.logger.info( 'removing file "%s"' % fpath )
- on_unused_file_found( fpath )
- except Exception, error:
- self.logger.exception( "Exception was catched, while executing 'on_unused_file_found' function." )
-
- def split_module( self
- , dir_name
- , huge_classes=None
- , on_unused_file_found=os.remove
- , use_files_sum_repository=False):
- """
- Writes module to multiple files
-
- @param dir_name: directory name
- @type dir_name: string
-
- @param huge_classes: list that contains reference to classes, that should be split
-
- @param on_unused_file_found: callable object that represents the action that should be taken on
- file, which is no more in use
-
- @use_files_sum_repository: Py++ can generate file, which will contain md5 sum of every generated file.
- Next time you generate code, md5sum will be loaded from the file and compared.
- This could speed-up code generation process by 10-15%.
- """
- self.__merge_user_code()
-
- files_sum_repository = None
- if use_files_sum_repository:
- cache_file = os.path.join( dir_name, self.code_creator.body.name + '.md5.sum' )
- files_sum_repository = file_writers.cached_repository_t( cache_file )
-
- written_files = []
- if None is huge_classes:
- written_files = file_writers.write_multiple_files(
- self.code_creator
- , dir_name
- , files_sum_repository=files_sum_repository
- , encoding=self.encoding)
- else:
- written_files = file_writers.write_class_multiple_files(
- self.code_creator
- , dir_name
- , huge_classes
- , files_sum_repository=files_sum_repository
- , encoding=self.encoding)
- self.__work_on_unused_files( dir_name, written_files, on_unused_file_found )
-
- return written_files
-
- def balanced_split_module( self
- , dir_name
- , number_of_files
- , on_unused_file_found=os.remove
- , use_files_sum_repository=False):
- """
- Writes module to fixed number of multiple cpp files
-
- @param number_of_files: the desired number of generated cpp files
- @type number_of_files: int
-
- @param dir_name: directory name
- @type dir_name: string
-
- @param on_unused_file_found: callable object that represents the action that should be taken on
- file, which is no more in use
-
- @use_files_sum_repository: Py++ can generate file, which will contain md5 sum of every generated file.
- Next time you generate code, md5sum will be loaded from the file and compared.
- This could speed-up code generation process by 10-15%.
- """
- self.__merge_user_code()
-
- files_sum_repository = None
- if use_files_sum_repository:
- cache_file = os.path.join( dir_name, self.code_creator.body.name + '.md5.sum' )
- files_sum_repository = file_writers.cached_repository_t( cache_file )
-
- written_files = file_writers.write_balanced_files( self.code_creator
- , dir_name
- , number_of_buckets=number_of_files
- , files_sum_repository=files_sum_repository
- , encoding=self.encoding)
-
- self.__work_on_unused_files( dir_name, written_files, on_unused_file_found )
-
- return written_files
-
- def _get_BOOST_PYTHON_MAX_ARITY( self ):
- return decl_wrappers.calldef_t.BOOST_PYTHON_MAX_ARITY
- def _set_BOOST_PYTHON_MAX_ARITY( self, value ):
- decl_wrappers.calldef_t.BOOST_PYTHON_MAX_ARITY = value
- BOOST_PYTHON_MAX_ARITY = property( _get_BOOST_PYTHON_MAX_ARITY, _set_BOOST_PYTHON_MAX_ARITY )
Copied: pyplusplus_dev/pyplusplus/module_builder/module_builder.py (from rev 1494, pyplusplus_dev/pyplusplus/module_builder/builder.py)
===================================================================
--- pyplusplus_dev/pyplusplus/module_builder/module_builder.py (rev 0)
+++ pyplusplus_dev/pyplusplus/module_builder/module_builder.py 2008-12-24 20:57:21 UTC (rev 1495)
@@ -0,0 +1,310 @@
+# Copyright 2004-2008 Roman Yakovenko.
+# Distributed under the Boost Software License, Version 1.0. (See
+# accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import os
+import sys
+
+from pyplusplus import _logging_
+from pyplusplus import decl_wrappers
+
+class module_builder_t(object):
+ """base class for different module builders."""
+
+ def __init__( self, global_ns=None, encoding='ascii' ):
+ """
+ """
+ object.__init__( self )
+ self.logger = _logging_.loggers.module_builder
+ self.__encoding = encoding
+ self.__global_ns = global_ns
+
+ def __get_global_ns( self ):
+ if not self.__global_ns:
+ raise RuntimeError( "Reference to global namespace declaration was not set." )
+ return self.__global_ns
+ def __set_global_ns( self, global_ns ):
+ self.__global_ns = global_ns
+
+ global_ns = property( __get_global_ns, __set_global_ns
+ , doc="""reference to global namespace""" )
+
+ @property
+ def encoding( self ):
+ return self.__encoding
+
+ def run_query_optimizer(self):
+ """
+ It is possible to optimze time that takes to execute queries. In most cases
+ this is done from __init__ method. But there are use-case, when you need
+ to disable optimizer at __init__ and run it later.
+ """
+ self.global_ns.init_optimizer()
+
+ def print_declarations(self, decl=None, detailed=True, recursive=True, writer=sys....
[truncated message content] |