pycxx-7.1.4/000755 000765 000024 00000000000 13664720516 013172 5ustar00barrystaff000000 000000 pycxx-7.1.4/Demo/000755 000765 000024 00000000000 13664720516 014056 5ustar00barrystaff000000 000000 pycxx-7.1.4/obj/000755 000765 000024 00000000000 13664720516 013744 5ustar00barrystaff000000 000000 pycxx-7.1.4/tag_pycxx.py000644 000765 000024 00000004160 12755034076 015552 0ustar00barrystaff000000 000000 import pysvn import sys import os def make_tag( from_url, tag_base_url, version ): client = pysvn.Client() client.callback_get_log_message = lambda : (True, 'Tag version '+version) client.callback_get_login = callback_getLogin try: from_files = client.ls( from_url, recurse=False ) print( 'Info: Found', from_url ) except pysvn.ClientError as e: print( 'Error: From does not exist',from_url ) return try: tag_files = client.ls( tag_base_url, recurse=False ) print( 'Info: Found', tag_base_url ) except pysvn.ClientError as e: print( 'Error: Tag base does not exist',tag_base_url ) return cur_versions = [os.path.basename(f['name']) for f in tag_files] if version in cur_versions: print( 'Error: Already tagged',version ) return try: to_url = tag_base_url + '/' + version print( 'Info: Copy',repr(from_url), repr(to_url) ) client.copy( from_url, to_url ) print( 'Info: Copy complete' ) except pysvn.ClientError as e: print( 'Error: ', str(e) ) return def callback_getLogin( realm, username, may_save ): print( 'May save:',may_save ) print( 'Realm:',realm ) if username: print( 'Username:',username ) else: sys.stdout.write( 'Username: ' ) username = sys.stdin.readline().strip() if len(username) == 0: return 0, '', '', False sys.stdout.write( 'Password: ' ) password = sys.stdin.readline().strip() save_password = 'x' while save_password.lower() not in ['y','ye','yes','n', 'no','']: sys.stdout.write( 'Save password? [y/n] ' ) save_password = sys.stdin.readline().strip() return 1, username, password, save_password in ['y','ye','yes'] def main(): if len(sys.argv) != 2: print( 'Usage: %s version' % sys.argv[0] ) return version = sys.argv[1] from_url = 'https://svn.code.sf.net/p/cxx/code/trunk/CXX' tag_base_url = 'https://svn.code.sf.net/p/cxx/code/tags' make_tag( from_url, tag_base_url, version ) if __name__ == '__main__': main() pycxx-7.1.4/make_src_kit.py000644 000765 000024 00000002230 13403242271 016160 0ustar00barrystaff000000 000000 import sys import os import shutil def main( argv ): f = open( 'CXX/Version.hxx' ) major = None minor = None patch = None for line in f: words = line.split() if words[0:2] == ['#define', 'PYCXX_VERSION_MAJOR']: major = words[2] if words[0:2] == ['#define', 'PYCXX_VERSION_MINOR']: minor = words[2] if words[0:2] == ['#define', 'PYCXX_VERSION_PATCH']: patch = words[2] print( 'version: %s, %s, %s' % (major, minor, patch) ) tmp_dir = os.environ.get('TMPDIR','/tmp') kit_name = 'pycxx-%s.%s.%s' % (major, minor, patch) kit_dir = os.path.join( tmp_dir, kit_name ) if os.path.exists( kit_dir ): print( 'Info: Removing tree at %s' % kit_dir ) shutil.rmtree( kit_dir ) os.mkdir( kit_dir ) print( 'Info: svn export %s' % kit_dir ) os.system( 'svn export --force . %s' % kit_dir ) print( 'Info: Creating %s.tar.gz' % kit_dir ) os.chdir( tmp_dir ) cmd = 'tar czf %s.tar.gz --exclude=%s/SourceForge %s' % (kit_dir, kit_name, kit_name) os.system( cmd ) return 0 if __name__ == '__main__': sys.exit( main( sys.argv ) ) pycxx-7.1.4/build-unlimited-api.sh000755 000765 000024 00000001004 13347675176 017373 0ustar00barrystaff000000 000000 #!/bin/bash set -x set -e set -o pipefail PYTHON=${1? python exe} case "$( uname )" in Darwin) OS=macosx ;; Linux): OS=linux ;; *) echo Unknown OS assuming Linux OS=linux ;; esac PYTHON_BASE=$(basename ${PYTHON}) ${PYTHON} setup_makefile.py ${OS} tmp-${PYTHON_BASE}-unlimited-api.mak make -f tmp-${PYTHON_BASE}-unlimited-api.mak clean 2>&1 | tee tmp-${PYTHON_BASE}-unlimited-api.log make -f tmp-${PYTHON_BASE}-unlimited-api.mak test 2>&1 | tee -a tmp-${PYTHON_BASE}-unlimited-api.log pycxx-7.1.4/CXX/000755 000765 000024 00000000000 13664720516 013634 5ustar00barrystaff000000 000000 pycxx-7.1.4/build-unlimited-api.cmd000644 000765 000024 00000004244 13432535510 017510 0ustar00barrystaff000000 000000 setlocal rem Mm e.g. 27 36 etc set PYTHON_VER=%1 rem win32 or win64 set PYTHON_ARCH=%2 rem 9.0, 14.0 set VC_VER=%3 echo ---------------------------------------------------- echo Testing unlimited API for python %1 %2 using VC %3 echo ---------------------------------------------------- if %PYTHON_ARCH% == win32 ( if %VC_VER% == 9.0 ( call "%LOCALAPPDATA%\Programs\Common\Microsoft\Visual C++ for Python\%VC_VER%\vcvarsall.bat" x86 ) else ( if exist "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\vcvarsall.bat" ( call "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\vcvarsall.bat" ) if exist "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" ( call "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" ) ) ) if %PYTHON_ARCH% == win64 ( if %VC_VER% == 9.0 ( call "%LOCALAPPDATA%\Programs\Common\Microsoft\Visual C++ for Python\%VC_VER%\vcvarsall.bat" x64 ) else ( if exist "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\bin\amd64\vcvars64.bat" ( call "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\bin\amd64\vcvars64.bat" ) if exist "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" ( call "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" ) ) ) if exist c:\python%PYTHON_VER%.%PYTHON_ARCH%\python.exe ( c:\python%PYTHON_VER%.%PYTHON_ARCH%\python setup_makefile.py %PYTHON_ARCH% tmp-%PYTHON_ARCH%-python%PYTHON_VER%-unlimited-build.mak if errorlevel 1 exit /b 1 nmake -f tmp-%PYTHON_ARCH%-python%PYTHON_VER%-unlimited-build.mak clean all 2>&1 | c:\UnxUtils\usr\local\wbin\tee.exe tmp-%PYTHON_ARCH%-python%PYTHON_VER%-unlimited-build.log if not exist obj\pycxx_iter.pyd exit /b 1 nmake -f tmp-%PYTHON_ARCH%-python%PYTHON_VER%-unlimited-build.mak test 2>&1 | c:\UnxUtils\usr\local\wbin\tee.exe tmp-%PYTHON_ARCH%-python%PYTHON_VER%-unlimited-test.log ) endlocal pycxx-7.1.4/build-all.cmd000644 000765 000024 00000002642 13432535510 015517 0ustar00barrystaff000000 000000 if not "%1%2" == "" goto :build_%1_%2 :build_27_32 call build-unlimited-api.cmd 27 win32 9.0 if not "%1%2" == "" goto :eof :build_33_32 call build-unlimited-api.cmd 33 win32 10.0 if not "%1%2" == "" goto :eof :build_34_32 call build-unlimited-api.cmd 34 win32 10.0 call build-limited-api.cmd 34 win32 10.0 3.4 if not "%1%2" == "" goto :eof :build_35_32 call build-unlimited-api.cmd 35 win32 14.0 call build-limited-api.cmd 35 win32 14.0 3.4 call build-limited-api.cmd 35 win32 14.0 3.5 if not "%1%2" == "" goto :eof :build_27_64 call build-unlimited-api.cmd 27 win64 9.0 if not "%1%2" == "" goto :eof :build_35_64 call build-unlimited-api.cmd 35 win64 14.0 call build-limited-api.cmd 35 win64 14.0 3.4 call build-limited-api.cmd 35 win64 14.0 3.5 if not "%1%2" == "" goto :eof :build_36_64 call build-unlimited-api.cmd 36 win64 14.0 call build-limited-api.cmd 36 win64 14.0 3.4 call build-limited-api.cmd 36 win64 14.0 3.6 if not "%1%2" == "" goto :eof :build_37_64 call build-unlimited-api.cmd 37 win64 14.0 call build-limited-api.cmd 37 win64 14.0 3.4 call build-limited-api.cmd 37 win64 14.0 3.7 if not "%1%2" == "" goto :eof :build_38_64 call build-unlimited-api.cmd 38 win64 14.0 call build-limited-api.cmd 38 win64 14.0 3.4 call build-limited-api.cmd 38 win64 14.0 3.7 if not "%1%2" == "" goto :eof pycxx-7.1.4/README.html000644 000765 000024 00000017657 13664720236 015034 0ustar00barrystaff000000 000000 PyCXX README

PyCXX -- README

Installation using distutils

Windows Installation and Demo

  1. Fetch http://prdownloads.sourceforge.net/cxx/pycxx-7.1.4.tar.gz
  2. Expand the archive into a directory of your choosing C:\ for example.
  3. Install the PyCXX files:
    1. C:> cd \pycxx-7.1.4
    2. C:\pycxx-7.1.4> python setup.py install
  4. Build and run the demo extensions:
    1. C:> cd \pycxx-7.1.4
    2. C:\pycxx-7.1.4> python setup_makefile.py win32 win32.mak 
    3. C:\pycxx-7.1.4> nmake -f win32.mak clean test

Unix Installation and Demo

  1. Fetch http://prdownloads.sourceforge.net/cxx/pycxx-7.1.4.tar.gz
  2. Login as root. root access is typically needed on Unix systems to install the PyCXX files into the Python directories.
  3. Expand the archive into a directory of your choosing ~\ for example.
  4. Install the PyCXX files:
    1. # cd ~/pycxx-7.1.4
    2. # python setup.py install
  5. Build and run the demo extensions:
    1. # cd ~/pycxx-7.1.4
    2. # python setup_makefile.py linux linux.mak
    3. # make -f linux.mak clean test

Revision History

Version: 7.1.4 (31-May-2020)

Add support for more number methods, like matrix and the inplace versions.

Use IsInstance checking so that derived classes of builtin types can be used.

Update Docs with recent changes.

Add support for python 3.9 beta 1 changes.

Version: 7.1.3 (8-Jul-2019)

Fix for https://sourceforge.net/p/cxx/bugs/43/ memory leak caused by wrong ref count on python3 Py::String objects.

Remove support for supportPrint() etc as the tp_print field is being removed from python either in 3.8 or 3.9.

Version: 7.1.2 (4-Mar-2019)

Fix problem with compiling for Python 2 and the _Py_PackageContext symbol.

Merge Fedora's patch for setup.py

Version: 7.1.1 (18-Feb-2019)

Add exception errorType() and errorValue() function to access the type and value of an exception.

Version: 7.1.0 (24-August-2018)

Add support for Py_LIMITED_API aka PEP-384

Version: 7.0.3 (23-April-2017)

Update Py::Long to support long long consitently between Python2 and Python3.

Version: 7.0.2 (16-April-2017)

Add Py::Char ord() method to return the long value of a character.

Fix String::size() that could return twice the actual length. This affected as_ucs4string() which would return a string with its second half as uninitialised memory.

Fix setup.py for the Demo code to build all the required C++ code.

Version: 7.0.1 (29-Aug-2016)

Add extra methods to Py::String that as needed on Windows to support full unicode range of code points.

On Windows Python defines Py_UNICODE as unsigned short, which is too small to hold all Unicode values. PyCXX has added to the Py::String API to support creationg from Py_UCS4 strings and converting Py::String() into Py::ucs4string objects.

Fix validate for Bytes to use the correct check function.

Version 7.0.0 (15-Aug-2016)

Warning: This version fixes a number of problems that require source incompatible changes.

However by defining PYCXX_6_2_COMPATIBILITY the V6.2.x API is restored. This is not recommended for new code.

The first version of python3 that is supported is 3.3.

A special thanks goes to Benjamin Webb, working at the US Army Engineer Research and Development Center, who has contributed to the design and testing of this release. 7.0.0 is better for his work.

New source file needs to built: Src/cxx_exceptions.cxx. This file implements the new exception handling features.

Fix the type used for lengths and sequence indexes to use Py_ssize_t. This will require sources changes for users of PyCXX.

Implement smart handling of Exceptions between C++ and Python. You can now catch exceptions in C++ by type that are raised in C++ or Python.

All builtin exceptions are support and are user defined exceptions.

The base exception type is now BaseException not Exception. To upgrade source code replace all use of Exception with BaseException.

The documentation has been updated to describe the new exception features.

The supportSequence, supportMapping, supportNumber etc functions now take a bit mask that defines which specific callbacks are handled.

Version 6.2.8 (10-May-2016)

Fix crash when a member function is called via callMemberFunction() and that function raises an expection.

Found in comment on StackOverFlow. Fix memory size allocated for new objects. It used the wrong size calculation, but was big enough to avoid problems.

Version 6.2.7 (28-Apr-2016)

Fix missing ptr__Unicode_Type.

Fixes from learn0more@gmail.com make python2 also remember the m_module and add accessor functions.

Fix for indirection issues from Vivian De Smedt.

Update to work with latest Microsoft Visual C++ for python 2.7. All test run in Win32 and Win64.

PyCXX.html documention has been updated, especially with 2TO3 information.

Use delete[] for objects allocated with new[].

Version 6.2.6 (04-Jan-2015)

Fix build issue with GCC 4.2.1 on FreeBSD and Mac OS X (stop python defining isspace as a macro).

Remove support for python 3.1 (API's are unstable).

Add Python 3.3 support.

Patch from Michael Droettboom to fix compilation issues.

Patch from Michael Droettboom to add buffer interface for python3.

Version 6.2.4 (3-Mar-2012)

Fix memory leak in string encode and decode functions

Fix indirect python loading on windows - Bool_type was missing

Version 6.2.3 (11-Mar-2011)

Version 6.2.2 (26-Dec-2010)

Fix problem compiling against Python 3.1.3

Version 6.2.1 (3-May-2010)

Fix problems with new style classes

Replace all example makefile and project files with setup_makefile.py script.

Add APIs to make calling python functions easier. See TupleN(), callOnSelf(), self()

Version 6.1.1 (26-Sep-2009)

Supports Python 3 starting at Python 3.1 and Python 2

Code clean up to fix compiler warnings reported by gcc 4.2.1 on Mac OS X when building for Python 3.

Version 6.1.0 (19-Jul-2009)

Support Python 3 and Python 2

pycxx-7.1.4/build-limited-api.sh000755 000765 000024 00000001045 13347675176 017035 0ustar00barrystaff000000 000000 #!/bin/bash set -x set -e set -o pipefail PYTHON=${1? python exe} API=${2? api version} case "$( uname )" in Darwin) OS=macosx ;; Linux): OS=linux ;; *) echo Unknown OS assuming Linux OS=linux ;; esac PYTHON_BASE=$(basename ${PYTHON}) ${PYTHON} setup_makefile.py ${OS} tmp-${PYTHON_BASE}-limited-api.mak --limited-api=${API} make -f tmp-${PYTHON_BASE}-limited-api.mak clean 2>&1 | tee tmp-${PYTHON_BASE}-limited-api.log make -f tmp-${PYTHON_BASE}-limited-api.mak test 2>&1 | tee -a tmp-${PYTHON_BASE}-limited-api.log pycxx-7.1.4/build-all.sh000755 000765 000024 00000001005 13305260623 015360 0ustar00barrystaff000000 000000 #!/bin/bash set -x set -e set -o pipefail for PYTHON in \ python2.6 \ python2.7 \ python3.3 \ python3.4 \ python3.5 \ python3.6 \ python3.7 \ python3.8 \ python3.9 \ ; do if which $PYTHON >/dev/null then echo "Info: Found ${PYTHON}" ./build-unlimited-api.sh ${PYTHON} case "${PYTHON}" in python3.3) ;; python3.*) ./build-limited-api.sh ${PYTHON} ${PYTHON#python} ;; esac fi done pycxx-7.1.4/setup.py000755 000765 000024 00000004741 13437177573 014724 0ustar00barrystaff000000 000000 import os, sys from glob import glob from distutils.command.install import install from distutils.command.install_headers import install_headers from distutils.core import setup # either "Python2" or "Python3" python_ver = "Python" + sys.version[0] headers = [ (None, glob( os.path.join( "CXX", "*.hxx" ) ) + glob( os.path.join( "CXX", "*.h" ) )), (python_ver, glob( os.path.join( "CXX", python_ver, "*.hxx" ) )) ] sources = [ ("CXX", glob( os.path.join( "Src", "*.cxx" ) ) + glob( os.path.join( "Src", "*.c" ) )), (os.path.join( "CXX", python_ver ), glob( os.path.join( "Src", python_ver, "*" ) )) ] class my_install(install): def finalize_options( self ): if not self.install_data or (len(self.install_data) < 8): self.install_data = "$base/share/python$py_version_short" install.finalize_options (self) def run (self): self.distribution.data_files = sources self.distribution.headers = headers install.run( self ) class my_install_headers(install_headers): def run( self ): if not self.distribution.headers: return for subdir, headers in self.distribution.headers: try: dir = os.path.join( self.install_dir, subdir ) except: dir = self.install_dir self.mkpath( dir ) for header in headers: (out, _) = self.copy_file( header, dir ) self.outfiles.append( out ) # read the version from the master file CXX/Version.hxx v_maj = None v_min = None v_pat = None with open( 'CXX/Version.hxx', 'r' ) as f: for line in f: if line.startswith( '#define PYCXX_VERSION_' ): parts = line.strip().split() if parts[1] == 'PYCXX_VERSION_MAJOR': v_maj = parts[2] elif parts[1] == 'PYCXX_VERSION_MINOR': v_min = parts[2] elif parts[1] == 'PYCXX_VERSION_PATCH': v_pat = parts[2] setup( name = "CXX", version = "%s.%s.%s" % (v_maj, v_min, v_pat), maintainer = "Barry Scott", maintainer_email = "barry-scott@users.sourceforge.net", description = "Facility for extending Python with C++", url = "http://cxx.sourceforge.net", cmdclass = {'install': my_install, 'install_headers': my_install_headers}, packages = ['CXX'], package_dir = {'CXX': 'Lib'} ) pycxx-7.1.4/Lib/000755 000765 000024 00000000000 13664720516 013700 5ustar00barrystaff000000 000000 pycxx-7.1.4/build-limited-api.cmd000644 000765 000024 00000003615 13432535510 017146 0ustar00barrystaff000000 000000 setlocal rem Mm e.g. 24 36 etc set PYTHON_VER=%1 rem win32 or win64 set PYTHON_ARCH=%2 rem 10.0, 14.0 set VC_VER=%3 set API=%4 echo ------------------------------------------------------ echo Testing limited API %4 for python %1 %2 using VC %3 echo ------------------------------------------------------ if %PYTHON_ARCH% == win32 ( if exist "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\vcvarsall.bat" ( call "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\vcvarsall.bat" ) if exist "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" ( call "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" ) ) if %PYTHON_ARCH% == win64 ( if exist "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\bin\amd64\vcvars64.bat" ( call "C:\Program Files (x86)\Microsoft Visual Studio %VC_VER%\VC\bin\amd64\vcvars64.bat" ) if exist "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" ( call "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" ) ) if exist c:\python%PYTHON_VER%.%PYTHON_ARCH%\python.exe ( c:\python%PYTHON_VER%.%PYTHON_ARCH%\python setup_makefile.py %PYTHON_ARCH% tmp-%PYTHON_ARCH%-python%PYTHON_VER%-limited-%API%-build.mak --limited-api=%API% if errorlevel 1 exit /b 1 nmake -f tmp-%PYTHON_ARCH%-python%PYTHON_VER%-limited-%API%-build.mak clean all 2>&1 | c:\UnxUtils\usr\local\wbin\tee.exe tmp-%PYTHON_ARCH%-python%PYTHON_VER%-limited-%API%-build.log if not exist obj\pycxx_iter.pyd exit /b 1 nmake -f tmp-%PYTHON_ARCH%-python%PYTHON_VER%-limited-%API%-build.mak test 2>&1 | c:\UnxUtils\usr\local\wbin\tee.exe tmp-%PYTHON_ARCH%-python%PYTHON_VER%-limited-%API%-test.log echo All done ) endlocal pycxx-7.1.4/how_to_release_pycxx.txt000644 000765 000024 00000001624 13510630011 020144 0ustar00barrystaff000000 000000 How to release PyCXX -------------------- 0. Update CXX/Version.hxx with the releases version number Update README.html, README.txt with change log info 1. Tag the source using tag_pycxx.py (depends on pysvn). 2. Create the source kit using make_src_kit.py 3. Add new File release on sourceforge. 1. http://sourceforge.net/projects/cxx/ 2. Select Files tab 3. Open CXX folder 4. Click "Add Folder" 5. Name the Folder PyCXX V.. e.g. PyCXX V6.1.1 7. Upload the source kit and its README.txt 9. Click on the source kit (i) icon and choose Select All platforms. Do not select all for README.txt. 4. Add news about release 1. Click News 2. From side bar choose New Post 3. Add news with release note info - may be need to make it a bigger advert? 5. Email CXX mailing lists 6. Update docs on the PyCXX homepage 1. cd SourceForge 2. ./deploy.sh pycxx-7.1.4/RegressionTests/000755 000765 000024 00000000000 13664720516 016335 5ustar00barrystaff000000 000000 pycxx-7.1.4/Doc/000755 000765 000024 00000000000 13664720516 013677 5ustar00barrystaff000000 000000 pycxx-7.1.4/README.txt000644 000765 000024 00000000406 13664720236 014667 0ustar00barrystaff000000 000000 Version: 7.1.4 (31-May-2020) Add support for more number methods, like matrix and the inplace versions. Use IsInstance checking so that derived classes of builtin types can be used. Update Docs with recent changes. Add support for python 3.9 beta 1 changes. pycxx-7.1.4/COPYRIGHT000644 000765 000024 00000006226 10547732521 014467 0ustar00barrystaff000000 000000 Copyright (c) 1998 - 2007 The Regents of the University of California Produced at the Lawrence Livermore National Laboratory Written by Geoff Furnish, Paul F. Dubois, Barry A. Scott UCRL-CODE-227018 All rights reserved. This file is part of PyCXX. For details, see http://cxx.sourceforge.net. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the disclaimer below. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the disclaimer (as noted below) in the documentation and/or materials provided with the distribution. - Neither the name of the UC/LLNL nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Additional BSD Notice 1. This notice is required to be provided under our contract with the U.S. Department of Energy (DOE). This work was produced at the University of California, Lawrence Livermore National Laboratory under Contract No. W-7405-ENG-48 with the DOE. 2. Neither the United States Government nor the University of California nor any of their employees, makes any warranty, express or implied, or assumes any liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product, or process disclosed, or represents that its use would not infringe privately-owned rights. 3. Also, reference herein to any specific commercial products, process, or services by trade name, trademark, manufacturer or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or the University of California. The views and opinions of authors expressed herein do not necessarily state or reflect those of the United States Government or the University of California, and shall not be used for advertising or product endorsement purposes. pycxx-7.1.4/setup_makefile.py000644 000765 000024 00000054175 13354735735 016562 0ustar00barrystaff000000 000000 # # Copyright (c) 2010-2011 Barry A. Scott # import os import sys import distutils import distutils.sysconfig import distutils.util _debug = False def debug( msg ): if _debug: sys.stderr.write( 'Debug: %s\n' % (msg,) ) #-------------------------------------------------------------------------------- class Setup: def __init__( self, argv ): args = argv[1:] if len(args) < 2: raise ValueError( 'Usage: setup.py win32|win64|macosx|linux> ' ) self.opt_debug = False self.opt_pycxx_debug = False self.opt_limited_api = None self.is_pypy = hasattr( sys, 'pypy_version_info' ) self.platform = args[0] del args[0] self.__makefile = open( args[0], 'wt' ) del args[0] while len(args) > 0: if args[0] == '--debug': self.opt_debug = True del args[0] elif args[0] == '--pycxx-debug': self.opt_pycxx_debug = True del args[0] elif args[0] == '--limited-api': self.opt_limited_api = '0x03040000' del args[0] elif args[0].startswith( '--limited-api=' ): api = args[0][len('--limited-api='):] if api.startswith( '0x' ): self.opt_limited_api = api else: major, minor = [int(s) for s in api.split('.')] minor *= 0x10000 major *= 0x1000000 self.opt_limited_api = '0x%x' % (major+minor) del args[0] else: raise ValueError( 'Unknown arg %r' % (args[0],) ) self.setupCompile() def makePrint( self, line ): self.__makefile.write( line ) self.__makefile.write( '\n' ) def setupCompile( self ): if self.platform == 'win32': self.c_utils = Win32CompilerMSVC90( self ) self.c_python_extension = Win32CompilerMSVC90( self ) elif self.platform == 'win64': self.c_utils = Win32CompilerMSVC90( self ) self.c_python_extension = Win32CompilerMSVC90( self ) elif self.platform == 'macosx': self.c_utils = MacOsxCompilerGCC( self ) self.c_python_extension = MacOsxCompilerGCC( self ) elif self.platform == 'linux': self.c_utils = LinuxCompilerGCC( self ) self.c_python_extension = LinuxCompilerGCC( self ) else: raise ValueError( 'Unknown platform %r' % (self.platform,) ) self.c_python_extension.setupPythonExtension() self.pycxx_obj_file = [ Source( self.c_python_extension, 'Src/cxxsupport.cxx' ), Source( self.c_python_extension, 'Src/cxx_extensions.cxx' ), Source( self.c_python_extension, 'Src/cxx_exceptions.cxx' ), Source( self.c_python_extension, 'Src/cxxextensions.c' ), Source( self.c_python_extension, 'Src/IndirectPythonInterface.cxx' ), ] self.simple_obj_files = [ Source( self.c_python_extension, '%(DEMO_DIR)s/simple.cxx' ), ] + self.pycxx_obj_file self.example_obj_files = [ Source( self.c_python_extension, '%(DEMO_DIR)s/example.cxx' ), Source( self.c_python_extension, '%(DEMO_DIR)s/range.cxx' ), Source( self.c_python_extension, '%(DEMO_DIR)s/rangetest.cxx' ), ] + self.pycxx_obj_file self.pycxx_iter_obj_files = [ Source( self.c_python_extension, '%(DEMO_DIR)s/pycxx_iter.cxx' ), ] + self.pycxx_obj_file exe_simple = PythonExtension( self.c_python_extension, 'simple', self.simple_obj_files ) exe_example = PythonExtension( self.c_python_extension, 'example', self.example_obj_files ) exe_pycxx_iter = PythonExtension( self.c_python_extension, 'pycxx_iter', self.pycxx_iter_obj_files ) self.all_exe = [ exe_simple, exe_example, exe_pycxx_iter, ] self.all_test = [ TestPythonExtension( self.c_python_extension, '%(DEMO_DIR)s/test_simple.py', exe_simple ), TestPythonExtension( self.c_python_extension, '%(DEMO_DIR)s/test_example.py', exe_example ), TestPythonExtension( self.c_python_extension, '%(DEMO_DIR)s/test_pycxx_iter.py', exe_pycxx_iter ), ] def generateMakefile( self ): try: self.c_python_extension.generateMakefileHeader() self.makePrint( 'all: %s' % (' '.join( [exe.getTargetFilename() for exe in self.all_exe] )) ) self.makePrint( '' ) for exe in self.all_exe: exe.generateMakefile() for test in self.all_test: test.generateMakefile() self.__makefile.close() return 0 except ValueError: e = sys.exc_info()[1] sys.stderr.write( 'Error: %s\n' % (e,) ) return 1 #-------------------------------------------------------------------------------- class Compiler: def __init__( self, setup ): debug( 'Compiler.__init__()' ) self.setup = setup self.__variables = {} self._addVar( 'DEBUG', 'NDEBUG') def platformFilename( self, filename ): return filename def makePrint( self, line ): self.setup.makePrint( line ) def generateMakefileHeader( self ): raise NotImplementedError( 'generateMakefileHeader' ) def _addFromEnv( self, name ): debug( 'Compiler._addFromEnv( %r )' % (name,) ) self._addVar( name, os.environ[ name ] ) def _addVar( self, name, value ): debug( 'Compiler._addVar( %r, %r )' % (name, value) ) try: if '%' in value: value = value % self.__variables self.__variables[ name ] = value except TypeError: raise ValueError( 'Cannot translate name %r value %r' % (name, value) ) except KeyError: e = sys.exc_info()[1] raise ValueError( 'Cannot translate name %r value %r - %s' % (name, value, e) ) def expand( self, s ): try: return s % self.__variables except (TypeError, KeyError): e = sys.exc_info()[1] print( 'Error: %s' % (e,) ) print( 'String: %s' % (s,) ) print( 'Vairables: %r' % (self.__variables,) ) raise ValueError( 'Cannot translate string (%s)' % (e,) ) # MSVC 9.0 and later versions class Win32CompilerMSVC90(Compiler): def __init__( self, setup ): Compiler.__init__( self, setup ) self._addVar( 'PYTHONDIR', sys.exec_prefix ) if setup.opt_limited_api is None: self._addVar( 'PYTHON_LIBNAME', 'python%d%d' % (sys.version_info[0], sys.version_info[1]) ) else: self._addVar( 'PYTHON_LIBNAME', 'python3' ) self._addVar( 'PYTHON_INCLUDE', r'%(PYTHONDIR)s\include' ) self._addVar( 'PYTHON_LIB', r'%(PYTHONDIR)s\libs' ) self._addVar( 'PYTHON', sys.executable ) def platformFilename( self, filename ): return filename.replace( '/', '\\' ) def getPythonExtensionFileExt( self ): return '.pyd' def getProgramExt( self ): return '.exe' def generateMakefileHeader( self ): self.makePrint( '#' ) self.makePrint( '# PyCXX Makefile generated by setup_makefile.py' ) self.makePrint( '#' ) self.makePrint( 'CCC=cl /nologo /W4' ) self.makePrint( 'CC=cl /nologo /W4' ) self.makePrint( '' ) self.makePrint( 'LDSHARED=$(CCC) /LD /Zi /MT /EHsc' ) self.makePrint( 'LDEXE=$(CCC) /Zi /MT /EHsc' ) self.makePrint( '' ) def ruleLinkProgram( self, target ): pyd_filename = target.getTargetFilename() pdf_filename = target.getTargetFilename( '.pdf' ) all_objects = [source.getTargetFilename() for source in target.all_sources] rules = [''] rules.append( '' ) rules.append( '%s : %s' % (pyd_filename, ' '.join( all_objects )) ) rules.append( '\t@echo Link %s' % (pyd_filename,) ) rules.append( '\t$(LDEXE) %%(CCCFLAGS)s /Fe%s /Fd%s %s Advapi32.lib' % (pyd_filename, pdf_filename, ' '.join( all_objects )) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleLinkShared( self, target ): pyd_filename = target.getTargetFilename() pdf_filename = target.getTargetFilename( '.pdf' ) all_objects = [source.getTargetFilename() for source in target.all_sources] rules = [''] rules.append( '' ) rules.append( '%s : %s' % (pyd_filename, ' '.join( all_objects )) ) rules.append( '\t@echo Link %s' % (pyd_filename,) ) rules.append( '\t$(LDSHARED) %%(CCCFLAGS)s /Fe%s /Fd%s %s %%(PYTHON_LIB)s\%%(PYTHON_LIBNAME)s.lib' % (pyd_filename, pdf_filename, ' '.join( all_objects )) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleCxx( self, target ): obj_filename = target.getTargetFilename() rules = [] rules.append( '%s: %s %s' % (obj_filename, target.src_filename, ' '.join( target.all_dependencies )) ) rules.append( '\t@echo Compile: %s into %s' % (target.src_filename, target.getTargetFilename()) ) rules.append( '\t$(CCC) /c %%(CCCFLAGS)s /Fo%s /Fd%s %s' % (obj_filename, target.dependent.getTargetFilename( '.pdb' ), target.src_filename) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleC( self, target ): # can reuse the C++ rule self.ruleCxx( target ) def ruleClean( self, filename ): rules = [] rules.append( 'clean::' ) rules.append( '\tif exist %s del %s' % (filename, filename) ) rules.append( '' ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def setupPythonExtension( self ): self._addVar( 'PYTHON', sys.executable ) self._addVar( 'OBJ_DIR', 'obj' ) self._addVar( 'PYTHON_VERSION', '%d.%d' % (sys.version_info[0], sys.version_info[1]) ) self._addVar( 'DEMO_DIR', 'Demo\Python%d' % (sys.version_info[0],) ) self._addVar( 'PYCXX_DEBUG', '-DPYCXX_DEBUG=1' if self.setup.opt_pycxx_debug else '' ) self._addVar( 'PYCXX_API', ('-DPy_LIMITED_API=%s' % (self.setup.opt_limited_api,)) if self.setup.opt_limited_api else '' ) self._addVar( 'CCCFLAGS', r'/Zi /MT /EHsc ' r'-I. -ISrc -I%(PYTHON_INCLUDE)s ' r'-D_CRT_NONSTDC_NO_DEPRECATE ' r'-U_DEBUG ' r'-D%(DEBUG)s ' r'%(PYCXX_DEBUG)s' r'%(PYCXX_API)s' ) def ruleTest( self, python_test ): rules = [] rules.append( 'test:: %s %s' % (python_test.getTargetFilename(), python_test.python_extension.getTargetFilename()) ) rules.append( '\tset PYTHONPATH=obj' ) rules.append( '\t%%(PYTHON)s -W default %s' % (python_test.getTargetFilename(),) ) rules.append( '' ) self.makePrint( self.expand( '\n'.join( rules ) ) ) class CompilerGCC(Compiler): def __init__( self, setup ): Compiler.__init__( self, setup ) if self.setup.platform == 'macosx': if sys.version_info[0] == 2: maxsize = sys.maxint else: maxsize = sys.maxsize if maxsize == (2**31-1): arch = 'i386' else: arch = 'x86_64' self._addVar( 'CCC', 'g++ -arch %s' % (arch,) ) self._addVar( 'CC', 'gcc -arch %s' % (arch,) ) else: self._addVar( 'CCC', 'g++' ) self._addVar( 'CC', 'gcc' ) def getPythonExtensionFileExt( self ): return '.so' def getProgramExt( self ): return '' def generateMakefileHeader( self ): self.makePrint( '#' ) self.makePrint( '# PyCXX Makefile generated by setup_makefile.py' ) self.makePrint( '#' ) self.makePrint( '' ) def ruleLinkProgram( self, target ): target_filename = target.getTargetFilename() all_objects = [source.getTargetFilename() for source in target.all_sources] rules = [] rules.append( '%s : %s' % (target_filename, ' '.join( all_objects )) ) rules.append( '\t@echo Link %s' % (target_filename,) ) rules.append( '\t%%(LDEXE)s -o %s %%(CCCFLAGS)s %s' % (target_filename, ' '.join( all_objects )) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleLinkShared( self, target ): target_filename = target.getTargetFilename() all_objects = [source.getTargetFilename() for source in target.all_sources] rules = [] rules.append( '%s : %s' % (target_filename, ' '.join( all_objects )) ) rules.append( '\t@echo Link %s' % (target_filename,) ) rules.append( '\t%%(LDSHARED)s -o %s %%(CCCFLAGS)s %s' % (target_filename, ' '.join( all_objects )) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleCxx( self, target ): obj_filename = target.getTargetFilename() rules = [] rules.append( '%s: %s %s' % (obj_filename, target.src_filename, ' '.join( target.all_dependencies )) ) rules.append( '\t@echo Compile: %s into %s' % (target.src_filename, obj_filename) ) rules.append( '\t%%(CCC)s -c %%(CCCFLAGS)s -o%s %s' % (obj_filename, target.src_filename) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleC( self, target ): obj_filename = target.getTargetFilename() rules = [] rules.append( '%s: %s %s' % (obj_filename, target.src_filename, ' '.join( target.all_dependencies )) ) rules.append( '\t@echo Compile: %s into %s' % (target.src_filename, target) ) rules.append( '\t%%(CC)s -c %%(CCCFLAGS)s -o%s %s' % (obj_filename, target.src_filename) ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleClean( self, filename ): rules = [] rules.append( 'clean::' ) rules.append( '\trm -f %s' % (filename,) ) rules.append( '' ) self.makePrint( self.expand( '\n'.join( rules ) ) ) def ruleTest( self, python_test ): rules = [] rules.append( 'test:: %s %s' % (python_test.getTargetFilename(), python_test.python_extension.getTargetFilename()) ) rules.append( '\tPYTHONPATH=obj %%(PYTHON)s -W default %s' % (python_test.getTargetFilename(),) ) rules.append( '' ) self.makePrint( self.expand( '\n'.join( rules ) ) ) class MacOsxCompilerGCC(CompilerGCC): def __init__( self, setup ): CompilerGCC.__init__( self, setup ) def setupPythonExtension( self ): self._addVar( 'PYTHON', sys.executable ) self._addVar( 'OBJ_DIR', 'obj' ) self._addVar( 'PYTHON_VERSION', '%d.%d' % (sys.version_info[0], sys.version_info[1]) ) self._addVar( 'PYTHONDIR', sys.exec_prefix ) self._addVar( 'PYTHON', sys.executable ) if self.setup.is_pypy: self._addVar( 'PYTHON_INCLUDE', '%(PYTHONDIR)s/include' ) self._addVar( 'PYTHON_FRAMEWORK', '%(PYTHONDIR)s/bin/libpypy-c.dylib' ) else: self._addVar( 'PYTHON_INCLUDE', '%(PYTHONDIR)s/Headers' ) self._addVar( 'PYTHON_FRAMEWORK', '%(PYTHONDIR)s/Python' ) self._addVar( 'DEMO_DIR', 'Demo/Python%d' % (sys.version_info[0],) ) self._addVar( 'PYCXX_DEBUG', '-DPYCXX_DEBUG=1' if self.setup.opt_pycxx_debug else '' ) self._addVar( 'PYCXX_API', ('-DPy_LIMITED_API=%s' % (self.setup.opt_limited_api,)) if self.setup.opt_limited_api else '' ) self._addVar( 'CCCFLAGS', '-g ' '-Wall -fPIC -fexceptions -frtti ' '-I. -ISrc -I%(PYTHON_INCLUDE)s ' '-D%(DEBUG)s ' '%(PYCXX_DEBUG)s' '%(PYCXX_API)s' ) self._addVar( 'LDSHARED', '%(CCC)s -bundle -g ' '-framework System ' '%(PYTHON_FRAMEWORK)s ' ) class LinuxCompilerGCC(CompilerGCC): def __init__( self, setup ): CompilerGCC.__init__( self, setup ) def setupPythonExtension( self ): self._addVar( 'PYTHON', sys.executable ) self._addVar( 'OBJ_DIR', 'obj' ) self._addVar( 'DEMO_DIR', 'Demo/Python%d' % (sys.version_info[0],) ) self._addVar( 'PYTHON_VERSION', '%d.%d' % (sys.version_info[0], sys.version_info[1]) ) self._addVar( 'PYTHON_INCLUDE', distutils.sysconfig.get_python_inc() ) self._addVar( 'PYCXX_DEBUG', '-DPYCXX_DEBUG=1' if self.setup.opt_pycxx_debug else '' ) self._addVar( 'PYCXX_API', ('-DPy_LIMITED_API=%s' % (self.setup.opt_limited_api,)) if self.setup.opt_limited_api else '' ) self._addVar( 'CCCFLAGS', '-g ' '-Wall -fPIC -fexceptions -frtti ' '-I. -ISrc -I%(PYTHON_INCLUDE)s ' '-D%(DEBUG)s ' '%(PYCXX_DEBUG)s' '%(PYCXX_API)s' ) self._addVar( 'LDEXE', '%(CCC)s -g' ) self._addVar( 'LDSHARED', '%(CCC)s -shared -g ' ) #-------------------------------------------------------------------------------- class Target: def __init__( self, compiler, all_sources ): self.compiler = compiler self.__generated = False self.dependent = None self.all_sources = all_sources for source in self.all_sources: source.setDependent( self ) def getTargetFilename( self ): raise NotImplementedError( '%s.getTargetFilename' % self.__class__.__name__ ) def generateMakefile( self ): if self.__generated: return self.__generated = True return self._generateMakefile() def _generateMakefile( self ): raise NotImplementedError( '_generateMakefile' ) def ruleClean( self, ext=None ): if ext is None: target_filename = self.getTargetFilename() else: target_filename = self.getTargetFilename( ext ) self.compiler.ruleClean( target_filename ) def setDependent( self, dependent ): debug( '%r.setDependent( %r )' % (self, dependent,) ) self.dependent = dependent class TestPythonExtension(Target): def __init__( self, compiler, test_source, python_extension ): self.test_source = test_source self.python_extension = python_extension Target.__init__( self, compiler, [] ) def __repr__( self ): return '' % (id(self), self.test_source ) def getTargetFilename( self ): return self.compiler.platformFilename( self.compiler.expand( self.test_source ) ) def _generateMakefile( self ): self.compiler.ruleTest( self ) class PythonExtension(Target): def __init__( self, compiler, output, all_sources ): self.output = output Target.__init__( self, compiler, all_sources ) debug( 'PythonExtension:0x%8.8x.__init__( %r, ... )' % (id(self), output,) ) for source in self.all_sources: source.setDependent( self ) def __repr__( self ): return '' % (id(self), self.output) def getTargetFilename( self, ext=None ): if ext is None: ext = self.compiler.getPythonExtensionFileExt() return self.compiler.platformFilename( self.compiler.expand( '%%(OBJ_DIR)s/%s%s' % (self.output, ext) ) ) def _generateMakefile( self ): debug( 'PythonExtension:0x%8.8x.generateMakefile() for %r' % (id(self), self.output,) ) self.compiler.ruleLinkShared( self ) self.compiler.ruleClean( self.getTargetFilename( '.*' ) ) for source in self.all_sources: source.generateMakefile() class Source(Target): def __init__( self, compiler, src_filename, all_dependencies=None ): self.src_filename = compiler.platformFilename( compiler.expand( src_filename ) ) Target.__init__( self, compiler, [] ) debug( 'Source:0x%8.8x.__init__( %r, %r )' % (id(self), src_filename, all_dependencies) ) self.all_dependencies = all_dependencies if self.all_dependencies is None: self.all_dependencies = [] def __repr__( self ): return '' % (id(self), self.src_filename) def getTargetFilename( self ): #if not os.path.exists( self.src_filename ): # raise ValueError( 'Cannot find source %s' % (self.src_filename,) ) basename = os.path.basename( self.src_filename ) if basename.endswith( '.cpp' ): return self.compiler.platformFilename( self.compiler.expand( r'%%(OBJ_DIR)s/%s.obj' % (basename[:-len('.cpp')],) ) ) if basename.endswith( '.cxx' ): return self.compiler.platformFilename( self.compiler.expand( r'%%(OBJ_DIR)s/%s.obj' % (basename[:-len('.cxx')],) ) ) if basename.endswith( '.c' ): return self.compiler.platformFilename( self.compiler.expand( r'%%(OBJ_DIR)s/%s.obj' % (basename[:-len('.c')],) ) ) raise ValueError( 'unknown source %r' % (self.src_filename,) ) def _generateMakefile( self ): debug( 'Source:0x%8.8x.generateMakefile() for %r' % (id(self), self.src_filename,) ) self.compiler.ruleCxx( self ) self.compiler.ruleClean( self.getTargetFilename() ) #-------------------------------------------------------------------------------- def main( argv ): try: s = Setup( argv ) s.generateMakefile() return 0 except ValueError: e = sys.exc_info()[1] sys.stderr.write( 'Error: %s\n' % (e,) ) return 1 if __name__ == '__main__': sys.exit( main( sys.argv ) ) pycxx-7.1.4/run_tests.cmd000644 000765 000024 00000000473 11146621572 015704 0ustar00barrystaff000000 000000 setlocal set PY_MAJ=2 if not "%1" == "" set PY_MAJ=%1 set PY_MIN=5 if not "%2" == "" set PY_MIN=%2 set PYTHONPATH=pyds%PY_MAJ%%PY_MIN% c:\python%PY_MAJ%%PY_MIN%\python Demo\test_example.py if exist pyds%PY_MAJ%%PY_MIN%\pycxx_iter.pyd c:\python%PY_MAJ%%PY_MIN%\python Demo\test_pycxx_iter.py endlocal pycxx-7.1.4/Src/000755 000765 000024 00000000000 13664720516 013721 5ustar00barrystaff000000 000000 pycxx-7.1.4/Src/cxxextensions.c000644 000765 000024 00000004356 11146072165 017010 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "Src/Python2/cxxextensions.c" #else #include "Src/Python3/cxxextensions.c" #endif pycxx-7.1.4/Src/Python3/000755 000765 000024 00000000000 13664720516 015265 5ustar00barrystaff000000 000000 pycxx-7.1.4/Src/cxxsupport.cxx000644 000765 000024 00000004354 11146072165 016703 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "Src/Python2/cxxsupport.cxx" #else #include "Src/Python3/cxxsupport.cxx" #endif pycxx-7.1.4/Src/Python2/000755 000765 000024 00000000000 13664720516 015264 5ustar00barrystaff000000 000000 pycxx-7.1.4/Src/cxx_exceptions.cxx000644 000765 000024 00000000220 12721375410 017472 0ustar00barrystaff000000 000000 #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "Python2/cxx_exceptions.cxx" #else #include "Python3/cxx_exceptions.cxx" #endif pycxx-7.1.4/Src/cxx_extensions.cxx000644 000765 000024 00000004354 11146072165 017525 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "Python2/cxx_extensions.cxx" #else #include "Python3/cxx_extensions.cxx" #endif pycxx-7.1.4/Src/IndirectPythonInterface.cxx000644 000765 000024 00000052641 13561767747 021256 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/IndirectPythonInterface.hxx" namespace Py { static int _IsInstance( PyObject *op, PyTypeObject *type ) { return PyObject_IsInstance( op, reinterpret_cast( type ) ); } bool _CFunction_Check( PyObject *op ) { return _IsInstance( op, _CFunction_Type() ) > 0; } bool _Complex_Check( PyObject *op ) { return _IsInstance( op, _Complex_Type() ) > 0; } bool _Dict_Check( PyObject *op ) { return _IsInstance( op, _Dict_Type() ) > 0; } bool _Float_Check( PyObject *op ) { return _IsInstance( op, _Float_Type() ) > 0; } #if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) bool _Function_Check( PyObject *op ) { return _IsInstance( op, _Function_Type() ) > 0; } #endif bool _Boolean_Check( PyObject *op ) { return _IsInstance( op, _Bool_Type() ) > 0; } bool _List_Check( PyObject *op ) { return _IsInstance( op, _List_Type() ) > 0; } bool _Long_Check( PyObject *op ) { return _IsInstance( op, _Long_Type() ) > 0; } #if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) bool _Method_Check( PyObject *op ) { return _IsInstance( op, _Method_Type() ) > 0; } #endif bool _Module_Check( PyObject *op ) { return _IsInstance( op, _Module_Type() ) > 0; } bool _Range_Check( PyObject *op ) { return _IsInstance( op, _Range_Type() ) > 0; } bool _Slice_Check( PyObject *op ) { return _IsInstance( op, _Slice_Type() ) > 0; } bool _TraceBack_Check( PyObject *op ) { return _IsInstance( op, _TraceBack_Type() ) > 0; } bool _Tuple_Check( PyObject *op ) { return _IsInstance( op, _Tuple_Type() ) > 0; } bool _Type_Check( PyObject *op ) { return _IsInstance( op, _Type_Type() ) > 0; } bool _Unicode_Check( PyObject *op ) { return _IsInstance( op, _Unicode_Type() ) > 0; } #if PY_MAJOR_VERSION == 2 bool _String_Check( PyObject *op ) { return _IsInstance( op, _String_Type() ) > 0; } bool _Int_Check( PyObject *op ) { return _IsInstance( op, _Int_Type() ) > 0; } bool _CObject_Check( PyObject *op ) { return _IsInstance( op, _CObject_Type() ) > 0; } #endif #if PY_MAJOR_VERSION >= 3 bool _Bytes_Check( PyObject *op ) { return _IsInstance( op, _Bytes_Type() ) > 0; } #endif #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) # if defined(MS_WINDOWS) # include static HMODULE python_dll; # define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ static PyObject *ptr_Exc_##eclass = NULL; # if PY_MAJOR_VERSION == 2 # include "CXX/Python2/cxx_standard_exceptions.hxx" # else # include "CXX/Python3/cxx_standard_exceptions.hxx" # endif # undef PYCXX_STANDARD_EXCEPTION static PyTypeObject *ptr__CFunction_Type = NULL; static PyTypeObject *ptr__Complex_Type = NULL; static PyTypeObject *ptr__Dict_Type = NULL; static PyTypeObject *ptr__Float_Type = NULL; # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) static PyTypeObject *ptr__Function_Type = NULL; # endif static PyTypeObject *ptr__Bool_Type = NULL; static PyTypeObject *ptr__List_Type = NULL; static PyTypeObject *ptr__Long_Type = NULL; # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) static PyTypeObject *ptr__Method_Type = NULL; # endif static PyTypeObject *ptr__Module_Type = NULL; static PyTypeObject *ptr__Range_Type = NULL; static PyTypeObject *ptr__Slice_Type = NULL; static PyTypeObject *ptr__TraceBack_Type = NULL; static PyTypeObject *ptr__Tuple_Type = NULL; static PyTypeObject *ptr__Type_Type = NULL; static PyTypeObject *ptr__Unicode_Type = NULL; # if PY_MAJOR_VERSION == 2 static PyTypeObject *ptr__Int_Type = NULL; static PyTypeObject *ptr__String_Type = NULL; static PyTypeObject *ptr__CObject_Type = NULL; # endif # if PY_MAJOR_VERSION >= 3 static PyTypeObject *ptr__Bytes_Type = NULL; # endif # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) static int *ptr_Py_DebugFlag = NULL; static int *ptr_Py_InteractiveFlag = NULL; static int *ptr_Py_OptimizeFlag = NULL; static int *ptr_Py_NoSiteFlag = NULL; static int *ptr_Py_VerboseFlag = NULL; # if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 static const char **ptr__Py_PackageContext = NULL; # else static char **ptr__Py_PackageContext = NULL; # endif # endif # ifdef Py_REF_DEBUG int *ptr_Py_RefTotal; # endif //-------------------------------------------------------------------------------- class GetAddressException { public: GetAddressException( const char *_name ) : name( _name ) {} virtual ~GetAddressException() {} const char *name; }; //-------------------------------------------------------------------------------- static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return *(PyObject **)addr; } static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return (PyObject *)addr; } static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return *(PyTypeObject **)addr; } static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return (PyTypeObject *)addr; } static int *GetInt_as_IntPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return (int *)addr; } static char **GetCharPointer_as_CharPointerPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return (char **)addr; } #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 static char **GetConstCharPointer_as_ConstCharPointerPointer( const char *name ) { FARPROC addr = GetProcAddress( python_dll, name ); if( addr == NULL ) throw GetAddressException( name ); return (const char **)addr; } #endif # ifdef _DEBUG static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; # else static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; # endif //-------------------------------------------------------------------------------- bool InitialisePythonIndirectInterface() { char python_dll_name[sizeof(python_dll_name_format)]; _snprintf( python_dll_name, sizeof(python_dll_name_format) / sizeof(char) - 1, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); python_dll = LoadLibraryA( python_dll_name ); if( python_dll == NULL ) return false; try { # ifdef Py_REF_DEBUG ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); # endif # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); # if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 ptr__Py_PackageContext = GetConstCharPointer_as_ConstCharPointerPointer( "_Py_PackageContext" ); # else ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); # endif # endif # define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) ptr_Exc_#eclass = GetPyTypeObject_As_PyTypeObjectPointer( "PyExc_" #eclass ); # if PY_MAJOR_VERSION == 2 # include "CXX/Python2/cxx_standard_exceptions.hxx" # else # include "CXX/Python3/cxx_standard_exceptions.hxx" # endif # undef PYCXX_STANDARD_EXCEPTION ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); # if PY_MAJOR_VERSION == 2 ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); # else ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_FalseStruct" ); # endif ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); # endif ptr__Bool_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBool_Type" ); ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); # endif ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); # if PY_MAJOR_VERSION == 2 ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); # endif # if PY_MAJOR_VERSION >= 3 ptr__Bytes_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBytes_Type" ); # endif } catch( GetAddressException &e ) { OutputDebugStringA( python_dll_name ); OutputDebugStringA( " does not contain symbol " ); OutputDebugStringA( e.name ); OutputDebugStringA( "\n" ); return false; } return true; } // // Wrap variables as function calls // PyObject *_Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } PyObject *_Exc_AssertionError() { return ptr__Exc_AssertionError; } PyObject *_Exc_AttributeError() { return ptr__Exc_AttributeError; } PyObject *_Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } PyObject *_Exc_EOFError() { return ptr__Exc_EOFError; } PyObject *_Exc_Exception() { return ptr__Exc_Exception; } PyObject *_Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } PyObject *_Exc_ImportError() { return ptr__Exc_ImportError; } PyObject *_Exc_IndexError() { return ptr__Exc_IndexError; } PyObject *_Exc_IOError() { return ptr__Exc_IOError; } PyObject *_Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } PyObject *_Exc_KeyError() { return ptr__Exc_KeyError; } PyObject *_Exc_LookupError() { return ptr__Exc_LookupError; } PyObject *_Exc_MemoryError() { return ptr__Exc_MemoryError; } PyObject *_Exc_NameError() { return ptr__Exc_NameError; } PyObject *_Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } PyObject *_Exc_OSError() { return ptr__Exc_OSError; } PyObject *_Exc_OverflowError() { return ptr__Exc_OverflowError; } PyObject *_Exc_RuntimeError() { return ptr__Exc_RuntimeError; } # if PY_MAJOR_VERSION == 2 PyObject *_Exc_StandardError() { return ptr__Exc_StandardError; } # endif PyObject *_Exc_SyntaxError() { return ptr__Exc_SyntaxError; } PyObject *_Exc_SystemError() { return ptr__Exc_SystemError; } PyObject *_Exc_SystemExit() { return ptr__Exc_SystemExit; } PyObject *_Exc_TypeError() { return ptr__Exc_TypeError; } PyObject *_Exc_ValueError() { return ptr__Exc_ValueError; } # ifdef MS_WINDOWS PyObject *_Exc_WindowsError() { return ptr__Exc_WindowsError; } # endif PyObject *_Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } PyObject *_Exc_IndentationError() { return ptr__Exc_IndentationError; } PyObject *_Exc_TabError() { return ptr__Exc_TabError; } PyObject *_Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } PyObject *_Exc_UnicodeError() { return ptr__Exc_UnicodeError; } // // wrap items in Object.h // PyObject *_None() { return ptr__PyNone; } PyObject *_False() { return ptr__PyFalse; } PyObject *_True() { return ptr__PyTrue; } PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } PyTypeObject *_Float_Type() { return ptr__Float_Type; } # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) PyTypeObject *_Function_Type() { return ptr__Function_Type; } # endif PyTypeObject *_Bool_Type() { return ptr__Bool_Type; } PyTypeObject *_List_Type() { return ptr__List_Type; } PyTypeObject *_Long_Type() { return ptr__Long_Type; } # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) PyTypeObject *_Method_Type() { return ptr__Method_Type; } # endif PyTypeObject *_Module_Type() { return ptr__Module_Type; } PyTypeObject *_Range_Type() { return ptr__Range_Type; } PyTypeObject *_Slice_Type() { return ptr__Slice_Type; } PyTypeObject *_TraceBack_Type() { return ptr__TraceBack_Type; } PyTypeObject *_Tuple_Type() { return ptr__Tuple_Type; } PyTypeObject *_Type_Type() { return ptr__Type_Type; } PyTypeObject *_Unicode_Type() { return ptr__Unicode_Type; } # if PY_MAJOR_VERSION == 2 PyTypeObject *_String_Type() { return ptr__String_Type; } PyTypeObject *_Int_Type() { return ptr__Int_Type; } PyTypeObject *_CObject_Type() { return ptr__CObject_Type; } # endif # if PY_MAJOR_VERSION >= 3 PyTypeObject *_Bytes_Type() { return ptr__Bytes_Type; } # endif // // wrap the Python Flag variables // # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } # endif # if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 const char *__Py_PackageContext() { return *ptr__Py_PackageContext; } # else char *__Py_PackageContext() { return *ptr__Py_PackageContext; } # endif # if 0 # define Py_INCREF(op) ( \ _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ ((PyObject*)(op))->ob_refcnt++) # define Py_DECREF(op) \ if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ --((PyObject*)(op))->ob_refcnt != 0) \ _Py_CHECK_REFCNT(op) \ else \ _Py_Dealloc((PyObject *)(op)) # endif void _XINCREF( PyObject *op ) { // This function must match the contents of Py_XINCREF(op) if( op == NULL ) return; # ifdef Py_REF_DEBUG (*ptr_Py_RefTotal)++; # endif (op)->ob_refcnt++; } void _XDECREF( PyObject *op ) { // This function must match the contents of Py_XDECREF(op); if( op == NULL ) return; # ifdef Py_REF_DEBUG (*ptr_Py_RefTotal)--; # endif if (--(op)->ob_refcnt == 0) _Py_Dealloc((PyObject *)(op)); } # else # error "Can only delay load under Win32" # endif #else //================================================================================ // // Map onto Macros // //================================================================================ // // Wrap variables as function calls // # define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ PyObject *_Exc_##eclass() { return ::PyExc_##eclass; } # if PY_MAJOR_VERSION == 2 # include "CXX/Python2/cxx_standard_exceptions.hxx" # else # include "CXX/Python3/cxx_standard_exceptions.hxx" # endif # undef PYCXX_STANDARD_EXCEPTION // // wrap items in Object.h // PyObject *_None() { return &::_Py_NoneStruct; } PyObject *_False() { return Py_False; } PyObject *_True() { return Py_True; } PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } PyTypeObject *_Complex_Type() { return &PyComplex_Type; } PyTypeObject *_Dict_Type() { return &PyDict_Type; } PyTypeObject *_Float_Type() { return &PyFloat_Type; } # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) PyTypeObject *_Function_Type() { return &PyFunction_Type; } # endif PyTypeObject *_Bool_Type() { return &PyBool_Type; } PyTypeObject *_List_Type() { return &PyList_Type; } PyTypeObject *_Long_Type() { return &PyLong_Type; } # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) PyTypeObject *_Method_Type() { return &PyMethod_Type; } # endif PyTypeObject *_Module_Type() { return &PyModule_Type; } PyTypeObject *_Range_Type() { return &PyRange_Type; } PyTypeObject *_Slice_Type() { return &PySlice_Type; } PyTypeObject *_TraceBack_Type() { return &PyTraceBack_Type; } PyTypeObject *_Tuple_Type() { return &PyTuple_Type; } PyTypeObject *_Type_Type() { return &PyType_Type; } PyTypeObject *_Unicode_Type() { return &PyUnicode_Type; } # if PY_MAJOR_VERSION == 2 PyTypeObject *_String_Type() { return &PyString_Type; } PyTypeObject *_Int_Type() { return &PyInt_Type; } PyTypeObject *_CObject_Type() { return &PyCObject_Type; } # endif # if PY_MAJOR_VERSION >= 3 PyTypeObject *_Bytes_Type() { return &PyBytes_Type; } # endif // // wrap flags // # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) int &_Py_DebugFlag() { return Py_DebugFlag; } int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } int &_Py_VerboseFlag() { return Py_VerboseFlag; } # if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 const char *__Py_PackageContext() { return _Py_PackageContext; } # else char *__Py_PackageContext() { return _Py_PackageContext; } # endif # endif // // Needed to keep the abstactions for delayload interface // void _XINCREF( PyObject *op ) { Py_XINCREF( op ); } void _XDECREF( PyObject *op ) { Py_XDECREF( op ); } #endif } pycxx-7.1.4/Src/Python2/cxxextensions.c000644 000765 000024 00000004370 13662723705 020357 0ustar00barrystaff000000 000000 /*---------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //---------------------------------------------------------------------------*/ #include "CXX/WrapPython.h" #ifdef __cplusplus extern "C" { #endif PyObject py_object_initializer = {PyObject_HEAD_INIT(0)}; #ifdef __cplusplus } #endif pycxx-7.1.4/Src/Python2/cxxsupport.cxx000644 000765 000024 00000012115 13662723705 020250 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/Objects.hxx" namespace Py { Py_UNICODE unicode_null_string[1] = { 0 }; Type Object::type () const { return Type (PyObject_Type (p), true); } String Object::str () const { return String (PyObject_Str (p), true); } String Object::repr () const { return String (PyObject_Repr (p), true); } std::string Object::as_string() const { return static_cast(str()); } List Object::dir () const { return List (PyObject_Dir (p), true); } bool Object::isType (const Type& t) const { return type ().ptr() == t.ptr(); } Char::operator String() const { return String(ptr()); } // TMM: non-member operaters for iterators - see above // I've also made a bug fix in respect to the cxx code // (dereffed the left.seq and right.seq comparison) bool operator==(const Sequence::iterator& left, const Sequence::iterator& right) { return left.eql( right ); } bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right) { return left.neq( right ); } bool operator< (const Sequence::iterator& left, const Sequence::iterator& right) { return left.lss( right ); } bool operator> (const Sequence::iterator& left, const Sequence::iterator& right) { return left.gtr( right ); } bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right) { return left.leq( right ); } bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right) { return left.geq( right ); } // now for const_iterator bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right) { return left.eql( right ); } bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) { return left.neq( right ); } bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right) { return left.lss( right ); } bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right) { return left.gtr( right ); } bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) { return left.leq( right ); } bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right) { return left.geq( right ); } // For mappings: bool operator==(const Mapping::iterator& left, const Mapping::iterator& right) { return left.eql( right ); } bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right) { return left.neq( right ); } // now for const_iterator bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right) { return left.eql( right ); } bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right) { return left.neq( right ); } // TMM: 31May'01 - Added the #ifndef so I can exclude iostreams. #ifndef CXX_NO_IOSTREAMS // output std::ostream& operator<< (std::ostream& os, const Object& ob) { return (os << static_cast(ob.str())); } #endif } // Py pycxx-7.1.4/Src/Python2/cxx_exceptions.cxx000644 000765 000024 00000003231 12733320460 021040 0ustar00barrystaff000000 000000 // // cxx_exceptions.cxx // #include #include #include namespace Py { typedef void (*throw_exception_func_t)( void ); std::map py_exc_type_to_exc_func; void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t func ) { py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type.ptr(), func ) ); } void addPythonException( PyObject *py_exc_type, throw_exception_func_t func ) { py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type, func ) ); } void ifPyErrorThrowCxxException() { if( PyErr_Occurred() ) { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch( &ptype, &pvalue, &ptrace ); PyErr_Restore( ptype, pvalue, ptrace ); Object q( ptype ); std::map::iterator func = py_exc_type_to_exc_func.find( ptype ); if( func != py_exc_type_to_exc_func.end() ) { #ifdef PYCXX_DEBUG std::cout << "ifPyErrorThrowCxxException found throwFunc: " << q << std::endl; #endif (func->second)(); } else { #ifdef PYCXX_DEBUG std::cout << "ifPyErrorThrowCxxException no throwFunc: " << q << std::endl; #endif throw Exception(); } } } void initExceptions() { static bool init_done = false; if( init_done ) { return; } #define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ addPythonException( eclass::exceptionType(), eclass::throwFunc ); #include #undef PYCXX_STANDARD_EXCEPTION init_done = true; } } // end of namespace Py pycxx-7.1.4/Src/Python2/cxx_extensions.cxx000644 000765 000024 00000152444 13005636021 021065 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/Extensions.hxx" #include "CXX/Exception.hxx" #include #ifdef PYCXX_DEBUG // // Functions useful when debugging PyCXX // void bpt( void ) { } void printRefCount( PyObject *obj ) { std::cout << "RefCount of 0x" << std::hex << reinterpret_cast< unsigned long >( obj ) << std::dec << " is " << Py_REFCNT( obj ) << std::endl; } #endif namespace Py { #ifdef PYCXX_PYTHON_2TO3 std::string String::as_std_string( const char *encoding, const char *error ) const { if( isUnicode() ) { Bytes encoded( encode( encoding, error ) ); return encoded.as_std_string(); } else { return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); } } Bytes String::encode( const char *encoding, const char *error ) const { if( isUnicode() ) { return Bytes( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); } else { return Bytes( PyString_AsEncodedObject( ptr(), encoding, error ) ); } } #else std::string String::as_std_string( const char *encoding, const char *error ) const { if( isUnicode() ) { String encoded( encode( encoding, error ) ); return encoded.as_std_string(); } else { return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); } } #endif void Object::validate() { // release pointer if not the right type if( !accepts( p ) ) { #if defined( _CPPRTTI ) || defined( __GNUG__ ) std::string s( "PyCXX: Error creating object of type " ); s += (typeid( *this )).name(); if( p != NULL ) { String from_repr = repr(); s += " from "; s += from_repr.as_std_string( "utf-8" ); } else { s += " from (nil)"; } #endif release(); // Error message already set ifPyErrorThrowCxxException(); // Better error message if RTTI available #if defined( _CPPRTTI ) || defined( __GNUG__ ) throw TypeError( s ); #else throw TypeError( "PyCXX: type error." ); #endif } } //================================================================================ // // Implementation of MethodTable // //================================================================================ PyMethodDef MethodTable::method( const char *method_name, PyCFunction f, int flags, const char *doc ) { PyMethodDef m; m.ml_name = const_cast( method_name ); m.ml_meth = f; m.ml_flags = flags; m.ml_doc = const_cast( doc ); return m; } MethodTable::MethodTable() { t.push_back( method( 0, 0, 0, 0 ) ); mt = NULL; } MethodTable::~MethodTable() { delete [] mt; } void MethodTable::add( const char *method_name, PyCFunction f, const char *doc, int flag ) { if( !mt ) { t.insert( t.end()-1, method( method_name, f, flag, doc ) ); } else { throw RuntimeError( "Too late to add a module method!" ); } } PyMethodDef *MethodTable::table() { if( !mt ) { Py_ssize_t t1size = t.size(); mt = new PyMethodDef[ t1size ]; int j = 0; for( std::vector::iterator i = t.begin(); i != t.end(); i++ ) { mt[ j++ ] = *i; } } return mt; } //================================================================================ // // Implementation of ExtensionModule // //================================================================================ ExtensionModuleBase::ExtensionModuleBase( const char *name ) : m_module_name( name ) , m_full_module_name( __Py_PackageContext() != NULL ? std::string( __Py_PackageContext() ) : m_module_name ) , m_method_table() , m_module( NULL ) {} ExtensionModuleBase::~ExtensionModuleBase() {} const std::string &ExtensionModuleBase::name() const { return m_module_name; } const std::string &ExtensionModuleBase::fullName() const { return m_full_module_name; } class ExtensionModuleBasePtr : public PythonExtension { public: ExtensionModuleBasePtr( ExtensionModuleBase *_module ) : module( _module ) {} virtual ~ExtensionModuleBasePtr() {} ExtensionModuleBase *module; }; void ExtensionModuleBase::initialize( const char *module_doc ) { PyObject *module_ptr = new ExtensionModuleBasePtr( this ); m_module = Py_InitModule4 ( const_cast( m_module_name.c_str() ), // name m_method_table.table(), // methods const_cast( module_doc ), // docs module_ptr, // pass to functions as "self" PYTHON_API_VERSION // API version ); } Module ExtensionModuleBase::module( void ) const { return Module( m_full_module_name ); } Dict ExtensionModuleBase::moduleDictionary( void ) const { return module().getDict(); } Object ExtensionModuleBase::moduleObject( void ) const { return Object( m_module ); } //================================================================================ // // Implementation of PythonType // //================================================================================ extern "C" { static void standard_dealloc( PyObject *p ); // // All the following functions redirect the call from Python // onto the matching virtual function in PythonExtensionBase // #if defined( PYCXX_PYTHON_2TO3 ) static int print_handler( PyObject *, FILE *, int ); #endif static PyObject *getattr_handler( PyObject *, char * ); static int setattr_handler( PyObject *, char *, PyObject * ); static PyObject *getattro_handler( PyObject *, PyObject * ); static int setattro_handler( PyObject *, PyObject *, PyObject * ); #if defined( PYCXX_PYTHON_2TO3 ) static int compare_handler( PyObject *, PyObject * ); #endif static PyObject *rich_compare_handler( PyObject *, PyObject *, int ); static PyObject *repr_handler( PyObject * ); static PyObject *str_handler( PyObject * ); static long hash_handler( PyObject * ); static PyObject *call_handler( PyObject *, PyObject *, PyObject * ); static PyObject *iter_handler( PyObject * ); static PyObject *iternext_handler( PyObject * ); // Sequence methods static Py_ssize_t sequence_length_handler( PyObject * ); static PyObject *sequence_concat_handler( PyObject *,PyObject * ); static PyObject *sequence_repeat_handler( PyObject *, Py_ssize_t ); static PyObject *sequence_item_handler( PyObject *, Py_ssize_t ); static PyObject *sequence_slice_handler( PyObject *, Py_ssize_t, Py_ssize_t ); static int sequence_ass_item_handler( PyObject *, Py_ssize_t, PyObject * ); static int sequence_ass_slice_handler( PyObject *, Py_ssize_t, Py_ssize_t, PyObject * ); static PyObject *sequence_inplace_concat_handler( PyObject *, PyObject * ); static PyObject *sequence_inplace_repeat_handler( PyObject *, Py_ssize_t ); static int sequence_contains_handler( PyObject *, PyObject * ); // Mapping static Py_ssize_t mapping_length_handler( PyObject * ); static PyObject *mapping_subscript_handler( PyObject *, PyObject * ); static int mapping_ass_subscript_handler( PyObject *, PyObject *, PyObject * ); // Numeric methods static int number_nonzero_handler( PyObject * ); static PyObject *number_negative_handler( PyObject * ); static PyObject *number_positive_handler( PyObject * ); static PyObject *number_absolute_handler( PyObject * ); static PyObject *number_invert_handler( PyObject * ); static PyObject *number_int_handler( PyObject * ); static PyObject *number_float_handler( PyObject * ); static PyObject *number_long_handler( PyObject * ); static PyObject *number_oct_handler( PyObject * ); static PyObject *number_hex_handler( PyObject * ); static PyObject *number_add_handler( PyObject *, PyObject * ); static PyObject *number_subtract_handler( PyObject *, PyObject * ); static PyObject *number_multiply_handler( PyObject *, PyObject * ); static PyObject *number_divide_handler( PyObject *, PyObject * ); static PyObject *number_remainder_handler( PyObject *, PyObject * ); static PyObject *number_divmod_handler( PyObject *, PyObject * ); static PyObject *number_lshift_handler( PyObject *, PyObject * ); static PyObject *number_rshift_handler( PyObject *, PyObject * ); static PyObject *number_and_handler( PyObject *, PyObject * ); static PyObject *number_xor_handler( PyObject *, PyObject * ); static PyObject *number_or_handler( PyObject *, PyObject * ); static PyObject *number_power_handler( PyObject *, PyObject *, PyObject * ); // Buffer static Py_ssize_t buffer_getreadbuffer_handler( PyObject *, Py_ssize_t, void ** ); static Py_ssize_t buffer_getwritebuffer_handler( PyObject *, Py_ssize_t, void ** ); static Py_ssize_t buffer_getsegcount_handler( PyObject *, Py_ssize_t * ); } extern "C" void standard_dealloc( PyObject *p ) { PyMem_DEL( p ); } bool PythonType::readyType() { return PyType_Ready( table ) >= 0; } PythonType &PythonType::supportSequenceType( int methods_to_support ) { if( !sequence_table ) { sequence_table = new PySequenceMethods; memset( sequence_table, 0, sizeof( PySequenceMethods ) ); // ensure new fields are 0 table->tp_as_sequence = sequence_table; if( methods_to_support&support_sequence_length ) { sequence_table->sq_length = sequence_length_handler; } if( methods_to_support&support_sequence_repeat ) { sequence_table->sq_repeat = sequence_repeat_handler; } if( methods_to_support&support_sequence_item ) { sequence_table->sq_item = sequence_item_handler; } if( methods_to_support&support_sequence_slice ) { sequence_table->sq_slice = sequence_slice_handler; } if( methods_to_support&support_sequence_concat ) { sequence_table->sq_concat = sequence_concat_handler; } if( methods_to_support&support_sequence_ass_item ) { sequence_table->sq_ass_item = sequence_ass_item_handler; } if( methods_to_support&support_sequence_ass_slice ) { sequence_table->sq_ass_slice = sequence_ass_slice_handler; } if( methods_to_support&support_sequence_inplace_concat ) { sequence_table->sq_inplace_concat = sequence_inplace_concat_handler; } if( methods_to_support&support_sequence_inplace_repeat ) { sequence_table->sq_inplace_repeat = sequence_inplace_repeat_handler; } if( methods_to_support&support_sequence_contains ) { sequence_table->sq_contains = sequence_contains_handler; } } return *this; } PythonType &PythonType::supportMappingType( int methods_to_support ) { if( !mapping_table ) { mapping_table = new PyMappingMethods; memset( mapping_table, 0, sizeof( PyMappingMethods ) ); // ensure new fields are 0 table->tp_as_mapping = mapping_table; if( methods_to_support&support_mapping_length ) { mapping_table->mp_length = mapping_length_handler; } if( methods_to_support&support_mapping_subscript ) { mapping_table->mp_subscript = mapping_subscript_handler; } if( methods_to_support&support_mapping_ass_subscript ) { mapping_table->mp_ass_subscript = mapping_ass_subscript_handler; } } return *this; } PythonType &PythonType::supportNumberType( int methods_to_support ) { if( !number_table ) { number_table = new PyNumberMethods; memset( number_table, 0, sizeof( PyNumberMethods ) ); // ensure new fields are 0 table->tp_as_number = number_table; number_table->nb_coerce = 0; if( methods_to_support&support_number_add ) { number_table->nb_add = number_add_handler; } if( methods_to_support&support_number_subtract ) { number_table->nb_subtract = number_subtract_handler; } if( methods_to_support&support_number_multiply ) { number_table->nb_multiply = number_multiply_handler; } if( methods_to_support&support_number_divide ) { number_table->nb_divide = number_divide_handler; } if( methods_to_support&support_number_remainder ) { number_table->nb_remainder = number_remainder_handler; } if( methods_to_support&support_number_divmod ) { number_table->nb_divmod = number_divmod_handler; } if( methods_to_support&support_number_power ) { number_table->nb_power = number_power_handler; } if( methods_to_support&support_number_negative ) { number_table->nb_negative = number_negative_handler; } if( methods_to_support&support_number_positive ) { number_table->nb_positive = number_positive_handler; } if( methods_to_support&support_number_absolute ) { number_table->nb_absolute = number_absolute_handler; } if( methods_to_support&support_number_nonzero ) { number_table->nb_nonzero = number_nonzero_handler; } if( methods_to_support&support_number_invert ) { number_table->nb_invert = number_invert_handler; } if( methods_to_support&support_number_lshift ) { number_table->nb_lshift = number_lshift_handler; } if( methods_to_support&support_number_rshift ) { number_table->nb_rshift = number_rshift_handler; } if( methods_to_support&support_number_and ) { number_table->nb_and = number_and_handler; } if( methods_to_support&support_number_xor ) { number_table->nb_xor = number_xor_handler; } if( methods_to_support&support_number_or ) { number_table->nb_or = number_or_handler; } if( methods_to_support&support_number_int ) { number_table->nb_int = number_int_handler; } if( methods_to_support&support_number_long ) { number_table->nb_long = number_long_handler; } if( methods_to_support&support_number_float ) { number_table->nb_float = number_float_handler; } if( methods_to_support&support_number_oct ) { number_table->nb_oct = number_oct_handler; } if( methods_to_support&support_number_hex ) { number_table->nb_hex = number_hex_handler; } } return *this; } PythonType &PythonType::supportBufferType( int methods_to_support ) { if( !buffer_table ) { buffer_table = new PyBufferProcs; memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 table->tp_as_buffer = buffer_table; if( methods_to_support&support_buffer_getreadbuffer ) { buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler; } if( methods_to_support&support_buffer_getwritebuffer ) { buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler; } if( methods_to_support&support_buffer_getsegcount ) { buffer_table->bf_getsegcount = buffer_getsegcount_handler; } } return *this; } // // if you define add methods that you hook. Use the hook_XXX to choice what to hook. // PythonType::PythonType( size_t basic_size, int itemsize, const char *default_name ) : table( new PyTypeObject ) , sequence_table( NULL ) , mapping_table( NULL ) , number_table( NULL ) , buffer_table( NULL ) { // PyTypeObject is defined in /Include/object.h memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 *reinterpret_cast( table ) = py_object_initializer; table->ob_type = _Type_Type(); table->ob_size = 0; table->tp_name = const_cast( default_name ); table->tp_basicsize = basic_size; table->tp_itemsize = itemsize; // Methods to implement standard operations table->tp_dealloc = (destructor)standard_dealloc; table->tp_print = 0; table->tp_getattr = 0; table->tp_setattr = 0; table->tp_compare = 0; table->tp_repr = 0; // Method suites for standard classes table->tp_as_number = 0; table->tp_as_sequence = 0; table->tp_as_mapping = 0; // More standard operations (here for binary compatibility) table->tp_hash = 0; table->tp_call = 0; table->tp_str = 0; table->tp_getattro = 0; table->tp_setattro = 0; // Functions to access object as input/output buffer table->tp_as_buffer = 0; // Flags to define presence of optional/expanded features table->tp_flags = Py_TPFLAGS_DEFAULT; // Documentation string table->tp_doc = 0; #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 0) table->tp_traverse = 0L; // delete references to contained objects table->tp_clear = 0L; #else table->tp_xxx5 = 0L; table->tp_xxx6 = 0L; #endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) // first defined in 2.1 table->tp_richcompare = 0L; // weak reference enabler table->tp_weaklistoffset = 0L; #else table->tp_xxx7 = 0L; table->tp_xxx8 = 0L; #endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 2) // first defined in 2.3 // Iterators table->tp_iter = 0L; table->tp_iternext = 0L; #endif #ifdef COUNT_ALLOCS table->tp_alloc = 0; table->tp_free = 0; table->tp_maxalloc = 0; table->tp_next = 0; #endif } PythonType::~PythonType() { delete table; delete sequence_table; delete mapping_table; delete number_table; delete buffer_table; } PyTypeObject *PythonType::type_object() const { return table; } PythonType &PythonType::name( const char *nam ) { table->tp_name = const_cast( nam ); return *this; } const char *PythonType::getName() const { return table->tp_name; } PythonType &PythonType::doc( const char *d ) { table->tp_doc = const_cast( d ); return *this; } const char *PythonType::getDoc() const { return table->tp_doc; } PythonType &PythonType::set_tp_dealloc( void (*tp_dealloc)( PyObject *self ) ) { table->tp_dealloc = tp_dealloc; return *this; } PythonType &PythonType::set_tp_init( int (*tp_init)( PyObject *self, PyObject *args, PyObject *kwds ) ) { table->tp_init = tp_init; return *this; } PythonType &PythonType::set_tp_new( PyObject *(*tp_new)( PyTypeObject *subtype, PyObject *args, PyObject *kwds ) ) { table->tp_new = tp_new; return *this; } PythonType &PythonType::set_methods( PyMethodDef *methods ) { table->tp_methods = methods; return *this; } PythonType &PythonType::supportClass() { table->tp_flags |= Py_TPFLAGS_BASETYPE; return *this; } PythonType &PythonType::dealloc( void( *f )( PyObject * )) { table->tp_dealloc = f; return *this; } #if defined( PYCXX_PYTHON_2TO3 ) PythonType &PythonType::supportPrint() { table->tp_print = print_handler; return *this; } #endif PythonType &PythonType::supportGetattr() { table->tp_getattr = getattr_handler; return *this; } PythonType &PythonType::supportSetattr() { table->tp_setattr = setattr_handler; return *this; } PythonType &PythonType::supportGetattro() { table->tp_getattro = getattro_handler; return *this; } PythonType &PythonType::supportSetattro() { table->tp_setattro = setattro_handler; return *this; } #if defined( PYCXX_PYTHON_2TO3 ) PythonType &PythonType::supportCompare() { table->tp_compare = compare_handler; return *this; } #endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) PythonType &PythonType::supportRichCompare() { table->tp_richcompare = rich_compare_handler; return *this; } #endif PythonType &PythonType::supportRepr() { table->tp_repr = repr_handler; return *this; } PythonType &PythonType::supportStr() { table->tp_str = str_handler; return *this; } PythonType &PythonType::supportHash() { table->tp_hash = hash_handler; return *this; } PythonType &PythonType::supportCall() { table->tp_call = call_handler; return *this; } PythonType &PythonType::supportIter( int methods_to_support ) { if( methods_to_support&support_iter_iter ) { table->tp_iter = iter_handler; } if( methods_to_support&support_iter_iternext ) { table->tp_iternext = iternext_handler; } return *this; } //-------------------------------------------------------------------------------- // // Handlers // //-------------------------------------------------------------------------------- PythonExtensionBase *getPythonExtensionBase( PyObject *self ) { if( self->ob_type->tp_flags&Py_TPFLAGS_BASETYPE ) { PythonClassInstance *instance = reinterpret_cast( self ); return instance->m_pycxx_object; } else { return static_cast( self ); } } #if defined( PYCXX_PYTHON_2TO3 ) extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->print( fp, flags ); } catch( BaseException &) { return -1; // indicate error } } #endif extern "C" PyObject *getattr_handler( PyObject *self, char *name ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->getattr( name ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" int setattr_handler( PyObject *self, char *name, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->setattr( name, Object( value ) ); } catch( BaseException &) { return -1; // indicate error } } extern "C" PyObject *getattro_handler( PyObject *self, PyObject *name ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->getattro( String( name ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->setattro( String( name ), Object( value ) ); } catch( BaseException &) { return -1; // indicate error } } #if defined( PYCXX_PYTHON_2TO3 ) extern "C" int compare_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->compare( Object( other ) ); } catch( BaseException &) { return -1; // indicate error } } #endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) extern "C" PyObject *rich_compare_handler( PyObject *self, PyObject *other, int op ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->rich_compare( Object( other ), op ) ); } catch( BaseException &) { return NULL; // indicate error } } #endif extern "C" PyObject *repr_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->repr() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *str_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->str() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" long hash_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->hash(); } catch( BaseException &) { return -1; // indicate error } } extern "C" PyObject *call_handler( PyObject *self, PyObject *args, PyObject *kw ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); if( kw != NULL ) return new_reference_to( p->call( Object( args ), Object( kw ) ) ); else return new_reference_to( p->call( Object( args ), Object() ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *iter_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->iter() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *iternext_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->iternext(); // might be a NULL ptr on end of iteration } catch( BaseException &) { return NULL; // indicate error } } // Sequence methods extern "C" Py_ssize_t sequence_length_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_length(); } catch( BaseException &) { return -1; // indicate error } } extern "C" PyObject *sequence_concat_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_concat( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *sequence_repeat_handler( PyObject *self, Py_ssize_t count ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_repeat( count ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *sequence_item_handler( PyObject *self, Py_ssize_t index ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_item( index ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *sequence_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_slice( first, last ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" int sequence_ass_item_handler( PyObject *self, Py_ssize_t index, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_ass_item( index, Object( value ) ); } catch( BaseException &) { return -1; // indicate error } } extern "C" int sequence_ass_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_ass_slice( first, last, Object( value ) ); } catch( BaseException &) { return -1; // indicate error } } extern "C" PyObject *sequence_inplace_concat_handler( PyObject *self, PyObject *o2 ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_inplace_concat( Object( o2 ) ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *sequence_inplace_repeat_handler( PyObject *self, Py_ssize_t count ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_inplace_repeat( count ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" int sequence_contains_handler( PyObject *self, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_contains( Object( value ) ); } catch( BaseException & ) { return -1; // indicate error } } // Mapping extern "C" Py_ssize_t mapping_length_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->mapping_length(); } catch( BaseException &) { return -1; // indicate error } } extern "C" PyObject *mapping_subscript_handler( PyObject *self, PyObject *key ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->mapping_subscript( Object( key ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" int mapping_ass_subscript_handler( PyObject *self, PyObject *key, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->mapping_ass_subscript( Object( key ), Object( value ) ); } catch( BaseException &) { return -1; // indicate error } } // Number extern "C" int number_nonzero_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->number_nonzero(); } catch( BaseException &) { return -1; // indicate error } } extern "C" PyObject *number_negative_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_negative() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_positive_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_positive() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_absolute_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_absolute() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_invert_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_invert() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_int_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_int() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_float_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_float() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_long_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_long() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_oct_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_oct() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_hex_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_hex() ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_add_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_add( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_subtract_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_subtract( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_multiply_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_multiply( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_divide_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_divide( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_remainder_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_remainder( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_divmod_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_divmod( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_lshift_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_lshift( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_rshift_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_rshift( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_and_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_and( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_xor_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_xor( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_or_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_or( Object( other ) ) ); } catch( BaseException &) { return NULL; // indicate error } } extern "C" PyObject *number_power_handler( PyObject *self, PyObject *x1, PyObject *x2 ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->number_power( Object( x1 ), Object( x2 ) ) ); } catch( BaseException &) { return NULL; // indicate error } } // Buffer extern "C" Py_ssize_t buffer_getreadbuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->buffer_getreadbuffer( index, pp ); } catch( BaseException &) { return -1; // indicate error } } extern "C" Py_ssize_t buffer_getwritebuffer_handler( PyObject *self, Py_ssize_t index, void **pp ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->buffer_getwritebuffer( index, pp ); } catch( BaseException &) { return -1; // indicate error } } extern "C" Py_ssize_t buffer_getsegcount_handler( PyObject *self, Py_ssize_t *count ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->buffer_getsegcount( count ); } catch( BaseException &) { return -1; // indicate error } } //================================================================================ // // Implementation of PythonExtensionBase // //================================================================================ #define missing_method( method ) \ throw RuntimeError( "Extension object missing implement of " #method ); PythonExtensionBase::PythonExtensionBase() { ob_refcnt = 0; } PythonExtensionBase::~PythonExtensionBase() { assert( ob_refcnt == 0 ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name ) { TupleN args; return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1 ) { TupleN args( arg1 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2 ) { TupleN args( arg1, arg2 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3 ) { TupleN args( arg1, arg2, arg3 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4 ) { TupleN args( arg1, arg2, arg3, arg4 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5 ) { TupleN args( arg1, arg2, arg3, arg4, arg5 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8, const Object &arg9 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); return self().callMemberFunction( fn_name, args ); } void PythonExtensionBase::reinit( Tuple &/*args*/, Dict &/*kwds*/ ) { throw RuntimeError( "Must not call __init__ twice on this class" ); } Object PythonExtensionBase::genericGetAttro( const String &name ) { return asObject( PyObject_GenericGetAttr( selfPtr(), name.ptr() ) ); } int PythonExtensionBase::genericSetAttro( const String &name, const Object &value ) { return PyObject_GenericSetAttr( selfPtr(), name.ptr(), value.ptr() ); } int PythonExtensionBase::print( FILE *, int ) { missing_method( print ); } Object PythonExtensionBase::getattr( const char * ) { missing_method( getattr ); } int PythonExtensionBase::setattr( const char *, const Object &) { missing_method( setattr ); } Object PythonExtensionBase::getattro( const String &name ) { return genericGetAttro( name ); } int PythonExtensionBase::setattro( const String &name, const Object &value ) { return genericSetAttro( name, value ); } int PythonExtensionBase::compare( const Object &) { missing_method( compare ); } #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) Object PythonExtensionBase::rich_compare( const Object &, int /*op*/ ) { missing_method( rich_compare ); } #endif Object PythonExtensionBase::repr() { missing_method( repr ); } Object PythonExtensionBase::str() { missing_method( str ); } long PythonExtensionBase::hash() { missing_method( hash ); } Object PythonExtensionBase::call( const Object &, const Object &) { missing_method( call ); } Object PythonExtensionBase::iter() { missing_method( iter ); } PyObject *PythonExtensionBase::iternext() { missing_method( iternext ); } // Sequence methods PyCxx_ssize_t PythonExtensionBase::sequence_length() { missing_method( sequence_length ); } Object PythonExtensionBase::sequence_concat( const Object &) { missing_method( sequence_concat ); } Object PythonExtensionBase::sequence_repeat( Py_ssize_t ) { missing_method( sequence_repeat ); } Object PythonExtensionBase::sequence_item( Py_ssize_t ) { missing_method( sequence_item ); } Object PythonExtensionBase::sequence_slice( Py_ssize_t, Py_ssize_t ) { missing_method( sequence_slice ); } int PythonExtensionBase::sequence_ass_item( Py_ssize_t, const Object &) { missing_method( sequence_ass_item ); } int PythonExtensionBase::sequence_ass_slice( Py_ssize_t, Py_ssize_t, const Object &) { missing_method( sequence_ass_slice ); } Object PythonExtensionBase::sequence_inplace_concat( const Object & ) { missing_method( sequence_inplace_concat ); } Object PythonExtensionBase::sequence_inplace_repeat( Py_ssize_t ) { missing_method( sequence_inplace_repeat ); } int PythonExtensionBase::sequence_contains( const Object & ) { missing_method( sequence_contains ); } // Mapping Sequence::size_type PythonExtensionBase::mapping_length() { missing_method( mapping_length ); } Object PythonExtensionBase::mapping_subscript( const Object &) { missing_method( mapping_subscript ); } int PythonExtensionBase::mapping_ass_subscript( const Object &, const Object &) { missing_method( mapping_ass_subscript ); } // Number int PythonExtensionBase::number_nonzero() { missing_method( number_nonzero ); } Object PythonExtensionBase::number_negative() { missing_method( number_negative ); } Object PythonExtensionBase::number_positive() { missing_method( number_positive ); } Object PythonExtensionBase::number_absolute() { missing_method( number_absolute ); } Object PythonExtensionBase::number_invert() { missing_method( number_invert ); } Object PythonExtensionBase::number_int() { missing_method( number_int ); } Object PythonExtensionBase::number_float() { missing_method( number_float ); } Object PythonExtensionBase::number_long() { missing_method( number_long ); } Object PythonExtensionBase::number_oct() { missing_method( number_oct ); } Object PythonExtensionBase::number_hex() { missing_method( number_hex ); } Object PythonExtensionBase::number_add( const Object &) { missing_method( number_add ); } Object PythonExtensionBase::number_subtract( const Object &) { missing_method( number_subtract ); } Object PythonExtensionBase::number_multiply( const Object &) { missing_method( number_multiply ); } Object PythonExtensionBase::number_divide( const Object &) { missing_method( number_divide ); } Object PythonExtensionBase::number_remainder( const Object &) { missing_method( number_remainder ); } Object PythonExtensionBase::number_divmod( const Object &) { missing_method( number_divmod ); } Object PythonExtensionBase::number_lshift( const Object &) { missing_method( number_lshift ); } Object PythonExtensionBase::number_rshift( const Object &) { missing_method( number_rshift ); } Object PythonExtensionBase::number_and( const Object &) { missing_method( number_and ); } Object PythonExtensionBase::number_xor( const Object &) { missing_method( number_xor ); } Object PythonExtensionBase::number_or( const Object &) { missing_method( number_or ); } Object PythonExtensionBase::number_power( const Object &, const Object &) { missing_method( number_power ); } // Buffer Py_ssize_t PythonExtensionBase::buffer_getreadbuffer( Py_ssize_t, void** ) { missing_method( buffer_getreadbuffer ); } Py_ssize_t PythonExtensionBase::buffer_getwritebuffer( Py_ssize_t, void** ) { missing_method( buffer_getwritebuffer ); } Py_ssize_t PythonExtensionBase::buffer_getsegcount( Py_ssize_t* ) { missing_method( buffer_getsegcount ); } //-------------------------------------------------------------------------------- // // Method call handlers for // PythonExtensionBase // ExtensionModuleBase // //-------------------------------------------------------------------------------- extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); Object result( self->invoke_method_noargs( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ) ); return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); Tuple args( _args ); Object result ( self->invoke_method_varargs ( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args ) ); return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); Tuple args( _args ); if( _keywords == NULL ) { Dict keywords; // pass an empty dict Object result ( self->invoke_method_keyword ( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args, keywords ) ); return new_reference_to( result.ptr() ); } else { Dict keywords( _keywords ); // make dict Object result ( self->invoke_method_keyword ( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args, keywords ) ); return new_reference_to( result.ptr() ); } } catch( BaseException & ) { return 0; } } extern "C" void do_not_dealloc( void * ) {} //-------------------------------------------------------------------------------- // // ExtensionExceptionType // //-------------------------------------------------------------------------------- ExtensionExceptionType::ExtensionExceptionType() : Object() { } void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name ) { std::string module_name( module.fullName() ); module_name += "."; module_name += name; set( PyErr_NewException( const_cast( module_name.c_str() ), NULL, NULL ), true ); } void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name, ExtensionExceptionType &parent) { std::string module_name( module.fullName() ); module_name += "."; module_name += name; set( PyErr_NewException( const_cast( module_name.c_str() ), parent.ptr(), NULL ), true ); } ExtensionExceptionType::~ExtensionExceptionType() { } // ------------------------------------------------------------ // // BaseException // //------------------------------------------------------------ BaseException::BaseException( ExtensionExceptionType &exception, const std::string &reason ) { PyErr_SetString( exception.ptr(), reason.c_str() ); } BaseException::BaseException( ExtensionExceptionType &exception, Object &reason ) { PyErr_SetObject( exception.ptr(), reason.ptr() ); } BaseException::BaseException( PyObject *exception, Object &reason ) { PyErr_SetObject( exception, reason.ptr() ); } BaseException::BaseException( PyObject *exception, const std::string &reason ) { PyErr_SetString( exception, reason.c_str() ); } BaseException::BaseException() {} void BaseException::clear() { PyErr_Clear(); } bool BaseException::matches( ExtensionExceptionType &exc ) // is the exception this specific exception 'exc' { return PyErr_ExceptionMatches( exc.ptr() ) != 0; } } // end of namespace Py pycxx-7.1.4/Src/Python3/cxxextensions.c000644 000765 000024 00000004470 13662723705 020361 0ustar00barrystaff000000 000000 /*---------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //---------------------------------------------------------------------------*/ #include "CXX/WrapPython.h" #ifdef __cplusplus extern "C" { #endif PyObject py_object_initializer = { _PyObject_EXTRA_INIT 1, NULL // type must be init'ed by user }; #ifdef __cplusplus } #endif pycxx-7.1.4/Src/Python3/cxxsupport.cxx000644 000765 000024 00000014273 13662723705 020260 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/Objects.hxx" namespace Py { #if !defined(Py_LIMITED_API) Py_UNICODE unicode_null_string[1] = { 0 }; #endif Py_UCS4 ucs4_null_string[1] = { 0 }; Type Object::type() const { return Type( PyObject_Type( p ), true ); } String Object::str() const { return String( PyObject_Str( p ), true ); } String Object::repr() const { return String( PyObject_Repr( p ), true ); } std::string Object::as_string() const { return static_cast( str() ); } List Object::dir() const { return List( PyObject_Dir( p ), true ); } bool Object::isType( const Type &t ) const { return type().ptr() == t.ptr(); } Char::operator String() const { return String( ptr() ); } String Bytes::decode( const char *encoding, const char *error ) { return String( PyUnicode_FromEncodedObject( ptr(), encoding, error ), true ); } // Object compares bool operator==( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_EQ ); ifPyErrorThrowCxxException(); return k != 0; } bool operator!=( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_NE ); ifPyErrorThrowCxxException(); return k != 0; } bool operator>=( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_GE ); ifPyErrorThrowCxxException(); return k != 0; } bool operator<=( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_LE ); ifPyErrorThrowCxxException(); return k != 0; } bool operator<( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_LT ); ifPyErrorThrowCxxException(); return k != 0; } bool operator>( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_GT ); ifPyErrorThrowCxxException(); return k != 0; } // iterator compares bool operator==( const Sequence::iterator &left, const Sequence::iterator &right ) { return left.eql( right ); } bool operator!=( const Sequence::iterator &left, const Sequence::iterator &right ) { return left.neq( right ); } bool operator<( const Sequence::iterator &left, const Sequence::iterator &right ) { return left.lss( right ); } bool operator>( const Sequence::iterator &left, const Sequence::iterator &right ) { return left.gtr( right ); } bool operator<=( const Sequence::iterator &left, const Sequence::iterator &right ) { return left.leq( right ); } bool operator>=( const Sequence::iterator &left, const Sequence::iterator &right ) { return left.geq( right ); } // const_iterator compares bool operator==( const Sequence::const_iterator &left, const Sequence::const_iterator &right ) { return left.eql( right ); } bool operator!=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ) { return left.neq( right ); } bool operator<( const Sequence::const_iterator &left, const Sequence::const_iterator &right ) { return left.lss( right ); } bool operator>( const Sequence::const_iterator &left, const Sequence::const_iterator &right ) { return left.gtr( right ); } bool operator<=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ) { return left.leq( right ); } bool operator>=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ) { return left.geq( right ); } // For mappings: bool operator==( const Mapping::iterator &left, const Mapping::iterator &right ) { return left.eql( right ); } bool operator!=( const Mapping::iterator &left, const Mapping::iterator &right ) { return left.neq( right ); } // now for const_iterator bool operator==( const Mapping::const_iterator &left, const Mapping::const_iterator &right ) { return left.eql( right ); } bool operator!=( const Mapping::const_iterator &left, const Mapping::const_iterator &right ) { return left.neq( right ); } // TMM: 31May'01 - Added the #ifndef so I can exclude iostreams. #ifndef CXX_NO_IOSTREAMS // output std::ostream &operator<<( std::ostream &os, const Object &ob ) { return( os << static_cast( ob.str() ) ); } #endif } // Py pycxx-7.1.4/Src/Python3/cxx_exceptions.cxx000644 000765 000024 00000003231 12733215337 021047 0ustar00barrystaff000000 000000 // // cxx_exceptions.cxx // #include #include #include namespace Py { typedef void (*throw_exception_func_t)( void ); std::map py_exc_type_to_exc_func; void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t func ) { py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type.ptr(), func ) ); } void addPythonException( PyObject *py_exc_type, throw_exception_func_t func ) { py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type, func ) ); } void ifPyErrorThrowCxxException() { if( PyErr_Occurred() ) { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch( &ptype, &pvalue, &ptrace ); PyErr_Restore( ptype, pvalue, ptrace ); Object q( ptype ); std::map::iterator func = py_exc_type_to_exc_func.find( ptype ); if( func != py_exc_type_to_exc_func.end() ) { #ifdef PYCXX_DEBUG std::cout << "ifPyErrorThrowCxxException found throwFunc: " << q << std::endl; #endif (func->second)(); } else { #ifdef PYCXX_DEBUG std::cout << "ifPyErrorThrowCxxException no throwFunc: " << q << std::endl; #endif throw Exception(); } } } void initExceptions() { static bool init_done = false; if( init_done ) { return; } #define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ addPythonException( eclass::exceptionType(), eclass::throwFunc ); #include #undef PYCXX_STANDARD_EXCEPTION init_done = true; } } // end of namespace Py pycxx-7.1.4/Src/Python3/cxx_extensions.cxx000644 000765 000024 00000155724 13561772255 021113 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/Extensions.hxx" #include "CXX/Exception.hxx" #include "CXX/Objects.hxx" #include #ifdef PYCXX_DEBUG // // Functions useful when debugging PyCXX // void bpt( void ) { } void printRefCount( PyObject *obj ) { std::cout << "RefCount of 0x" << std::hex << reinterpret_cast< unsigned long >( obj ) << std::dec << " is " << Py_REFCNT( obj ) << std::endl; } #endif namespace Py { void Object::validate() { // release pointer if not the right type if( !accepts( p ) ) { #if defined( _CPPRTTI ) || defined( __GNUG__ ) std::string s( "PyCXX: Error creating object of type " ); s += (typeid( *this )).name(); if( p != NULL ) { String from_repr = repr(); s += " from "; s += from_repr.as_std_string(); } else { s += " from (nil)"; } #endif release(); // If error message already set ifPyErrorThrowCxxException(); // Better error message if RTTI available #if defined( _CPPRTTI ) || defined( __GNUG__ ) throw TypeError( s ); #else throw TypeError( "PyCXX: type error." ); #endif } } //================================================================================ // // Implementation of MethodTable // //================================================================================ PyMethodDef MethodTable::method( const char *method_name, PyCFunction f, int flags, const char *doc ) { PyMethodDef m; m.ml_name = const_cast( method_name ); m.ml_meth = f; m.ml_flags = flags; m.ml_doc = const_cast( doc ); return m; } MethodTable::MethodTable() { t.push_back( method( 0, 0, 0, 0 ) ); mt = NULL; } MethodTable::~MethodTable() { delete [] mt; } void MethodTable::add( const char *method_name, PyCFunction f, const char *doc, int flag ) { if( !mt ) { t.insert( t.end()-1, method( method_name, f, flag, doc ) ); } else { throw RuntimeError( "Too late to add a module method!" ); } } PyMethodDef *MethodTable::table() { if( !mt ) { Py_ssize_t t1size = t.size(); mt = new PyMethodDef[ t1size ]; int j = 0; for( std::vector::iterator i = t.begin(); i != t.end(); i++ ) { mt[ j++ ] = *i; } } return mt; } //================================================================================ // // Implementation of ExtensionModule // //================================================================================ ExtensionModuleBase::ExtensionModuleBase( const char *name ) : m_module_name( name ) #if defined( Py_LIMITED_API ) , m_full_module_name( m_module_name ) #else , m_full_module_name( __Py_PackageContext() != NULL ? std::string( __Py_PackageContext() ) : m_module_name ) #endif , m_method_table() //m_module_def , m_module( NULL ) {} ExtensionModuleBase::~ExtensionModuleBase() {} const std::string &ExtensionModuleBase::name() const { return m_module_name; } const std::string &ExtensionModuleBase::fullName() const { return m_full_module_name; } class ExtensionModuleBasePtr : public PythonExtension { public: ExtensionModuleBasePtr( ExtensionModuleBase *_module ) : module( _module ) {} virtual ~ExtensionModuleBasePtr() {} ExtensionModuleBase *module; }; void initExceptions(); void ExtensionModuleBase::initialize( const char *module_doc ) { // init the exception code initExceptions(); memset( &m_module_def, 0, sizeof( m_module_def ) ); m_module_def.m_name = const_cast( m_module_name.c_str() ); m_module_def.m_doc = const_cast( module_doc ); m_module_def.m_methods = m_method_table.table(); // where does module_ptr get passed in? m_module = PyModule_Create( &m_module_def ); } Module ExtensionModuleBase::module( void ) const { return Module( m_module ); } Dict ExtensionModuleBase::moduleDictionary( void ) const { return module().getDict(); } Object ExtensionModuleBase::moduleObject( void ) const { return Object( m_module ); } //================================================================================ // // Implementation of PythonType // //================================================================================ extern "C" { static void standard_dealloc( PyObject *p ); // // All the following functions redirect the call from Python // onto the matching virtual function in PythonExtensionBase // #if defined( PYCXX_PYTHON_2TO3 ) && !defined( Py_LIMITED_API ) && PY_MINOR_VERSION <= 7 static int print_handler( PyObject *, FILE *, int ); #endif static PyObject *getattr_handler( PyObject *, char * ); static int setattr_handler( PyObject *, char *, PyObject * ); static PyObject *getattro_handler( PyObject *, PyObject * ); static int setattro_handler( PyObject *, PyObject *, PyObject * ); static PyObject *rich_compare_handler( PyObject *, PyObject *, int ); static PyObject *repr_handler( PyObject * ); static PyObject *str_handler( PyObject * ); static Py_hash_t hash_handler( PyObject * ); static PyObject *call_handler( PyObject *, PyObject *, PyObject * ); static PyObject *iter_handler( PyObject * ); static PyObject *iternext_handler( PyObject * ); // Sequence methods static Py_ssize_t sequence_length_handler( PyObject * ); static PyObject *sequence_concat_handler( PyObject *,PyObject * ); static PyObject *sequence_repeat_handler( PyObject *, Py_ssize_t ); static PyObject *sequence_item_handler( PyObject *, Py_ssize_t ); static int sequence_ass_item_handler( PyObject *, Py_ssize_t, PyObject * ); static PyObject *sequence_inplace_concat_handler( PyObject *, PyObject * ); static PyObject *sequence_inplace_repeat_handler( PyObject *, Py_ssize_t ); static int sequence_contains_handler( PyObject *, PyObject * ); // Mapping static Py_ssize_t mapping_length_handler( PyObject * ); static PyObject *mapping_subscript_handler( PyObject *, PyObject * ); static int mapping_ass_subscript_handler( PyObject *, PyObject *, PyObject * ); // Numeric methods static PyObject *number_negative_handler( PyObject * ); static PyObject *number_positive_handler( PyObject * ); static PyObject *number_absolute_handler( PyObject * ); static PyObject *number_invert_handler( PyObject * ); static PyObject *number_int_handler( PyObject * ); static PyObject *number_float_handler( PyObject * ); static PyObject *number_add_handler( PyObject *, PyObject * ); static PyObject *number_subtract_handler( PyObject *, PyObject * ); static PyObject *number_multiply_handler( PyObject *, PyObject * ); static PyObject *number_remainder_handler( PyObject *, PyObject * ); static PyObject *number_divmod_handler( PyObject *, PyObject * ); static PyObject *number_lshift_handler( PyObject *, PyObject * ); static PyObject *number_rshift_handler( PyObject *, PyObject * ); static PyObject *number_and_handler( PyObject *, PyObject * ); static PyObject *number_xor_handler( PyObject *, PyObject * ); static PyObject *number_or_handler( PyObject *, PyObject * ); static PyObject *number_power_handler( PyObject *, PyObject *, PyObject * ); static PyObject *number_floor_divide_handler( PyObject *, PyObject * ); static PyObject *number_true_divide_handler( PyObject *, PyObject * ); static PyObject *number_index_handler( PyObject * ); #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 static PyObject *number_matrix_multiply_handler( PyObject *, PyObject * ); #endif static PyObject *number_inplace_add_handler( PyObject *, PyObject * ); static PyObject *number_inplace_subtract_handler( PyObject *, PyObject * ); static PyObject *number_inplace_multiply_handler( PyObject *, PyObject * ); static PyObject *number_inplace_remainder_handler( PyObject *, PyObject * ); static PyObject *number_inplace_power_handler( PyObject *, PyObject *, PyObject * ); static PyObject *number_inplace_lshift_handler( PyObject *, PyObject * ); static PyObject *number_inplace_rshift_handler( PyObject *, PyObject * ); static PyObject *number_inplace_and_handler( PyObject *, PyObject * ); static PyObject *number_inplace_xor_handler( PyObject *, PyObject * ); static PyObject *number_inplace_or_handler( PyObject *, PyObject * ); static PyObject *number_inplace_floor_divide_handler( PyObject *, PyObject * ); static PyObject *number_inplace_true_divide_handler( PyObject *, PyObject * ); #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 static PyObject *number_inplace_matrix_multiply_handler( PyObject *, PyObject * ); #endif // Buffer #if !defined( Py_LIMITED_API ) static int buffer_get_handler( PyObject *, Py_buffer *, int ); static void buffer_release_handler( PyObject *, Py_buffer * ); #endif } extern "C" void standard_dealloc( PyObject *p ) { PyMem_DEL( p ); } bool PythonType::readyType() { #if defined( Py_LIMITED_API ) if( !tp_object ) { std::vector spec_slots( slots.size() + 1 ); int index = 0; for (std::unordered_map::const_iterator i = slots.cbegin(); i != slots.cend(); i++) { spec_slots[ index ].slot = i->first; spec_slots[ index ].pfunc = i->second; index++; } spec_slots[ index ].slot = 0; spec->slots = spec_slots.data(); tp_object = reinterpret_cast( PyType_FromSpec(spec) ); } return tp_object != NULL; #else return PyType_Ready( table ) >= 0; #endif } #if defined( Py_LIMITED_API ) #define FILL_SEQUENCE_SLOT(slot) \ if( methods_to_support&support_sequence_ ## slot ) { \ slots[ Py_sq_ ## slot ] = reinterpret_cast( sequence_ ## slot ## _handler ); \ } #else #define FILL_SEQUENCE_SLOT(slot) \ if( methods_to_support&support_sequence_ ## slot ) { \ sequence_table->sq_ ## slot = sequence_ ## slot ## _handler; \ } #endif PythonType &PythonType::supportSequenceType( int methods_to_support ) { #if !defined( Py_LIMITED_API ) if(sequence_table) { return *this; } sequence_table = new PySequenceMethods; memset( sequence_table, 0, sizeof( PySequenceMethods ) ); // ensure new fields are 0 table->tp_as_sequence = sequence_table; #endif FILL_SEQUENCE_SLOT(length) FILL_SEQUENCE_SLOT(concat) FILL_SEQUENCE_SLOT(repeat) FILL_SEQUENCE_SLOT(item) FILL_SEQUENCE_SLOT(ass_item) FILL_SEQUENCE_SLOT(inplace_concat) FILL_SEQUENCE_SLOT(inplace_repeat) FILL_SEQUENCE_SLOT(contains) return *this; } #undef FILL_SEQUENCE_SLOT #if defined( Py_LIMITED_API ) #define FILL_MAPPING_SLOT(slot) \ if( methods_to_support&support_mapping_ ## slot ) { \ slots[ Py_mp_ ## slot ] = reinterpret_cast( mapping_ ## slot ## _handler ); \ } #else #define FILL_MAPPING_SLOT(slot) \ if( methods_to_support&support_mapping_ ## slot ) { \ mapping_table->mp_ ## slot = mapping_ ## slot ## _handler; \ } #endif PythonType &PythonType::supportMappingType( int methods_to_support ) { #if !defined( Py_LIMITED_API ) if( mapping_table ) { return *this; } mapping_table = new PyMappingMethods; memset( mapping_table, 0, sizeof( PyMappingMethods ) ); // ensure new fields are 0 table->tp_as_mapping = mapping_table; #endif FILL_MAPPING_SLOT(length) FILL_MAPPING_SLOT(subscript) FILL_MAPPING_SLOT(ass_subscript) return *this; } #undef FILL_MAPPING_SLOT #if defined( Py_LIMITED_API ) #define FILL_NUMBER_SLOT(slot) \ if( methods_to_support&support_number_ ## slot ) { \ slots[ Py_nb_ ## slot ] = reinterpret_cast( number_ ## slot ## _handler ); \ } #define FILL_NUMBER_INPLACE_SLOT(slot) \ if( inplace_methods_to_support&support_number_ ## slot ) { \ slots[ Py_nb_ ## slot ] = reinterpret_cast( number_ ## slot ## _handler ); \ } #else #define FILL_NUMBER_SLOT(slot) \ if( methods_to_support&support_number_ ## slot ) { \ number_table->nb_ ## slot = number_ ## slot ## _handler; \ } #define FILL_NUMBER_INPLACE_SLOT(slot) \ if( inplace_methods_to_support&support_number_ ## slot ) { \ number_table->nb_ ## slot = number_ ## slot ## _handler; \ } #endif PythonType &PythonType::supportNumberType( int methods_to_support, int inplace_methods_to_support ) { #if !defined( Py_LIMITED_API ) if( number_table ) { return *this; } number_table = new PyNumberMethods; memset( number_table, 0, sizeof( PyNumberMethods ) ); // ensure new fields are 0 table->tp_as_number = number_table; #endif FILL_NUMBER_SLOT(add) FILL_NUMBER_SLOT(subtract) FILL_NUMBER_SLOT(multiply) FILL_NUMBER_SLOT(remainder) FILL_NUMBER_SLOT(divmod) FILL_NUMBER_SLOT(power) FILL_NUMBER_SLOT(negative) FILL_NUMBER_SLOT(positive) FILL_NUMBER_SLOT(absolute) FILL_NUMBER_SLOT(invert) FILL_NUMBER_SLOT(lshift) FILL_NUMBER_SLOT(rshift) FILL_NUMBER_SLOT(and) FILL_NUMBER_SLOT(xor) FILL_NUMBER_SLOT(or) FILL_NUMBER_SLOT(int) FILL_NUMBER_SLOT(float) FILL_NUMBER_SLOT(floor_divide) FILL_NUMBER_SLOT(true_divide) FILL_NUMBER_SLOT(index) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 FILL_NUMBER_SLOT(matrix_multiply) #endif FILL_NUMBER_INPLACE_SLOT(inplace_add) FILL_NUMBER_INPLACE_SLOT(inplace_subtract) FILL_NUMBER_INPLACE_SLOT(inplace_multiply) FILL_NUMBER_INPLACE_SLOT(inplace_remainder) FILL_NUMBER_INPLACE_SLOT(inplace_power) FILL_NUMBER_INPLACE_SLOT(inplace_lshift) FILL_NUMBER_INPLACE_SLOT(inplace_rshift) FILL_NUMBER_INPLACE_SLOT(inplace_and) FILL_NUMBER_INPLACE_SLOT(inplace_xor) FILL_NUMBER_INPLACE_SLOT(inplace_or) FILL_NUMBER_INPLACE_SLOT(inplace_floor_divide) FILL_NUMBER_INPLACE_SLOT(inplace_true_divide) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 FILL_NUMBER_INPLACE_SLOT(inplace_matrix_multiply) #endif return *this; } #undef FILL_NUMBER_SLOT #if !defined( Py_LIMITED_API ) PythonType &PythonType::supportBufferType( int methods_to_support ) { if( !buffer_table ) { buffer_table = new PyBufferProcs; memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 table->tp_as_buffer = buffer_table; if( methods_to_support&support_buffer_getbuffer ) { buffer_table->bf_getbuffer = buffer_get_handler; } if( methods_to_support&support_buffer_releasebuffer ) { buffer_table->bf_releasebuffer = buffer_release_handler; } } return *this; } #endif // if you define one sequence method you must define // all of them except the assigns #if defined( Py_LIMITED_API ) PythonType::PythonType( size_t basic_size, int itemsize, const char *default_name ) : spec( new PyType_Spec ) { memset( spec, 0, sizeof( PyType_Spec ) ); spec->name = const_cast( default_name ); spec->basicsize = basic_size; spec->itemsize = itemsize; spec->flags = Py_TPFLAGS_DEFAULT; slots[ Py_tp_dealloc ] = reinterpret_cast( standard_dealloc ); tp_object = 0; } #else PythonType::PythonType( size_t basic_size, int itemsize, const char *default_name ) : table( new PyTypeObject ) , sequence_table( NULL ) , mapping_table( NULL ) , number_table( NULL ) , buffer_table( NULL ) { // PyTypeObject is defined in /Include/object.h memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 *reinterpret_cast( table ) = py_object_initializer; reinterpret_cast( table )->ob_type = _Type_Type(); // QQQ table->ob_size = 0; table->tp_name = const_cast( default_name ); table->tp_basicsize = basic_size; table->tp_itemsize = itemsize; // Methods to implement standard operations table->tp_dealloc = (destructor)standard_dealloc; #if PY_MINOR_VERSION <= 7 table->tp_print = 0; #endif table->tp_getattr = 0; table->tp_setattr = 0; table->tp_repr = 0; // Method suites for standard classes table->tp_as_number = 0; table->tp_as_sequence = 0; table->tp_as_mapping = 0; // More standard operations (here for binary compatibility) table->tp_hash = 0; table->tp_call = 0; table->tp_str = 0; table->tp_getattro = 0; table->tp_setattro = 0; // Functions to access object as input/output buffer table->tp_as_buffer = 0; // Flags to define presence of optional/expanded features table->tp_flags = Py_TPFLAGS_DEFAULT; // Documentation string table->tp_doc = 0; table->tp_traverse = 0; // delete references to contained objects table->tp_clear = 0; // Assigned meaning in release 2.1 // rich comparisons table->tp_richcompare = 0; // weak reference enabler table->tp_weaklistoffset = 0; // Iterators table->tp_iter = 0; table->tp_iternext = 0; // Attribute descriptor and subclassing stuff table->tp_methods = 0; table->tp_members = 0; table->tp_getset = 0; table->tp_base = 0; table->tp_dict = 0; table->tp_descr_get = 0; table->tp_descr_set = 0; table->tp_dictoffset = 0; table->tp_init = 0; table->tp_alloc = 0; table->tp_new = 0; table->tp_free = 0; // Low-level free-memory routine table->tp_is_gc = 0; // For PyObject_IS_GC table->tp_bases = 0; table->tp_mro = 0; // method resolution order table->tp_cache = 0; table->tp_subclasses = 0; table->tp_weaklist = 0; table->tp_del = 0; // Type attribute cache version tag. Added in version 2.6 table->tp_version_tag = 0; #ifdef COUNT_ALLOCS table->tp_alloc = 0; table->tp_free = 0; table->tp_maxalloc = 0; table->tp_orev = 0; table->tp_next = 0; #endif } #endif PythonType::~PythonType() { #if defined( Py_LIMITED_API ) delete spec; PyObject_Free( tp_object ); #else delete table; delete sequence_table; delete mapping_table; delete number_table; delete buffer_table; #endif } PyTypeObject *PythonType::type_object() const { #if defined( Py_LIMITED_API ) return tp_object; #else return table; #endif } PythonType &PythonType::name( const char *nam ) { #if defined( Py_LIMITED_API ) spec->name = nam; #else table->tp_name = const_cast( nam ); #endif return *this; } const char *PythonType::getName() const { #if defined( Py_LIMITED_API ) return spec->name; #else return table->tp_name; #endif } PythonType &PythonType::doc( const char *d ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_doc ] = reinterpret_cast( const_cast( d ) ); #else table->tp_doc = const_cast( d ); #endif return *this; } const char *PythonType::getDoc() const { #if defined( Py_LIMITED_API ) if( tp_object ) return reinterpret_cast( PyType_GetSlot( tp_object, Py_tp_doc ) ); std::unordered_map::const_iterator slot = slots.find( Py_tp_doc ); if( slot == slots.end() ) return NULL; return reinterpret_cast( slot->second ); #else return table->tp_doc; #endif } PythonType &PythonType::set_tp_dealloc( void (*tp_dealloc)( PyObject *self ) ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_dealloc ] = reinterpret_cast( tp_dealloc ); #else table->tp_dealloc = tp_dealloc; #endif return *this; } PythonType &PythonType::set_tp_init( int (*tp_init)( PyObject *self, PyObject *args, PyObject *kwds ) ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_init ] = reinterpret_cast( tp_init ); #else table->tp_init = tp_init; #endif return *this; } PythonType &PythonType::set_tp_new( PyObject *(*tp_new)( PyTypeObject *subtype, PyObject *args, PyObject *kwds ) ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_new ] = reinterpret_cast( tp_new ); #else table->tp_new = tp_new; #endif return *this; } PythonType &PythonType::set_methods( PyMethodDef *methods ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_methods ] = reinterpret_cast( methods ); #else table->tp_methods = methods; #endif return *this; } PythonType &PythonType::supportClass() { #if defined( Py_LIMITED_API ) spec->flags |= Py_TPFLAGS_BASETYPE; #else table->tp_flags |= Py_TPFLAGS_BASETYPE; #endif return *this; } #if defined( PYCXX_PYTHON_2TO3 ) && !defined( Py_LIMITED_API ) && PY_MINOR_VERSION <= 7 PythonType &PythonType::supportPrint() { table->tp_print = print_handler; return *this; } #endif PythonType &PythonType::supportGetattr() { #if defined( Py_LIMITED_API ) slots[ Py_tp_getattr ] = reinterpret_cast( getattr_handler ); #else table->tp_getattr = getattr_handler; #endif return *this; } PythonType &PythonType::supportSetattr() { #if defined( Py_LIMITED_API ) slots[ Py_tp_setattr ] = reinterpret_cast( setattr_handler ); #else table->tp_setattr = setattr_handler; #endif return *this; } PythonType &PythonType::supportGetattro() { #if defined( Py_LIMITED_API ) slots[ Py_tp_getattro ] = reinterpret_cast( getattro_handler ); #else table->tp_getattro = getattro_handler; #endif return *this; } PythonType &PythonType::supportSetattro() { #if defined( Py_LIMITED_API ) slots[ Py_tp_setattro ] = reinterpret_cast( setattro_handler ); #else table->tp_setattro = setattro_handler; #endif return *this; } #ifdef PYCXX_PYTHON_2TO3 PythonType &PythonType::supportCompare( void ) { return *this; } #endif PythonType &PythonType::supportRichCompare() { #if defined( Py_LIMITED_API ) slots[ Py_tp_richcompare ] = reinterpret_cast( rich_compare_handler ); #else table->tp_richcompare = rich_compare_handler; #endif return *this; } PythonType &PythonType::supportRepr() { #if defined( Py_LIMITED_API ) slots[ Py_tp_repr ] = reinterpret_cast( repr_handler ); #else table->tp_repr = repr_handler; #endif return *this; } PythonType &PythonType::supportStr() { #if defined( Py_LIMITED_API ) slots[ Py_tp_str ] = reinterpret_cast( str_handler ); #else table->tp_str = str_handler; #endif return *this; } PythonType &PythonType::supportHash() { #if defined( Py_LIMITED_API ) slots[ Py_tp_hash ] = reinterpret_cast( hash_handler ); #else table->tp_hash = hash_handler; #endif return *this; } PythonType &PythonType::supportCall() { #if defined( Py_LIMITED_API ) slots[ Py_tp_call ] = reinterpret_cast( call_handler ); #else table->tp_call = call_handler; #endif return *this; } PythonType &PythonType::supportIter( int methods_to_support ) { if( methods_to_support&support_iter_iter ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_iter ] = reinterpret_cast( iter_handler ); #else table->tp_iter = iter_handler; #endif } if( methods_to_support&support_iter_iternext ) { #if defined( Py_LIMITED_API ) slots[ Py_tp_iternext ] = reinterpret_cast( iternext_handler ); #else table->tp_iternext = iternext_handler; #endif } return *this; } //-------------------------------------------------------------------------------- // // Handlers // //-------------------------------------------------------------------------------- PythonExtensionBase *getPythonExtensionBase( PyObject *self ) { if(PyType_HasFeature(self->ob_type, Py_TPFLAGS_BASETYPE)) { PythonClassInstance *instance = reinterpret_cast( self ); return instance->m_pycxx_object; } else { return static_cast( self ); } } #if defined( PYCXX_PYTHON_2TO3 ) && !defined ( Py_LIMITED_API ) && PY_MINOR_VERSION <= 7 extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->print( fp, flags ); } catch( BaseException & ) { return -1; // indicate error } } #endif extern "C" PyObject *getattr_handler( PyObject *self, char *name ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->getattr( name ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" int setattr_handler( PyObject *self, char *name, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->setattr( name, Object( value ) ); } catch( BaseException & ) { return -1; // indicate error } } extern "C" PyObject *getattro_handler( PyObject *self, PyObject *name ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->getattro( String( name ) ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->setattro( String( name ), Object( value ) ); } catch( BaseException & ) { return -1; // indicate error } } extern "C" PyObject *rich_compare_handler( PyObject *self, PyObject *other, int op ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->rich_compare( Object( other ), op ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *repr_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->repr() ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *str_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->str() ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" Py_hash_t hash_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->hash(); } catch( BaseException & ) { return -1; // indicate error } } extern "C" PyObject *call_handler( PyObject *self, PyObject *args, PyObject *kw ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); if( kw != NULL ) return new_reference_to( p->call( Object( args ), Object( kw ) ) ); else return new_reference_to( p->call( Object( args ), Object() ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *iter_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->iter() ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *iternext_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->iternext(); // might be a NULL ptr on end of iteration } catch( BaseException & ) { return NULL; // indicate error } } // Sequence methods extern "C" Py_ssize_t sequence_length_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_length(); } catch( BaseException & ) { return -1; // indicate error } } extern "C" PyObject *sequence_concat_handler( PyObject *self, PyObject *other ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_concat( Object( other ) ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *sequence_repeat_handler( PyObject *self, Py_ssize_t count ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_repeat( count ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *sequence_item_handler( PyObject *self, Py_ssize_t index ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_item( index ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" int sequence_ass_item_handler( PyObject *self, Py_ssize_t index, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_ass_item( index, Object( value ) ); } catch( BaseException & ) { return -1; // indicate error } } extern "C" PyObject *sequence_inplace_concat_handler( PyObject *self, PyObject *o2 ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_inplace_concat( Object( o2 ) ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" PyObject *sequence_inplace_repeat_handler( PyObject *self, Py_ssize_t count ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->sequence_inplace_repeat( count ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" int sequence_contains_handler( PyObject *self, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->sequence_contains( Object( value ) ); } catch( BaseException & ) { return -1; // indicate error } } // Mapping extern "C" Py_ssize_t mapping_length_handler( PyObject *self ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->mapping_length(); } catch( BaseException & ) { return -1; // indicate error } } extern "C" PyObject *mapping_subscript_handler( PyObject *self, PyObject *key ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return new_reference_to( p->mapping_subscript( Object( key ) ) ); } catch( BaseException & ) { return NULL; // indicate error } } extern "C" int mapping_ass_subscript_handler( PyObject *self, PyObject *key, PyObject *value ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->mapping_ass_subscript( Object( key ), Object( value ) ); } catch( BaseException & ) { return -1; // indicate error } } // Number #define NUMBER_UNARY( slot ) \ extern "C" PyObject *number_ ## slot ## _handler( PyObject *self ) \ { \ try \ { \ PythonExtensionBase *p = getPythonExtensionBase( self ); \ return new_reference_to( p->number_ ## slot() ); \ } \ catch( BaseException & ) \ { \ return NULL; /* indicates error */ \ } \ } #define NUMBER_BINARY( slot ) \ extern "C" PyObject *number_ ## slot ## _handler( PyObject *self, PyObject *other ) \ { \ try \ { \ PythonExtensionBase *p = getPythonExtensionBase( self ); \ return new_reference_to( p->number_ ## slot( Object( other ) ) ); \ } \ catch( BaseException & ) \ { \ return NULL; /* indicates error */ \ } \ } #define NUMBER_TERNARY( slot ) \ extern "C" PyObject *number_ ## slot ## _handler( PyObject *self, PyObject *other1, PyObject *other2 ) \ { \ try \ { \ PythonExtensionBase *p = getPythonExtensionBase( self ); \ return new_reference_to( p->number_ ## slot( Object( other1 ), Object( other2 ) ) ); \ } \ catch( BaseException & ) \ { \ return NULL; /* indicates error */ \ } \ } NUMBER_UNARY( negative ) NUMBER_UNARY( positive ) NUMBER_UNARY( absolute ) NUMBER_UNARY( invert ) NUMBER_UNARY( int ) NUMBER_UNARY( float ) NUMBER_BINARY( add ) NUMBER_BINARY( subtract ) NUMBER_BINARY( multiply ) NUMBER_BINARY( remainder ) NUMBER_BINARY( divmod ) NUMBER_BINARY( lshift ) NUMBER_BINARY( rshift ) NUMBER_BINARY( and ) NUMBER_BINARY( xor ) NUMBER_BINARY( or ) NUMBER_TERNARY( power ) NUMBER_BINARY( floor_divide ) NUMBER_BINARY( true_divide ) NUMBER_UNARY( index ) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 NUMBER_BINARY( matrix_multiply ) #endif NUMBER_BINARY( inplace_add ) NUMBER_BINARY( inplace_subtract ) NUMBER_BINARY( inplace_multiply ) NUMBER_BINARY( inplace_remainder ) NUMBER_TERNARY( inplace_power ) NUMBER_BINARY( inplace_lshift ) NUMBER_BINARY( inplace_rshift ) NUMBER_BINARY( inplace_and ) NUMBER_BINARY( inplace_xor ) NUMBER_BINARY( inplace_or ) NUMBER_BINARY( inplace_floor_divide ) NUMBER_BINARY( inplace_true_divide ) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 NUMBER_BINARY( inplace_matrix_multiply ) #endif #undef NUMBER_UNARY #undef NUMBER_BINARY #undef NUMBER_TERNARY // Buffer #ifndef Py_LIMITED_API extern "C" int buffer_get_handler( PyObject *self, Py_buffer *buf, int flags ) { try { PythonExtensionBase *p = getPythonExtensionBase( self ); return p->buffer_get( buf, flags ); } catch( BaseException & ) { return -1; // indicate error } } extern "C" void buffer_release_handler( PyObject *self, Py_buffer *buf ) { PythonExtensionBase *p = getPythonExtensionBase( self ); p->buffer_release( buf ); // NOTE: No way to indicate error to Python } #endif //================================================================================ // // Implementation of PythonExtensionBase // //================================================================================ #define missing_method( method ) \ throw RuntimeError( "Extension object missing implement of " #method ); PythonExtensionBase::PythonExtensionBase() { ob_refcnt = 0; } PythonExtensionBase::~PythonExtensionBase() { assert( ob_refcnt == 0 ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name ) { TupleN args; return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1 ) { TupleN args( arg1 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2 ) { TupleN args( arg1, arg2 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3 ) { TupleN args( arg1, arg2, arg3 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4 ) { TupleN args( arg1, arg2, arg3, arg4 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5 ) { TupleN args( arg1, arg2, arg3, arg4, arg5 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); return self().callMemberFunction( fn_name, args ); } Object PythonExtensionBase::callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8, const Object &arg9 ) { TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); return self().callMemberFunction( fn_name, args ); } void PythonExtensionBase::reinit( Tuple &/*args*/, Dict &/*kwds*/ ) { throw RuntimeError( "Must not call __init__ twice on this class" ); } Object PythonExtensionBase::genericGetAttro( const String &name ) { return asObject( PyObject_GenericGetAttr( selfPtr(), name.ptr() ) ); } int PythonExtensionBase::genericSetAttro( const String &name, const Object &value ) { return PyObject_GenericSetAttr( selfPtr(), name.ptr(), value.ptr() ); } #if defined( PYCXX_PYTHON_2TO3 ) && !defined( Py_LIMITED_API ) && PY_MINOR_VERSION <= 7 int PythonExtensionBase::print( FILE *, int ) { missing_method( print ); } #endif Object PythonExtensionBase::getattr( const char * ) { missing_method( getattr ); } int PythonExtensionBase::setattr( const char *, const Object & ) { missing_method( setattr ); } Object PythonExtensionBase::getattro( const String &name ) { return asObject( PyObject_GenericGetAttr( selfPtr(), name.ptr() ) ); } int PythonExtensionBase::setattro( const String &name, const Object &value ) { return PyObject_GenericSetAttr( selfPtr(), name.ptr(), value.ptr() ); } int PythonExtensionBase::compare( const Object & ) { missing_method( compare ); } Object PythonExtensionBase::rich_compare( const Object &, int ) { missing_method( rich_compare ); } Object PythonExtensionBase::repr() { missing_method( repr ); } Object PythonExtensionBase::str() { missing_method( str ); } long PythonExtensionBase::hash() { missing_method( hash ); } Object PythonExtensionBase::call( const Object &, const Object & ) { missing_method( call ); } Object PythonExtensionBase::iter() { missing_method( iter ); } PyObject *PythonExtensionBase::iternext() { missing_method( iternext ); } // Sequence methods Sequence::size_type PythonExtensionBase::sequence_length() { missing_method( sequence_length ); } Object PythonExtensionBase::sequence_concat( const Object & ) { missing_method( sequence_concat ); } Object PythonExtensionBase::sequence_repeat( Py_ssize_t ) { missing_method( sequence_repeat ); } Object PythonExtensionBase::sequence_item( Py_ssize_t ) { missing_method( sequence_item ); } int PythonExtensionBase::sequence_ass_item( Py_ssize_t, const Object & ) { missing_method( sequence_ass_item ); } Object PythonExtensionBase::sequence_inplace_concat( const Object & ) { missing_method( sequence_inplace_concat ); } Object PythonExtensionBase::sequence_inplace_repeat( Py_ssize_t ) { missing_method( sequence_inplace_repeat ); } int PythonExtensionBase::sequence_contains( const Object & ) { missing_method( sequence_contains ); } // Mapping PyCxx_ssize_t PythonExtensionBase::mapping_length() { missing_method( mapping_length ); } Object PythonExtensionBase::mapping_subscript( const Object & ) { missing_method( mapping_subscript ); } int PythonExtensionBase::mapping_ass_subscript( const Object &, const Object & ) { missing_method( mapping_ass_subscript ); } // Number #define NUMBER_UNARY( slot ) Object PythonExtensionBase::number_ ## slot() \ { missing_method( number_ ## slot ); } #define NUMBER_BINARY( slot ) Object PythonExtensionBase::number_ ## slot( const Object & ) \ { missing_method( number_ ## slot ); } #define NUMBER_TERNARY( slot ) Object PythonExtensionBase::number_ ## slot( const Object &, const Object & ) \ { missing_method( number_ ## slot ); } NUMBER_UNARY( negative ) NUMBER_UNARY( positive ) NUMBER_UNARY( absolute ) NUMBER_UNARY( invert ) NUMBER_UNARY( int ) NUMBER_UNARY( float ) NUMBER_BINARY( add ) NUMBER_BINARY( subtract ) NUMBER_BINARY( multiply ) NUMBER_BINARY( remainder ) NUMBER_BINARY( divmod ) NUMBER_BINARY( lshift ) NUMBER_BINARY( rshift ) NUMBER_BINARY( and ) NUMBER_BINARY( xor ) NUMBER_BINARY( or ) NUMBER_TERNARY( power ) NUMBER_BINARY( floor_divide ) NUMBER_BINARY( true_divide ) NUMBER_UNARY( index ) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 NUMBER_BINARY( matrix_multiply ) #endif NUMBER_BINARY( inplace_add ) NUMBER_BINARY( inplace_subtract ) NUMBER_BINARY( inplace_multiply ) NUMBER_BINARY( inplace_remainder ) NUMBER_TERNARY( inplace_power ) NUMBER_BINARY( inplace_lshift ) NUMBER_BINARY( inplace_rshift ) NUMBER_BINARY( inplace_and ) NUMBER_BINARY( inplace_xor ) NUMBER_BINARY( inplace_or ) NUMBER_BINARY( inplace_floor_divide ) NUMBER_BINARY( inplace_true_divide ) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 NUMBER_BINARY( inplace_matrix_multiply ) #endif #undef NUMBER_UNARY #undef NUMBER_BINARY #undef NUMBER_TERNARY // Buffer #ifndef Py_LIMITED_API int PythonExtensionBase::buffer_get( Py_buffer * /*buf*/, int /*flags*/ ) { missing_method( buffer_get ); } int PythonExtensionBase::buffer_release( Py_buffer * /*buf*/ ) { // This method is optional and only required if the buffer's // memory is dynamic. return 0; } #endif //-------------------------------------------------------------------------------- // // Method call handlers for // PythonExtensionBase // ExtensionModuleBase // //-------------------------------------------------------------------------------- // Note: Python calls noargs as varargs buts args==NULL extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); Object result( self->invoke_method_noargs( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ) ); return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); Tuple args( _args ); Object result ( self->invoke_method_varargs ( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), args ) ); return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); Tuple args( _args ); if( _keywords == NULL ) { Dict keywords; // pass an empty dict Object result ( self->invoke_method_keyword ( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), args, keywords ) ); return new_reference_to( result.ptr() ); } else { Dict keywords( _keywords ); // make dict Object result ( self->invoke_method_keyword ( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), args, keywords ) ); return new_reference_to( result.ptr() ); } } catch( BaseException & ) { return 0; } } //-------------------------------------------------------------------------------- // // ExtensionExceptionType // //-------------------------------------------------------------------------------- ExtensionExceptionType::ExtensionExceptionType() : Object() { } void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name ) { std::string module_name( module.fullName() ); module_name += "."; module_name += name; set( PyErr_NewException( const_cast( module_name.c_str() ), NULL, NULL ), true ); } void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name, ExtensionExceptionType &parent ) { std::string module_name( module.fullName() ); module_name += "."; module_name += name; set( PyErr_NewException( const_cast( module_name.c_str() ), parent.ptr(), NULL ), true ); } ExtensionExceptionType::~ExtensionExceptionType() { } BaseException::BaseException( ExtensionExceptionType &exception, const std::string& reason ) { PyErr_SetString( exception.ptr(), reason.c_str() ); } BaseException::BaseException( ExtensionExceptionType &exception, Object &reason ) { PyErr_SetObject( exception.ptr(), reason.ptr() ); } BaseException::BaseException( PyObject *exception, Object &reason ) { PyErr_SetObject( exception, reason.ptr() ); } BaseException::BaseException( PyObject *exception, const std::string &reason ) { PyErr_SetString( exception, reason.c_str() ); } BaseException::BaseException() { } void BaseException::clear() { PyErr_Clear(); } // is the exception this specific exception 'exc' bool BaseException::matches( ExtensionExceptionType &exc ) { return PyErr_ExceptionMatches( exc.ptr() ) != 0; } Object BaseException::errorType() { PyObject *type, *value, *traceback; PyErr_Fetch( &type, &value, &traceback ); Object result( type ); PyErr_Restore( type, value, traceback ); return result; } Object BaseException::errorValue() { PyObject *type, *value, *traceback; PyErr_Fetch( &type, &value, &traceback ); Object result( value ); PyErr_Restore( type, value, traceback ); return result; } //------------------------------------------------------------ #if 1 //------------------------------------------------------------ // compare operators bool operator!=( const Long &a, const Long &b ) { return a.as_long() != b.as_long(); } bool operator!=( const Long &a, int b ) { return a.as_long() != b; } bool operator!=( const Long &a, long b ) { return a.as_long() != b; } bool operator!=( int a, const Long &b ) { return a != b.as_long(); } bool operator!=( long a, const Long &b ) { return a != b.as_long(); } //------------------------------ bool operator==( const Long &a, const Long &b ) { return a.as_long() == b.as_long(); } bool operator==( const Long &a, int b ) { return a.as_long() == b; } bool operator==( const Long &a, long b ) { return a.as_long() == b; } bool operator==( int a, const Long &b ) { return a == b.as_long(); } bool operator==( long a, const Long &b ) { return a == b.as_long(); } //------------------------------ bool operator>( const Long &a, const Long &b ) { return a.as_long() > b.as_long(); } bool operator>( const Long &a, int b ) { return a.as_long() > b; } bool operator>( const Long &a, long b ) { return a.as_long() > b; } bool operator>( int a, const Long &b ) { return a > b.as_long(); } bool operator>( long a, const Long &b ) { return a > b.as_long(); } //------------------------------ bool operator>=( const Long &a, const Long &b ) { return a.as_long() >= b.as_long(); } bool operator>=( const Long &a, int b ) { return a.as_long() >= b; } bool operator>=( const Long &a, long b ) { return a.as_long() >= b; } bool operator>=( int a, const Long &b ) { return a >= b.as_long(); } bool operator>=( long a, const Long &b ) { return a >= b.as_long(); } //------------------------------ bool operator<( const Long &a, const Long &b ) { return a.as_long() < b.as_long(); } bool operator<( const Long &a, int b ) { return a.as_long() < b; } bool operator<( const Long &a, long b ) { return a.as_long() < b; } bool operator<( int a, const Long &b ) { return a < b.as_long(); } bool operator<( long a, const Long &b ) { return a < b.as_long(); } //------------------------------ bool operator<=( const Long &a, const Long &b ) { return a.as_long() <= b.as_long(); } bool operator<=( int a, const Long &b ) { return a <= b.as_long(); } bool operator<=( long a, const Long &b ) { return a <= b.as_long(); } bool operator<=( const Long &a, int b ) { return a.as_long() <= b; } bool operator<=( const Long &a, long b ) { return a.as_long() <= b; } #ifdef HAVE_LONG_LONG //------------------------------ bool operator!=( const Long &a, PY_LONG_LONG b ) { return a.as_long_long() != b; } bool operator!=( PY_LONG_LONG a, const Long &b ) { return a != b.as_long_long(); } //------------------------------ bool operator==( const Long &a, PY_LONG_LONG b ) { return a.as_long_long() == b; } bool operator==( PY_LONG_LONG a, const Long &b ) { return a == b.as_long_long(); } //------------------------------ bool operator>( const Long &a, PY_LONG_LONG b ) { return a.as_long_long() > b; } bool operator>( PY_LONG_LONG a, const Long &b ) { return a > b.as_long_long(); } //------------------------------ bool operator>=( const Long &a, PY_LONG_LONG b ) { return a.as_long_long() >= b; } bool operator>=( PY_LONG_LONG a, const Long &b ) { return a >= b.as_long_long(); } //------------------------------ bool operator<( const Long &a, PY_LONG_LONG b ) { return a.as_long_long() < b; } bool operator<( PY_LONG_LONG a, const Long &b ) { return a < b.as_long_long(); } //------------------------------ bool operator<=( const Long &a, PY_LONG_LONG b ) { return a.as_long_long() <= b; } bool operator<=( PY_LONG_LONG a, const Long &b ) { return a <= b.as_long_long(); } #endif #endif //------------------------------------------------------------ // compare operators bool operator!=( const Float &a, const Float &b ) { return a.as_double() != b.as_double(); } bool operator!=( const Float &a, double b ) { return a.as_double() != b; } bool operator!=( double a, const Float &b ) { return a != b.as_double(); } //------------------------------ bool operator==( const Float &a, const Float &b ) { return a.as_double() == b.as_double(); } bool operator==( const Float &a, double b ) { return a.as_double() == b; } bool operator==( double a, const Float &b ) { return a == b.as_double(); } //------------------------------ bool operator>( const Float &a, const Float &b ) { return a.as_double() > b.as_double(); } bool operator>( const Float &a, double b ) { return a.as_double() > b; } bool operator>( double a, const Float &b ) { return a > b.as_double(); } //------------------------------ bool operator>=( const Float &a, const Float &b ) { return a.as_double() >= b.as_double(); } bool operator>=( const Float &a, double b ) { return a.as_double() >= b; } bool operator>=( double a, const Float &b ) { return a >= b.as_double(); } //------------------------------ bool operator<( const Float &a, const Float &b ) { return a.as_double() < b.as_double(); } bool operator<( const Float &a, double b ) { return a.as_double() < b; } bool operator<( double a, const Float &b ) { return a < b.as_double(); } //------------------------------ bool operator<=( const Float &a, const Float &b ) { return a.as_double() <= b.as_double(); } bool operator<=( double a, const Float &b ) { return a <= b.as_double(); } bool operator<=( const Float &a, double b ) { return a.as_double() <= b; } } // end of namespace Py pycxx-7.1.4/Doc/Python3/000755 000765 000024 00000000000 13664720516 015243 5ustar00barrystaff000000 000000 pycxx-7.1.4/Doc/Python2/000755 000765 000024 00000000000 13664720516 015242 5ustar00barrystaff000000 000000 pycxx-7.1.4/Doc/Python2/style.css000644 000765 000024 00000003047 11146615306 017111 0ustar00barrystaff000000 000000 /* Copyright (c) 2008-2009 Barry A. Scott */ h1, h2, h3, h4 { color: #000099; background-color: #aaaaff; } h3 { position: relative; left: 20px margin-right: 40px; } body { background-color: #ffffff; width: 95%; } p { position: relative; left: 20px; width: 45em; margin-right: 40px; } pre { color: #0000cc; background-color: #eeeeee; position: relative; left: 40px; margin-right: 80px; border-style: solid; border-color: black; border-width: thin; } kbd { color: #990000; } p cite, ol cite, ul cite { font-family: monospace; font-style: normal; font-size: normal; } li { width: 43em; } li var, pre var, p var, kbd var { color: #009900; font-style: italic; } li samp, pre samp, p samp, kbd samp { color: #009900; font-weight: bold; } li p { position: relative; left: 0; } table { position: relative; left: 20px; margin-right: 40px; border: solid #888888 1px; background-color: #eeeeee; } table th { border: solid #888888 1px; background-color: #88dd88; color: black; text-align: left; } table td { border: solid #888888 1px; } table td.code { border: solid #888888 1px; font-family: monospace; font-style: normal; font-size: normal; } p.param { background-color: #eeeeee; border-top: lightskyblue solid 4; } p.center { text-align: center; } pycxx-7.1.4/Doc/Python2/PyCXX.html000644 000765 000024 00000202404 13305260623 017073 0ustar00barrystaff000000 000000 Writing Python Extensions in C++ with PyCXX

Writing Python Extensions in C++

Barry Scott
Reading, Berkshire, England
barry@barrys-emacs.org

Paul F. Dubois, dubois1@llnl.gov
Lawrence Livermore National Laboratory
Livermore, California, U.S.A.

Acknowledgment

Thank you to Geoffrey Furnish for patiently teaching me the finer points of C++ and its template facility, and his critique of PyCXX in particular. With version 4 I welcome Barry Scott as co-author. -- Paul Dubois

Paul is no longer contributing to PyCXX. Thanks for all your great work on PyCXX Paul. -- Barry Scott.

Overview

PyCXX is designed to make it easier to extend Python with C++

PyCXX is a set of C++ facilities to make it easier to write Python extensions. The chief way in which PyCXX makes it easier to write Python extensions is that it greatly increases the probability that your program will not make a reference-counting error and will not have to continually check error returns from the Python C API. PyCXX integrates Python with C++ in these ways:

  • C++ exception handling is relied on to detect errors and clean up. In a complicated function this is often a tremendous problem when writing in C. With PyCXX, we let the compiler keep track of what objects need to be dereferenced when an error occurs.
  • The Standard Template Library (STL) and its many algorithms plug and play with Python containers such as lists and tuples.
  • The optional CXX/Extensions facility allows you to replace the clumsy C tables with objects and method calls that define your modules and extension objects.

Download and Installation

Download PyCXX from http://sourceforge.net/projects/cxx/.

The distribution layout is:

DirectoryDescription
.Makefile for Unix and Windows, Release documentation
./CXXHeader files
./SrcSource files
./DocDocumentation
./DemoTesting and Demonstartion files

To use PyCXX you use its include files and add its source routines to your module.

Installation:

  • Install the PyCXX files into a directory of your choice. For example:
    Windows: C:\PyCXX
    Unix: /usr/local/PyCXX
  • Tell your compiler where the PyCXX header files are:
    Windows: cl /I=C:\PyCXX ...
    Unix: g++ -I/usr/local/PyCXX ...
  • Include PyCXX headers files in your code using the CXX prefix:
    #include "CXX/Objects.hxx"

The header file CXX/config.h may need to be adjusted for the compiler you use. As of this writing, only a fairly obscure reference to part of the standard library needs this adjustment. Unlike prior releases, PyCXX now assumes namespace support and a standard C++ library.

PyCXX - Supporting Python 2 and Python 3

It is possible to have common code that can be compiled to work with Python 2 or Python 3.

Define PYCXX_PYTHON_2TO3 to turn on the compatibility support. When compiling against Python 2 this means faking up the Python 3 API and when compiling against Python 3 faking the old Python 2 API.

The changes from Python 2 to Python 3 that require code changes are:

  • string is unicode only in Python 3 - Py::String API changed to match python 3 usage
  • byte is for byte date in Python 3 - Py::Bytes added to PyCXX
  • int has been removed - Py::Int has been removed from PyCXX

This means that you will need to:

  • Replace Py::Nothing with Py::None - required
  • Replace Py::Int with Py::Long - recommended
  • Replace Py::LongLong with Py::Long -recommended
  • Replace as_std_string() with as_std_string( "encoding" ) or as_std_string( NULL ) - required
  • Replace Py::String that holds non unicode data with Py::Bytes - required

Use of namespaces

All PyCXX assets are in namespace "Py". You need to include the Py:: prefix when referring to them, or include the statement:

using namespace Py;

Wrappers for standard objects: CXX/Objects.hxx

Header file CXX/Objects.hxx requires adding file Src/cxxsupport.cxx and Src/IndirectPythonInterface.cxx to your module sources. CXX/Objects provides a set of wrapper classes that allow you access to most of the Python C API using a C++ notation that closely resembles Python. For example, this Python:

d = {}
d["a"] = 1
d["b"] = 2
alist = d.keys()
print alist

Can be written in C++:

Dict d;
List alist;
d["a"] = Int(1);
d["b"] = Int(2);
alist = d.keys();
std::cout << alist << std::endl;

You can optionally use the CXX/Extensions.hxx facility described later to define Python extension modules and extension objects.

We avoid programming with Python object pointers

The essential idea is that we avoid, as much as possible, programming with pointers to Python objects, that is, variables of type PyObject*. Instead, we use instances of a family of C++ classes that represent the usual Python objects. This family is easily extendible to include new kinds of Python objects.

For example, consider the case in which we wish to write a method, taking a single integer argument, that will create a Python dict and insert into it that the integer plus one under the key value. In C we might do that as follows:

static PyObject* mymodule_addvalue (PyObject* args)
{
    PyObject *d;
    PyObject* f;
    int k;
    PyArgs_ParseTuple(args, "i", &k);
    d = PyDict_New();
    if (!d)
        return NULL;

    f = PyInt_NEW(k+1);
    if(!f)
    {
        Py_DECREF(d); /* have to get rid of d first */
        return NULL;
    }
    if(PyDict_SetItemString(d, "value", f) == -1)
    {
        Py_DECREF(f);
        Py_DECREF(d);
        return NULL;
    }

    return d;
}

If you have written a significant Python extension, this tedium looks all too familiar. The vast bulk of the coding is error checking and cleanup. Now compare the same thing written in C++ using CXX/Objects.hxx. The things with Python-like names (Int, Dict, Tuple) are from CXX/Objects.hxx.

static PyObject* mymodule_addvalue (PyObject* pargs)
{ 
    try
    {
        Tuple args(pargs); 
        args.verify_length(1); 

        Dict d; 
        Int k = args[0]; 
        d["value"] = k + 1;

        return new_reference_to(d); 
    } 
    catch (const PyException&)
    { 
        return NULL;
    }
}

If there are not the right number of arguments or the argument is not an integer, an exception is thrown. In this case we choose to catch it and convert it into a Python exception. The C++ exception handling mechanism takes care all the cleanup.

Note that the creation of the Int k got the first argument and verified that it is an Int.

Just to peek ahead, if you wrote this method in an ExtensionModule-derived module of your own, it would be a method and it could be written even more simply:

Object addvalue (const Tuple & args)
{
    args.verify_length(1);
    Dict d;
    Int k = args[0];
    d["value"] = k + 1;
    return d;
}

The basic concept is to wrap Python pointers

The basic concept of CXX/Objects.hxx is to create a wrapper around each PyObject * so that the reference counting can be done automatically, thus eliminating the most frequent source of errors. In addition, we can then add methods and operators so that Python objects can be manipulated in C++ much like you would in Python.

Each Object contains a PyObject * to which it owns a reference. When an Object is destroyed, it releases its ownership on the pointer. Since C++ calls the destructors on objects that are about to go out of scope, we are guaranteed that we will keep the reference counts right even if we unexpectedly leave a routine with an exception.

As a matter of philosophy, CXX/Objects.hxx prevents the creation of instances of its classes unless the instance will be a valid instance of its class. When an attempt is made to create an object that will not be valid, an exception is thrown.

Class Object represents the most general kind of Python object. The rest of the classes that represent Python objects inherit from it.

Object
Type
Int
Float
Long
Complex
Char
Sequence -> SeqBase<T>
    String
    Tuple
    List
Mapping -> MapBase<T>
    Dict
Callable
Module

There are several constructors for each of these classes. For example, you can create an Int from an integer as in

Int s(3)

However, you can also create an instance of one of these classes using any PyObject* or another Object. If the corresponding Python object does not actually have the type desired, an exception is thrown. This is accomplished as follows. Class Object defines a virtual function accepts:

virtual bool accepts(PyObject* p)

The base class version of accepts returns true for any pointer p except 0. This means we can create an Object using any PyObject *, or from any other Object. However, if we attempt to create an Int from a PyObject *, the overridding version of accepts in class Int will only accept pointers that correspond to Python ints. Therefore if we have a Tuple t and we wish to get the first element and be sure it is an Int, we do

Int first_element = t[0]

This will not only accomplish the goal of extracting the first element of the Tuple t, but it will ensure that the result is an Int. If not, an exception is thrown. The exception mechanism is discussed later.

Class Object

Class Object serves as the base class for the other classes. Its default constructor constructs a Py_None, the unique object of Python type None. The interface to Object consists of a large number of methods corresponding to the operations that are defined for every Python object. In each case, the methods throw an exception if anything goes wrong.

There is no method corresponding to PyObject_SetItem with an arbitrary Python object as a key. Instead, create an instance of a more specific child of Object and use the appropriate facilities.

The comparison operators use the Python comparison function to compare values. The method is is available to test for absolute identity.

A conversion to standard library string type std::string is supplied using method as_string. Stream output of PyCXX Object instances uses this conversion, which in turn uses the Python object's str() representation.

All the numeric operators are defined on all possible combinations of Object, long, and double. These use the corresponding Python operators, and should the operation fail for some reason, an exception is thrown.

Dealing with pointers returned by the Python C API

Often, PyObject * pointers are acquired from some function, particularly functions in the Python C API. If you wish to make an object from the pointer returned by such a function, you need to know if the function returns you an owned or unowned reference. Unowned references are unusual but there are some cases where unowned references are returned.

Usually, Object and its children acquire a new reference when constructed from a PyObject *. This is usually not the right behavior if the reference comes from one of the Python C API calls.

If p is an owned reference, you can add the boolean true as an extra argument in the creation routine, Object(p, true), or use the function asObject(p) which returns an Object created using the owned reference. For example, the routine PyString_FromString returns an owned reference to a Python string object. You could write:

Object w = asObject( PyString_FromString("my string") );

or using the constructor,

Object w( PyString_FromString("my string"), true );

In fact, you would never do this, since PyCXX has a class String and you can just say:

String w( "my string" );

Indeed, since most of the Python C API is similarly embodied in Object and its descendents, you probably will not use asObject all that often.

Table 1: Class Object

Returns Name(signature) Comment

Basic Methods

explicit Object (PyObject* pyob=Py_None, bool owned=false) Construct from pointer.
explicit Object (const Object& ob) Copycons; acquires an owned reference.
Object& operator= (const Object& rhs) Acquires an owned reference.
Object& operator= (PyObject* rhsp) Acquires an owned reference.
virtual ~Object () Releases the reference.
void increment_reference_count() Explicitly increment the count
void decrement_reference_count() Explicitly decrement count but not to zero
PyObject* operator* () const Lends the pointer
PyObject* ptr () const Lends the pointer
virtual bool accepts (PyObject *pyob) const Would assignment of pyob to this object succeed?
std::string as_string() const str() representation
Python API Interface
int reference_count () const reference count
Type type () const associated type object
String str () const str() representation
String repr () const repr () representation
bool hasAttr (const std::string& s) const hasattr(this, s)
Object getAttr (const std::string& s) const getattr(this, s)
Object getItem (const Object& key) const getitem(this, key)
long hashValue () const hash(this)
void setAttr (const std::string& s,
const Object& value)
this.s = value
void delAttr (const std::string& s) del this.s
void delItem (const Object& key) del this[key]
bool isCallable () const does this have callable behavior?
bool isList () const is this a Python list?
bool isMapping () const does this have mapping behaviors?
bool isNumeric () const does this have numeric behaviors?
bool isSequence () const does this have sequence behaviors?
bool isTrue () const is this true in the Python sense?
bool isType (const Type& t) const is type(this) == t?
bool isTuple() const is this a Python tuple?
bool isString() const is this a Python string?
bool isUnicode() const is this a Python Unicode string?
bool isDict() const is this a Python dictionary?
Comparison Operators
bool is(PyObject* pother) const test for identity
bool is(const Object& other) const test for identity
bool operator==(const Object& o2) const Comparisons use Python cmp
bool operator!=(const Object& o2) const Comparisons use Python cmp
bool operator>=(const Object& o2) const Comparisons use Python cmp
bool operator<=(const Object& o2) const Comparisons use Python cmp
bool operator<(const Object& o2) const Comparisons use Python cmp
bool operator>(const Object& o2) const Comparisons use Python cmp

The Basic Types

Corresponding to each of the basic Python types is a class that inherits from Object. Here are the interfaces for those types. Each of them inherits from Object and therefore has all of the inherited methods listed for Object. Where a virtual function is overridden in a class, the name is underlined.

Class Type

Class Type corresponds to Python type objects. There is no default constructor.

Table 2: class Type

Returns Name and Signature Comments
explicit Type (PyObject* pyob, bool owned = false) Constructor
explicit Type (const Object& ob) Constructor
explicit Type(const Type& t) Copycons
Type& operator= (const Object& rhs) Assignment
Type& operator= (PyObject* rhsp) Assignment
virtual bool accepts (PyObject *pyob) const Uses PyType_Check

Class Int

Class Int, derived publically from Object, corresponds to Python ints. Note that the latter correspond to C long ints. Class Int has an implicit user-defined conversion to long int. All constructors, on the other hand, are explicit. The default constructor creates a Python int zero.

Table 3: class Int

Returns Name and Signature Comments
explicit Int (PyObject *pyob, bool owned= false, bool owned = false) Constructor
explicit Int (const Int& ob) Constructor
explicit Int (long v = 0L) Construct from long
explicit Int (int v) Contruct from int
explicit Int (const Object& ob) Copycons
Int& operator= (const Object& rhs) Assignment
Int& operator= (PyObject* rhsp) Assignment
virtual bool   (PyObject *pyob) const Based on PyInt_Check
long operator long() const Implicit conversion to long int
Int& operator= (int v) Assign from int
Int& operator= (long v) Assign from long

Class Long

Class Long, derived publically from Object, corresponds to Python type long. In Python, a long is an integer type of unlimited size, and is usually used for applications such as cryptography, not as a normal integer. Implicit conversions to both double and long are provided, although the latter may of course fail if the number is actually too big. All constructors are explicit. The default constructor produces a Python long zero.

Table 4: Class Long

Returns Name and Signature Comments
explicit Long (PyObject *pyob, bool owned = false) Constructor
explicit Long (const Int& ob) Constructor
explicit Long (long v = 0L) Construct from long
explicit Long (int v) Contruct from int
explicit Long (const Object& ob) Copycons
Long& operator= (const Object& rhs) Assignment
Long& operator= (PyObject* rhsp) Assignment
virtual bool (PyObject *pyob) const Based on PyLong_Check
double operator double() const Implicit conversion to double
long operator long() const Implicit conversion to long
Long& operator= (int v) Assign from int
Long& operator= (long v) Assign from long

Class Float

Class Float corresponds to Python floats, which in turn correspond to C double. The default constructor produces the Python float 0.0.

Table 5: Class Float

Returns Name and Signature Comments
explicit Float (PyObject *pyob, bool owned = false) Constructor
Float (const Float& f)   Construct from float
explicit Float (double v=0.0) Construct from double
explicit Float (const Object& ob) Copycons
Float& operator= (const Object& rhs) Assignment
Float& operator= (PyObject* rhsp) Assignment
virtual bool accepts (PyObject *pyob) const Based on PyFloat_Check
double operator double () const Implicit conversion to double
Float& operator= (double v) Assign from double
Float& operator= (int v) Assign from int
Float& operator= (long v) Assign from long
Float& operator= (const Int& iob) Assign from Int

Sequences

PyCXX implements a quite sophisticated wrapper class for Python sequences. While every effort has been made to disguise the sophistication, it may pop up in the form of obscure compiler error messages, so in this documentation we will first detail normal usage and then discuss what is under the hood.

The basic idea is that we would like the subscript operator [] to work properly, and to be able to use STL-style iterators and STL algorithms across the elements of the sequence.

Sequences are implemented in terms of a templated base class, SeqBase<T>. The parameter T is the answer to the question, sequence of what? For Lists, for example, T is Object, because the most specific thing we know about an element of a List is simply that it is an Object. (Class List is defined below; it is a descendent of Object that holds a pointer to a Python list). For strings, T is Char, which is a wrapper in turn of Python strings whose length is one.

For convenience, the word Sequence is a typedef of SeqBase<Object>.

General sequences

Suppose you are writing an extension module method that expects the first argument to be any kind of Python sequence, and you wish to return the length of that sequence. You might write:

static PyObject*
my_module_seqlen (PyObject* args) {
try
    {
    Tuple t(args);       // set up a Tuple pointing to the arguments.
    if(t.length() != 1) 
         throw PyException("Incorrect number of arguments to seqlen.");
    Sequence s = t[0];   // get argument and be sure it is a sequence
    return new_reference_to(Int(s.length()));
    }
catch(const PyException&)
    {
    return Py_Null;
    }
}

As we will explain later, the try/catch structure converts any errors, such as the first argument not being a sequence, into a Python exception.

Subscripting

When a sequence is subscripted, the value returned is a special kind of object which serves as a proxy object. The general idea of proxy objects is discussed in Scott Meyers' book, "More Effective C++". Proxy objects are necessary because when one subscripts a sequence it is not clear whether the value is to be used or the location assigned to. Our proxy object is even more complicated than normal because a sequence reference such as s[i] is not a direct reference to the i'th object of s.

In normal use, you are not supposed to notice this magic going on behind your back. You write:

Object t;
Sequence s;
s[2] = t + s[1]

and here is what happens: s[1] returns a proxy object. Since there is no addition operator in Object that takes a proxy as an argument, the compiler decides to invoke an automatic conversion of the proxy to an Object, which returns the desired component of s. The addition takes place, and then there is an assignment operator in the proxy class created by the s[2], and that assignment operator stuffs the result into the 2 component of s.

It is possible to fool this mechanism and end up with a compiler failing to admit that a s[i] is an Object. If that happens, you can work around it by writing Object(s[i]), which makes the desired implicit conversion, explicit.

Iterators

Each sequence class provides the following interface. The class seqref<T> is the proxy class. We omit the details of the iterator, const_iterator, and seqref<T> here. See CXX/Objects.hxx if necessary. The purpose of most of this interface is to satisfy requirements of the STL.

The SeqBase<T> Interface

SeqBase<T> inherits from Object.

Type Name
typedef int size_type
typedef seqref<T> reference
typedef T const_reference
typedef seqref<T>* pointer
typedef int difference_type
virtual size_type max_size() const
virtual size_type capacity() const;
virtual void swap(SeqBase<T>& c);
virtual size_type size () const;
explicit SeqBase<T> ();
explicit SeqBase<T> (PyObject* pyob, bool owned = false);
explicit SeqBase<T> (const Object& ob);
SeqBase<T>& operator= (const Object& rhs);
SeqBase<T>& operator= (PyObject* rhsp);
virtual bool accepts (PyObject *pyob) const;
size_type length () const ;
const T operator[](size_type index) const;
seqref<T> operator[](size_type index);
virtual T getItem (size_type i) const;
virtual void setItem (size_type i, const T& ob);
SeqBase<T> repeat (int count) const;
SeqBase<T> concat (const SeqBase<T>& other) const ;
const T front () const;
seqref<T> front();
const T back () const;
seqref<T> back();
void verify_length(size_type required_size);
void verify_length(size_type min_size, size_type max_size);
class iterator;
iterator begin ();
iterator end ();
class const_iterator;
const_iterator begin () const;
const_iterator end () const;

Any heir of class Object that has a sequence behavior should inherit from class SeqBase<T>, where T is specified as the type of object that represents the individual elements of the sequence. The requirements on T are that it has a constructor that takes a PyObject* as an argument, that it has a default constructor, a copy constructor, and an assignment operator. In short, any properly defined heir of Object will work.

Classes Char and String

Python strings are unusual in that they are immutable sequences of characters. However, there is no character type per se; rather, when subscripted strings return a string of length one. To simulate this, we define two classes Char and String. The Char class represents a Python string object of length one. The String class represents a Python string, and its elements make up a sequence of Char's.

The user interface for Char is limited. Unlike String, for example, it is not a sequence.

The Char interface

Char inherits from Object.

Type Name
explicit Char (PyObject *pyob, bool owned = false)
Char (const Object& ob)
Char (const std::string& v = "")
Char (char v)
Char (Py_UNICODE v)
Char& operator= (const std::string& v)
Char& operator= (char v)
Char& operator= (Py_UNICODE v)
Char& operator= (std::basic_string v)
operator String() const
operator std::string () const

The String Interface

String inherits from SeqBase<Char>.

Type Name
explicit String (PyObject *pyob, bool owned = false)
String (const Object& ob)
String (const std::string& v = "")
String (const std::string& v, const char *encoding, const char *error="strict")
String (const char *s, const char *encoding, const char *error="strict")
String (const char *s, int len, const char *encoding, const char *error="strict")
String (const std::string& v, std::string::size_type vsize)
String (const char* v)
String& operator= (const std::string& v)
std::string operator std::string () const
String encode( const char *encoding, const char *error="strict" )
String decode( const char *encoding, const char *error="strict" )
std::string as_std_string() const
unicodestring as_unicodestring() const

Class Tuple

Class Tuple represents Python tuples. A Tuple is a Sequence. There are two kinds of constructors: one takes a PyObject* as usual, the other takes an integer number as an argument and returns a Tuple of that length, each component initialized to Py_None. The default constructor produces an empty Tuple.

Tuples are not immutable, but attempts to assign to their components will fail if the reference count is not 1. That is, it is safe to set the elements of a Tuple you have just made, but not thereafter.

Example: create a Tuple containing (1, 2, 4)

Tuple t(3)
t[0] = Int(1)
t[1] = Int(2)
t[2] = Int(4)

Example: create a Tuple from a list:

Dict d
...
Tuple t(d.keys())

The Tuple Interface

Tuple inherits from Sequence.. Special run-time checks prevent modification if the reference count is greater than one.

Type Name Comment
virtual void setItem (int offset, const Object&ob) setItem is overridden to handle tuples properly.
explicit Tuple (PyObject *pyob, bool owned = false)
Tuple (const Object& ob)
explicit Tuple (int size = 0) Create a tuple of the given size. Items initialize to Py_None. Default is an empty tuple.
explicit Tuple (const Sequence& s) Create a tuple from any sequence.
Tuple& operator= (const Object& rhs)
Tuple& operator= (PyObject* rhsp)
Tuple getSlice (int i, int j) const Equivalent to python's t[i:j]

Class List

Class List represents a Python list, and the methods available faithfully reproduce the Python API for lists. A List is a Sequence.

The List Interface

List inherits from Sequence.

Type Name Comment
explicit List (PyObject *pyob, bool owned = false)
List (const Object& ob)
List (int size = 0) Create a list of the given size. Items initialized to Py_None. Default is an empty list.
List (const Sequence& s) Create a list from any sequence.
List& operator= (const Object& rhs)
List& operator= (PyObject* rhsp)
List getSlice (int i, int j) const
void setSlice (int i, int j, const Object& v)
void append (const Object& ob)
void insert (int i, const Object& ob)
void sort () Sorts the list in place, using Python's member function. You can also use the STL sort function on any List instance.
void reverse () Reverses the list in place, using Python's member function.

Mappings

A class MapBase<T> is used as the base class for Python objects with a mapping behavior. The key behavior of this class is the ability to set and use items by subscripting with strings. A proxy class mapref<T> is defined to produce the correct behavior for both use and assignment.

For convenience, Mapping is a typedef for MapBase<Object>.

The MapBase<T> interface

MapBase<T> inherits from Object. T should be chosen to reflect the kind of element returned by the mapping.

Type Name Comment
T operator[](const std::string& key) const
mapref<T> operator[](const std::string& key)
int length () const Number of entries.
int hasKey (const std::string& s) const Is m[s] defined?
T getItem (const std::string& s) const m[s]
virtual void setItem (const std::string& s, const Object& ob) m[s] = ob
void delItem (const std::string& s) del m[s]
void delItem (const Object& s)
List keys () const A list of the keys.
List values () const A list of the values.
List items () const Each item is a key-value pair.

Class Dict

Class Dict represents Python dictionarys. A Dict is a Mapping. Assignment to subscripts can be used to set the components.

Dict d
d["Paul Dubois"] = "(925)-422-5426"

Interface for Class Dict

Dict inherits from MapBase<Object>.

Type Name Comment
explicit Dict (PyObject *pyob, bool owned = false)
Dict (const Dict& ob)
Dict () Creates an empty dictionary
Dict& operator= (const Object& rhs)
Dict& operator= (PyObject* rhsp)

Other classes and facilities.

Class Callable provides an interface to those Python objects that support a call method. Class Module holds a pointer to a module. If you want to create an extension module, however, see the extension facility. There is a large set of numeric operators.

Interface to class Callable

Type Name Comment
explicit Callable (PyObject *pyob, bool owned = false)
Callable& operator= (const Object& rhs)
Callable& operator= (PyObject* rhsp)
Object apply(const Tuple& args) const Call the object with the given arguments
Object apply(PyObject* pargs = 0) const Call the object with args as the arguments. Checks that pargs is a tuple.

Interface to class Module

Type Name Comment
explicit Module (PyObject* pyob, bool owned = false)
explicit Module (const std::string name) Construct from name of module; does the import if needed.
Module (const Module& ob) Copy constructor
Module& operator= (const Object& rhs) Assignment
Module& operator= (PyObject* rhsp) Assignment

Numeric interface

Unary operators for plus and minus, and binary operators +, -, *, /, and % are defined for pairs of objects and for objects with scalar integers or doubles (in either order). Functions abs(ob) and coerce(o1, o2) are also defined.

The signature for coerce is:

inline std::pair<Object,Object> coerce(const Object& a, const Object& b)

Unlike the C API function, this simply returns the pair after coercion.

Stream I/O

Any object can be printed using stream I/O, using std::ostream& operator<< (std::ostream& os, const Object& ob). The object's str() representation is converted to a standard string which is passed to std::ostream& operator<< (std::ostream& os, const std::string&).

Exceptions

The Python exception facility and the C++ exception facility can be merged via the use of try/catch blocks in the bodies of extension objects and module functions.

Class Exception and its children

A set of classes is provided. Each is derived from class Exception, and represents a particular sort of Python exception, such as IndexError, RuntimeError, ValueError. Each of them (other than Exception) has a constructor which takes an explanatory string as an argument, and is used in a throw statement such as:

throw IndexError("Index too large in MyObject access.");

If in using a routine from the Python API, you discover that it has returned a NULL indicating an error, then Python has already set the error message. In that case you merely throw Exception.

List of Exceptions

The exception hierarchy mirrors the Python exception hierarchy. The concrete exception classes are shown here.

Type Interface for class Exception
explicit Exception()
Exception (const std::string& reason)
Exception (PyObject* exception, const std::string& reason)
void clear()
Constructors for other children of class Exception
TypeError (const std::string& reason)
IndexError (const std::string& reason)
AttributeError (const std::string& reason)
NameError (const std::string& reason)
RuntimeError (const std::string& reason)
SystemError (const std::string& reason)
KeyError (const std::string& reason)
ValueError (const std::string& reason)
OverflowError (const std::string& reason)
ZeroDivisionError (const std::string& reason)
MemoryError (const std::string& reason)
SystemExit (const std::string& reason)

Using Exceptions in extension methods

The exception facility allows you to integrate the C++ and Python exception mechanisms. To do this, you must use the style described below when writing module methods in the old C style.

Note: If using the ExtensionModule or PythonExtension mechanisms described below, the method handlers include exception handling so that you only need to use exceptions explicitly in unusual cases.

Catching Exceptions from the Python API or PyCXX.

When writing an extension module method, you can use the following boilerplate. Any exceptions caused by the Python API or PyCXX itself will be converted into a Python exception. Note that Exception is the most general of the exceptions listed above, and therefore this one catch clause will serve to catch all of them. You may wish to catch other exceptions, not in the Exception family, in the same way. If so, you need to make sure you set the error in Python before returning.

static PyObject *
some_module_method(PyObject* args)
{
    Tuple a( args ); // we know args is a Tuple
    try
    {
        ...calculate something from a...
        return ...something, usually of the form new_reference_to(some Object);
    }
    catch( const Exception& )
    {
        //Exception caught, passing it on to Python
        return None();
    }
}

How to clear an Exception

If you anticipate that an Exception may be thrown and wish to recover from it, change the catch phrase to set a reference to an Exception, and use the method clear() from class Exception to clear it.:

catch( Exception& e )
{
    e.clear();
    ...now decide what to do about it...
}

Extension Facilities

CXX/Extensions.hxx provides facilities for:

  • Creating a Python extension module
  • Creating new Python extension types

These facilities use CXX/Objects.hxx and its support file cxxsupport.cxx.

If you use CXX/Extensions.hxx you must also include source files cxxextensions.c and cxx_extensions.cxx

Creating an Python extension module

The usual method of creating a Python extension module is to declare and initialize its method table in C. This requires knowledge of the correct form for the table and the order in which entries are to be made into it, and requires casts to get everything to compile without warning. The PyCXX header file CXX/Extensions.h offers a simpler method. Here is a sample usage, in which a module named "example" is created. Note that two details are necessary:

  • The initialization function must be declared to have external C linkage and to have the expected name. This is a requirement imposed by Python
  • The ExtensionModule object must have a storage class that survives the call to the initialization function. This is most easily accomplished by using a static local inside the initialization function, as in initexample below.

To create an extension module, you inherit from class ExtensionModule templated on yourself: In the constructor, you make calls to register methods of this class with Python as extension module methods. In this example, two methods are added (this is a simplified form of the example in Demo/example.cxx):

class example_module : public ExtensionModule<example_module>
{
public:
    example_module()
    : ExtensionModule<example_module>( "example" )
    {
        add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments");
        add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite");

        initialize( "documentation for the example module" );
    }

    virtual ~example_module() {}

private:
    Object ex_sum(const Tuple &a) { ... }
    Object ex_test(const Tuple &a) { ... }
};

To initialize the extension, you just instantiate one static instance (static so it does not destroy itself!):

void initexample()
{
    static example_module* example = new example_module;
}

The methods can be written to take Tuples as arguments and return Objects. If exceptions occur they are trapped for you and a Python exception is generated. So, for example, the implementation of ex_sum might be:

Object ex_sum (const Tuple &a)
{
    Float f(0.0);
    for( int i = 0; i < a.length(); i++ )
    {
        Float g(a[i]);
        f = f + g;
    }
    return f;
}

class ExtensionModule contains methods to return itself as a Module object, or to return its dictionary.

Interface to class ExtensionModule

Type Name Comment
explicit ExtensionModule (char* name) Create an extension module named "name"
virtual ~ExtensionModule () Destructor
Dict moduleDictionary() const Returns the module dictionary; module must be initialized.
Module module() const This module as a Module.
void add_varargs_method (char *name, method_varargs_function_t method, char *documentation="") Add a method to the module.
void add_keyword_method (char *name, method_keyword_function_t method, char *documentation="" Add a method that takes keywords
void initialize() (protected, call from constructor) Initialize the module once all methods have been added.

The signatures above are:

typedef Object (T::*method_varargs_function_t)( const Tuple &args );
typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws
);

That is, the methods take a Tuple or a Tuple and a Dict, and return an Object. The example below has an & in front of the name of the method; we found one compiler that needed this.

Creating a Python extension type

One of the great things about Python is the way you can create your own object types and have Python welcome them as first-class citizens. Unfortunately, part of the way you have to do this is not great. Key to the process is the creation of a Python "type object". All instances of this type must share a reference to this one unique type object. The type object itself has a multitude of "slots" into which the addresses of functions can be added in order to give the object the desired behavior.

Creating extension objects is of course harder since you must specify how the object behaves and give it methods. This is shown in some detail in the example range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo. If you have never created a Python extension before, you should read the Extension manual first and be very familiar with Python's "special class methods". Then what follows will make more sense.

The basic idea is to inherit from PythonExtension templated on your self

class MyObject: public PythonExtension<MyObject> {...}

As a consequence:

  • MyObject is a child of PyObject, so that a MyObject* is-a PyObject*.
  • A static method check(PyObject*) is created in class MyObject. This function returns a boolean, testing whether or not the argument is in fact a pointer to an instance of MyObject.
  • The user can connect methods of MyObject to Python so that they are methods on MyObject objects. Each such method has the signature:
    Object method_name (const Tuple& args).
  • The user can override virtual methods of PythonExtension in order to set behaviors.
  • A method is created to handle the deletion of an instance if and when its reference count goes to zero. This method ensures the calling of the class destructor ~MyObject(), if any, and releases the memory (see below).
  • Both automatic and heap-based instances of MyObject can be created.

Sample usage of PythonExtension

Here is a brief overview. You create a class that inherits from PythonExtension templated upon itself. You override various methods from PythonExtension to implement behaviors, such as getattr, sequence_item, etc. You can also add methods to the object that are usable from Python using a similar scheme as for module methods above.

One of the consequences of inheriting from PythonExtension is that you are inheriting from PyObject itself. So your class is-a PyObject and instances of it can be passed to the Python C API. Note: this example uses the namespace feature of PyCXX.

Hint: You can avoid needing to specify the Py:: prefix if you include the C++ statement using Py; at the top of your files.

class range: public Py::PythonExtension<range>
{
public:
    ... constructors, data, etc.
    ... methods not callable from Python
    // initializer, see below
    static void init_type();
    // override functions from PythonExtension
    virtual Py::Object repr();
    virtual Py::Object getattr( const char *name );

    virtual int sequence_length();
    virtual Py::Object sequence_item( int i );
    virtual Py::Object sequence_concat( const Py::Object &j );
    virtual Py::Object sequence_slice( int i, int j );

    // define python methods of this object
    Py::Object amethod (const Py::Tuple& args);
    Py::Object value (const Py::Tuple& args);
    Py::Object assign (const Py::Tuple& args); 
};

To initialize the type we provide a static method that we can call from some module's initializer. We set the name, doc string, and indicate which behaviors range objects support. Then we adds the methods.

void range::init_type()
{
    behaviors().name("range");
    behaviors().doc("range objects: start, stop, step");
    behaviors().supportRepr();
    behaviors().supportGetattr();
    behaviors().supportSequenceType();

    add_varargs_method("amethod", &range::amethod,
        "demonstrate how to document amethod");
    add_varargs_method("assign", &range::assign);
    add_varargs_method("value", &range::value);

    behaviors().readyType();
}

Do not forget to add the call range::init_type() to some module's init function. You will want a method in some module that can create range objects, too.

Interface to PythonExtension <T>

Your extension class T inherits PythonExtension<T>.

Type Name Comment
virtual ~PythonExtension<T>() Destructor
PyTypeObject* type_object() const Returns the object type object.
int check (PyObject* p) Is p a T?
Protected
void add_varargs_method (char *name, method_keyword_function_t method, char *documentation="" Add a method that takes arguments
void add_keyword_method (char *name, method_keyword_function_t method, char *documentation="" Add a method that takes keywords
static PythonType& behaviors() The type object
void initialize() (protected, call from constructor) Initialize the module once all methods have been added.

As before the signatures for the methods are Object mymethod(const Tuple& args) and Object mykeywordmethod (const Tuple& args, const Dict& keys). In this case, the methods must be methods of T.

To set the behaviors of the object you override some or all of these methods from PythonExtension<T>:

virtual int print( FILE *, int );
virtual Object getattr( const char * );
virtual int setattr( const char *, const Object & );
virtual Object getattro( const Object & );
virtual int setattro( const Object &, const Object & );
virtual int compare( const Object & );
virtual int rich_compare( const Object &, int op );
virtual Object repr();
virtual Object str();
virtual long hash();
virtual Object call( const Object &, const Object & );

// Sequence methods
virtual int sequence_length();
virtual Object sequence_concat( const Object & );
virtual Object sequence_repeat( int );
virtual Object sequence_item( int );
virtual Object sequence_slice( int, int );
virtual int sequence_ass_item( int, const Object & );
virtual int sequence_ass_slice( int, int, const Object & );

// Mapping
virtual int mapping_length();
virtual Object mapping_subscript( const Object & );
virtual int mapping_ass_subscript( const Object &, const Object & );

// Number
virtual int number_nonzero();
virtual Object number_negative();
virtual Object number_positive();
virtual Object number_absolute();
virtual Object number_invert();
virtual Object number_int();
virtual Object number_float();
virtual Object number_long();
virtual Object number_oct();
virtual Object number_hex();
virtual Object number_add( const Object & );
virtual Object number_subtract( const Object & );
virtual Object number_multiply( const Object & );
virtual Object number_divide( const Object & );
virtual Object number_remainder( const Object & );
virtual Object number_divmod( const Object & );
virtual Object number_lshift( const Object & );
virtual Object number_rshift( const Object & );
virtual Object number_and( const Object & );
virtual Object number_xor( const Object & );
virtual Object number_or( const Object & );
virtual Object number_power( const Object &, const Object & );

// Buffer
virtual int buffer_getreadbuffer( int, void** );
virtual int buffer_getwritebuffer( int, void** );
virtual int buffer_getsegcount( int* );

Note that dealloc is not one of the functions you can override. That is what your destructor is for. As noted below, dealloc behavior is provided for you by PythonExtension.

Type initialization

To initialize your type, supply a static public member function that can be called from the extension module. In that function, obtain the PythonType object by calling behaviors() and apply appropriate "support" methods from PythonType to turn on the support for that behavior or set of behaviors.

void supportPrint(void);
void supportGetattr(void);
void supportSetattr(void);
void supportGetattro(void);
void supportSetattro(void);
void supportCompare(void);
void supportRichCompare(void);
void supportRepr(void);
void supportStr(void);
void supportHash(void);
void supportCall(void);

void supportSequenceType( bool support_assignment=true, bool support_inplace=false, bool support_contains=false );
void supportMappingType( bool support_assignment=true );
void supportNumberType(void);
void supportBufferType(void);

Then call add_varargs_method or add_keyword_method to add any methods desired to the object.

Notes on memory management and extension objects

Normal Python objects exist only on the heap. That is unfortunate, as object creation and destruction can be relatively expensive. Class PythonExtension allows creation of both local and heap-based objects.

If an extension object is created using operator new, as in:

range* my_r_ref = new range(1, 20, 3)

then the entity my_r_ref can be thought of as "owning" the reference created in the new object. Thus, the object will never have a reference count of zero. If the creator wishes to delete this object, they should either make sure the reference count is 1 and then do delete my_r_ref, or decrement the reference with Py_DECREF(my_r_ref).

Should my_r_ref give up ownership by being used in an Object constructor, all will still be well. When the Object goes out of scope its destructor will be called, and that will decrement the reference count, which in turn will trigger the special dealloc routine that calls the destructor and deletes the pointer.

If the object is created with automatic scope, as in:

range my_r(1, 20, 3)

then my_r can be thought of as owning the reference, and when my_r goes out of scope the object will be destroyed. Of course, care must be taken not to have kept any permanent reference to this object. Fortunately, in the case of an exception, the C++ exception facility will call the destructor of my_r. Naturally, care must be taken not to end up with a dangling reference, but such objects can be created and destroyed more efficiently than heap-based PyObjects.

Putting it all together

The Demo directory of the distribution contains an extensive example of how to use many of the facilities in PyCXX. It also serves as a test routine. This test is not completely exhaustive but does excercise much of the facility.

pycxx-7.1.4/Doc/Python3/make_contents.py000644 000765 000024 00000002626 12740671067 020455 0ustar00barrystaff000000 000000 #!/usr/bin/python3 import sys all_lines = open( 'PyCXX.html' ).readlines() all_contents = [] for line in all_lines: if( line.startswith( '

' ) nested = False indent = '' cls = 'contents_h1' for line in all_contents: tag = line[0:len('

')] contents = line[len('

PyCXX: Writing Python Extensions in C++

Writing Python Extensions in C++ with PyCXX

Contents

Acknowledgments

Thank you to Geoffrey Furnish for patiently teaching me the finer points of C++ and its template facility, and his critique of PyCXX in particular. With version 4 I welcome Barry Scott as co-author. -- Paul Dubois

Paul is no longer contributing to PyCXX. Thanks for all your great work on PyCXX Paul. -- Barry Scott.

Overview

PyCXX is designed to make it easier to extend Python with C++

PyCXX Version 6.1 and later supports both Python 2 and Python 3.

PyCXX Version 7.1 and later support the Python 3 limited API (PEP-384).

PyCXX is a set of C++ facilities to make it easier to write Python extensions. The chief way in which PyCXX makes it easier to write Python extensions is that it greatly increases the probability that your program will not make a reference-counting error and will not have to continually check error returns from the Python C API. PyCXX integrates Python with C++ in these ways:

  • C++ exception handling is relied on to detect errors and clean up. In a complicated function this is often a tremendous problem when writing in C. With PyCXX, we let the compiler keep track of what objects need to be dereferenced when an error occurs.
  • The Standard Template Library (STL) and its many algorithms plug and play with Python containers such as lists and tuples.
  • The optional CXX/Extensions.hxx facility allows you to replace the clumsy C tables with objects and method calls that define your modules and extension objects.

Download and Installation

Download PyCXX from http://sourceforge.net/projects/cxx/.

The distribution layout is:

DirectoryDescription
.Makefile for Unix and Windows, Release documentation
./CXXHeader files
./SrcSource files
./DocDocumentation
./DemoTesting and Demonstartion files

To use PyCXX you use its include files and add its source routines to your module.

Installation:

  • Install the PyCXX files into a directory of your choice. For example:
    Windows: C:\PyCXX
    Unix: /usr/local/PyCXX
  • Tell your compiler where the PyCXX header files are:
    Windows: cl /I=C:\PyCXX ...
    Unix: g++ -I/usr/local/PyCXX ...
  • Include PyCXX headers files in your code using the CXX prefix:
    #include "CXX/Objects.hxx"

The header file CXX/config.h may need to be adjusted for the compiler you use. As of this writing, only a fairly obscure reference to part of the standard library needs this adjustment. Unlike prior releases, PyCXX now assumes namespace support and a standard C++ library.

Example code

The Demo directory of the distribution contains examples of how to use many of the facilities in PyCXX.

In the top level folder of the PyCXX distributions are a number of makefiles that can be used to build and run the example code.

For example on Linux example_linux_py30.mak will build and run the example code.

make -f example_linux_py30.mak clean test
SourceDescription
Demo/test_simple.py, Demo/simple.cxxThe simplest code needed to create a module and classes in C++.
Demo/test_example.py, Demo/example.cxxThe original PyCXX example code. It is now the main test suite for PyCXX.
Demo/range.hxx, Demo/range.cxxImpliments the range object use by example.cxx.

PyCXX - Supporting Python 3 limited API (PEP-384)

Starting with Python 3.4 and PyCXX 7.1.0 it is possible to create extensions that use the Python limited API. (It was not possible to support Python 3.3)

Choose the oldest version of python that you want support and the binary extension will run in that version and all the newer versions.

Define Py_LIMITED_API when compiling all your code and the PyCXX code.

The value of Py_LIMITED_API is the first python version that you want to support.

  • Python 3.4 or later: Defined Py_LIMITED_API as 0x03040000
  • Python 3.5 or later: Defined Py_LIMITED_API as 0x03050000
  • etc.

Note: Some of the PyCXX API cannot be supported in the Py_LIMITED_API mode. The header files only include classes and functions that can be supported.

PyCXX - Supporting Python 2 and Python 3

It is possible to have common code that can be compiled to work with Python 2 or Python 3.

Define PYCXX_PYTHON_2TO3 to turn on the compatibility support. When compiling against Python 2 this means faking up the Python 3 API and when compiling against Python 3 faking the old Python 2 API.

The changes from Python 2 to Python 3 that require code changes are:

  • string is unicode only in Python 3 - Py::String API changed to match python 3 usage
  • byte is for byte date in Python 3 - Py::Bytes added to PyCXX
  • int has been removed - Py::Int has been removed from PyCXX

This means that you will need to:

  • Replace Py::Nothing with Py::None - required
  • Replace Py::Int with Py::Long - recommended
  • Replace Py::LongLong with Py::Long - recommended
  • Replace as_std_string() with as_std_string( "encoding" ) or as_std_string( NULL ) - required
  • Replace Py::String that holds non unicode data with Py::Bytes - required

Use of namespaces

All PyCXX assets are in namespace "Py". You need to include the Py:: prefix when referring to them, or include the statement:

using namespace Py;

Wrapper for standard objects: <CXX/Objects.hxx>

Header file CXX/Objects.hxx requires adding file Src/cxxsupport.cxx and Src/IndirectPythonInterface.cxx to your module sources. CXX/Objects.hxx provides a set of wrapper classes that allow you access to most of the Python C API using a C++ notation that closely resembles Python. For example, this Python:

d = {}
d[ "a" ] = 1
d[ "b" ] = 2
alist = d.keys()
print alist

Can be written in C++:

Py::Dict d;
Py::List alist;
d[ "a" ] = Py::Long( 1 );
d[ "b" ] = Py::Long( 2 );
alist = d.keys();
std::cout << alist << std::endl;

You can optionally use the CXX/Extensions.hxx facility described later to define Python extension modules and extension objects.

We avoid programming with Python object pointers

The essential idea is that we avoid, as much as possible, programming with pointers to Python objects, that is, variables of type PyObject *. Instead, we use instances of a family of C++ classes that represent the usual Python objects. This family is easily extendible to include new kinds of Python objects.

For example, consider the case in which we wish to write a method, taking a single integer argument, that will create a Python dict and insert into it that the integer plus one under the key value. In C we might do that as follows:

static PyObject *mymodule_addvalue( PyObject *args )
{
    PyObject *d;
    PyObject *f;
    int k;
    PyArgs_ParseTuple( args, "i", &k );
    d = PyDict_New();
    if( !d )
        return NULL;

    f = PyInt_NEW( k+1 );
    if( !f )
    {
        Py_DECREF( d ); /* have to get rid of d first */
        return NULL;
    }
    if( PyDict_SetItemString( d, "value", f ) == -1 )
    {
        Py_DECREF( f );
        Py_DECREF( d );
        return NULL;
    }

    return d;
}

If you have written a significant Python extension, this tedium looks all too familiar. The vast bulk of the coding is error checking and cleanup. Now compare the same thing written in C++ using CXX/Objects.hxx. The things with Python-like names ( Long, Dict, Tuple ) are from CXX/Objects.hxx.

static PyObject *mymodule_addvalue( PyObject *pargs )
{ 
    try
    {
        Tuple args( pargs ); 
        args.verify_length( 1 ); 

        Dict d; 
        Long k = args[0]; 
        d["value"] = k + 1;

        return new_reference_to( d ); 
    } 
    catch( const PyException & )
    { 
        return NULL;
    }
}

If there are not the right number of arguments or the argument is not an integer, an exception is thrown. In this case we choose to catch it and convert it into a Python exception. The C++ exception handling mechanism takes care all the cleanup.

Note that the creation of the Long k got the first argument and verified that it is an Long.

Just to peek ahead, if you wrote this method in an ExtensionModule-derived module of your own, it would be a method and it could be written as:

Object addvalue( const Tuple &args )
{
    args.verify_length( 1 );
    Dict d;
    Long k = args[0];
    d["value"] = k + 1;
    return d;
}

The basic concept is to wrap Python pointers

The basic concept of CXX/Objects.hxx is to create a wrapper around each PyObject * so that the reference counting can be done automatically, thus eliminating the most frequent source of errors. In addition, we can then add methods and operators so that Python objects can be manipulated in C++ much like you would in Python.

Each Object contains a PyObject * to which it owns a reference. When an Object is destroyed, it releases its ownership on the pointer. Since C++ calls the destructors on objects that are about to go out of scope, we are guaranteed that we will keep the reference counts right even if we unexpectedly leave a routine with an exception.

As a matter of philosophy, CXX/Objects.hxx prevents the creation of instances of its classes unless the instance will be a valid instance of its class. When an attempt is made to create an object that will not be valid, an exception is thrown.

Class Object represents the most general kind of Python object. The rest of the classes that represent Python objects inherit from it.

Object
Type
Float
Long
Complex
Char
Sequence -> SeqBase<T>
    String
    Tuple
    List
Mapping -> MapBase<T>
    Dict
Callable
Module

There are several constructors for each of these classes. For example, you can create an Long from an integer as in

Long s( 3 )

However, you can also create an instance of one of these classes using any PyObject * or another Object. If the corresponding Python object does not actually have the type desired, an exception is thrown. This is accomplished as follows. Class Object defines a virtual function accepts:

virtual bool accepts( PyObject *p )

The base class version of accepts returns true for any pointer p except 0. This means we can create an Object using any PyObject *, or from any other Object. However, if we attempt to create an Long from a PyObject *, the overridding version of accepts in class Long will only accept pointers that correspond to Python ints. Therefore if we have a Tuple t and we wish to get the first element and be sure it is an Long, we do

Long first_element = t[0]

This will not only accomplish the goal of extracting the first element of the Tuple t, but it will ensure that the result is an Long. If not, an exception is thrown. The exception mechanism is discussed later.

global methods

global methods
Returns Name( signature ) Comment
ObjectasObject( PyObject *p )Convert an owned Python pointer into a PyCXX Object
PyObject *Null()return (PyObject *)NULL
PyObject *new_reference_to( PyObject *p )Increment the reference count of p
PyObject *new_reference_to( const Object &g )Increment the reference count of g
ObjectNone()Return the Python None opject
ObjectTrue()Return the Python True opject
ObjectFalse()Return the Python False opject

Comparisons

PyCXX implements a full set of comparison operators (==, !=, >=, >, < <=) for the PyCXX objects.

BetweenAnd
ObjectObject
LongLong
Longlong
Longint
LongPY_LONG_LONG
FloatFloat
Floatdouble
SeqBasea<T>::iteratorSeqBase<T>::iterator
SeqBase<T>::const_iteratorSeqBase<T>::const_iterator
Sequence::iteratorSequence::iterator
Sequence::const_iteratorSequence::const_iterator
MapBase<T>::iteratorMapBase<T>::iterator
MapBase<T>::const_iteratorMapBase<T>::const_iterator
Mapping::iteratorMapping::iterator
Mapping::const_iteratorMapping::const_iterator

Class Object

Class Object serves as the base class for the other classes. Its default constructor constructs a Py_None, the unique object of Python type None. The interface to Object consists of a large number of methods corresponding to the operations that are defined for every Python object. In each case, the methods throw an exception if anything goes wrong.

There is no method corresponding to PyObject_SetItem with an arbitrary Python object as a key. Instead, create an instance of a more specific child of Object and use the appropriate facilities.

The comparison operators use the Python comparison function to compare values. The method is is available to test for absolute identity.

A conversion to standard library string type std::string is supplied using method as_string. Stream output of PyCXX Object instances uses this conversion, which in turn uses the Python object's str() representation.

All the numeric operators are defined on all possible combinations of Object, long, and double. These use the corresponding Python operators, and should the operation fail for some reason, an exception is thrown.

Dealing with pointers returned by the Python C API

Often, PyObject * pointers are acquired from some function, particularly functions in the Python C API. If you wish to make an object from the pointer returned by such a function, you need to know if the function returns you an owned or unowned reference. Unowned references are unusual but there are some cases where unowned references are returned.

Usually, Object and its children acquire a new reference when constructed from a PyObject *. This is usually not the right behavior if the reference comes from one of the Python C API calls.

If p is an owned reference, you can add the boolean true as an extra argument in the creation routine, Object( p, true ), or use the function asObject( p ) which returns an Object created using the owned reference. For example, the routine PyString_FromString returns an owned reference to a Python string object. You could write:

Object w = asObject( PyString_FromString( "my string" ) );

or using the constructor,

Object w( PyString_FromString( "my string" ), true );

In fact, you would never do this, since PyCXX has a class String and you can just say:

String w( "my string" );

Indeed, since most of the Python C API is similarly embodied in Object and its descendents, you probably will not use asObject all that often.

Class Object
Returns Name( signature ) Comment
Basic Methods
explicit Object( PyObject *pyob=Py_None, bool owned=false ) Construct from pointer.
explicit Object( const Object &ob ) Copycons; acquires an owned reference.
Object & operator=( const Object &rhs ) Acquires an owned reference.
Object & operator=( PyObject *rhsp ) Acquires an owned reference.
virtual ~Object() Releases the reference.
void increment_reference_count() Explicitly increment the count
void decrement_reference_count() Explicitly decrement count but not to zero
PyObject* operator*() const Lends the pointer
PyObject* ptr() const Lends the pointer
virtual bool accepts( PyObject *pyob ) const Would assignment of pyob to this object succeed?
std::string as_string() const str() representation
Python API Interface
int reference_count() const reference count
Type type() const associated type object
String str() const str() representation
String repr() const repr() representation
bool hasAttr( const std::string &s ) const hasattr( this, s )
Object getAttr( const std::string &s ) const getattr( this, s )
Object getItem( const Object &key ) const getitem( this, key )
long hashValue() const hash( this )
void setAttr( const std::string &s,
const Object &value )
this.s = value
void delAttr( const std::string &s ) del this.s
void delItem( const Object &key ) del this[key]
bool isCallable() const does this have callable behavior?
bool isList() const is this a Python list?
bool isMapping() const does this have mapping behaviors?
bool isNumeric() const does this have numeric behaviors?
bool isSequence() const does this have sequence behaviors?
bool isTrue() const is this true in the Python sense?
bool isType( const Type &t ) const is type( this ) == t?
bool isTuple() const is this a Python tuple?
bool isString() const is this a Python string?
bool isUnicode() const is this a Python Unicode string?
bool isDict() const is this a Python dictionary?
Comparison Operators
bool is( PyObject *pother ) const test for identity
bool is( const Object &other ) const test for identity
bool operator==( const Object &o2 ) const Comparisons use Python rich compare
bool operator!=( const Object &o2 ) const Comparisons use Python rich compare
bool operator>=( const Object &o2 ) const Comparisons use Python rich compare
bool operator<=( const Object &o2 ) const Comparisons use Python rich compare
bool operator<( const Object &o2 ) const Comparisons use Python rich compare
bool operator>( const Object &o2 ) const Comparisons use Python rich compare

The Basic Types

Corresponding to each of the basic Python types is a class that inherits from Object. Here are the interfaces for those types. Each of them inherits from Object and therefore has all of the inherited methods listed for Object. Where a virtual function is overridden in a class, the name is underlined.

Class Type

Class Type corresponds to Python type objects. There is no default constructor.

class Type
Returns Name and Signature Comments
explicit Type( PyObject *pyob, bool owned = false ) Constructor
explicit Type( const Object &ob ) Constructor
explicit Type( const Type &t ) Copycons
Type& operator=( const Object &rhs ) Assignment
Type& operator=( PyObject *rhsp ) Assignment
virtual bool accepts( PyObject *pyob ) const Uses PyType_Check

Class Long

Class Long, derived publically from Object, corresponds to Python type long. In Python, a long is an integer type of unlimited size. Implicit conversions to both double and long are provided, although the latter may of course fail if the number is actually too big. All constructors are explicit. The default constructor produces a Python long zero.

class Long
Returns Name and Signature Comments
explicit Long( PyObject *pyob, bool owned = false ) Constructor
explicit Long( const Long &ob ) Constructor
explicit Long( long v = 0L ) Construct from long
explicit Long( int v ) Contruct from int
explicit Long( const Object &ob ) Copycons
Long & operator=( const Object &rhs ) Assignment
Long & operator=( PyObject *rhsp ) Assignment
virtual bool accepts( PyObject *pyob ) const Based on PyLong_Check
double operator double() const Implicit conversion to double
long operator long() const Implicit conversion to long
Long & operator=( int v ) Assign from int
Long & operator=( long v ) Assign from long

Class Float

Class Float corresponds to Python floats, which in turn correspond to C double. The default constructor produces the Python float 0.0.

class Float
Returns Name and Signature Comments
explicit Float( PyObject *pyob, bool owned = false ) Constructor
Float( const Float &f )   Construct from float
explicit Float( double v=0.0 ) Construct from double
explicit Float( const Object &ob ) Copycons
Float& operator=( const Object &rhs ) Assignment
Float& operator=( PyObject *rhsp ) Assignment
virtual bool accepts( PyObject *pyob ) const Based on PyFloat_Check
double operator double() const Implicit conversion to double
Float & operator=( double v ) Assign from double
Float & operator=( int v ) Assign from int
Float & operator=( long v ) Assign from long
Float & operator=( const Long &iob ) Assign from Long

Sequences

PyCXX implements a quite sophisticated wrapper class for Python sequences. While every effort has been made to disguise the sophistication, it may pop up in the form of obscure compiler error messages, so in this documentation we will first detail normal usage and then discuss what is under the hood.

The basic idea is that we would like the subscript operator [] to work properly, and to be able to use STL-style iterators and STL algorithms across the elements of the sequence.

Sequences are implemented in terms of a templated base class, SeqBase<T>. The parameter T is the answer to the question, sequence of what? For Lists, for example, T is Object, because the most specific thing we know about an element of a List is simply that it is an Object.( Class List is defined below; it is a descendent of Object that holds a pointer to a Python list ). For strings, T is Char, which is a wrapper in turn of Python strings whose length is one.

For convenience, the word Sequence is a typedef of SeqBase<Object>.

General sequences

Suppose you are writing an extension module method that expects the first argument to be any kind of Python sequence, and you wish to return the length of that sequence. You might write:

static PyObject*
my_module_seqlen( PyObject *args ) {
try
    {
    Tuple t( args );       // set up a Tuple pointing to the arguments.
    if( t.length() != 1 ) 
         throw PyException( "Incorrect number of arguments to seqlen." );
    Sequence s = t[0];   // get argument and be sure it is a sequence
    return new_reference_to( Long( s.length() ) );
    }
catch( const PyException  &)
    {
    return Py_Null;
    }
}

As we will explain later, the try/catch structure converts any errors, such as the first argument not being a sequence, into a Python exception.

Subscripting

When a sequence is subscripted, the value returned is a special kind of object which serves as a proxy object. The general idea of proxy objects is discussed in Scott Meyers' book, "More Effective C++". Proxy objects are necessary because when one subscripts a sequence it is not clear whether the value is to be used or the location assigned to. Our proxy object is even more complicated than normal because a sequence reference such as s[i] is not a direct reference to the i'th object of s.

In normal use, you are not supposed to notice this magic going on behind your back. You write:

Object t;
Sequence s;
s[2] = t + s[1]

and here is what happens: s[1] returns a proxy object. Since there is no addition operator in Object that takes a proxy as an argument, the compiler decides to invoke an automatic conversion of the proxy to an Object, which returns the desired component of s. The addition takes place, and then there is an assignment operator in the proxy class created by the s[2], and that assignment operator stuffs the result into the 2 component of s.

It is possible to fool this mechanism and end up with a compiler failing to admit that a s[i] is an Object. If that happens, you can work around it by writing Object( s[i] ), which makes the desired implicit conversion, explicit.

Iterators

Each sequence class provides the following interface. The class seqref<T> is the proxy class. We omit the details of the iterator, const_iterator, and seqref<T> here. See CXX/Objects.hxx if necessary. The purpose of most of this interface is to satisfy requirements of the STL.

The SeqBase<T> Interface

SeqBase<T> inherits from Object.

class SeqBase>T<
Type Name
typedef int size_type
typedef seqref<T> reference
typedef T const_reference
typedef seqref<T>* pointer
typedef int difference_type
virtual size_type max_size() const
virtual size_type capacity() const;
virtual void swap( SeqBase<T> &c );
virtual size_type size() const;
explicit SeqBase<T>();
explicit SeqBase<T>( PyObject *pyob, bool owned = false );
explicit SeqBase<T>( const Object &ob );
SeqBase<T> & operator=( const Object &rhs );
SeqBase<T> & operator=( PyObject *rhsp );
virtual bool accepts( PyObject *pyob ) const;
size_type length() const ;
const T operator[]( size_type index ) const;
seqref<T> operator[]( size_type index );
virtual T getItem( size_type i ) const;
virtual void setItem( size_type i, const T &ob );
SeqBase<T> repeat( int count ) const;
SeqBase<T> concat( const SeqBase<T> &other ) const ;
const T front() const;
seqref<T> front();
const T back() const;
seqref<T> back();
void verify_length( size_type required_size );
void verify_length( size_type min_size, size_type max_size );
class iterator;
iterator begin();
iterator end();
class const_iterator;
const_iterator begin() const;
const_iterator end() const;

Any heir of class Object that has a sequence behavior should inherit from class SeqBase<T>, where T is specified as the type of object that represents the individual elements of the sequence. The requirements on T are that it has a constructor that takes a PyObject *as an argument, that it has a default constructor, a copy constructor, and an assignment operator. In short, any properly defined heir of Object will work.

Classes Char and String

Python strings are unusual in that they are immutable sequences of characters. However, there is no character type per se; rather, when subscripted strings return a string of length one. To simulate this, we define two classes Char and String. The Char class represents a Python string object of length one. The String class represents a Python string, and its elements make up a sequence of Char's.

The user interface for Char is limited. Unlike String, for example, it is not a sequence.

The Char interface

Char inherits from Object. Char holds a single Unicode character.

unicodestring is a typedef for std::basic_string<Py_UNICODE>

class Char
Type Name
explicit Char( PyObject *pyob, bool owned = false )
Char( const Object &ob )
Char( int v )
Char( Py_UNICODE v )
Char( const unicodestring &v )
Char & operator=( const Object &o )
Char & operator=( PyObject *p )
Char & operator=( int v )
Char & operator=( Py_UNICODE v )
Char & operator=( unicodestring &v )
operator String() const

The String Interface

String inherits from SeqBase<Char>. String holds a sequence of Unicode characters.

The following is taken from Pythons's unicode.h.

Many of these APIs take two arguments encoding and errors. These parameters encoding and errors have the same semantics as the ones of the builtin unicode() API.

Setting encoding to NULL causes the default encoding to be used.

Error handling is set by errors which may also be set to NULL meaning to use the default handling defined for the codec. Default error handling for all builtin codecs is "strict" (ValueErrors are raised).

The codecs all use a similar interface. Only deviation from the generic ones are documented.

class String
Type Name
explicit String( PyObject *pyob, bool owned = false )
String( const Object &ob )
String()
String( const char *latin1 )
String( const char *latin1, Py_ssize_t size )
String( const std::string &latin1 )
String( const std::string &v, const char *encoding, const char *error=NULL )
String( const char *s, const char *encoding, const char *error=NULL )
String( const char *s, Py_ssize_t len, const char *encoding, const char *error=NULL )
String & operator=( const Object &o )
String & operator=( PyObject *p )
String & operator=( const unicodestring &v )
size_type size() const
size_type capacity() const
unicodestring as_unicodestring() const
std::string operator std::string() const
String encode( const char *encoding, const char *error="strict" )
std::string as_std_string( const char *encoding=NULL, const char *error="strict" ) const

Classes Byte and Bytes

Bytes corresponds to the Python type byte.

The Byte interface

Byte inherits from Object. Byte holds a single 8-bit byte of data.

class Byte
Type Name
explicit Byte( PyObject *pyob, bool owned = false )
Byte( const Object &ob )
Byte( const std::string &v )
Byte( char v )
Byte & operator=( const Object &o )
Byte & operator=( PyObject *p )
Byte & operator=( const std::string &v )
Byte & operator=( char v )
operator Bytes() const

The Bytes Interface

Bytes inherits from SeqBase<Byte>. Bytes holds a sequence of 8-bit data.

class Bytes
Type Name
explicit Bytes( PyObject *pyob, bool owned = false )
Bytes( const Object &ob )
Bytes()
Bytes( const char *v )
Bytes( const char *v, Py_ssize_t size )
Bytes( const std::string &v )
Bytes( const std::string &v, Py_ssize_t size )
Bytes( const char *v )
Bytes( const char *v, Py_ssize_t size )
Bytes & operator=( const Object &o )
Bytes & operator=( PyObject *p )
Bytes & operator=( const std::string &v )
size_type size() const
size_type capacity() const
String decode( const char *encoding, const char *error="strict" )
std::string operator std::string() const
Bytes encode( const char *encoding, const char *error="strict" )
std::string as_std_string() const

Class Tuple

Class Tuple represents Python tuples. A Tuple is a Sequence. There are two kinds of constructors: one takes a PyObject *as usual, the other takes an integer number as an argument and returns a Tuple of that length, each component initialized to Py_None. The default constructor produces an empty Tuple.

Tuples are not immutable, but attempts to assign to their components will fail if the reference count is not 1. That is, it is safe to set the elements of a Tuple you have just made, but not thereafter.

Example: create a Tuple containing( 1, 2, 4 )

Tuple t( 3 );
t[0] = Long( 1 );
t[1] = Long( 2 );
t[2] = Long( 4 );

Example: create a Tuple from a list:

Dict d
...
Tuple t( d.keys() )

Tuple inherits from Sequence.. Special run-time checks prevent modification if the reference count is greater than one.

class Tuple
Type Name Comment
virtual void setItem( int offset, const Object &ob ) setItem is overridden to handle tuples properly.
explicit Tuple( PyObject *pyob, bool owned = false )
Tuple( const Object &ob )
explicit Tuple( int size = 0 ) Create a tuple of the given size. Items initialize to Py_None. Default is an empty tuple.
explicit Tuple( const Sequence &s ) Create a tuple from any sequence.
Tuple& operator=( const Object &rhs )
Tuple& operator=( PyObject *rhsp )
Tuple getSlice( int i, int j ) const Equivalent to python's t[i:j]

Class TupleN

Class TupleN is an easy way to make a Tuple of N items.

Example: create a Tuple containing( 1, 2, 4 )

TupleN t3( Long( 1 ), Long( 2 ), Long( 3 ) );

Example: create a Tuple containing( "Hello", "World" )

TupleN t2( String( "Hello" ), String( "Hello" ) );
class TupleN
Type Name Comment
  TupleN() Tuple of 0 elements
  TupleN( const Object &ob1 ) Tuple of 1 element
  TupleN( const Object &ob1, const Object &ob2 ) Tuple of 2 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3 ) Tuple of 3 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3,
        const Object &ob4 )
Tuple of 4 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3,
        const Object &ob4, const Object &ob5 )
Tuple of 5 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3,
        const Object &ob4, const Object &ob5, const Object &ob6 )
Tuple of 6 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3,
        const Object &ob4, const Object &ob5, const Object &ob6,
        const Object &ob7 )
Tuple of 7 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3,
        const Object &ob4, const Object &ob5, const Object &ob6,
        const Object &ob7, const Object &ob8 )
Tuple of 8 elements
  TupleN( const Object &ob1, const Object &ob2, const Object &ob3,
        const Object &ob4, const Object &ob5, const Object &ob6,
        const Object &ob7, const Object &ob8, const Object &ob9 )
Tuple of 9 elements

Class List

Class List represents a Python list, and the methods available faithfully reproduce the Python API for lists. A List is a Sequence.

List inherits from Sequence.

class List
Type Name Comment
explicit List( PyObject *pyob, bool owned = false )
List( const Object &ob )
List( int size = 0 ) Create a list of the given size. Items initialized to Py_None. Default is an empty list.
List( const Sequence &s ) Create a list from any sequence.
List& operator=( const Object &rhs )
List& operator=( PyObject *rhsp )
List getSlice( int i, int j ) const
void setSlice( int i, int j, const Object &v )
void append( const Object &ob )
void insert( int i, const Object &ob )
void sort() Sorts the list in place, using Python's member function. You can also use the STL sort function on any List instance.
void reverse() Reverses the list in place, using Python's member function.

Mappings

A class MapBase<T> is used as the base class for Python objects with a mapping behavior. The key behavior of this class is the ability to set and use items by subscripting with strings. A proxy class mapref<T> is defined to produce the correct behavior for both use and assignment.

For convenience, Mapping is a typedef for MapBase<Object>.

The MapBase<T> interface

MapBase<T> inherits from Object. T should be chosen to reflect the kind of element returned by the mapping.

class MapBase<T>
Type Name Comment
T operator[]( const std::string &key ) const
mapref<T> operator[]( const std::string &key )
int length() const Number of entries.
int hasKey( const std::string &s ) const Is m[s] defined?
T getItem( const std::string &s ) const m[s]
virtual void setItem( const std::string &s, const Object &ob ) m[s] = ob
void delItem( const std::string &s ) del m[s]
void delItem( const Object &s )
List keys() const A list of the keys.
List values() const A list of the values.
List items() const Each item is a key-value pair.

Class Dict

Class Dict represents Python dictionarys. A Dict is a Mapping. Assignment to subscripts can be used to set the components.

Dict d
d["Paul Dubois"] = "( 925 )-422-5426"

Dict inherits from MapBase<Object>.

class Dict
Type Name Comment
explicit Dict( PyObject *pyob, bool owned = false )
Dict( const Dict &ob )
Dict() Creates an empty dictionary
Dict& operator=( const Object &rhs )
Dict& operator=( PyObject *rhsp )

Clsss Callable.

Class Callable provides an interface to those Python objects that support a call method. Class Module holds a pointer to a module. If you want to create an extension module, however, see the extension facility. There is a large set of numeric operators.

class Callable
TypeNameComment
explicitCallable( PyObject *pyob, bool owned = false )
Callable &operator=( const Object &rhs )
Callable &operator=( PyObject *rhsp )
Objectapply( const Tuple &args ) constCall the object with the given positional arguments
Objectapply( const Tuple &args, const Dict &kwd ) constCall the object with the given positional and keyword arguments
Objectapply( PyObject *pargs = 0 ) const Call the object with args as the arguments. Checks that pargs is a tuple.

Interface to class Module

class Module
Type Name Comment
explicit Module( PyObject *pyob, bool owned = false )
explicit Module( const std::string name ) Construct from name of module; does the import if needed.
Module( const Module &ob ) Copy constructor
Module& operator=( const Object &rhs ) Assignment
Module& operator=( PyObject *rhsp ) Assignment

Numeric interface

Unary operators for plus and minus, and binary operators +, -, *, /, and % are defined for pairs of objects and for objects with scalar integers or doubles( in either order ). Functions abs( ob ) and coerce( o1, o2 ) are also defined.

The signature for coerce is:

inline std::pair<Object,Object> coerce( const Object &a, const Object &b )

Unlike the C API function, this simply returns the pair after coercion.

Stream I/O

Any object can be printed using stream I/O, using std::ostream &operator<< ( std::ostream &os, const Object &ob ). The object's str() representation is converted to a standard string which is passed to std::ostream &operator<< ( std::ostream &os, const std::string &).

Exceptions

All the standard python exceptions have a C++ equivilent that can to caught and thrown.

In addition new exceptions can be defined using PyCXX as well.

Exceptions thrown from C++ will be converted into Python exceptions when returning to Python code.

Python exceptions are converted into C++ exceptions when returning from Python code back into C++ code.

class BaseException and its children

All the Python standard exceptions are provided as C++ classes. The C++ class hierarchy mirrors the Python class hierarchy. The base of the exception hierarchy is class BaseException.

The derived exception class, such as IndexError, RuntimeError and ValueError, has a constructor which takes an explanatory string as an argument, and is used in a throw statement such as:

throw IndexError( "Index too large in MyObject access." );

You cannot throw BaseException, but you can catch it.

See the Python documentation for a list of all the standard exceptions.

List of Exceptions

The exception hierarchy mirrors the Python exception hierarchy. The concrete exception classes are shown here. With ValueError being the pattern for all the other expections.

BaseException
Type Interface for class Exception Comment
explicit BaseException()
BaseException( const std::string &reason )
BaseException( PyObject *exception, const std::string &reason )
void clear() Clear the exception.
Object errorType() Returns the type of the exception
Object errorValue() Returns the value of the exception
Python Standard Exceptions
Type Interface for class Exception
void python-standard-exception( const std::string &reason )

Using Exceptions in extension methods

The exception facility allows you to integrate the C++ and Python exception mechanisms. To do this, you must use the style described below when writing module methods in the old C style.

Note: If using the ExtensionModule or PythonExtension mechanisms described below, the method handlers include exception handling so that you only need to use exceptions explicitly in unusual cases.

Catching Exceptions from the Python API or PyCXX.

In the example, some_method, any expections raise from the C++ will be automatically converted into Python exceptions.

Object
some_method( Object &args )
{
    Tuple a( args ); // we know args is a Tuple

    if( a.length() != 2 )
    {
        throw AttributeError( "2 arguments expected" );
    }

    // do something useful
    // and return a result

    return result;
}

And in this example the call_python method is calling back into python and handling ArithmeticError from the "func". Any other expections will be passed back to Python.

The exceptions error type and error value can be obtained with the errorType() and errorValue() functions.

Object
cal_python( Object &args )
{
    Tuple a( args ); // we know args is a Tuple
    Callable func( a[0] );   // first arg expected to be a python callable

    ...
    Tuple call_args( 1 );
    call_args[0] = Long( 42 );
    try
    {
        Object result = func.apply( call_args );
    }
    catch( ArithmeticError &e )
    {
        Object err_type = e.errorType();
        Object err_value = e.errorValue();

        // get the text of the error for reporting
        String message = err_value.str();

        // handle error
        e.clear();
    }

    return result;
}

How to clear an Exception

If you anticipate that an Exception may be thrown and wish to recover from it then add a try/catch block for the expected exception. Then use the method clear() to tell python that the expection has been handled.

catch( ValueError &e )
{
    // handle expection
    e.clear();
}

Extension Facilities

CXX/Extensions.hxx provides facilities for:

  • Creating a Python extension module
  • Creating new Python extension types

These facilities use CXX/Objects.hxx and its support file cxxsupport.cxx.

If you use CXX/Extensions.hxx you must also include source files cxxextensions.c and cxx_extensions.cxx

Creating an Python extension module

The usual method of creating a Python extension module is to declare and initialize its method table in C. This requires knowledge of the correct form for the table and the order in which entries are to be made into it, and requires casts to get everything to compile without warning. The PyCXX header file CXX/Extensions.h offers a simpler method. Here is a sample usage, in which a module named "example" is created. Note that two details are necessary:

  • The initialization function must be declared to have external C linkage and to have the expected name. This is a requirement imposed by Python
  • The ExtensionModule object must have a storage class that survives the call to the initialization function. This is most easily accomplished by using a static local inside the initialization function, as in initexample below.

To create an extension module, you inherit from class ExtensionModule templated on yourself: In the constructor, you make calls to register methods of this class with Python as extension module methods. In this example, two methods are added( this is a simplified form of the example in Demo/example.cxx ):

class example_module : public ExtensionModule<example_module>
{
public:
    example_module()
    : ExtensionModule<example_module>( "example" )
    {
        add_varargs_method( "sum", &example_module::ex_sum, "sum( arglist ) = sum of arguments" );
        add_varargs_method( "test", &example_module::ex_test, "test( arglist ) runs a test suite" );

        initialize( "documentation for the example module" );
    }

    virtual ~example_module() {}

private:
    Object ex_sum( const Tuple &a ) { ... }
    Object ex_test( const Tuple &a ) { ... }
};

To initialize the extension, you just instantiate one static instance( static so it does not destroy itself! ):

void initexample()
{
    static example_module* example = new example_module;
}

The methods can be written to take Tuples as arguments and return Objects. If exceptions occur they are trapped for you and a Python exception is generated. So, for example, the implementation of ex_sum might be:

Object ex_sum( const Tuple &a )
{
    Float f( 0.0 );
    for( int i = 0; i < a.length(); i++ )
    {
        Float g( a[i] );
        f = f + g;
    }
    return f;
}

class ExtensionModule contains methods to return itself as a Module object, or to return its dictionary.

class ExtensionModule
Type Name Comment
explicit ExtensionModule( char* name ) Create an extension module named "name"
virtual ~ExtensionModule() Destructor
Dict moduleDictionary() const Returns the module dictionary; module must be initialized.
Module module() const This module as a Module.
void add_varargs_method( char *name, method_varargs_function_t method, char *documentation="" ) Add a method to the module.
void add_keyword_method( char *name, method_keyword_function_t method, char *documentation="" Add a method that takes keywords
void initialize()( protected, call from constructor ) Initialize the module once all methods have been added.

The signatures above are:

typedef Object( T::*method_varargs_function_t )( const Tuple &args );
typedef Object( T::*method_keyword_function_t )( const Tuple &args, const Dict &kws
 );

That is, the methods take a Tuple or a Tuple and a Dict, and return an Object. The example below has an &in front of the name of the method; we found one compiler that needed this.

Creating a Python extension type

One of the great things about Python is the way you can create your own object types and have Python welcome them as first-class citizens. Unfortunately, part of the way you have to do this is not great. Key to the process is the creation of a Python "type object". All instances of this type must share a reference to this one unique type object. The type object itself has a multitude of "slots" into which the addresses of functions can be added in order to give the object the desired behavior.

Creating extension objects is of course harder since you must specify how the object behaves and give it methods. This is shown in some detail in the example range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo. If you have never created a Python extension before, you should read the Extension manual first and be very familiar with Python's "special class methods". Then what follows will make more sense.

The basic idea is to inherit from PythonExtension templated on your self

class MyObject: public PythonExtension<MyObject> {...}

As a consequence:

  • MyObject is a child of PyObject, so that a MyObject* is-a PyObject*.
  • A static method check( PyObject * ) is created in class MyObject. This function returns a boolean, testing whether or not the argument is in fact a pointer to an instance of MyObject.
  • The user can connect methods of MyObject to Python so that they are methods on MyObject objects. Each such method has the signature:
    Object method_name( const Tuple &args ).
  • The user can override virtual methods of PythonExtension in order to set behaviors.
  • A method is created to handle the deletion of an instance if and when its reference count goes to zero. This method ensures the calling of the class destructor ~MyObject(), if any, and releases the memory( see below ).
  • Both automatic and heap-based instances of MyObject can be created.

Sample usage of PythonExtension

Here is a brief overview. You create a class that inherits from PythonExtension templated upon itself. You override various methods from PythonExtension to implement behaviors, such as getattr, sequence_item, etc. You can also add methods to the object that are usable from Python using a similar scheme as for module methods above.

One of the consequences of inheriting from PythonExtension is that you are inheriting from PyObject itself. So your class is-a PyObject and instances of it can be passed to the Python C API. Note: this example uses the namespace feature of PyCXX.

Hint: You can avoid needing to specify the Py:: prefix if you include the C++ statement using Py; at the top of your files.

class range: public Py::PythonExtension<range>
{
public:
    ... constructors, data, etc.
    ... methods not callable from Python
    // initializer, see below
    static void init_type();
    // override functions from PythonExtension
    virtual Py::Object repr();
    virtual Py::Object getattr( const char *name );

    virtual int sequence_length();
    virtual Py::Object sequence_item( int i );
    virtual Py::Object sequence_concat( const Py::Object &j );
    virtual Py::Object sequence_slice( int i, int j );

    // define python methods of this object
    Py::Object amethod( const Py::Tuple &args );
    Py::Object value( const Py::Tuple &args );
    Py::Object assign( const Py::Tuple &args ); 
};

To initialize the type we provide a static method that we can call from some module's initializer. We set the name, doc string, and indicate which behaviors range objects support. Then we adds the methods.

void range::init_type()
{
    behaviors().name( "range" );
    behaviors().doc( "range objects: start, stop, step" );
    behaviors().supportRepr();
    behaviors().supportGetattr();
    behaviors().supportSequenceType();

    add_varargs_method( "amethod", &range::amethod, "demonstrate how to document amethod" );
    add_varargs_method( "assign", &range::assign );
    add_varargs_method( "value", &range::value );

    behaviors().readyType();
}

Do not forget to add the call range::init_type() to some module's init function. You will want a method in some module that can create range objects, too.

Your extension class T inherits PythonExtension<T>.

class PythonExtension<T>
Type Name Comment
virtual ~PythonExtension<T>() Destructor
PyTypeObject* type_object() const Returns the object type object.
int check( PyObject *p ) Is p a T?
Protected
void add_varargs_method( char *name, method_keyword_function_t method, char *documentation="" Add a method that takes arguments
void add_keyword_method( char *name, method_keyword_function_t method, char *documentation="" Add a method that takes keywords
static PythonType& behaviors() The type object
void initialize()( protected, call from constructor ) Initialize the module once all methods have been added.

As before the signatures for the methods are Object mymethod( const Tuple &args ) and Object mykeywordmethod( const Tuple &args, const Dict &keys ). In this case, the methods must be methods of T.

To set the behaviors of the object you override some or all of these methods from PythonExtension<T>:

virtual int print( FILE *, int );
virtual Object getattr( const char * );
virtual int setattr( const char *, const Object &);
virtual Object getattro( const Object &);
virtual int setattro( const Object &, const Object &);
virtual int compare( const Object &);
virtual Object repr();
virtual Object str();
virtual long hash();
virtual Object call( const Object &, const Object &);

// Sequence methods
virtual int sequence_length();
virtual Object sequence_concat( const Object &);
virtual Object sequence_repeat( int );
virtual Object sequence_item( int );
virtual Object sequence_slice( int, int );
virtual int sequence_ass_item( int, const Object &);
virtual int sequence_ass_slice( int, int, const Object &);

// Mapping
virtual int mapping_length();
virtual Object mapping_subscript( const Object &);
virtual int mapping_ass_subscript( const Object &, const Object &);

// Number
virtual int number_nonzero();
virtual Object number_negative();
virtual Object number_positive();
virtual Object number_absolute();
virtual Object number_invert();
virtual Object number_int();
virtual Object number_float();
virtual Object number_long();
virtual Object number_oct();
virtual Object number_hex();
virtual Object number_add( const Object &);
virtual Object number_subtract( const Object &);
virtual Object number_multiply( const Object &);
virtual Object number_divide( const Object &);
virtual Object number_remainder( const Object &);
virtual Object number_divmod( const Object &);
virtual Object number_lshift( const Object &);
virtual Object number_rshift( const Object &);
virtual Object number_and( const Object &);
virtual Object number_xor( const Object &);
virtual Object number_or( const Object &);
virtual Object number_power( const Object &, const Object &);

// Buffer
virtual int buffer_getreadbuffer( int, void** );
virtual int buffer_getwritebuffer( int, void** );
virtual int buffer_getsegcount( int* );

Note that dealloc is not one of the functions you can override. That is what your destructor is for. As noted below, dealloc behavior is provided for you by PythonExtension.

Type initialization

To initialize your type, supply a static public member function that can be called from the extension module. In that function, obtain the PythonType object by calling behaviors() and apply appropriate "support" methods from PythonType to turn on the support for that behavior or set of behaviors.

void supportPrint( void );
void supportGetattr( void );
void supportSetattr( void );
void supportGetattro( void );
void supportSetattro( void );
void supportCompare( void );
void supportRepr( void );
void supportStr( void );
void supportHash( void );
void supportCall( void );

void supportSequenceType( int methods_to_support=
                        support_sequence_length |
                        support_sequence_repeat |
                        support_sequence_item |
                        support_sequence_slice |
                        support_sequence_concat );
void supportMappingType( int methods_to_support=
                        support_mapping_length |
                        support_mapping_subscript );
void supportNumberType( int methods_to_support=
                support_number_add |
                support_number_subtract |
                support_number_multiply |
                support_number_remainder |
                support_number_divmod |
                support_number_power |
                support_number_negative |
                support_number_positive |
                support_number_absolute |
                support_number_invert |
                support_number_lshift |
                support_number_rshift |
                support_number_and |
                support_number_xor |
                support_number_or |
                support_number_int |
                support_number_float,
            int inplace_methods_to_support=0
             );
void supportBufferType(  int methods_to_support=
                    support_buffer_getbuffer |
                    support_buffer_releasebuffer );

Then call add_varargs_method or add_keyword_method to add any methods desired to the object.

Notes on memory management and extension objects

Normal Python objects exist only on the heap. That is unfortunate, as object creation and destruction can be relatively expensive. Class PythonExtension allows creation of both local and heap-based objects.

If an extension object is created using operator new, as in:

range* my_r_ref = new range( 1, 20, 3 )

then the entity my_r_ref can be thought of as "owning" the reference created in the new object. Thus, the object will never have a reference count of zero. If the creator wishes to delete this object, they should either make sure the reference count is 1 and then do delete my_r_ref, or decrement the reference with Py_DECREF( my_r_ref ).

Should my_r_ref give up ownership by being used in an Object constructor, all will still be well. When the Object goes out of scope its destructor will be called, and that will decrement the reference count, which in turn will trigger the special dealloc routine that calls the destructor and deletes the pointer.

If the object is created with automatic scope, as in:

range my_r( 1, 20, 3 )

then my_r can be thought of as owning the reference, and when my_r goes out of scope the object will be destroyed. Of course, care must be taken not to have kept any permanent reference to this object. Fortunately, in the case of an exception, the C++ exception facility will call the destructor of my_r. Naturally, care must be taken not to end up with a dangling reference, but such objects can be created and destroyed more efficiently than heap-based PyObjects.

pycxx-7.1.4/RegressionTests/mem-leak.py000644 000765 000024 00000001161 11523511652 020365 0ustar00barrystaff000000 000000 import simple import time import sys import os def report( title ): print( title ) os.system( 'ps uww -p %d' % (os.getpid(),) ) report( 'Start:' ) if sys.argv[1] == 'encode': for x in range( 1000000 ): y = '%6d-Hello-%6d' % (x, x) else: for x in range( 1000000 ): y = ('%6d-Hello-%6d' % (x, x)).encode( 'utf-8' ) report( 'InitDone:' ) if sys.argv[1] == 'encode': for x in range( 1000000 ): y = simple.encode_test( '%6d-Hello-%6d' % (x, x) ) else: for x in range( 1000000 ): y = simple.decode_test( ('%6d-Hello-%6d' % (x, x)).encode( 'utf-8' ) ) report( 'Done:' ) pycxx-7.1.4/Lib/__init__.py000644 000765 000024 00000004410 12711370232 015774 0ustar00barrystaff000000 000000 #----------------------------------------------------------------------------- # # Copyright (c) 1998 - 2007, The Regents of the University of California # Produced at the Lawrence Livermore National Laboratory # All rights reserved. # # This file is part of PyCXX. For details,see http:#cxx.sourceforge.net/. The # full copyright notice is contained in the file COPYRIGHT located at the root # of the PyCXX distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the disclaimer below. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the disclaimer (as noted below) in the # documentation and/or materials provided with the distribution. # - Neither the name of the UC/LLNL nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF # CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # #----------------------------------------------------------------------------- print( """CXX is installed. The support files you need are in the PYTHON/etc/CXX directory. The include files are in the distutils include path already. Just refer to them as "CXX/CXX_Objects.h", etc. """ ) pycxx-7.1.4/CXX/Exception.hxx000644 000765 000024 00000004352 11146066410 016314 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "CXX/Python2/Exception.hxx" #else #include "CXX/Python3/Exception.hxx" #endif pycxx-7.1.4/CXX/Extensions.hxx000644 000765 000024 00000004354 11146066410 016517 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "CXX/Python2/Extensions.hxx" #else #include "CXX/Python3/Extensions.hxx" #endif pycxx-7.1.4/CXX/IndirectPythonInterface.hxx000644 000765 000024 00000000252 11146072165 021141 0ustar00barrystaff000000 000000 #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "CXX/Python2/IndirectPythonInterface.hxx" #else #include "CXX/Python3/IndirectPythonInterface.hxx" #endif pycxx-7.1.4/CXX/Python3/000755 000765 000024 00000000000 13664720516 015200 5ustar00barrystaff000000 000000 pycxx-7.1.4/CXX/Python2/000755 000765 000024 00000000000 13664720516 015177 5ustar00barrystaff000000 000000 pycxx-7.1.4/CXX/Objects.hxx000644 000765 000024 00000004346 11146066410 015752 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if PY_MAJOR_VERSION == 2 #include "CXX/Python2/Objects.hxx" #else #include "CXX/Python3/Objects.hxx" #endif pycxx-7.1.4/CXX/Version.hxx000644 000765 000024 00000004666 13660477654 016036 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __PyCXX_version_hxx__ #define __PyCXX_version_hxx__ #define PYCXX_VERSION_MAJOR 7 #define PYCXX_VERSION_MINOR 1 #define PYCXX_VERSION_PATCH 4 #define PYCXX_MAKEVERSION( major, minor, patch ) ((major<<16)|(minor<<8)|(patch)) #define PYCXX_VERSION PYCXX_MAKEVERSION( PYCXX_VERSION_MAJOR, PYCXX_VERSION_MINOR, PYCXX_VERSION_PATCH ) #endif pycxx-7.1.4/CXX/Config.hxx000644 000765 000024 00000004536 12754334502 015575 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #include "CXX/WrapPython.h" #if defined( PYCXX_6_2_COMPATIBILITY ) typedef int PyCxx_ssize_t; #else typedef Py_ssize_t PyCxx_ssize_t; #endif #if PY_MAJOR_VERSION == 2 #include "CXX/Python2/Config.hxx" #else #include "CXX/Python3/Config.hxx" #endif pycxx-7.1.4/CXX/CxxDebug.hxx000644 000765 000024 00000004313 12754100607 016067 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #if PY_MAJOR_VERSION == 2 #include "CXX/Python2/CxxDebug.hxx" #else #include "CXX/Python3/CxxDebug.hxx" #endif pycxx-7.1.4/CXX/WrapPython.h000644 000765 000024 00000005561 11771611632 016122 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __PyCXX_wrap_python_hxx__ #define __PyCXX_wrap_python_hxx__ // On some platforms we have to include time.h to get select defined #if !defined(__WIN32__) && !defined(WIN32) && !defined(_WIN32) && !defined(_WIN64) #include #endif // Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h #if defined(__sun) || defined(sun) #if defined(_XPG4) #undef _XPG4 #endif #endif // Python.h will redefine these and generate warning in the process #undef _XOPEN_SOURCE #undef _POSIX_C_SOURCE // pull in python definitions #include // fix issue with Python assuming that isspace, toupper etc are macros #if defined(isspace) #undef isspace #undef isupper #undef islower #undef isalnum #undef isalpha #undef toupper #undef tolower #endif #endif pycxx-7.1.4/CXX/Python2/Exception.hxx000644 000765 000024 00000013403 13146323403 017654 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Exception_h #define __CXX_Exception_h #include "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Python2/Config.hxx" #include "CXX/Python2/CxxDebug.hxx" #include "CXX/Python2/IndirectPythonInterface.hxx" #include #include // This mimics the Python structure, in order to minimize confusion namespace Py { class ExtensionExceptionType; class Object; class BaseException { public: BaseException( ExtensionExceptionType &exception, const std::string &reason ); BaseException( ExtensionExceptionType &exception, Object &reason ); BaseException( PyObject *exception, Object &reason ); BaseException( PyObject *exception, const std::string &reason ); explicit BaseException(); void clear(); // clear the error // is the exception this specific exception 'exc' bool matches( ExtensionExceptionType &exc ); }; #if defined( PYCXX_6_2_COMPATIBILITY ) class Exception : public BaseException { public: Exception( ExtensionExceptionType &exception, const std::string &reason ) : BaseException( exception, reason ) {} Exception( ExtensionExceptionType &exception, Object &reason ) : BaseException( exception, reason ) {} Exception( PyObject *exception, Object &reason ) : BaseException ( exception, reason ) {} Exception( PyObject *exception, const std::string &reason ) : BaseException( exception, reason ) {} explicit Exception() : BaseException() {} }; #endif // for user defined exceptions to be made know to pycxx typedef void (*throw_exception_func_t)( void ); void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t throw_func ); #define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ class eclass : public bclass \ { \ public: \ eclass() {} \ eclass( const char *reason ) { PyErr_SetString( _Exc_##eclass(), reason ); } \ eclass( const std::string &reason ) { PyErr_SetString( _Exc_##eclass(), reason.c_str() ); } \ ~eclass() {} \ \ static void throwFunc() { throw eclass(); } \ static PyObject *exceptionType() { return _Exc_##eclass(); } \ }; \ #include #undef PYCXX_STANDARD_EXCEPTION #define PYCXX_USER_EXCEPTION_STR_ARG( uclass ) \ class uclass : public Py::BaseException \ { \ public: \ uclass( const std::string &reason ) \ : Py::BaseException( m_error, reason ) \ { } \ ~uclass() {} \ static void init( Py::ExtensionModuleBase &module ) \ { \ m_error.init( module, #uclass ); \ Py::addPythonException( m_error, throwFunc ); \ Py::Dict d( module.moduleDictionary() ); \ d[#uclass] = m_error; \ } \ private: \ uclass() : Py::BaseException() {} \ static void throwFunc() \ { \ throw uclass(); \ } \ static Py::ExtensionExceptionType m_error; \ }; \ Py::ExtensionExceptionType uclass::m_error; #define PYCXX_USER_EXCEPTION_NO_ARG( uclass ) \ class uclass : public Py::BaseException \ { \ public: \ uclass() \ : Py::BaseException() \ { } \ ~uclass() {} \ static void init( Py::ExtensionModuleBase &module ) \ { \ m_error.init( module, #uclass ); \ Py::addPythonException( m_error, throwFunc ); \ Py::Dict d( module.moduleDictionary() ); \ d[#uclass] = m_error; \ } \ private: \ static void throwFunc() \ { \ throw uclass(); \ } \ static Py::ExtensionExceptionType m_error; \ }; \ Py::ExtensionExceptionType uclass::m_error; }// Py #endif pycxx-7.1.4/CXX/Python2/Extensions.hxx000644 000765 000024 00000015625 12745352476 020105 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Extensions__h #define __CXX_Extensions__h #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // okay to ignore #pragma warning( disable: 4786 ) #endif #include "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Python2/Config.hxx" #include "CXX/Python2/CxxDebug.hxx" #include "CXX/Python2/Objects.hxx" extern "C" { extern PyObject py_object_initializer; } #include #include // ---------------------------------------------------------------------- namespace Py { class ExtensionModuleBase; // Make an Exception Type for use in raising custom exceptions class ExtensionExceptionType : public Object { public: ExtensionExceptionType(); virtual ~ExtensionExceptionType(); // call init to create the type void init( ExtensionModuleBase &module, const std::string &name, ExtensionExceptionType &parent ); void init( ExtensionModuleBase &module, const std::string &name ); }; class MethodTable { public: MethodTable(); virtual ~MethodTable(); void add( const char *method_name, PyCFunction f, const char *doc="", int flag=1 ); PyMethodDef *table(); protected: std::vector t; // accumulator of PyMethodDef's PyMethodDef *mt; // Actual method table produced when full static PyMethodDef method( const char* method_name, PyCFunction f, int flags=1, const char* doc="" ); private: // // prevent the compiler generating these unwanted functions // MethodTable( const MethodTable &m ); //unimplemented void operator=( const MethodTable &m ); //unimplemented }; // end class MethodTable // Note: Python calls noargs as varargs buts args==NULL extern "C" typedef PyObject *(*method_noargs_call_handler_t)( PyObject *_self, PyObject * ); extern "C" typedef PyObject *(*method_varargs_call_handler_t)( PyObject *_self, PyObject *_args ); extern "C" typedef PyObject *(*method_keyword_call_handler_t)( PyObject *_self, PyObject *_args, PyObject *_dict ); template class MethodDefExt { public: typedef Object (T::*method_noargs_function_t)(); typedef Object (T::*method_varargs_function_t)( const Tuple &args ); typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); // NOARGS MethodDefExt ( const char *_name, method_noargs_function_t _function, method_noargs_call_handler_t _handler, const char *_doc ) { ext_meth_def.ml_name = const_cast( _name ); ext_meth_def.ml_meth = reinterpret_cast( _handler ); ext_meth_def.ml_flags = METH_NOARGS; ext_meth_def.ml_doc = const_cast( _doc ); ext_noargs_function = _function; ext_varargs_function = NULL; ext_keyword_function = NULL; } // VARARGS MethodDefExt ( const char *_name, method_varargs_function_t _function, method_varargs_call_handler_t _handler, const char *_doc ) { ext_meth_def.ml_name = const_cast( _name ); ext_meth_def.ml_meth = reinterpret_cast( _handler ); ext_meth_def.ml_flags = METH_VARARGS; ext_meth_def.ml_doc = const_cast( _doc ); ext_noargs_function = NULL; ext_varargs_function = _function; ext_keyword_function = NULL; } // VARARGS + KEYWORD MethodDefExt ( const char *_name, method_keyword_function_t _function, method_keyword_call_handler_t _handler, const char *_doc ) { ext_meth_def.ml_name = const_cast( _name ); ext_meth_def.ml_meth = reinterpret_cast( _handler ); ext_meth_def.ml_flags = METH_VARARGS|METH_KEYWORDS; ext_meth_def.ml_doc = const_cast( _doc ); ext_noargs_function = NULL; ext_varargs_function = NULL; ext_keyword_function = _function; } ~MethodDefExt() {} PyMethodDef ext_meth_def; method_noargs_function_t ext_noargs_function; method_varargs_function_t ext_varargs_function; method_keyword_function_t ext_keyword_function; Object py_method; }; } // Namespace Py #include "CXX/Python2/ExtensionModule.hxx" #include "CXX/Python2/PythonType.hxx" #include "CXX/Python2/ExtensionTypeBase.hxx" #include "CXX/Python2/ExtensionOldType.hxx" #include "CXX/Python2/ExtensionType.hxx" // End of CXX_Extensions.h #endif pycxx-7.1.4/CXX/Python2/IndirectPythonInterface.hxx000644 000765 000024 00000011224 13437177573 022523 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ #define __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ #include "CXX/WrapPython.h" namespace Py { bool InitialisePythonIndirectInterface(); // // Wrap Exception variables as function calls // PyObject * _Exc_BaseException(); #define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ PyObject * _Exc_##eclass(); #include "CXX/Python2/cxx_standard_exceptions.hxx" #undef PYCXX_STANDARD_EXCEPTION // // Wrap Object variables as function calls // PyObject * _None(); PyObject * _False(); PyObject * _True(); // // Wrap Type variables as function calls // PyTypeObject * _List_Type(); bool _List_Check( PyObject *o ); PyTypeObject * _Buffer_Type(); bool _Buffer_Check( PyObject *op ); PyTypeObject * _Class_Type(); bool _Class_Check( PyObject *op ); PyTypeObject * _Instance_Type(); bool _Instance_Check( PyObject *op ); PyTypeObject * _Method_Type(); bool _Method_Check( PyObject *op ); PyTypeObject * _CObject_Type(); bool _CObject_Check( PyObject *op ); PyTypeObject * _Complex_Type(); bool _Complex_Check( PyObject *op ); PyTypeObject * _Dict_Type(); bool _Dict_Check( PyObject *op ); PyTypeObject * _File_Type(); bool _File_Check( PyObject *op ); PyTypeObject * _Float_Type(); bool _Float_Check( PyObject *op ); PyTypeObject * _Frame_Type(); bool _Frame_Check( PyObject *op ); PyTypeObject * _Function_Type(); bool _Function_Check( PyObject *op ); PyTypeObject * _Bool_Type(); bool _Boolean_Check( PyObject *op ); PyTypeObject * _Int_Type(); bool _Int_Check( PyObject *op ); PyTypeObject * _List_Type(); bool _List_Check( PyObject *op ); PyTypeObject * _Long_Type(); bool _Long_Check( PyObject *op ); PyTypeObject * _CFunction_Type(); bool _CFunction_Check( PyObject *op ); PyTypeObject * _Module_Type(); bool _Module_Check( PyObject *op ); PyTypeObject * _Type_Type(); bool _Type_Check( PyObject *op ); PyTypeObject * _Range_Type(); bool _Range_Check( PyObject *op ); PyTypeObject * _Slice_Type(); bool _Slice_Check( PyObject *op ); PyTypeObject * _String_Type(); bool _String_Check( PyObject *op ); PyTypeObject * _TraceBack_Type(); bool _TraceBack_Check( PyObject *v ); PyTypeObject * _Tuple_Type(); bool _Tuple_Check( PyObject *op ); #if PY_MAJOR_VERSION >= 2 PyTypeObject * _Unicode_Type(); bool _Unicode_Check( PyObject *op ); #endif int &_Py_DebugFlag(); int &_Py_InteractiveFlag(); int &_Py_OptimizeFlag(); int &_Py_NoSiteFlag(); int &_Py_TabcheckFlag(); int &_Py_VerboseFlag(); void _XINCREF( PyObject *op ); void _XDECREF( PyObject *op ); char *__Py_PackageContext(); } #endif // __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ pycxx-7.1.4/CXX/Python2/ExtensionTypeBase.hxx000644 000765 000024 00000020656 13662723705 021353 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionTypeBase__h #define __CXX_ExtensionTypeBase__h namespace Py { // Class PythonExtension is what you inherit from to create // a new Python extension type. You give your class itself // as the template paramter. // There are two ways that extension objects can get destroyed. // 1. Their reference count goes to zero // 2. Someone does an explicit delete on a pointer. // In(1) the problem is to get the destructor called // We register a special deallocator in the Python type object // (see behaviors()) to do this. // In(2) there is no problem, the dtor gets called. // PythonExtension does not use the usual Python heap allocator, // instead using new/delete. We do the setting of the type object // and reference count, usually done by PyObject_New, in the // base class ctor. // This special deallocator does a delete on the pointer. class PythonExtensionBase : public PyObject { public: PythonExtensionBase(); virtual ~PythonExtensionBase(); public: // object virtual void reinit( Tuple &args, Dict &kwds ); // object basics virtual int print( FILE *, int ); virtual Object getattr( const char * ); virtual int setattr( const char *, const Object & ); virtual Object getattro( const String & ); Object genericGetAttro( const String & ); virtual int setattro( const String &, const Object & ); int genericSetAttro( const String &, const Object & ); virtual int compare( const Object & ); virtual Object rich_compare( const Object &, int ); virtual Object repr(); virtual Object str(); virtual long hash(); virtual Object call( const Object &, const Object & ); virtual Object iter(); virtual PyObject *iternext(); // Sequence methods virtual PyCxx_ssize_t sequence_length(); virtual Object sequence_concat( const Object & ); virtual Object sequence_repeat( Py_ssize_t ); virtual Object sequence_item( Py_ssize_t ); virtual Object sequence_slice( Py_ssize_t, Py_ssize_t ); virtual int sequence_ass_item( Py_ssize_t, const Object & ); virtual int sequence_ass_slice( Py_ssize_t, Py_ssize_t, const Object & ); virtual Object sequence_inplace_concat( const Object & ); virtual Object sequence_inplace_repeat( Py_ssize_t ); virtual int sequence_contains( const Object & ); // Mapping virtual PyCxx_ssize_t mapping_length(); virtual Object mapping_subscript( const Object & ); virtual int mapping_ass_subscript( const Object &, const Object & ); // Number virtual int number_nonzero(); virtual Object number_negative(); virtual Object number_positive(); virtual Object number_absolute(); virtual Object number_invert(); virtual Object number_int(); virtual Object number_float(); virtual Object number_long(); virtual Object number_oct(); virtual Object number_hex(); virtual Object number_add( const Object & ); virtual Object number_subtract( const Object & ); virtual Object number_multiply( const Object & ); virtual Object number_divide( const Object & ); virtual Object number_remainder( const Object & ); virtual Object number_divmod( const Object & ); virtual Object number_lshift( const Object & ); virtual Object number_rshift( const Object & ); virtual Object number_and( const Object & ); virtual Object number_xor( const Object & ); virtual Object number_or( const Object & ); virtual Object number_power( const Object &, const Object & ); // Buffer virtual Py_ssize_t buffer_getreadbuffer( Py_ssize_t, void** ); virtual Py_ssize_t buffer_getwritebuffer( Py_ssize_t, void** ); virtual Py_ssize_t buffer_getsegcount( Py_ssize_t* ); public: // helper functions to call function fn_name with 0 to 9 args Object callOnSelf( const std::string &fn_name ); Object callOnSelf( const std::string &fn_name, const Object &arg1 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8, const Object &arg9 ); public: virtual PyObject *selfPtr() = 0; virtual Object self() = 0; private: void missing_method( void ); static PyObject *method_call_handler( PyObject *self, PyObject *args ); }; } // Namespace Py // End of __CXX_ExtensionTypeBase__h #endif pycxx-7.1.4/CXX/Python2/ExtensionType.hxx000644 000765 000024 00000034244 13662723705 020556 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionClass__h #define __CXX_ExtensionClass__h #define PYCXX_NOARGS_METHOD_NAME( NAME ) _callNoArgsMethod__##NAME #define PYCXX_VARARGS_METHOD_NAME( NAME ) _callVarArgsMethod__##NAME #define PYCXX_KEYWORDS_METHOD_NAME( NAME ) _callKeywordsMethod__##NAME #define PYCXX_NOARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_NOARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *, PyObject * ) \ { \ try \ { \ Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ Py::Object r( (self->NAME)() ); \ return Py::new_reference_to( r.ptr() ); \ } \ catch( Py::BaseException & ) \ { \ return 0; \ } \ } #define PYCXX_VARARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_VARARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject * ) \ { \ try \ { \ Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ Py::Tuple a( _a ); \ Py::Object r( (self->NAME)( a ) ); \ return Py::new_reference_to( r.ptr() ); \ } \ catch( Py::BaseException & ) \ { \ return 0; \ } \ } #define PYCXX_KEYWORDS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_KEYWORDS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject *_k ) \ { \ try \ { \ Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ Py::Tuple a( _a ); \ Py::Dict k; \ if( _k != NULL ) \ k = _k; \ Py::Object r( (self->NAME)( a, k ) ); \ return Py::new_reference_to( r.ptr() ); \ } \ catch( Py::BaseException & ) \ { \ return 0; \ } \ } // need to support METH_STATIC and METH_CLASS #define PYCXX_ADD_NOARGS_METHOD( PYNAME, NAME, docs ) \ add_method( #PYNAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) #define PYCXX_ADD_VARARGS_METHOD( PYNAME, NAME, docs ) \ add_method( #PYNAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) #define PYCXX_ADD_KEYWORDS_METHOD( PYNAME, NAME, docs ) \ add_method( #PYNAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) namespace Py { extern PythonExtensionBase *getPythonExtensionBase( PyObject *self ); struct PythonClassInstance { PyObject_HEAD PythonExtensionBase *m_pycxx_object; }; class ExtensionClassMethodsTable { public: ExtensionClassMethodsTable() : m_methods_table( new PyMethodDef[ METHOD_TABLE_SIZE_INCREMENT ] ) , m_methods_used( 0 ) , m_methods_size( METHOD_TABLE_SIZE_INCREMENT ) { // add the sentinel marking the table end PyMethodDef *p = &m_methods_table[ 0 ]; p->ml_name = NULL; p->ml_meth = NULL; p->ml_flags = 0; p->ml_doc = NULL; } ~ExtensionClassMethodsTable() { delete[] m_methods_table; } // check that all methods added are unique void check_unique_method_name( const char *_name ) { std::string name( _name ); for( int i=0; iml_name = const_cast( name ); p->ml_meth = function; p->ml_flags = flags; p->ml_doc = const_cast( doc ); m_methods_used++; p++; // add the sentinel marking the table end p->ml_name = NULL; p->ml_meth = NULL; p->ml_flags = 0; p->ml_doc = NULL; return m_methods_table; } private: enum {METHOD_TABLE_SIZE_INCREMENT = 1}; PyMethodDef *m_methods_table; int m_methods_used; int m_methods_size; }; template class PythonClass : public PythonExtensionBase { protected: explicit PythonClass( PythonClassInstance *self, Tuple &/*args*/, Dict &/*kwds*/ ) : PythonExtensionBase() , m_class_instance( self ) { } virtual ~PythonClass() {} static ExtensionClassMethodsTable &methodTable() { static ExtensionClassMethodsTable *method_table; if( method_table == NULL ) method_table = new ExtensionClassMethodsTable; return *method_table; } static void add_method( const char *name, PyCFunction function, int flags, const char *doc=NULL ) { behaviors().set_methods( methodTable().add_method( name, function, flags, doc ) ); } static PythonType &behaviors() { static PythonType *p; if( p == NULL ) { #if defined( _CPPRTTI ) || defined( __GNUG__ ) const char *default_name = (typeid( T )).name(); #else const char *default_name = "unknown"; #endif p = new PythonType( sizeof( PythonClassInstance ), 0, default_name ); p->set_tp_new( extension_object_new ); p->set_tp_init( extension_object_init ); p->set_tp_dealloc( extension_object_deallocator ); // we are a class p->supportClass(); // always support get and set attr p->supportGetattro(); p->supportSetattro(); } return *p; } static PyObject *extension_object_new( PyTypeObject *subtype, PyObject * /*args*/, PyObject * /*kwds*/ ) { #ifdef PYCXX_DEBUG std::cout << "extension_object_new()" << std::endl; #endif PythonClassInstance *o = reinterpret_cast( subtype->tp_alloc( subtype, 0 ) ); if( o == NULL ) return NULL; o->m_pycxx_object = NULL; PyObject *self = reinterpret_cast( o ); #ifdef PYCXX_DEBUG std::cout << "extension_object_new() => self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << std::endl; #endif return self; } static int extension_object_init( PyObject *_self, PyObject *args_, PyObject *kwds_ ) { try { Py::Tuple args( args_ ); Py::Dict kwds; if( kwds_ != NULL ) kwds = kwds_; PythonClassInstance *self = reinterpret_cast( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_init( self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << " )" << std::endl; std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif if( self->m_pycxx_object == NULL ) { self->m_pycxx_object = new T( self, args, kwds ); #ifdef PYCXX_DEBUG std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif } else { #ifdef PYCXX_DEBUG std::cout << " reinit - self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif self->m_pycxx_object->reinit( args, kwds ); } } catch( BaseException & ) { return -1; } return 0; } static void extension_object_deallocator( PyObject *_self ) { PythonClassInstance *self = reinterpret_cast< PythonClassInstance * >( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_deallocator( self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << " )" << std::endl; std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif delete self->m_pycxx_object; _self->ob_type->tp_free( _self ); } public: static PyTypeObject *type_object() { return behaviors().type_object(); } static Object type() { return Object( reinterpret_cast( behaviors().type_object() ) ); } static bool check( PyObject *p ) { // is p a me or a derived me switch( PyObject_IsInstance( p, reinterpret_cast( type_object() ) ) ) { default: case -1: throw Exception(); case 0: return false; case 1: return true; } } static bool check( const Object &ob ) { return check( ob.ptr() ); } virtual PyObject *selfPtr() { return reinterpret_cast( m_class_instance ); } virtual Object self() { return Object( reinterpret_cast( m_class_instance ) ); } protected: private: PythonClassInstance *m_class_instance; private: // // prevent the compiler generating these unwanted functions // explicit PythonClass( const PythonClass &other ); void operator=( const PythonClass &rhs ); }; // // ExtensionObject is an Object that will accept only T's. // template class PythonClassObject: public Object { public: explicit PythonClassObject( PyObject *pyob ) : Object( pyob ) { validate(); } PythonClassObject( const PythonClassObject &other ) : Object( *other ) { validate(); } PythonClassObject( const Object &other ) : Object( *other ) { validate(); } PythonClassObject &operator=( const Object &rhs ) { *this = *rhs; return *this; } PythonClassObject &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return( pyob && T::check( pyob ) ); } // // Obtain a pointer to the PythonExtension object // T *getCxxObject( void ) { return dynamic_cast< T * >( getPythonExtensionBase( ptr() ) ); } }; } // Namespace Py // End of __CXX_ExtensionClass__h #endif pycxx-7.1.4/CXX/Python2/Objects.hxx000644 000765 000024 00000277457 13662723705 017350 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Objects__h #define __CXX_Objects__h #include "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Config.hxx" #include "CXX/Exception.hxx" #include #include STR_STREAM #include #include #include #include #include namespace Py { void ifPyErrorThrowCxxException(); typedef PyCxx_ssize_t sequence_index_type; // type of an index into a sequence // Forward declarations class Object; class Type; template class SeqBase; class String; class List; template class MapBase; class Tuple; class Dict; // new_reference_to also overloaded below on Object inline PyObject* new_reference_to(PyObject* p) { Py::_XINCREF(p); return p; } // returning Null() from an extension method triggers a // Python exception inline PyObject* Null() { return (static_cast(0)); } //===========================================================================// // class Object // The purpose of this class is to serve as the most general kind of // Python object, for the purpose of writing C++ extensions in Python // Objects hold a PyObject* which they own. This pointer is always a // valid pointer to a Python object. In children we must maintain this behavior. // // Instructions on how to make your own class MyType descended from Object: // (0) Pick a base class, either Object or perhaps SeqBase or MapBase. // This example assumes Object. // (1) Write a routine int MyType_Check (PyObject *) modeled after PyInt_Check, // PyFloat_Check, etc. // (2) Add method accepts: // virtual bool accepts (PyObject *pyob) const { // return pyob && MyType_Check (pyob); // } // (3) Include the following constructor and copy constructor // /* explicit MyType (PyObject *pyob): Object(pyob) { validate(); } MyType(const Object& other): Object(other.ptr()) { validate(); } */ // Alernate version for the constructor to allow for construction from owned pointers: /* explicit MyType (PyObject *pyob) : Object(pyob) { validate(); } */ // You may wish to add other constructors; see the classes below for examples. // Each constructor must use "set" to set the pointer // and end by validating the pointer you have created. // (4) Each class needs at least these two assignment operators: /* MyType& operator= (const Object& rhs) { return (*this = *rhs); } Mytype& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set(rhsp); return *this; } */ // Note on accepts: constructors call the base class // version of a virtual when calling the base class constructor, // so the test has to be done explicitly in a descendent. // If you are inheriting from PythonExtension to define an object // note that it contains PythonExtension::check // which you can use in accepts when writing a wrapper class. // See Demo/range.h and Demo/range.cxx for an example. class Object { private: // the pointer to the Python object // Only Object sets this directly. // The default constructor for Object sets it to Py_None and // child classes must use "set" to set it // PyObject* p; protected: void set (PyObject* pyob, bool owned = false) { release(); p = pyob; if (!owned) { Py::_XINCREF (p); } validate(); } void release () { Py::_XDECREF (p); p = 0; } void validate(); public: // Constructor acquires new ownership of pointer unless explicitly told not to. explicit Object (PyObject* pyob=Py::_None(), bool owned = false) : p(pyob) { if(!owned) { Py::_XINCREF (p); } validate(); } // Copy constructor acquires new ownership of pointer Object (const Object& ob) : p(ob.p) { Py::_XINCREF (p); validate(); } // Assignment acquires new ownership of pointer Object& operator= (const Object& rhs) { set(rhs.p); return *this; } Object& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Destructor virtual ~Object () { release (); } // Loaning the pointer to others, retain ownership PyObject* operator* () const { return p; } // Explicit reference_counting changes void increment_reference_count() { Py::_XINCREF(p); } void decrement_reference_count() { // not allowed to commit suicide, however if(reference_count() == 1) throw RuntimeError("Object::decrement_reference_count error."); Py::_XDECREF(p); } // Would like to call this pointer() but messes up STL in SeqBase PyObject* ptr () const { return p; } // // Queries // // Can pyob be used in this object's constructor? virtual bool accepts (PyObject *) const { // allow any object or NULL return true; } Py_ssize_t reference_count () const { // the reference count return p ? p->ob_refcnt : 0; } Type type () const; // the type object associated with this one String str () const; // the str() representation std::string as_string() const; String repr () const; // the repr () representation List dir () const; // the dir() list bool hasAttr (const std::string& s) const { return PyObject_HasAttrString (p, const_cast(s.c_str())) ? true: false; } Object getAttr (const std::string& s) const { return Object (PyObject_GetAttrString (p, const_cast(s.c_str())), true); } Object callMemberFunction( const std::string& function_name ) const; Object callMemberFunction( const std::string& function_name, const Tuple &args ) const; Object callMemberFunction( const std::string& function_name, const Tuple &args, const Dict &kw ) const; Object getItem (const Object& key) const { return Object (PyObject_GetItem(p, *key), true); } long hashValue () const { return PyObject_Hash (p); } // convert to bool bool as_bool() const { return PyObject_IsTrue( ptr() ) != 0; } bool is(PyObject *pother) const { // identity test return p == pother; } bool is(const Object& other) const { // identity test return p == other.p; } bool isNull() const { return p == NULL; } bool isNone() const { return p == _None(); } bool isCallable () const { return PyCallable_Check (p) != 0; } bool isInstance () const { return PyInstance_Check (p) != 0; } bool isDict () const { return Py::_Dict_Check (p); } bool isList () const { return Py::_List_Check (p); } bool isMapping () const { return PyMapping_Check (p) != 0; } bool isNumeric () const { return PyNumber_Check (p) != 0; } bool isSequence () const { return PySequence_Check (p) != 0; } bool isTrue () const { return PyObject_IsTrue (p) != 0; } bool isType (const Type& t) const; bool isTuple() const { return Py::_Tuple_Check(p); } bool isString() const { return Py::_String_Check(p) || Py::_Unicode_Check(p); } bool isUnicode() const { return Py::_Unicode_Check( p ); } bool isBoolean() const { return Py::_Boolean_Check( p ); } // Commands void setAttr (const std::string& s, const Object& value) { if(PyObject_SetAttrString (p, const_cast(s.c_str()), *value) == -1) ifPyErrorThrowCxxException(); } void delAttr (const std::string& s) { if(PyObject_DelAttrString (p, const_cast(s.c_str())) == -1) ifPyErrorThrowCxxException(); } // PyObject_SetItem is too weird to be using from C++ // so it is intentionally omitted. void delItem (const Object& key) { if(PyObject_DelItem(p, *key) == -1) ifPyErrorThrowCxxException(); } // Equality and comparison use PyObject_RichCompareBool bool operator==(const Object& o2) const { int k = PyObject_RichCompareBool (p, *o2, Py_EQ); ifPyErrorThrowCxxException(); return k != 0; } bool operator!=(const Object& o2) const { int k = PyObject_RichCompareBool (p, *o2, Py_NE); ifPyErrorThrowCxxException(); return k != 0; } bool operator>=(const Object& o2) const { int k = PyObject_RichCompareBool (p, *o2, Py_GE); ifPyErrorThrowCxxException(); return k != 0; } bool operator<=(const Object& o2) const { int k = PyObject_RichCompareBool (p, *o2, Py_LE); ifPyErrorThrowCxxException(); return k != 0; } bool operator<(const Object& o2) const { int k = PyObject_RichCompareBool (p, *o2, Py_LT); ifPyErrorThrowCxxException(); return k != 0; } bool operator>(const Object& o2) const { int k = PyObject_RichCompareBool (p, *o2, Py_GT); ifPyErrorThrowCxxException(); return k != 0; } }; // End of class Object inline PyObject* new_reference_to(const Object& g) { PyObject* p = g.ptr(); Py::_XINCREF(p); return p; } // Nothing() is what an extension method returns if // there is no other return value. inline Object Nothing() { return Object(Py::_None()); } // Python special None value inline Object None() { return Object(Py::_None()); } // Python special Boolean values inline Object False() { return Object(Py::_False()); } inline Object True() { return Object(Py::_True()); } // TMM: 31May'01 - Added the #ifndef so I can exlude iostreams. #ifndef CXX_NO_IOSTREAMS std::ostream& operator<< (std::ostream& os, const Object& ob); #endif // Class Type class Type: public Object { public: explicit Type (PyObject* pyob, bool owned = false): Object(pyob, owned) { validate(); } Type (const Object& ob): Object(*ob) { validate(); } Type(const Type& t): Object(t) { validate(); } Type& operator= (const Object& rhs) { return (*this = *rhs); } Type& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Type_Check (pyob); } }; // // Convert an owned Python pointer into a CXX Object // inline Object asObject (PyObject *p) { return Object(p, true); } // =============================================== // class boolean class Boolean: public Object { public: // Constructor Boolean (PyObject *pyob, bool owned = false) : Object (pyob, owned) { validate(); } Boolean (const Boolean& ob): Object(*ob) { validate(); } // create from bool Boolean (bool v=false) { set(PyBool_FromLong(v ? 1 : 0), true); validate(); } explicit Boolean (const Object& ob) : Object( *ob ) { validate(); } // Assignment increases reference count on pointer Boolean& operator= (const Object& rhs) { return (*this = *rhs); } Boolean& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && PyObject_IsTrue(pyob) != -1; } // convert to long operator bool() const { return PyObject_IsTrue (ptr()) != 0; } Boolean& operator= (bool v) { set (PyBool_FromLong (v ? 1 : 0), true); return *this; } }; // =============================================== // class Int class Int: public Object { public: // Constructor Int (PyObject *pyob, bool owned = false): Object (pyob, owned) { validate(); } Int (const Int& ob): Object(*ob) { validate(); } // create from long Int (long v = 0L): Object(PyInt_FromLong(v), true) { validate(); } // create from int Int (int v) { long w = v; set(PyInt_FromLong(w), true); validate(); } // create from bool Int (bool v) { long w = v ? 1 : 0; set(PyInt_FromLong(w), true); validate(); } explicit Int (const Object& ob) { set(PyNumber_Int(*ob), true); validate(); } // Assignment acquires new ownership of pointer Int& operator= (const Object& rhs) { return (*this = *rhs); } Int& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (PyNumber_Int(rhsp), true); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Int_Check (pyob); } // convert to long operator long() const { return PyInt_AsLong (ptr()); } #ifdef HAVE_LONG_LONG // convert to long long PY_LONG_LONG asLongLong() const { return PyLong_AsLongLong (ptr()); } // convert to unsigned long long unsigned PY_LONG_LONG asUnsignedLongLong() const { return PyLong_AsUnsignedLongLong (ptr()); } #endif // assign from an int Int& operator= (int v) { set (PyInt_FromLong (long(v)), true); return *this; } // assign from long Int& operator= (long v) { set (PyInt_FromLong (v), true); return *this; } #ifdef HAVE_LONG_LONG // assign from long long Int& operator= (PY_LONG_LONG v) { set (PyLong_FromLongLong (v), true); return *this; } // assign from unsigned long long Int& operator= (unsigned PY_LONG_LONG v) { set (PyLong_FromUnsignedLongLong (v), true); return *this; } #endif }; // =============================================== // class Long class Long: public Object { public: // Constructor explicit Long (PyObject *pyob, bool owned = false) : Object (pyob, owned) { validate(); } Long (const Long& ob) : Object(ob.ptr()) { validate(); } // try to create from any object explicit Long (const Object& ob) : Object(PyNumber_Long(*ob), true) { validate(); } // create from long explicit Long (long v = 0L) : Object(PyLong_FromLong(v), true) { validate(); } // create from unsigned long explicit Long (unsigned long v) : Object(PyLong_FromUnsignedLong(v), true) { validate(); } // create from int explicit Long (int v) : Object(PyLong_FromLong(static_cast(v)), true) { validate(); } #ifdef HAVE_LONG_LONG // create from long long explicit Long( PY_LONG_LONG v ) : Object( PyLong_FromLongLong( v ), true ) { validate(); } // create from unsigned long long explicit Long( unsigned PY_LONG_LONG v ) : Object( PyLong_FromUnsignedLongLong( v ), true ) { validate(); } #endif // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Long_Check (pyob); } // Assignment acquires new ownership of pointer Long& operator= (const Object& rhs) { return *this = *rhs; } Long& operator= (PyObject* rhsp) { if(ptr() != rhsp) set (PyNumber_Long(rhsp), true); return *this; } // assign from an int Long& operator= (int v) { set(PyLong_FromLong (long(v)), true); return *this; } // assign from long Long& operator= (long v) { set(PyLong_FromLong (v), true); return *this; } // assign from unsigned long Long& operator= (unsigned long v) { set(PyLong_FromUnsignedLong (v), true); return *this; } #ifdef HAVE_LONG_LONG Long &operator=( PY_LONG_LONG v ) { set( PyLong_FromLongLong( v ), true ); return *this; } Long &operator=( unsigned PY_LONG_LONG v ) { set( PyLong_FromUnsignedLongLong( v ), true ); return *this; } #endif // convert to long long as_long() const { return PyLong_AsLong( ptr() ); } operator long() const { return as_long(); } operator int() const { return static_cast( as_long() ); } // convert to unsigned long as_unsigned_long() const { return PyLong_AsUnsignedLong( ptr() ); } // convert to unsigned operator unsigned long() const { return as_unsigned_long(); } double as_double() const { return PyLong_AsDouble( ptr() ); } operator double() const { return as_double(); } #ifdef HAVE_LONG_LONG PY_LONG_LONG as_long_long() const { return PyLong_AsLongLong( ptr() ); } operator PY_LONG_LONG() const { return as_long_long(); } unsigned PY_LONG_LONG as_unsigned_long_long() const { return PyLong_AsUnsignedLongLong( ptr() ); } operator unsigned PY_LONG_LONG() const { return as_unsigned_long_long(); } #endif // prefix ++ Long operator++() { set( PyNumber_Add( ptr(), *Long( 1 ) ) ); return *this; } // postfix ++ Long operator++( int ) { Long a = *this; set( PyNumber_Add( ptr(), *Long( 1 ) ) ); return a; } // prefix -- Long operator--() { set( PyNumber_Subtract( ptr(), *Long( 1 ) ) ); return *this; } // postfix -- Long operator--( int ) { Long a = *this; set( PyNumber_Subtract( ptr(), *Long( 1 ) ) ); return a; } }; #ifdef HAVE_LONG_LONG // =============================================== // class LongLong class LongLong: public Object { public: // Constructor explicit LongLong (PyObject *pyob, bool owned = false): Object (pyob, owned) { validate(); } LongLong (const LongLong& ob): Object(ob.ptr()) { validate(); } // create from long long explicit LongLong (PY_LONG_LONG v = 0L) : Object(PyLong_FromLongLong(v), true) { validate(); } // create from unsigned long long explicit LongLong (unsigned PY_LONG_LONG v) : Object(PyLong_FromUnsignedLongLong(v), true) { validate(); } // create from long explicit LongLong (long v) : Object(PyLong_FromLongLong(v), true) { validate(); } // create from unsigned long explicit LongLong (unsigned long v) : Object(PyLong_FromUnsignedLongLong(v), true) { validate(); } // create from int explicit LongLong (int v) : Object(PyLong_FromLongLong(static_cast(v)), true) { validate(); } // try to create from any object LongLong (const Object& ob) : Object(PyNumber_Long(*ob), true) { validate(); } // Assignment acquires new ownership of pointer LongLong& operator= (const Object& rhs) { return (*this = *rhs); } LongLong& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (PyNumber_Long(rhsp), true); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Long_Check (pyob); } // convert to long long operator PY_LONG_LONG() const { return PyLong_AsLongLong (ptr()); } // convert to unsigned long operator unsigned PY_LONG_LONG() const { return PyLong_AsUnsignedLongLong (ptr()); } // convert to long operator long() const { return PyLong_AsLong (ptr()); } // convert to unsigned operator unsigned long() const { return PyLong_AsUnsignedLong (ptr()); } operator double() const { return PyLong_AsDouble (ptr()); } // assign from an int LongLong& operator= (int v) { set(PyLong_FromLongLong (long(v)), true); return *this; } // assign from long long LongLong& operator= (PY_LONG_LONG v) { set(PyLong_FromLongLong (v), true); return *this; } // assign from unsigned long long LongLong& operator= (unsigned PY_LONG_LONG v) { set(PyLong_FromUnsignedLongLong (v), true); return *this; } // assign from long LongLong& operator= (long v) { set(PyLong_FromLongLong (v), true); return *this; } // assign from unsigned long LongLong& operator= (unsigned long v) { set(PyLong_FromUnsignedLongLong (v), true); return *this; } }; #endif // =============================================== // class Float // class Float: public Object { public: // Constructor explicit Float (PyObject *pyob, bool owned = false): Object(pyob, owned) { validate(); } Float (const Float& f): Object(f) { validate(); } // make from double explicit Float (double v=0.0) : Object(PyFloat_FromDouble (v), true) { validate(); } // try to make from any object Float (const Object& ob) : Object(PyNumber_Float(*ob), true) { validate(); } Float& operator= (const Object& rhs) { return (*this = *rhs); } Float& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (PyNumber_Float(rhsp), true); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Float_Check (pyob); } // convert to double operator double () const { return PyFloat_AsDouble (ptr()); } // assign from a double Float& operator= (double v) { set(PyFloat_FromDouble (v), true); return *this; } // assign from an int Float& operator= (int v) { set(PyFloat_FromDouble (double(v)), true); return *this; } // assign from long Float& operator= (long v) { set(PyFloat_FromDouble (double(v)), true); return *this; } // assign from an Int Float& operator= (const Int& iob) { set(PyFloat_FromDouble (double(long(iob))), true); return *this; } }; // =============================================== // class Complex class Complex: public Object { public: // Constructor explicit Complex (PyObject *pyob, bool owned = false): Object(pyob, owned) { validate(); } Complex (const Complex& f): Object(f) { validate(); } // make from double explicit Complex (double v=0.0, double w=0.0) :Object(PyComplex_FromDoubles (v, w), true) { validate(); } Complex& operator= (const Object& rhs) { return (*this = *rhs); } Complex& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Complex_Check (pyob); } // convert to Py_complex operator Py_complex () const { return PyComplex_AsCComplex (ptr()); } // assign from a Py_complex Complex& operator= (const Py_complex& v) { set(PyComplex_FromCComplex (v), true); return *this; } // assign from a double Complex& operator= (double v) { set(PyComplex_FromDoubles (v, 0.0), true); return *this; } // assign from an int Complex& operator= (int v) { set(PyComplex_FromDoubles (double(v), 0.0), true); return *this; } // assign from long Complex& operator= (long v) { set(PyComplex_FromDoubles (double(v), 0.0), true); return *this; } // assign from an Int Complex& operator= (const Int& iob) { set(PyComplex_FromDoubles (double(long(iob)), 0.0), true); return *this; } double real() const { return PyComplex_RealAsDouble(ptr()); } double imag() const { return PyComplex_ImagAsDouble(ptr()); } }; // Sequences // Sequences are here represented as sequences of items of type T. // The base class SeqBase represents that. // In basic Python T is always "Object". // seqref is what you get if you get elements from a non-const SeqBase. // Note: seqref could probably be a nested class in SeqBase but that might stress // some compilers needlessly. Simlarly for mapref later. // While this class is not intended for enduser use, it needs some public // constructors for the benefit of the STL. // See Scott Meyer's More Essential C++ for a description of proxies. // This application is even more complicated. We are doing an unusual thing // in having a double proxy. If we want the STL to work // properly we have to compromise by storing the rvalue inside. The // entire Object API is repeated so that things like s[i].isList() will // work properly. // Still, once in a while a weird compiler message may occur using expressions like x[i] // Changing them to Object(x[i]) helps the compiler to understand that the // conversion of a seqref to an Object is wanted. template class seqref { protected: SeqBase& s; // the sequence sequence_index_type offset; // item number T the_item; // lvalue public: seqref (SeqBase& seq, sequence_index_type j) : s(seq), offset(j), the_item (s.getItem(j)) {} seqref (const seqref& range) : s(range.s), offset(range.offset), the_item(range.the_item) {} // TMM: added this seqref ctor for use with STL algorithms seqref (Object& obj) : s(dynamic_cast< SeqBase&>(obj)) , offset( 0 ) , the_item(s.getItem(offset)) {} ~seqref() {} operator T() const { // rvalue return the_item; } seqref& operator=(const seqref& rhs) { //used as lvalue the_item = rhs.the_item; s.setItem(offset, the_item); return *this; } seqref& operator=(const T& ob) { // used as lvalue the_item = ob; s.setItem(offset, ob); return *this; } // forward everything else to the item PyObject* ptr () const { return the_item.ptr(); } int reference_count () const { // the reference count return the_item.reference_count(); } Type type () const { return the_item.type(); } String str () const; String repr () const; bool hasAttr (const std::string& attr_name) const { return the_item.hasAttr(attr_name); } Object getAttr (const std::string& attr_name) const { return the_item.getAttr(attr_name); } Object getItem (const Object& key) const { return the_item.getItem(key); } long hashValue () const { return the_item.hashValue(); } bool isCallable () const { return the_item.isCallable(); } bool isInstance () const { return the_item.isInstance(); } bool isDict () const { return the_item.isDict(); } bool isList () const { return the_item.isList(); } bool isMapping () const { return the_item.isMapping(); } bool isNumeric () const { return the_item.isNumeric(); } bool isSequence () const { return the_item.isSequence(); } bool isTrue () const { return the_item.isTrue(); } bool isType (const Type& t) const { return the_item.isType (t); } bool isTuple() const { return the_item.isTuple(); } bool isString() const { return the_item.isString(); } // Commands void setAttr (const std::string& attr_name, const Object& value) { the_item.setAttr(attr_name, value); } void delAttr (const std::string& attr_name) { the_item.delAttr(attr_name); } void delItem (const Object& key) { the_item.delItem(key); } bool operator==(const Object& o2) const { return the_item == o2; } bool operator!=(const Object& o2) const { return the_item != o2; } bool operator>=(const Object& o2) const { return the_item >= o2; } bool operator<=(const Object& o2) const { return the_item <= o2; } bool operator<(const Object& o2) const { return the_item < o2; } bool operator>(const Object& o2) const { return the_item > o2; } }; // end of seqref // class SeqBase // ...the base class for all sequence types template class SeqBase: public Object { public: // STL definitions typedef PyCxx_ssize_t size_type; typedef seqref reference; typedef T const_reference; typedef seqref* pointer; typedef int difference_type; typedef T value_type; // TMM: 26Jun'01 virtual size_type max_size() const { return static_cast( std::string::npos ); // why this constant - its not from python? } virtual size_type capacity() const { return size(); } virtual void swap( SeqBase &c ) { SeqBase temp = c; c = ptr(); set(temp.ptr()); } virtual size_type size() const { return PySequence_Length (ptr()); } explicit SeqBase () : Object( PyTuple_New( 0 ), true ) { validate(); } explicit SeqBase (PyObject* pyob, bool owned=false) : Object( pyob, owned ) { validate(); } SeqBase (const Object& ob): Object(ob) { validate(); } // Assignment acquires new ownership of pointer SeqBase& operator= (const Object& rhs) { return (*this = *rhs); } SeqBase& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } virtual bool accepts (PyObject *pyob) const { return pyob && PySequence_Check (pyob); } Py_ssize_t length () const { return PySequence_Length (ptr()); } // Element access const T operator[](sequence_index_type index) const { return getItem(index); } seqref operator[](sequence_index_type index) { return seqref(*this, index); } virtual T getItem (sequence_index_type i) const { return T(asObject(PySequence_GetItem (ptr(), i))); } virtual void setItem (sequence_index_type i, const T& ob) { if (PySequence_SetItem (ptr(), i, *ob) == -1) { ifPyErrorThrowCxxException(); } } SeqBase repeat (int count) const { return SeqBase (PySequence_Repeat (ptr(), count), true); } SeqBase concat (const SeqBase& other) const { return SeqBase (PySequence_Concat(ptr(), *other), true); } // more STL compatability const T front () const { return getItem(0); } seqref front() { return seqref(*this, 0); } const T back() const { return getItem(size()-1); } seqref back() { return seqref(*this, size()-1); } void verify_length( size_type required_size ) const { if (size() != required_size) throw IndexError ("Unexpected SeqBase length."); } void verify_length( size_type min_size, size_type max_size ) const { size_type n = size(); if (n < min_size || n > max_size) throw IndexError ("Unexpected SeqBase length."); } class iterator: public random_access_iterator_parent(seqref) { protected: friend class SeqBase; SeqBase* seq; sequence_index_type count; public: ~iterator () {} iterator () : seq( 0 ) , count( 0 ) {} iterator (SeqBase* s, sequence_index_type where) : seq( s ) , count( where ) {} iterator (const iterator& other) : seq( other.seq ) , count( other.count ) {} bool eql (const iterator& other) const { return (seq->ptr() == other.seq->ptr()) && (count == other.count); } bool neq (const iterator& other) const { return (seq->ptr() != other.seq->ptr()) || (count != other.count); } bool lss (const iterator& other) const { return (count < other.count); } bool gtr (const iterator& other) const { return (count > other.count); } bool leq (const iterator& other) const { return (count <= other.count); } bool geq (const iterator& other) const { return (count >= other.count); } seqref operator*() { return seqref(*seq, count); } seqref operator[] (sequence_index_type i) { return seqref(*seq, count + i); } iterator& operator=(const iterator& other) { if (this == &other) return *this; seq = other.seq; count = other.count; return *this; } iterator operator+(sequence_index_type n) const { return iterator(seq, count + n); } iterator operator-(sequence_index_type n) const { return iterator(seq, count - n); } iterator& operator+=(sequence_index_type n) { count = count + n; return *this; } iterator& operator-=(sequence_index_type n) { count = count - n; return *this; } int operator-(const iterator& other) const { if (*seq != *other.seq) throw RuntimeError ("SeqBase::iterator comparison error"); return count - other.count; } // prefix ++ iterator& operator++ () { count++; return *this; } // postfix ++ iterator operator++ (int) { return iterator(seq, count++); } // prefix -- iterator& operator-- () { count--; return *this; } // postfix -- iterator operator-- (int) { return iterator(seq, count--); } std::string diagnose() const { std::OSTRSTREAM oss; oss << "iterator diagnosis " << seq << ", " << count << std::ends; return std::string(oss.str()); } }; // end of class SeqBase::iterator iterator begin () { return iterator(this, 0); } iterator end () { return iterator(this, length()); } class const_iterator : public random_access_iterator_parent(const Object) { protected: friend class SeqBase; const SeqBase* seq; sequence_index_type count; private: const_iterator (const SeqBase* s, sequence_index_type where) : seq( s ) , count( where ) {} public: ~const_iterator () {} const_iterator () : seq( 0 ) , count( 0 ) {} const_iterator(const const_iterator& other) : seq( other.seq ) , count( other.count ) {} const T operator*() const { return seq->getItem(count); } const T operator[] (sequence_index_type i) const { return seq->getItem(count + i); } const_iterator& operator=(const const_iterator& other) { if (this == &other) return *this; seq = other.seq; count = other.count; return *this; } const_iterator operator+(sequence_index_type n) const { return const_iterator(seq, count + n); } bool eql (const const_iterator& other) const { return (seq->ptr() == other.seq->ptr()) && (count == other.count); } bool neq (const const_iterator& other) const { return (seq->ptr() != other.seq->ptr()) || (count != other.count); } bool lss (const const_iterator& other) const { return (count < other.count); } bool gtr (const const_iterator& other) const { return (count > other.count); } bool leq (const const_iterator& other) const { return (count <= other.count); } bool geq (const const_iterator& other) const { return (count >= other.count); } const_iterator operator-(sequence_index_type n) { return const_iterator(seq, count - n); } const_iterator& operator+=(sequence_index_type n) { count = count + n; return *this; } const_iterator& operator-=(sequence_index_type n) { count = count - n; return *this; } int operator-(const const_iterator& other) const { if (*seq != *other.seq) throw RuntimeError ("SeqBase::const_iterator::- error"); return count - other.count; } // prefix ++ const_iterator& operator++ () { count++; return *this; } // postfix ++ const_iterator operator++ (int) { return const_iterator(seq, count++); } // prefix -- const_iterator& operator-- () { count--; return *this; } // postfix -- const_iterator operator-- (int) { return const_iterator(seq, count--); } }; // end of class SeqBase::const_iterator const_iterator begin () const { return const_iterator(this, 0); } const_iterator end () const { return const_iterator(this, length()); } }; // Here's an important typedef you might miss if reading too fast... typedef SeqBase Sequence; template bool operator==(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator!=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator< (const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator> (const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator<=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator>=(const EXPLICIT_TYPENAME SeqBase::iterator& left, const EXPLICIT_TYPENAME SeqBase::iterator& right); template bool operator==(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator!=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator< (const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator> (const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator<=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator>=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); extern bool operator==(const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator< (const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator> (const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right); extern bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); extern bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right); extern bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right); extern bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); extern bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right); // ================================================== // class Char // Python strings return strings as individual elements. // I'll try having a class Char which is a String of length 1 // typedef std::basic_string unicodestring; extern Py_UNICODE unicode_null_string[1]; class Char: public Object { public: explicit Char (PyObject *pyob, bool owned = false): Object(pyob, owned) { validate(); } Char (const Object& ob): Object(ob) { validate(); } Char (const std::string& v = "") :Object(PyString_FromStringAndSize( const_cast(v.c_str()), 1 ), true) { validate(); } Char (char v) : Object(PyString_FromStringAndSize (&v, 1), true) { validate(); } Char (Py_UNICODE v) : Object(PyUnicode_FromUnicode (&v, 1), true) { validate(); } // Assignment acquires new ownership of pointer Char& operator= (const Object& rhs) { return (*this = *rhs); } Char& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return (pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)) && PySequence_Length (pyob) == 1); } // Assignment from C string Char& operator= (const std::string& v) { set(PyString_FromStringAndSize (const_cast(v.c_str()),1), true); return *this; } Char& operator= (char v) { set(PyString_FromStringAndSize (&v, 1), true); return *this; } Char& operator= (const unicodestring& v) { set(PyUnicode_FromUnicode (const_cast(v.data()),1), true); return *this; } Char& operator= (Py_UNICODE v) { set(PyUnicode_FromUnicode (&v, 1), true); return *this; } long ord() { if( Py::_Unicode_Check( ptr() ) ) { Py_UNICODE *unicode = PyUnicode_AS_UNICODE( ptr() ); return static_cast( unicode[0] ); } else { unsigned char *str = reinterpret_cast( PyString_AS_STRING( ptr() ) ); return static_cast( str[0] ); } } // Conversion operator String() const; operator std::string () const { return std::string(PyString_AsString (ptr())); } }; #ifdef PYCXX_PYTHON_2TO3 // String and Bytes compatible with Python3 version in 6.0.0 PyCXX class Bytes; class String: public SeqBase { public: virtual size_type capacity() const { return max_size(); } explicit String( PyObject *pyob, bool owned = false) : SeqBase( pyob, owned ) { validate(); } String( const Object& ob): SeqBase(ob) { validate(); } String() : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) { validate(); } String( const std::string& v ) : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), v.length() ), true ) { validate(); } String( const Py_UNICODE *s, int length ) : SeqBase( PyUnicode_FromUnicode( s, length ), true ) { validate(); } String( const char *s, const char *encoding, const char *error="strict" ) : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) { validate(); } String( const char *s, int len, const char *encoding, const char *error="strict" ) : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) { validate(); } String( const std::string &s, const char *encoding, const char *error="strict" ) : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) { validate(); } String( const char *v, int vsize ) : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { validate(); } String( const char *v ) : SeqBase( PyString_FromString( v ), true ) { validate(); } // Assignment acquires new ownership of pointer String &operator=( const Object &rhs ) { return *this = *rhs; } String& operator= (PyObject *rhsp) { if( ptr() == rhsp ) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)); } // Assignment from C string String& operator=( const std::string &v ) { set( PyString_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); return *this; } String& operator=( const unicodestring &v ) { set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); return *this; } // Encode Bytes encode( const char *encoding, const char *error="strict" ) const; // Queries virtual size_type size() const { if( isUnicode() ) { return PyUnicode_GET_SIZE (ptr()); } else { return PyString_Size (ptr()); } } operator std::string() const { return as_std_string( "utf-8" ); } std::string as_std_string( const char *encoding, const char *error="strict" ) const; unicodestring as_unicodestring() const { if( isUnicode() ) { return unicodestring( PyUnicode_AS_UNICODE( ptr() ), PyUnicode_GET_SIZE( ptr() ) ); } else { throw TypeError("can only return unicodestring from Unicode object"); } } const Py_UNICODE *unicode_data() const { if( isUnicode() ) { return PyUnicode_AS_UNICODE( ptr() ); } else { throw TypeError("can only return unicode_data from Unicode object"); } } }; class Bytes: public SeqBase { public: virtual size_type capacity() const { return max_size(); } explicit Bytes (PyObject *pyob, bool owned = false) : SeqBase(pyob, owned) { validate(); } Bytes (const Object& ob): SeqBase(ob) { validate(); } Bytes() : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) { validate(); } Bytes( const std::string& v ) : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), v.length()), true ) { validate(); } Bytes( const char *v, size_type vsize ) : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { validate(); } Bytes( const char *v ) : SeqBase( PyString_FromString( v ), true ) { validate(); } // Assignment acquires new ownership of pointer Bytes &operator= ( const Object& rhs ) { return *this = *rhs; } Bytes &operator= (PyObject *rhsp) { if( ptr() == rhsp ) return *this; set (rhsp); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && (Py::_String_Check( pyob ) || Py::_Unicode_Check( pyob )); } // Assignment from C string Bytes &operator= (const std::string& v) { set( PyString_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); return *this; } Bytes &operator= (const unicodestring& v) { set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); return *this; } String decode( const char *encoding, const char *error="strict" ) { return Object( PyString_AsDecodedObject( ptr(), encoding, error ), true ); } // Queries virtual size_type size () const { if( isUnicode() ) { return PyUnicode_GET_SIZE (ptr()); } else { return PyString_Size (ptr()); } } operator std::string () const { return as_std_string(); } std::string as_std_string() const { if( isUnicode() ) { throw TypeError("cannot return std::string from Unicode object"); } else { return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); } } unicodestring as_unicodestring() const { if( isUnicode() ) { return unicodestring( PyUnicode_AS_UNICODE( ptr() ), static_cast( PyUnicode_GET_SIZE( ptr() ) ) ); } else { throw TypeError("can only return unicodestring from Unicode object"); } } }; #else // original PyCXX 5.4.x version of String class String: public SeqBase { public: virtual size_type capacity() const { return max_size(); } explicit String (PyObject *pyob, bool owned = false): SeqBase(pyob, owned) { validate(); } String (const Object& ob): SeqBase(ob) { validate(); } String() : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) { validate(); } String( const std::string& v ) : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), v.length() ), true ) { validate(); } String( const char *s, const char *encoding, const char *error="strict" ) : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) { validate(); } String( const char *s, size_type len, const char *encoding, const char *error="strict" ) : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) { validate(); } String( const std::string &s, const char *encoding, const char *error="strict" ) : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) { validate(); } String( const char *v, size_type vsize ) : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { validate(); } String( const char* v ) : SeqBase( PyString_FromString( v ), true ) { validate(); } // Assignment acquires new ownership of pointer String& operator= ( const Object& rhs ) { return *this = *rhs; } String& operator= (PyObject* rhsp) { if( ptr() == rhsp ) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)); } // Assignment from C string String& operator= (const std::string& v) { set( PyString_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); return *this; } String& operator= (const unicodestring& v) { set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); return *this; } // Encode String encode( const char *encoding, const char *error="strict" ) const { if( isUnicode() ) { return String( PyUnicode_AsEncodedString( ptr(), encoding, error ), true ); } else { return String( PyString_AsEncodedObject( ptr(), encoding, error ), true ); } } String decode( const char *encoding, const char *error="strict" ) { return Object( PyString_AsDecodedObject( ptr(), encoding, error ), true ); } // Queries virtual size_type size () const { if( isUnicode() ) { return PyUnicode_GET_SIZE (ptr()); } else { return PyString_Size (ptr()); } } operator std::string () const { return as_std_string(); } std::string as_std_string() const { if( isUnicode() ) { throw TypeError("cannot return std::string from Unicode object"); } else { return std::string( PyString_AsString( ptr() ), static_cast( PyString_Size( ptr() ) ) ); } } std::string as_std_string( const char *encoding, const char *error="strict" ) const; unicodestring as_unicodestring() const { if( isUnicode() ) { return unicodestring( PyUnicode_AS_UNICODE( ptr() ), static_cast( PyUnicode_GET_SIZE( ptr() ) ) ); } else { throw TypeError("can only return unicodestring from Unicode object"); } } }; #endif // ================================================== // class Tuple class Tuple: public Sequence { public: virtual void setItem (sequence_index_type offset, const Object&ob) { // note PyTuple_SetItem is a thief... if(PyTuple_SetItem (ptr(), offset, new_reference_to(ob)) == -1) { ifPyErrorThrowCxxException(); } } // Constructor explicit Tuple (PyObject *pyob, bool owned = false): Sequence (pyob, owned) { validate(); } Tuple (const Object& ob): Sequence(ob) { validate(); } // New tuple of a given size explicit Tuple (int size = 0) { set(PyTuple_New (size), true); validate (); for (sequence_index_type i=0; i < size; i++) { if(PyTuple_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1) { ifPyErrorThrowCxxException(); } } } // Tuple from any sequence explicit Tuple (const Sequence& s) { sequence_index_type limit( sequence_index_type( s.length() ) ); set(PyTuple_New (limit), true); validate(); for(sequence_index_type i=0; i < limit; i++) { if(PyTuple_SetItem (ptr(), i, new_reference_to(s[i])) == -1) { ifPyErrorThrowCxxException(); } } } // Assignment acquires new ownership of pointer Tuple& operator= (const Object& rhs) { return (*this = *rhs); } Tuple& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Tuple_Check (pyob); } Tuple getSlice (int i, int j) const { return Tuple (PySequence_GetSlice (ptr(), i, j), true); } }; class TupleN: public Tuple { public: TupleN() : Tuple( 0 ) { } TupleN( const Object &obj1 ) : Tuple( 1 ) { setItem( 0, obj1 ); } TupleN( const Object &obj1, const Object &obj2 ) : Tuple( 2 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3 ) : Tuple( 3 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4 ) : Tuple( 4 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5 ) : Tuple( 5 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6 ) : Tuple( 6 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6, const Object &obj7 ) : Tuple( 7 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); setItem( 6, obj7 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6, const Object &obj7, const Object &obj8 ) : Tuple( 8 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); setItem( 6, obj7 ); setItem( 7, obj8 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6, const Object &obj7, const Object &obj8, const Object &obj9 ) : Tuple( 9 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); setItem( 6, obj7 ); setItem( 7, obj8 ); setItem( 8, obj9 ); } virtual ~TupleN() { } }; // ================================================== // class List class List: public Sequence { public: // Constructor explicit List (PyObject *pyob, bool owned = false): Sequence(pyob, owned) { validate(); } List (const Object& ob): Sequence(ob) { validate(); } // Creation at a fixed size List (size_type size = 0) { set(PyList_New (size), true); validate(); for (sequence_index_type i=0; i < size; i++) { if(PyList_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1) { ifPyErrorThrowCxxException(); } } } // List from a sequence List (const Sequence& s): Sequence() { size_type n = s.length(); set(PyList_New (n), true); validate(); for (sequence_index_type i=0; i < n; i++) { if(PyList_SetItem (ptr(), i, new_reference_to(s[i])) == -1) { ifPyErrorThrowCxxException(); } } } virtual size_type capacity() const { return max_size(); } // Assignment acquires new ownership of pointer List& operator= (const Object& rhs) { return (*this = *rhs); } List& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_List_Check (pyob); } List getSlice (int i, int j) const { return List (PyList_GetSlice (ptr(), i, j), true); } void setSlice (int i, int j, const Object& v) { if(PyList_SetSlice (ptr(), i, j, *v) == -1) { ifPyErrorThrowCxxException(); } } void append (const Object& ob) { if(PyList_Append (ptr(), *ob) == -1) { ifPyErrorThrowCxxException(); } } void insert (int i, const Object& ob) { if(PyList_Insert (ptr(), i, *ob) == -1) { ifPyErrorThrowCxxException(); } } void sort () { if(PyList_Sort(ptr()) == -1) { ifPyErrorThrowCxxException(); } } void reverse () { if(PyList_Reverse(ptr()) == -1) { ifPyErrorThrowCxxException(); } } }; // Mappings // ================================================== template class mapref { protected: MapBase& s; // the map Object key; // item key T the_item; public: mapref (MapBase& map, const std::string& k) : s(map), the_item() { key = String(k); if(map.hasKey(key)) the_item = map.getItem(key); } mapref (MapBase& map, const Object& k) : s(map), key(k), the_item() { if(map.hasKey(key)) the_item = map.getItem(key); } virtual ~mapref() {} // MapBase stuff // lvalue mapref& operator=(const mapref& other) { if(this == &other) return *this; the_item = other.the_item; s.setItem(key, other.the_item); return *this; } mapref& operator= (const T& ob) { the_item = ob; s.setItem (key, ob); return *this; } // rvalue operator T() const { return the_item; } // forward everything else to the_item PyObject* ptr () const { return the_item.ptr(); } int reference_count () const { // the mapref count return the_item.reference_count(); } Type type () const { return the_item.type(); } String str () const { return the_item.str(); } String repr () const { return the_item.repr(); } bool hasAttr (const std::string& attr_name) const { return the_item.hasAttr(attr_name); } Object getAttr (const std::string& attr_name) const { return the_item.getAttr(attr_name); } Object getItem (const Object& k) const { return the_item.getItem(k); } long hashValue () const { return the_item.hashValue(); } bool isCallable () const { return the_item.isCallable(); } bool isInstance () const { return the_item.isInstance(); } bool isList () const { return the_item.isList(); } bool isMapping () const { return the_item.isMapping(); } bool isNumeric () const { return the_item.isNumeric(); } bool isSequence () const { return the_item.isSequence(); } bool isTrue () const { return the_item.isTrue(); } bool isType (const Type& t) const { return the_item.isType (t); } bool isTuple() const { return the_item.isTuple(); } bool isString() const { return the_item.isString(); } // Commands void setAttr (const std::string& attr_name, const Object& value) { the_item.setAttr(attr_name, value); } void delAttr (const std::string& attr_name) { the_item.delAttr(attr_name); } void delItem (const Object& k) { the_item.delItem(k); } }; // end of mapref // TMM: now for mapref template< class T > bool operator==(const mapref& left, const mapref& right) { return true; // NOT completed. } template< class T > bool operator!=(const mapref& left, const mapref& right) { return true; // not completed. } template class MapBase: public Object { protected: explicit MapBase() {} public: // reference: proxy class for implementing [] // TMM: 26Jun'01 - the types // If you assume that Python mapping is a hash_map... // hash_map::value_type is not assignable, but // (*it).second = data must be a valid expression typedef PyCxx_ssize_t size_type; typedef Object key_type; typedef mapref data_type; typedef std::pair< const T, T > value_type; typedef std::pair< const T, mapref > reference; typedef const std::pair< const T, const T > const_reference; typedef std::pair< const T, mapref > pointer; // Constructor explicit MapBase (PyObject *pyob, bool owned = false): Object(pyob, owned) { validate(); } // TMM: 02Jul'01 - changed MapBase to Object in next line MapBase (const Object& ob): Object(ob) { validate(); } // Assignment acquires new ownership of pointer MapBase& operator= (const Object& rhs) { return (*this = *rhs); } MapBase& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && PyMapping_Check(pyob); } // Clear -- PyMapping Clear is missing // void clear () { List k = keys(); for(List::iterator i = k.begin(); i != k.end(); i++) { delItem(*i); } } virtual Py_ssize_t size() const { return PyMapping_Length (ptr()); } // Element Access T operator[](const std::string& key) const { return getItem(key); } T operator[](const Object& key) const { return getItem(key); } mapref operator[](const std::string& key) { return mapref(*this, key); } mapref operator[](const Object& key) { return mapref(*this, key); } Py_ssize_t length () const { return PyMapping_Length (ptr()); } bool hasKey (const std::string& s) const { return PyMapping_HasKeyString (ptr(),const_cast(s.c_str())) != 0; } bool hasKey (const Object& s) const { return PyMapping_HasKey (ptr(), s.ptr()) != 0; } T getItem (const std::string& s) const { return T( asObject(PyMapping_GetItemString (ptr(),const_cast(s.c_str()))) ); } T getItem (const Object& s) const { return T( asObject(PyObject_GetItem (ptr(), s.ptr())) ); } virtual void setItem (const char *s, const Object& ob) { if (PyMapping_SetItemString (ptr(), const_cast(s), *ob) == -1) { ifPyErrorThrowCxxException(); } } virtual void setItem (const std::string& s, const Object& ob) { if (PyMapping_SetItemString (ptr(), const_cast(s.c_str()), *ob) == -1) { ifPyErrorThrowCxxException(); } } virtual void setItem (const Object& s, const Object& ob) { if (PyObject_SetItem (ptr(), s.ptr(), ob.ptr()) == -1) { ifPyErrorThrowCxxException(); } } void delItem (const std::string& s) { if (PyMapping_DelItemString (ptr(), const_cast(s.c_str())) == -1) { ifPyErrorThrowCxxException(); } } void delItem (const Object& s) { if (PyMapping_DelItem (ptr(), *s) == -1) { ifPyErrorThrowCxxException(); } } // Queries List keys () const { static char keys[] = {'k', 'e', 'y', 's', 0}; return List(PyObject_CallMethod( ptr(), keys, NULL ), true ); } List values () const { // each returned item is a (key, value) pair return List(PyMapping_Values(ptr()), true); } List items () const { return List(PyMapping_Items(ptr()), true); } class iterator { // : public forward_iterator_parent( std::pair ) { protected: typedef std::forward_iterator_tag iterator_category; typedef std::pair< const T, T > value_type; typedef int difference_type; typedef std::pair< const T, mapref > pointer; typedef std::pair< const T, mapref > reference; friend class MapBase; // MapBase *map; List keys; // for iterating over the map sequence_index_type pos; // index into the keys private: iterator( MapBase* m, List k, sequence_index_type p ) : map( m ) , keys( k ) , pos( p ) {} public: ~iterator () {} iterator () : map( 0 ) , keys() , pos() {} iterator (MapBase* m, bool end = false ) : map( m ) , keys( m->keys() ) , pos( end ? keys.length() : 0 ) {} iterator (const iterator& other) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} reference operator*() { Object key = keys[ pos ]; return std::make_pair(key, mapref(*map,key)); } iterator& operator=(const iterator& other) { if (this == &other) return *this; map = other.map; keys = other.keys; pos = other.pos; return *this; } bool eql(const iterator& right) const { return map->ptr() == right.map->ptr() && pos == right.pos; } bool neq( const iterator& right ) const { return map->ptr() != right.map->ptr() || pos != right.pos; } // pointer operator->() { // return ; // } // prefix ++ iterator& operator++ () { pos++; return *this;} // postfix ++ iterator operator++ (int) { return iterator(map, keys, pos++);} // prefix -- iterator& operator-- () { pos--; return *this;} // postfix -- iterator operator-- (int) { return iterator(map, keys, pos--);} std::string diagnose() const { std::OSTRSTREAM oss; oss << "iterator diagnosis " << map << ", " << pos << std::ends; return std::string(oss.str()); } }; // end of class MapBase::iterator iterator begin () { return iterator(this); } iterator end () { return iterator(this, true); } class const_iterator { protected: typedef std::forward_iterator_tag iterator_category; typedef const std::pair< const T, T > value_type; typedef int difference_type; typedef const std::pair< const T, T > pointer; typedef const std::pair< const T, T > reference; friend class MapBase; const MapBase *map; List keys; // for iterating over the map sequence_index_type pos; // index into the keys private: const_iterator( const MapBase* m, List k, int p ) : map( m ) , keys( k ) , pos( p ) {} public: ~const_iterator () {} const_iterator () : map( 0 ) , keys() , pos() {} const_iterator (const MapBase* m, bool end = false ) : map( m ) , keys( m->keys() ) , pos( end ? keys.length() : 0 ) {} const_iterator(const const_iterator& other) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} bool eql(const const_iterator& right) const { return map->ptr() == right.map->ptr() && pos == right.pos; } bool neq( const const_iterator& right ) const { return map->ptr() != right.map->ptr() || pos != right.pos; } const_reference operator*() { Object key = keys[ pos ]; return std::make_pair( key, mapref( *map, key ) ); } const_iterator& operator=(const const_iterator& other) { if (this == &other) return *this; map = other.map; keys = other.keys; pos = other.pos; return *this; } // prefix ++ const_iterator& operator++ () { pos++; return *this;} // postfix ++ const_iterator operator++ (int) { return const_iterator(map, keys, pos++);} // prefix -- const_iterator& operator-- () { pos--; return *this;} // postfix -- const_iterator operator-- (int) { return const_iterator(map, keys, pos--);} }; // end of class MapBase::const_iterator const_iterator begin () const { return const_iterator(this); } const_iterator end () const { return const_iterator(this, true); } }; // end of MapBase typedef MapBase Mapping; template bool operator==(const EXPLICIT_TYPENAME MapBase::iterator& left, const EXPLICIT_TYPENAME MapBase::iterator& right); template bool operator!=(const EXPLICIT_TYPENAME MapBase::iterator& left, const EXPLICIT_TYPENAME MapBase::iterator& right); template bool operator==(const EXPLICIT_TYPENAME MapBase::const_iterator& left, const EXPLICIT_TYPENAME MapBase::const_iterator& right); template bool operator!=(const EXPLICIT_TYPENAME MapBase::const_iterator& left, const EXPLICIT_TYPENAME MapBase::const_iterator& right); extern bool operator==(const Mapping::iterator& left, const Mapping::iterator& right); extern bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right); extern bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right); extern bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right); // ================================================== // class Dict class Dict: public Mapping { public: // Constructor explicit Dict (PyObject *pyob, bool owned=false): Mapping (pyob, owned) { validate(); } Dict (const Object& ob): Mapping(ob) { validate(); } // Creation Dict () { set(PyDict_New (), true); validate(); } // Assignment acquires new ownership of pointer Dict& operator= (const Object& rhs) { return (*this = *rhs); } Dict& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set(rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && Py::_Dict_Check (pyob); } }; class Callable: public Object { public: // Constructor explicit Callable (): Object() {} explicit Callable (PyObject *pyob, bool owned = false): Object (pyob, owned) { validate(); } Callable (const Object& ob): Object(ob) { validate(); } // Assignment acquires new ownership of pointer Callable& operator= (const Object& rhs) { return (*this = *rhs); } Callable& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set (rhsp); return *this; } // Membership virtual bool accepts (PyObject *pyob) const { return pyob && PyCallable_Check (pyob); } // Call Object apply(const Tuple& args) const { PyObject *result = PyObject_CallObject( ptr(), args.ptr() ); if( result == NULL ) { ifPyErrorThrowCxxException(); } return asObject( result ); } // Call with keywords Object apply(const Tuple& args, const Dict& kw) const { PyObject *result = PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ); if( result == NULL ) { ifPyErrorThrowCxxException(); } return asObject( result ); } Object apply(PyObject* pargs = 0) const { if( pargs == 0 ) { return apply( Tuple() ); } else { return apply( Tuple( pargs ) ); } } }; class Module: public Object { public: explicit Module (PyObject* pyob, bool owned = false): Object (pyob, owned) { validate(); } // Construct from module name explicit Module (const std::string&s): Object() { PyObject *m = PyImport_AddModule( const_cast(s.c_str()) ); set( m, false ); validate (); } // Copy constructor acquires new ownership of pointer Module (const Module& ob): Object(*ob) { validate(); } Module& operator= (const Object& rhs) { return (*this = *rhs); } Module& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set(rhsp); return *this; } Dict getDict() { return Dict(PyModule_GetDict(ptr())); // Caution -- PyModule_GetDict returns borrowed reference! } }; // Call function helper inline Object Object::callMemberFunction( const std::string &function_name ) const { Callable target( getAttr( function_name ) ); Tuple args( 0 ); return target.apply( args ); } inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args ) const { Callable target( getAttr( function_name ) ); return target.apply( args ); } inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const { Callable target( getAttr( function_name ) ); return target.apply( args, kw ); } // Numeric interface inline Object operator+ (const Object& a) { return asObject(PyNumber_Positive(*a)); } inline Object operator- (const Object& a) { return asObject(PyNumber_Negative(*a)); } inline Object abs(const Object& a) { return asObject(PyNumber_Absolute(*a)); } inline std::pair coerce(const Object& a, const Object& b) { PyObject *p1, *p2; p1 = *a; p2 = *b; if(PyNumber_Coerce(&p1,&p2) == -1) { ifPyErrorThrowCxxException(); } return std::pair(asObject(p1), asObject(p2)); } inline Object operator+ (const Object& a, const Object& b) { return asObject(PyNumber_Add(*a, *b)); } inline Object operator+ (const Object& a, int j) { return asObject(PyNumber_Add(*a, *Int(j))); } inline Object operator+ (const Object& a, double v) { return asObject(PyNumber_Add(*a, *Float(v))); } inline Object operator+ (int j, const Object& b) { return asObject(PyNumber_Add(*Int(j), *b)); } inline Object operator+ (double v, const Object& b) { return asObject(PyNumber_Add(*Float(v), *b)); } inline Object operator- (const Object& a, const Object& b) { return asObject(PyNumber_Subtract(*a, *b)); } inline Object operator- (const Object& a, int j) { return asObject(PyNumber_Subtract(*a, *Int(j))); } inline Object operator- (const Object& a, double v) { return asObject(PyNumber_Subtract(*a, *Float(v))); } inline Object operator- (int j, const Object& b) { return asObject(PyNumber_Subtract(*Int(j), *b)); } inline Object operator- (double v, const Object& b) { return asObject(PyNumber_Subtract(*Float(v), *b)); } inline Object operator* (const Object& a, const Object& b) { return asObject(PyNumber_Multiply(*a, *b)); } inline Object operator* (const Object& a, int j) { return asObject(PyNumber_Multiply(*a, *Int(j))); } inline Object operator* (const Object& a, double v) { return asObject(PyNumber_Multiply(*a, *Float(v))); } inline Object operator* (int j, const Object& b) { return asObject(PyNumber_Multiply(*Int(j), *b)); } inline Object operator* (double v, const Object& b) { return asObject(PyNumber_Multiply(*Float(v), *b)); } inline Object operator/ (const Object& a, const Object& b) { return asObject(PyNumber_Divide(*a, *b)); } inline Object operator/ (const Object& a, int j) { return asObject(PyNumber_Divide(*a, *Int(j))); } inline Object operator/ (const Object& a, double v) { return asObject(PyNumber_Divide(*a, *Float(v))); } inline Object operator/ (int j, const Object& b) { return asObject(PyNumber_Divide(*Int(j), *b)); } inline Object operator/ (double v, const Object& b) { return asObject(PyNumber_Divide(*Float(v), *b)); } inline Object operator% (const Object& a, const Object& b) { return asObject(PyNumber_Remainder(*a, *b)); } inline Object operator% (const Object& a, int j) { return asObject(PyNumber_Remainder(*a, *Int(j))); } inline Object operator% (const Object& a, double v) { return asObject(PyNumber_Remainder(*a, *Float(v))); } inline Object operator% (int j, const Object& b) { return asObject(PyNumber_Remainder(*Int(j), *b)); } inline Object operator% (double v, const Object& b) { return asObject(PyNumber_Remainder(*Float(v), *b)); } inline Object type(const BaseException&) // return the type of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch(&ptype, &pvalue, &ptrace); Object result; if(ptype) result = ptype; PyErr_Restore(ptype, pvalue, ptrace); return result; } inline Object value(const BaseException&) // return the value of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch(&ptype, &pvalue, &ptrace); Object result; if(pvalue) result = pvalue; PyErr_Restore(ptype, pvalue, ptrace); return result; } inline Object trace(const BaseException&) // return the traceback of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch(&ptype, &pvalue, &ptrace); Object result; if(ptrace) result = ptrace; PyErr_Restore(ptype, pvalue, ptrace); return result; } template String seqref::str () const { return the_item.str(); } template String seqref::repr () const { return the_item.repr(); } } // namespace Py #endif // __CXX_Objects__h pycxx-7.1.4/CXX/Python2/Config.hxx000644 000765 000024 00000010022 13662724004 017122 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __PyCXX_config_hh__ #define __PyCXX_config_hh__ // // Microsoft VC++ 6.0 has no traits // #if defined( _MSC_VER ) # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 #elif defined( __GNUC__ ) # if __GNUC__ >= 3 # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 # else # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 0 #endif // // Assume all other compilers do // #else // Macros to deal with deficiencies in compilers # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 #endif #if STANDARD_LIBRARY_HAS_ITERATOR_TRAITS # define random_access_iterator_parent(itemtype) std::iterator #else # define random_access_iterator_parent(itemtype) std::random_access_iterator #endif // // Which C++ standard is in use? // #if defined( _MSC_VER ) # if _MSC_VER <= 1200 // MSVC++ 6.0 # define PYCXX_ISO_CPP_LIB 0 # define STR_STREAM # define TEMPLATE_TYPENAME class # else # define PYCXX_ISO_CPP_LIB 1 # define STR_STREAM # define TEMPLATE_TYPENAME typename # endif #elif defined( __GNUC__ ) # if __GNUC__ >= 3 # define PYCXX_ISO_CPP_LIB 1 # define STR_STREAM # define TEMPLATE_TYPENAME typename # else # define PYCXX_ISO_CPP_LIB 0 # define STR_STREAM # define TEMPLATE_TYPENAME class # endif #endif #if PYCXX_ISO_CPP_LIB # define STR_STREAM # define OSTRSTREAM ostringstream # define EXPLICIT_TYPENAME typename # define EXPLICIT_CLASS class # define TEMPLATE_TYPENAME typename #else # define STR_STREAM # define OSTRSTREAM ostrstream # define EXPLICIT_TYPENAME # define EXPLICIT_CLASS # define TEMPLATE_TYPENAME class #endif // before 2.5 Py_ssize_t was missing #ifndef PY_MAJOR_VERSION #error not defined PY_MAJOR_VERSION #endif #if PY_MAJOR_VERSION < 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5) typedef int Py_ssize_t; #endif #endif // __PyCXX_config_hh__ pycxx-7.1.4/CXX/Python2/cxx_standard_exceptions.hxx000644 000765 000024 00000005421 12754100607 022645 0ustar00barrystaff000000 000000 #if !defined( PYCXX_STANDARD_EXCEPTION ) #pragma error( "define PYCXX_STANDARD_EXCEPTION before including" ) #endif PYCXX_STANDARD_EXCEPTION( SystemExit, BaseException ) PYCXX_STANDARD_EXCEPTION( KeyboardInterrupt,BaseException ) PYCXX_STANDARD_EXCEPTION( GeneratorExit, BaseException ) #if !defined( PYCXX_6_2_COMPATIBILITY ) PYCXX_STANDARD_EXCEPTION( Exception, BaseException ) #endif PYCXX_STANDARD_EXCEPTION( StopIteration, Exception ) PYCXX_STANDARD_EXCEPTION( StandardError, Exception ) PYCXX_STANDARD_EXCEPTION( BufferError, StandardError ) PYCXX_STANDARD_EXCEPTION( ArithmeticError, StandardError ) PYCXX_STANDARD_EXCEPTION( FloatingPointError, ArithmeticError ) PYCXX_STANDARD_EXCEPTION( OverflowError, ArithmeticError ) PYCXX_STANDARD_EXCEPTION( ZeroDivisionError, ArithmeticError ) PYCXX_STANDARD_EXCEPTION( AssertionError, StandardError ) PYCXX_STANDARD_EXCEPTION( AttributeError, StandardError ) PYCXX_STANDARD_EXCEPTION( EnvironmentError, StandardError ) PYCXX_STANDARD_EXCEPTION( IOError, EnvironmentError ) PYCXX_STANDARD_EXCEPTION( OSError, EnvironmentError ) #ifdef MS_WINDOWS PYCXX_STANDARD_EXCEPTION( WindowsError, OSError ) #endif PYCXX_STANDARD_EXCEPTION( EOFError, StandardError ) PYCXX_STANDARD_EXCEPTION( ImportError, StandardError ) PYCXX_STANDARD_EXCEPTION( LookupError, StandardError ) PYCXX_STANDARD_EXCEPTION( IndexError, LookupError ) PYCXX_STANDARD_EXCEPTION( KeyError, LookupError ) PYCXX_STANDARD_EXCEPTION( MemoryError, StandardError ) PYCXX_STANDARD_EXCEPTION( NameError, StandardError ) PYCXX_STANDARD_EXCEPTION( UnboundLocalError,NameError ) PYCXX_STANDARD_EXCEPTION( ReferenceError, StandardError ) PYCXX_STANDARD_EXCEPTION( RuntimeError, StandardError ) PYCXX_STANDARD_EXCEPTION( NotImplementedError, RuntimeError ) PYCXX_STANDARD_EXCEPTION( SyntaxError, StandardError ) PYCXX_STANDARD_EXCEPTION( IndentationError, SyntaxError ) PYCXX_STANDARD_EXCEPTION( TabError, IndentationError ) PYCXX_STANDARD_EXCEPTION( SystemError, StandardError ) PYCXX_STANDARD_EXCEPTION( TypeError, StandardError ) PYCXX_STANDARD_EXCEPTION( ValueError, StandardError ) PYCXX_STANDARD_EXCEPTION( UnicodeError, ValueError ) PYCXX_STANDARD_EXCEPTION( UnicodeDecodeError, UnicodeError ) PYCXX_STANDARD_EXCEPTION( UnicodeEncodeError, UnicodeError ) PYCXX_STANDARD_EXCEPTION( UnicodeTranslateError,UnicodeError ) pycxx-7.1.4/CXX/Python2/CxxDebug.hxx000644 000765 000024 00000000402 11150315604 017417 0ustar00barrystaff000000 000000 // // CxxDebug.hxx // // Copyright (c) 2008 Barry A. Scott // #ifndef __CXX_Debug_hxx #define __CXX_Debug_hxx // // Functions useful when debugging PyCXX // #ifdef PYCXX_DEBUG extern void bpt(); extern void printRefCount( PyObject *obj ); #endif #endif pycxx-7.1.4/CXX/Python2/ExtensionOldType.hxx000644 000765 000024 00000031636 12733537475 021224 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionOldType__h #define __CXX_ExtensionOldType__h namespace Py { template class PythonExtension : public PythonExtensionBase { public: static PyTypeObject *type_object() { return behaviors().type_object(); } static bool check( PyObject *p ) { // is p like me? return p->ob_type == type_object(); } static bool check( const Object &ob ) { return check( ob.ptr() ); } // // every object needs getattr implemented // to support methods // virtual Object getattr( const char *name ) { return getattr_methods( name ); } PyObject *selfPtr() { return this; } Object self() { return asObject( this ); } protected: explicit PythonExtension() : PythonExtensionBase() { PyObject_Init( this, type_object() ); // every object must support getattr behaviors().supportGetattr(); } virtual ~PythonExtension() {} static PythonType &behaviors() { static PythonType* p; if( p == NULL ) { #if defined( _CPPRTTI ) || defined( __GNUG__ ) const char *default_name =( typeid( T ) ).name(); #else const char *default_name = "unknown"; #endif p = new PythonType( sizeof( T ), 0, default_name ); p->set_tp_dealloc( extension_object_deallocator ); } return *p; } typedef Object (T::*method_noargs_function_t)(); typedef Object (T::*method_varargs_function_t)( const Tuple &args ); typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); typedef std::map *> method_map_t; // support the default attributes, __name__, __doc__ and methods virtual Object getattr_default( const char *_name ) { std::string name( _name ); if( name == "__name__" && type_object()->tp_name != NULL ) { return Py::String( type_object()->tp_name ); } if( name == "__doc__" && type_object()->tp_doc != NULL ) { return Py::String( type_object()->tp_doc ); } // trying to fake out being a class for help() // else if( name == "__bases__" ) // { // return Py::Tuple( 0 ); // } // else if( name == "__module__" ) // { // return Py::Nothing(); // } // else if( name == "__dict__" ) // { // return Py::Dict(); // } return getattr_methods( _name ); } // turn a name into function object virtual Object getattr_methods( const char *_name ) { std::string name( _name ); method_map_t &mm = methods(); // see if name exists and get entry with method EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.find( name ); if( i == mm.end() ) { if( name == "__methods__" ) { List methods; i = mm.begin(); EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); for( ; i != i_end; ++i ) methods.append( String( (*i).first ) ); return methods; } throw AttributeError( name ); } MethodDefExt *method_def = i->second; Tuple self( 2 ); self[0] = Object( this ); self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); PyObject *func = PyCFunction_NewEx( &method_def->ext_meth_def, self.ptr(), NULL ); return Object(func, true); } // check that all methods added are unique static void check_unique_method_name( const char *name ) { method_map_t &mm = methods(); EXPLICIT_TYPENAME method_map_t::const_iterator i; i = mm.find( name ); if( i != mm.end() ) throw AttributeError( name ); } static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) { check_unique_method_name( name ); method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_noargs_call_handler, doc ); } static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) { check_unique_method_name( name ); method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_varargs_call_handler, doc ); } static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) { check_unique_method_name( name ); method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_keyword_call_handler, doc ); } private: static method_map_t &methods( void ) { static method_map_t *map_of_methods = NULL; if( map_of_methods == NULL ) map_of_methods = new method_map_t; return *map_of_methods; } // Note: Python calls noargs as varargs buts args==NULL static PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Object result; // Adding try & catch in case of STL debug-mode exceptions. #ifdef _STLP_DEBUG try { result = (self->*meth_def->ext_noargs_function)(); } catch( std::__stl_debug_exception ) { // throw cxx::RuntimeError( sErrMsg ); throw RuntimeError( "Error message not set yet." ); } #else result = (self->*meth_def->ext_noargs_function)(); #endif // _STLP_DEBUG return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } static PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Tuple args( _args ); Object result; // Adding try & catch in case of STL debug-mode exceptions. #ifdef _STLP_DEBUG try { result = (self->*meth_def->ext_varargs_function)( args ); } catch( std::__stl_debug_exception ) { throw RuntimeError( "Error message not set yet." ); } #else result = (self->*meth_def->ext_varargs_function)( args ); #endif // _STLP_DEBUG return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } static PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Tuple args( _args ); // _keywords may be NULL so be careful about the way the dict is created Dict keywords; if( _keywords != NULL ) keywords = Dict( _keywords ); Object result( ( self->*meth_def->ext_keyword_function )( args, keywords ) ); return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } static void extension_object_deallocator( PyObject* t ) { delete (T *)( t ); } // // prevent the compiler generating these unwanted functions // explicit PythonExtension( const PythonExtension &other ); void operator=( const PythonExtension &rhs ); }; // // ExtensionObject is an Object that will accept only T's. // template class ExtensionObject: public Object { public: explicit ExtensionObject( PyObject *pyob ) : Object( pyob ) { validate(); } ExtensionObject( const ExtensionObject &other ) : Object( *other ) { validate(); } ExtensionObject( const Object &other ) : Object( *other ) { validate(); } ExtensionObject &operator=( const Object &rhs ) { return( *this = *rhs ); } ExtensionObject &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return( pyob && T::check( pyob ) ); } // // Obtain a pointer to the PythonExtension object // T *extensionObject( void ) { return static_cast( ptr() ); } }; } // Namespace Py // End of __CXX_ExtensionOldType__h #endif pycxx-7.1.4/CXX/Python2/PythonType.hxx000644 000765 000024 00000021007 13662723705 020054 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_PythonType__h #define __CXX_PythonType__h namespace Py { class PythonType { public: #define B(n) (1<<(n)) // if you define one sequence method you must define // all of them except the assigns PythonType( size_t base_size, int itemsize, const char *default_name ); virtual ~PythonType(); const char *getName() const; const char *getDoc() const; PyTypeObject *type_object() const; PythonType &name( const char *nam ); PythonType &doc( const char *d ); PythonType &supportClass( void ); PythonType &dealloc( void (*f)( PyObject* ) ); #if defined( PYCXX_PYTHON_2TO3 ) PythonType &supportPrint( void ); #endif PythonType &supportGetattr( void ); PythonType &supportSetattr( void ); PythonType &supportGetattro( void ); PythonType &supportSetattro( void ); #if defined( PYCXX_PYTHON_2TO3 ) PythonType &supportCompare( void ); #endif PythonType &supportRichCompare( void ); PythonType &supportRepr( void ); PythonType &supportStr( void ); PythonType &supportHash( void ); PythonType &supportCall( void ); enum { support_iter_iter = B(0), support_iter_iternext = B(1) }; PythonType &supportIter( int methods_to_support= support_iter_iter | support_iter_iternext ); enum { support_sequence_length = B(0), support_sequence_repeat = B(1), support_sequence_item = B(2), support_sequence_slice = B(3), support_sequence_concat = B(4), support_sequence_ass_item = B(5), support_sequence_ass_slice = B(6), support_sequence_inplace_concat = B(7), support_sequence_inplace_repeat = B(8), support_sequence_contains = B(9) }; PythonType &supportSequenceType( int methods_to_support= support_sequence_length | support_sequence_repeat | support_sequence_item | support_sequence_slice | support_sequence_concat ); enum { support_mapping_length = B(0), support_mapping_subscript = B(1), support_mapping_ass_subscript = B(2) }; PythonType &supportMappingType( int methods_to_support= support_mapping_length | support_mapping_subscript ); enum { support_number_add = B(0), support_number_subtract = B(1), support_number_multiply = B(2), support_number_divide = B(3), support_number_remainder = B(4), support_number_divmod = B(5), support_number_power = B(6), support_number_negative = B(7), support_number_positive = B(8), support_number_absolute = B(9), support_number_nonzero = B(10), support_number_invert = B(11), support_number_lshift = B(12), support_number_rshift = B(13), support_number_and = B(14), support_number_xor = B(15), support_number_or = B(16), support_number_int = B(17), support_number_long = B(18), support_number_float = B(19), support_number_oct = B(20), support_number_hex = B(21) }; PythonType &supportNumberType( int methods_to_support= support_number_add | support_number_subtract | support_number_multiply | support_number_divide | support_number_remainder | support_number_divmod | support_number_power | support_number_negative | support_number_positive | support_number_absolute | support_number_nonzero | support_number_invert | support_number_lshift | support_number_rshift | support_number_and | support_number_xor | support_number_or | support_number_int | support_number_long | support_number_float | support_number_oct | support_number_hex ); enum { support_buffer_getreadbuffer = B(0), support_buffer_getwritebuffer = B(1), support_buffer_getsegcount = B(2) }; PythonType &supportBufferType( int methods_to_support= support_buffer_getreadbuffer | support_buffer_getwritebuffer | support_buffer_getsegcount ); #undef B PythonType &set_tp_dealloc( void (*tp_dealloc)( PyObject * ) ); PythonType &set_tp_init( int (*tp_init)( PyObject *self, PyObject *args, PyObject *kwds ) ); PythonType &set_tp_new( PyObject *(*tp_new)( PyTypeObject *subtype, PyObject *args, PyObject *kwds ) ); PythonType &set_methods( PyMethodDef *methods ); // call once all support functions have been called to ready the type bool readyType(); protected: PyTypeObject *table; PySequenceMethods *sequence_table; PyMappingMethods *mapping_table; PyNumberMethods *number_table; PyBufferProcs *buffer_table; private: // // prevent the compiler generating these unwanted functions // PythonType( const PythonType &tb ); // unimplemented void operator=( const PythonType &t ); // unimplemented }; } // Namespace Py // End of __CXX_PythonType__h #endif pycxx-7.1.4/CXX/Python2/ExtensionModule.hxx000644 000765 000024 00000021171 12733537475 021062 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionModule__h #define __CXX_ExtensionModule__h namespace Py { class ExtensionModuleBase { public: ExtensionModuleBase( const char *name ); virtual ~ExtensionModuleBase(); Module module( void ) const; // only valid after initialize() has been called Dict moduleDictionary( void ) const; // only valid after initialize() has been called virtual Object invoke_method_noargs( void *method_def ) = 0; virtual Object invoke_method_keyword( void *method_def, const Tuple &_args, const Dict &_keywords ) = 0; virtual Object invoke_method_varargs( void *method_def, const Tuple &_args ) = 0; const std::string &name() const; const std::string &fullName() const; // what is returned from PyInit_ function Object moduleObject( void ) const; protected: // Initialize the module void initialize( const char *module_doc ); const std::string m_module_name; const std::string m_full_module_name; MethodTable m_method_table; PyObject *m_module; private: // // prevent the compiler generating these unwanted functions // ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented void operator=( const ExtensionModuleBase & ); //unimplemented }; // Note: Python calls noargs as varargs buts args==NULL extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ); extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ); extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ); extern "C" void do_not_dealloc( void * ); template class ExtensionModule : public ExtensionModuleBase { public: ExtensionModule( const char *name ) : ExtensionModuleBase( name ) {} virtual ~ExtensionModule() {} protected: typedef Object (T::*method_noargs_function_t)(); typedef Object (T::*method_varargs_function_t)( const Tuple &args ); typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); typedef std::map *> method_map_t; static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) { method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_noargs_call_handler, doc ); } static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) { method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_varargs_call_handler, doc ); } static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) { method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_keyword_call_handler, doc ); } void initialize( const char *module_doc="" ) { ExtensionModuleBase::initialize( module_doc ); Dict dict( moduleDictionary() ); // // put each of the methods into the modules dictionary // so that we get called back at the function in T. // method_map_t &mm = methods(); EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.begin(); EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); for ( ; i != i_end; ++i ) { MethodDefExt *method_def = (*i).second; static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); Tuple args( 2 ); args[0] = Object( self, true ); args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); assert( m_module != NULL ); PyObject *func = PyCFunction_NewEx ( &method_def->ext_meth_def, new_reference_to( args ), m_module ); method_def->py_method = Object( func, true ); dict[ (*i).first ] = method_def->py_method; } } protected: // Tom Malcolmson reports that derived classes need access to these static method_map_t &methods( void ) { static method_map_t *map_of_methods = NULL; if( map_of_methods == NULL ) map_of_methods = new method_map_t; return *map_of_methods; } // this invoke function must be called from within a try catch block virtual Object invoke_method_noargs( void *method_def ) { // cast up to the derived class, method_def and call T *self = static_cast( this ); MethodDefExt *meth_def = reinterpret_cast *>( method_def ); return (self->*meth_def->ext_noargs_function)(); } // this invoke function must be called from within a try catch block virtual Object invoke_method_varargs( void *method_def, const Tuple &args ) { // cast up to the derived class, method_def and call T *self = static_cast( this ); MethodDefExt *meth_def = reinterpret_cast *>( method_def ); return (self->*meth_def->ext_varargs_function)( args ); } // this invoke function must be called from within a try catch block virtual Object invoke_method_keyword( void *method_def, const Tuple &args, const Dict &keywords ) { // cast up to the derived class, method_def and call T *self = static_cast( this ); MethodDefExt *meth_def = reinterpret_cast *>( method_def ); return (self->*meth_def->ext_keyword_function)( args, keywords ); } private: // // prevent the compiler generating these unwanted functions // ExtensionModule( const ExtensionModule & ); //unimplemented void operator=( const ExtensionModule & ); //unimplemented }; } // Namespace Py // End of __CXX_ExtensionModule__h #endif pycxx-7.1.4/CXX/Python3/Exception.hxx000644 000765 000024 00000013600 13430341141 017647 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Exception_h #define __CXX_Exception_h #include "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Config.hxx" #include "CXX/CxxDebug.hxx" #include "CXX/IndirectPythonInterface.hxx" #include #include // This mimics the Python structure, in order to minimize confusion namespace Py { class ExtensionExceptionType; class Object; class BaseException { public: BaseException( ExtensionExceptionType &exception, const std::string &reason ); BaseException( ExtensionExceptionType &exception, Object &reason ); BaseException( PyObject *exception, Object &reason ); BaseException( PyObject *exception, const std::string &reason ); explicit BaseException(); void clear(); // clear the error // is the exception this specific exception 'exc' bool matches( ExtensionExceptionType &exc ); Object errorType(); // get the error type of the active exception Object errorValue();// get the error value of the active exception }; // for user defined exceptions to be made know to pycxx typedef void (*throw_exception_func_t)( void ); void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t throw_func ); #if defined( PYCXX_6_2_COMPATIBILITY ) class Exception : public BaseException { public: Exception( ExtensionExceptionType &exception, const std::string &reason ) : BaseException( exception, reason ) {} Exception( ExtensionExceptionType &exception, Object &reason ) : BaseException( exception, reason ) {} Exception( PyObject *exception, Object &reason ) : BaseException( exception, reason ) {} Exception( PyObject *exception, const std::string &reason ) : BaseException( exception, reason ) {} explicit Exception() : BaseException() {} }; #endif #define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ class eclass : public bclass \ { \ public: \ eclass() {} \ eclass( const char *reason ) { PyErr_SetString( _Exc_##eclass(), reason ); } \ eclass( const std::string &reason ) { PyErr_SetString( _Exc_##eclass(), reason.c_str() ); } \ ~eclass() {} \ \ static void throwFunc() { throw eclass(); } \ static PyObject *exceptionType() { return _Exc_##eclass(); } \ }; \ #include #undef PYCXX_STANDARD_EXCEPTION #define PYCXX_USER_EXCEPTION_STR_ARG( uclass ) \ class uclass : public Py::BaseException \ { \ public: \ uclass( const std::string &reason ) \ : Py::BaseException( m_error, reason ) \ { } \ ~uclass() {} \ static void init( Py::ExtensionModuleBase &module ) \ { \ m_error.init( module, #uclass ); \ Py::addPythonException( m_error, throwFunc ); \ Py::Dict d( module.moduleDictionary() ); \ d[#uclass] = m_error; \ } \ private: \ uclass() : Py::BaseException() {} \ static void throwFunc() \ { \ throw uclass(); \ } \ static Py::ExtensionExceptionType m_error; \ }; \ Py::ExtensionExceptionType uclass::m_error; #define PYCXX_USER_EXCEPTION_NO_ARG( uclass ) \ class uclass : public Py::BaseException \ { \ public: \ uclass() \ : Py::BaseException() \ { } \ ~uclass() {} \ static void init( Py::ExtensionModuleBase &module ) \ { \ m_error.init( module, #uclass ); \ Py::addPythonException( m_error, throwFunc ); \ Py::Dict d( module.moduleDictionary() ); \ d[#uclass] = m_error; \ } \ private: \ static void throwFunc() \ { \ throw uclass(); \ } \ static Py::ExtensionExceptionType m_error; \ }; \ Py::ExtensionExceptionType uclass::m_error; }// Py #endif pycxx-7.1.4/CXX/Python3/Extensions.hxx000644 000765 000024 00000015625 12745352476 020106 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Extensions__h #define __CXX_Extensions__h #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // okay to ignore #pragma warning( disable: 4786 ) #endif #include "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Python3/Config.hxx" #include "CXX/Python3/CxxDebug.hxx" #include "CXX/Python3/Objects.hxx" extern "C" { extern PyObject py_object_initializer; } #include #include // ---------------------------------------------------------------------- namespace Py { class ExtensionModuleBase; // Make an Exception Type for use in raising custom exceptions class ExtensionExceptionType : public Object { public: ExtensionExceptionType(); virtual ~ExtensionExceptionType(); // call init to create the type void init( ExtensionModuleBase &module, const std::string &name, ExtensionExceptionType &parent ); void init( ExtensionModuleBase &module, const std::string &name ); }; class MethodTable { public: MethodTable(); virtual ~MethodTable(); void add( const char *method_name, PyCFunction f, const char *doc="", int flag=1 ); PyMethodDef *table(); protected: std::vector t; // accumulator of PyMethodDef's PyMethodDef *mt; // Actual method table produced when full static PyMethodDef method( const char* method_name, PyCFunction f, int flags=1, const char* doc="" ); private: // // prevent the compiler generating these unwanted functions // MethodTable( const MethodTable &m ); //unimplemented void operator=( const MethodTable &m ); //unimplemented }; // end class MethodTable // Note: Python calls noargs as varargs buts args==NULL extern "C" typedef PyObject *(*method_noargs_call_handler_t)( PyObject *_self, PyObject * ); extern "C" typedef PyObject *(*method_varargs_call_handler_t)( PyObject *_self, PyObject *_args ); extern "C" typedef PyObject *(*method_keyword_call_handler_t)( PyObject *_self, PyObject *_args, PyObject *_dict ); template class MethodDefExt { public: typedef Object (T::*method_noargs_function_t)(); typedef Object (T::*method_varargs_function_t)( const Tuple &args ); typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); // NOARGS MethodDefExt ( const char *_name, method_noargs_function_t _function, method_noargs_call_handler_t _handler, const char *_doc ) { ext_meth_def.ml_name = const_cast( _name ); ext_meth_def.ml_meth = reinterpret_cast( _handler ); ext_meth_def.ml_flags = METH_NOARGS; ext_meth_def.ml_doc = const_cast( _doc ); ext_noargs_function = _function; ext_varargs_function = NULL; ext_keyword_function = NULL; } // VARARGS MethodDefExt ( const char *_name, method_varargs_function_t _function, method_varargs_call_handler_t _handler, const char *_doc ) { ext_meth_def.ml_name = const_cast( _name ); ext_meth_def.ml_meth = reinterpret_cast( _handler ); ext_meth_def.ml_flags = METH_VARARGS; ext_meth_def.ml_doc = const_cast( _doc ); ext_noargs_function = NULL; ext_varargs_function = _function; ext_keyword_function = NULL; } // VARARGS + KEYWORD MethodDefExt ( const char *_name, method_keyword_function_t _function, method_keyword_call_handler_t _handler, const char *_doc ) { ext_meth_def.ml_name = const_cast( _name ); ext_meth_def.ml_meth = reinterpret_cast( _handler ); ext_meth_def.ml_flags = METH_VARARGS|METH_KEYWORDS; ext_meth_def.ml_doc = const_cast( _doc ); ext_noargs_function = NULL; ext_varargs_function = NULL; ext_keyword_function = _function; } ~MethodDefExt() {} PyMethodDef ext_meth_def; method_noargs_function_t ext_noargs_function; method_varargs_function_t ext_varargs_function; method_keyword_function_t ext_keyword_function; Object py_method; }; } // Namespace Py #include "CXX/Python3/ExtensionModule.hxx" #include "CXX/Python3/PythonType.hxx" #include "CXX/Python3/ExtensionTypeBase.hxx" #include "CXX/Python3/ExtensionOldType.hxx" #include "CXX/Python3/ExtensionType.hxx" // End of CXX_Extensions.h #endif pycxx-7.1.4/CXX/Python3/IndirectPythonInterface.hxx000644 000765 000024 00000011403 13305260623 022502 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ # define __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ # include "CXX/WrapPython.h" namespace Py { bool InitialisePythonIndirectInterface(); // // Wrap Exception variables as function calls // PyObject * _Exc_BaseException(); # define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ PyObject * _Exc_##eclass(); # include "CXX/Python3/cxx_standard_exceptions.hxx" # undef PYCXX_STANDARD_EXCEPTION // // Wrap Object variables as function calls // PyObject * _None(); PyObject * _False(); PyObject * _True(); // // Wrap Type variables as function calls // PyTypeObject * _List_Type(); bool _List_Check( PyObject *o ); PyTypeObject * _Buffer_Type(); bool _Buffer_Check( PyObject *op ); PyTypeObject * _Class_Type(); bool _Class_Check( PyObject *op ); PyTypeObject * _Instance_Type(); bool _Instance_Check( PyObject *op ); # if !defined( Py_LIMITED_API ) PyTypeObject * _Method_Type(); bool _Method_Check( PyObject *op ); PyTypeObject * _Function_Type(); bool _Function_Check( PyObject *op ); # endif PyTypeObject * _Complex_Type(); bool _Complex_Check( PyObject *op ); PyTypeObject * _Dict_Type(); bool _Dict_Check( PyObject *op ); PyTypeObject * _File_Type(); bool _File_Check( PyObject *op ); PyTypeObject * _Float_Type(); bool _Float_Check( PyObject *op ); PyTypeObject * _Frame_Type(); bool _Frame_Check( PyObject *op ); PyTypeObject * _Bool_Type(); bool _Boolean_Check( PyObject *op ); PyTypeObject * _Int_Type(); bool _Int_Check( PyObject *op ); PyTypeObject * _List_Type(); bool _List_Check( PyObject *op ); PyTypeObject * _Long_Type(); bool _Long_Check( PyObject *op ); PyTypeObject * _CFunction_Type(); bool _CFunction_Check( PyObject *op ); PyTypeObject * _Module_Type(); bool _Module_Check( PyObject *op ); PyTypeObject * _Type_Type(); bool _Type_Check( PyObject *op ); PyTypeObject * _Range_Type(); bool _Range_Check( PyObject *op ); PyTypeObject * _Slice_Type(); bool _Slice_Check( PyObject *op ); PyTypeObject * _Unicode_Type(); bool _Unicode_Check( PyObject *op ); PyTypeObject * _Bytes_Type(); bool _Bytes_Check( PyObject *op ); PyTypeObject * _TraceBack_Type(); bool _TraceBack_Check( PyObject *v ); PyTypeObject * _Tuple_Type(); bool _Tuple_Check( PyObject *op ); # if PY_MAJOR_VERSION == 2 || !defined( Py_LIMITED_API ) int &_Py_DebugFlag(); int &_Py_InteractiveFlag(); int &_Py_OptimizeFlag(); int &_Py_NoSiteFlag(); int &_Py_TabcheckFlag(); int &_Py_VerboseFlag(); # if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7 const char *__Py_PackageContext(); # else char *__Py_PackageContext(); # endif # endif void _XINCREF( PyObject *op ); void _XDECREF( PyObject *op ); }; #endif // __CXX_INDIRECT_PYTHON_INTERFACE__HXX__ pycxx-7.1.4/CXX/Python3/ExtensionTypeBase.hxx000644 000765 000024 00000022453 13662723705 021351 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionTypeBase__h #define __CXX_ExtensionTypeBase__h namespace Py { // Class PythonExtension is what you inherit from to create // a new Python extension type. You give your class itself // as the template paramter. // There are two ways that extension objects can get destroyed. // 1. Their reference count goes to zero // 2. Someone does an explicit delete on a pointer. // In(1) the problem is to get the destructor called // We register a special deallocator in the Python type object // (see behaviors()) to do this. // In(2) there is no problem, the dtor gets called. // PythonExtension does not use the usual Python heap allocator, // instead using new/delete. We do the setting of the type object // and reference count, usually done by PyObject_New, in the // base class ctor. // This special deallocator does a delete on the pointer. class PythonExtensionBase : public PyObject { public: PythonExtensionBase(); virtual ~PythonExtensionBase(); public: // object virtual void reinit( Tuple &args, Dict &kwds ); // object basics #if defined( PYCXX_PYTHON_2TO3 ) && !defined( Py_LIMITED_API ) && PY_MINOR_VERSION <= 7 virtual int print( FILE *, int ); #endif virtual Object getattr( const char * ); virtual int setattr( const char *, const Object & ); virtual Object getattro( const String & ); Object genericGetAttro( const String & ); virtual int setattro( const String &, const Object & ); int genericSetAttro( const String &, const Object & ); virtual int compare( const Object & ); virtual Object rich_compare( const Object &, int ); virtual Object repr(); virtual Object str(); virtual long hash(); virtual Object call( const Object &, const Object & ); virtual Object iter(); virtual PyObject *iternext(); // Sequence methods virtual PyCxx_ssize_t sequence_length(); virtual Object sequence_concat( const Object & ); virtual Object sequence_repeat( Py_ssize_t ); virtual Object sequence_item( Py_ssize_t ); virtual int sequence_ass_item( Py_ssize_t, const Object & ); virtual Object sequence_inplace_concat( const Object & ); virtual Object sequence_inplace_repeat( Py_ssize_t ); virtual int sequence_contains( const Object & ); // Mapping virtual PyCxx_ssize_t mapping_length(); virtual Object mapping_subscript( const Object & ); virtual int mapping_ass_subscript( const Object &, const Object & ); // Number virtual Object number_negative(); virtual Object number_positive(); virtual Object number_absolute(); virtual Object number_invert(); virtual Object number_int(); virtual Object number_float(); virtual Object number_add( const Object & ); virtual Object number_subtract( const Object & ); virtual Object number_multiply( const Object & ); virtual Object number_remainder( const Object & ); virtual Object number_divmod( const Object & ); virtual Object number_lshift( const Object & ); virtual Object number_rshift( const Object & ); virtual Object number_and( const Object & ); virtual Object number_xor( const Object & ); virtual Object number_or( const Object & ); virtual Object number_power( const Object &, const Object & ); virtual Object number_floor_divide( const Object & ); virtual Object number_true_divide( const Object & ); virtual Object number_index(); #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 virtual Object number_matrix_multiply( const Object & ); #endif virtual Object number_inplace_add( const Object & ); virtual Object number_inplace_subtract( const Object & ); virtual Object number_inplace_multiply( const Object & ); virtual Object number_inplace_remainder( const Object & ); virtual Object number_inplace_power( const Object &, const Object & ); virtual Object number_inplace_lshift( const Object & ); virtual Object number_inplace_rshift( const Object & ); virtual Object number_inplace_and( const Object & ); virtual Object number_inplace_xor( const Object & ); virtual Object number_inplace_or( const Object & ); virtual Object number_inplace_floor_divide( const Object & ); virtual Object number_inplace_true_divide( const Object & ); #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 virtual Object number_inplace_matrix_multiply( const Object & ); #endif #if !defined( Py_LIMITED_API ) // Buffer virtual int buffer_get( Py_buffer *, int flags ); virtual int buffer_release( Py_buffer *buf ); #endif public: // helper functions to call function fn_name with 0 to 9 args Object callOnSelf( const std::string &fn_name ); Object callOnSelf( const std::string &fn_name, const Object &arg1 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8 ); Object callOnSelf( const std::string &fn_name, const Object &arg1, const Object &arg2, const Object &arg3, const Object &arg4, const Object &arg5, const Object &arg6, const Object &arg7, const Object &arg8, const Object &arg9 ); public: virtual PyObject *selfPtr() = 0; virtual Object self() = 0; private: void missing_method( void ); static PyObject *method_call_handler( PyObject *self, PyObject *args ); }; } // Namespace Py // End of __CXX_ExtensionTypeBase__h #endif pycxx-7.1.4/CXX/Python3/ExtensionType.hxx000644 000765 000024 00000034745 13662723705 020565 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionClass__h #define __CXX_ExtensionClass__h #define PYCXX_NOARGS_METHOD_NAME( NAME ) _callNoArgsMethod__##NAME #define PYCXX_VARARGS_METHOD_NAME( NAME ) _callVarArgsMethod__##NAME #define PYCXX_KEYWORDS_METHOD_NAME( NAME ) _callKeywordsMethod__##NAME #define PYCXX_NOARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_NOARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *, PyObject * ) \ { \ try \ { \ Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ Py::Object r( (self->NAME)() ); \ return Py::new_reference_to( r.ptr() ); \ } \ catch( Py::BaseException & ) \ { \ return 0; \ } \ } #define PYCXX_VARARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_VARARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject * ) \ { \ try \ { \ Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ Py::Tuple a( _a ); \ Py::Object r( (self->NAME)( a ) ); \ return Py::new_reference_to( r.ptr() ); \ } \ catch( Py::BaseException & ) \ { \ return 0; \ } \ } #define PYCXX_KEYWORDS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_KEYWORDS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject *_k ) \ { \ try \ { \ Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ Py::Tuple a( _a ); \ Py::Dict k; \ if( _k != NULL ) \ k = _k; \ Py::Object r( (self->NAME)( a, k ) ); \ return Py::new_reference_to( r.ptr() ); \ } \ catch( Py::BaseException & ) \ { \ return 0; \ } \ } // need to support METH_STATIC and METH_CLASS #define PYCXX_ADD_NOARGS_METHOD( PYNAME, NAME, docs ) \ add_method( #PYNAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) #define PYCXX_ADD_VARARGS_METHOD( PYNAME, NAME, docs ) \ add_method( #PYNAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) #define PYCXX_ADD_KEYWORDS_METHOD( PYNAME, NAME, docs ) \ add_method( #PYNAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) namespace Py { extern PythonExtensionBase *getPythonExtensionBase( PyObject *self ); struct PythonClassInstance { PyObject_HEAD PythonExtensionBase *m_pycxx_object; }; class ExtensionClassMethodsTable { public: ExtensionClassMethodsTable() : m_methods_table( new PyMethodDef[ METHOD_TABLE_SIZE_INCREMENT ] ) , m_methods_used( 0 ) , m_methods_size( METHOD_TABLE_SIZE_INCREMENT ) { // add the sentinel marking the table end PyMethodDef *p = &m_methods_table[ 0 ]; p->ml_name = NULL; p->ml_meth = NULL; p->ml_flags = 0; p->ml_doc = NULL; } ~ExtensionClassMethodsTable() { delete[] m_methods_table; } // check that all methods added are unique void check_unique_method_name( const char *_name ) { std::string name( _name ); for( int i=0; iml_name = name; p->ml_meth = function; p->ml_flags = flags; p->ml_doc = doc; m_methods_used++; p++; // add the sentinel marking the table end p->ml_name = NULL; p->ml_meth = NULL; p->ml_flags = 0; p->ml_doc = NULL; return m_methods_table; } private: enum {METHOD_TABLE_SIZE_INCREMENT = 1}; PyMethodDef *m_methods_table; int m_methods_used; int m_methods_size; }; template class PythonClass : public PythonExtensionBase { protected: explicit PythonClass( PythonClassInstance *self, Tuple &/*args*/, Dict &/*kwds*/ ) : PythonExtensionBase() , m_class_instance( self ) { } virtual ~PythonClass() {} static ExtensionClassMethodsTable &methodTable() { static ExtensionClassMethodsTable *method_table; if( method_table == NULL ) method_table = new ExtensionClassMethodsTable; return *method_table; } static void add_method( const char *name, PyCFunction function, int flags, const char *doc=NULL ) { behaviors().set_methods( methodTable().add_method( name, function, flags, doc ) ); } static PythonType &behaviors() { static PythonType *p; if( p == NULL ) { #if defined( _CPPRTTI ) || defined( __GNUG__ ) const char *default_name = (typeid( T )).name(); #else const char *default_name = "unknown"; #endif p = new PythonType( sizeof( PythonClassInstance ), 0, default_name ); p->set_tp_new( extension_object_new ); p->set_tp_init( extension_object_init ); p->set_tp_dealloc( extension_object_deallocator ); // we are a class p->supportClass(); // always support get and set attr p->supportGetattro(); p->supportSetattro(); } return *p; } static PyObject *extension_object_new( PyTypeObject *subtype, PyObject * /*args*/, PyObject * /*kwds*/ ) { #ifdef PYCXX_DEBUG std::cout << "extension_object_new()" << std::endl; #endif #if defined( Py_LIMITED_API ) PyObject *object = reinterpret_cast( PyType_GetSlot( subtype, Py_tp_alloc ) )( subtype, 0 ); #else PyObject *object = subtype->tp_alloc( subtype, 0 ); #endif if( object == NULL ) return NULL; PythonClassInstance *o = reinterpret_cast( object ); o->m_pycxx_object = NULL; PyObject *self = reinterpret_cast( o ); #ifdef PYCXX_DEBUG std::cout << "extension_object_new() => self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << std::endl; #endif return self; } static int extension_object_init( PyObject *_self, PyObject *args_, PyObject *kwds_ ) { try { Py::Tuple args( args_ ); Py::Dict kwds; if( kwds_ != NULL ) kwds = kwds_; PythonClassInstance *self = reinterpret_cast( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_init( self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << " )" << std::endl; std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif if( self->m_pycxx_object == NULL ) { self->m_pycxx_object = new T( self, args, kwds ); #ifdef PYCXX_DEBUG std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif } else { #ifdef PYCXX_DEBUG std::cout << " reinit - self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif self->m_pycxx_object->reinit( args, kwds ); } } catch( BaseException & ) { return -1; } return 0; } static void extension_object_deallocator( PyObject *_self ) { PythonClassInstance *self = reinterpret_cast< PythonClassInstance * >( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_deallocator( self=0x" << std::hex << reinterpret_cast< unsigned long >( self ) << std::dec << " )" << std::endl; std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( self->m_pycxx_object ) << std::dec << std::endl; #endif delete self->m_pycxx_object; #ifdef Py_LIMITED_API freefunc fn = reinterpret_cast( PyType_GetSlot( _self->ob_type, Py_tp_free ) ); fn( _self ); #else _self->ob_type->tp_free( _self ); #endif } public: static PyTypeObject *type_object() { return behaviors().type_object(); } static Object type() { return Object( reinterpret_cast( behaviors().type_object() ) ); } static bool check( PyObject *p ) { // is p a me or a derived me switch( PyObject_IsInstance( p, reinterpret_cast( type_object() ) ) ) { default: case -1: throw Exception(); case 0: return false; case 1: return true; } } static bool check( const Object &ob ) { return check( ob.ptr() ); } virtual PyObject *selfPtr() { return reinterpret_cast( m_class_instance ); } virtual Object self() { return Object( reinterpret_cast( m_class_instance ) ); } protected: private: PythonClassInstance *m_class_instance; private: // // prevent the compiler generating these unwanted functions // explicit PythonClass( const PythonClass &other ); void operator=( const PythonClass &rhs ); }; // // ExtensionObject is an Object that will accept only T's. // template class PythonClassObject: public Object { public: explicit PythonClassObject( PyObject *pyob ) : Object( pyob ) { validate(); } PythonClassObject( const PythonClassObject &other ) : Object( *other ) { validate(); } PythonClassObject( const Object &other ) : Object( *other ) { validate(); } PythonClassObject &operator=( const Object &rhs ) { *this = *rhs; return *this; } PythonClassObject &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return( pyob && T::check( pyob ) ); } // // Obtain a pointer to the PythonExtension object // T *getCxxObject( void ) { return dynamic_cast< T * >( getPythonExtensionBase( ptr() ) ); } }; } // Namespace Py // End of __CXX_ExtensionClass__h #endif pycxx-7.1.4/CXX/Python3/Objects.hxx000644 000765 000024 00000274443 13662723705 017341 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_Objects__h #define __CXX_Objects__h #include "CXX/WrapPython.h" #include "CXX/Version.hxx" #include "CXX/Python3/Config.hxx" #include "CXX/Python3/CxxDebug.hxx" #include "CXX/Python3/Exception.hxx" #include #include STR_STREAM #include #include #include #include #include namespace Py { void ifPyErrorThrowCxxException(); typedef Py_ssize_t sequence_index_type; // type of an index into a sequence // Forward declarations class Object; class Type; template class SeqBase; class Bytes; class String; class List; template class MapBase; class Tuple; class Dict; //===========================================================================// // class Object // The purpose of this class is to serve as the most general kind of // Python object, for the purpose of writing C++ extensions in Python // Objects hold a PyObject* which they own. This pointer is always a // valid pointer to a Python object. In children we must maintain this behavior. // // Instructions on how to make your own class MyType descended from Object: // (0) Pick a base class, either Object or perhaps SeqBase or MapBase. // This example assumes Object. // (1) Write a routine int MyType_Check( PyObject * ) modeled after PyInt_Check, // PyFloat_Check, etc. // (2) Add method accepts: // virtual bool accepts( PyObject *pyob ) const { // return pyob && MyType_Check( pyob ); // } // (3) Include the following constructor and copy constructor // /* explicit MyType( PyObject *pyob ): Object( pyob ) { validate(); } MyType( const Object &other ): Object( other.ptr() ) { validate(); } */ // Alernate version for the constructor to allow for construction from owned pointers: /* explicit MyType( PyObject *pyob ): Object( pyob ) { validate(); } */ // You may wish to add other constructors; see the classes below for examples. // Each constructor must use "set" to set the pointer // and end by validating the pointer you have created. //( 4 ) Each class needs at least these two assignment operators: /* MyType &operator=( const Object &rhs ) { return *this = *rhs; } Mytype &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } */ // Note on accepts: constructors call the base class // version of a virtual when calling the base class constructor, // so the test has to be done explicitly in a descendent. // If you are inheriting from PythonExtension to define an object // note that it contains PythonExtension::check // which you can use in accepts when writing a wrapper class. // See Demo/range.h and Demo/range.cxx for an example. class Object { private: // the pointer to the Python object // Only Object sets this directly. // The default constructor for Object sets it to Py_None and // child classes must use "set" to set it // PyObject *p; protected: void set( PyObject *pyob, bool owned = false ) { release(); p = pyob; if( !owned ) { Py::_XINCREF( p ); } validate(); } void release() { Py::_XDECREF( p ); p = NULL; } void validate(); public: // Constructor acquires new ownership of pointer unless explicitly told not to. explicit Object( PyObject *pyob=Py::_None(), bool owned = false ) : p( pyob ) { if( !owned ) { Py::_XINCREF( p ); } validate(); } // Copy constructor acquires new ownership of pointer Object( const Object &ob ) : p( ob.p ) { Py::_XINCREF( p ); validate(); } // Assignment acquires new ownership of pointer Object &operator=( const Object &rhs ) { set( rhs.p ); return *this; } Object &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Destructor virtual ~Object() { release(); } // Loaning the pointer to others, retain ownership PyObject *operator*() const { return p; } // Explicit reference_counting changes void increment_reference_count() { Py::_XINCREF( p ); } void decrement_reference_count() { // not allowed to commit suicide, however if( reference_count() == 1 ) { throw RuntimeError( "Object::decrement_reference_count error." ); } Py::_XDECREF( p ); } // Would like to call this pointer() but messes up STL in SeqBase PyObject *ptr() const { return p; } // // Queries // // Can pyob be used in this object's constructor? virtual bool accepts( PyObject * ) const { // allow any object or NULL return true; } Py_ssize_t reference_count() const { // the reference count return p ? p->ob_refcnt : 0; } Type type() const; // the type object associated with this one String str() const; // the str() representation std::string as_string() const; String repr() const; // the repr() representation List dir() const; // the dir() list bool hasAttr( const std::string &s ) const { return PyObject_HasAttrString( p, const_cast( s.c_str() ) ) ? true: false; } Object getAttr( const std::string &s ) const { return Object( PyObject_GetAttrString( p, const_cast( s.c_str() ) ), true ); } Object callMemberFunction( const std::string &function_name ) const; Object callMemberFunction( const std::string &function_name, const Tuple &args ) const; Object callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const; Object getItem( const Object &key ) const { return Object( PyObject_GetItem( p, *key ), true ); } Py_hash_t hashValue() const { return PyObject_Hash( p ); } // convert to bool bool as_bool() const { return PyObject_IsTrue( ptr() ) != 0; } bool is( PyObject *pother ) const { // identity test return p == pother; } bool is( const Object &other ) const { // identity test return p == other.p; } bool isNull() const { return p == NULL; } bool isNone() const { return p == _None(); } bool isCallable() const { return PyCallable_Check( p ) != 0; } bool isDict() const { return Py::_Dict_Check( p ); } bool isList() const { return Py::_List_Check( p ); } bool isMapping() const { return PyMapping_Check( p ) != 0; } bool isNumeric() const { return PyNumber_Check( p ) != 0; } bool isSequence() const { return PySequence_Check( p ) != 0; } bool isTrue() const { return PyObject_IsTrue( p ) != 0; } bool isType( const Type &t ) const; bool isTuple() const { return Py::_Tuple_Check( p ); } bool isString() const { return Py::_Unicode_Check( p ); } bool isBytes() const { return Py::_Bytes_Check( p ); } bool isBoolean() const { return Py::_Boolean_Check( p ); } // Commands void setAttr( const std::string &s, const Object &value ) { if( PyObject_SetAttrString( p, const_cast( s.c_str() ), *value ) == -1 ) { ifPyErrorThrowCxxException(); } } void delAttr( const std::string &s ) { if( PyObject_DelAttrString( p, const_cast( s.c_str() ) ) == -1 ) { ifPyErrorThrowCxxException(); } } // PyObject_SetItem is too weird to be using from C++ // so it is intentionally omitted. void delItem( const Object &key ) { if( PyObject_DelItem( p, *key ) == -1 ) { ifPyErrorThrowCxxException(); } } // Equality and comparison use PyObject_Compare }; // End of class Object // Null can be return from when it is require to return NULL to Python from a method class Null: public Object { public: Null() : Object( NULL ) { } virtual ~Null() { } virtual bool accepts( PyObject *pyob ) const { return pyob == NULL; } }; //------------------------------------------------------------ bool operator==( const Object &o1, const Object &o2 ); bool operator!=( const Object &o1, const Object &o2 ); bool operator>=( const Object &o1, const Object &o2 ); bool operator<=( const Object &o1, const Object &o2 ); bool operator<( const Object &o1, const Object &o2 ); bool operator>( const Object &o1, const Object &o2 ); //------------------------------------------------------------ // // Convert an owned Python pointer into a PyCXX Object // inline Object asObject( PyObject *p ) { return Object( p, true ); } // new_reference_to also overloaded below on Object inline PyObject *new_reference_to( PyObject *p ) { Py::_XINCREF( p ); return p; } inline PyObject *new_reference_to( const Object &g ) { PyObject *p = g.ptr(); Py::_XINCREF( p ); return p; } // Python special None value inline Object None() { return Object( Py::_None() ); } // Python special Boolean values inline Object False() { return Object( Py::_False() ); } inline Object True() { return Object( Py::_True() ); } // TMM: 31May'01 - Added the #ifndef so I can exlude iostreams. #ifndef CXX_NO_IOSTREAMS std::ostream &operator<<( std::ostream &os, const Object &ob ); #endif // Class Type class Type: public Object { public: explicit Type( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Type( const Object &ob ) : Object( *ob ) { validate(); } Type( const Type &t ) : Object( t ) { validate(); } Type &operator=( const Object &rhs ) { return *this = *rhs; } Type &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Type_Check( pyob ); } }; // =============================================== // class boolean class Boolean: public Object { public: // Constructor Boolean( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Boolean( const Boolean &ob ) : Object( *ob ) { validate(); } // create from bool Boolean( bool v=false ) { set( PyBool_FromLong( v ? 1 : 0 ), true ); validate(); } explicit Boolean( const Object &ob ) : Object( *ob ) { validate(); } // Assignment acquires new ownership of pointer Boolean &operator=( const Object &rhs ) { return *this = *rhs; } Boolean &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { // accepts any object that can be converted to a boolean return pyob && PyObject_IsTrue( pyob ) != -1; } Boolean &operator=( bool v ) { set( PyBool_FromLong( v ? 1 : 0 ), true ); return *this; } operator bool() const { return as_bool(); } }; // =============================================== // class Long class Long: public Object { public: // Constructor explicit Long( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Long( const Long &ob ) : Object( ob.ptr() ) { validate(); } // try to create from any object explicit Long( const Object &ob ) : Object( PyNumber_Long( *ob ), true ) { validate(); } // create from long explicit Long( long v = 0L ) : Object( PyLong_FromLong( v ), true ) { validate(); } // create from unsigned long explicit Long( unsigned long v ) : Object( PyLong_FromUnsignedLong( v ), true ) { validate(); } // create from int explicit Long( int v ) : Object( PyLong_FromLong( static_cast( v ) ), true ) { validate(); } #ifdef HAVE_LONG_LONG // create from long long explicit Long( PY_LONG_LONG v ) : Object( PyLong_FromLongLong( v ), true ) { validate(); } // create from unsigned long long explicit Long( unsigned PY_LONG_LONG v ) : Object( PyLong_FromUnsignedLongLong( v ), true ) { validate(); } #endif // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Long_Check( pyob ); } // Assignment acquires new ownership of pointer Long &operator=( const Object &rhs ) { return *this = *rhs; } Long &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( PyNumber_Long( rhsp ), true ); return *this; } // assign from an int Long &operator=( int v ) { set( PyLong_FromLong( long( v ) ), true ); return *this; } // assign from long Long &operator=( long v ) { set( PyLong_FromLong( v ), true ); return *this; } // assign from unsigned long Long &operator=( unsigned long v ) { set( PyLong_FromUnsignedLong( v ), true ); return *this; } #ifdef HAVE_LONG_LONG Long &operator=( PY_LONG_LONG v ) { set( PyLong_FromLongLong( v ), true ); return *this; } Long &operator=( unsigned PY_LONG_LONG v ) { set( PyLong_FromUnsignedLongLong( v ), true ); return *this; } #endif // convert to long long as_long() const { return PyLong_AsLong( ptr() ); } operator long() const { return as_long(); } operator int() const { return static_cast( as_long() ); } // convert to unsigned long as_unsigned_long() const { return PyLong_AsUnsignedLong( ptr() ); } // convert to unsigned operator unsigned long() const { return as_unsigned_long(); } double as_double() const { return PyLong_AsDouble( ptr() ); } operator double() const { return as_double(); } #ifdef HAVE_LONG_LONG PY_LONG_LONG as_long_long() const { return PyLong_AsLongLong( ptr() ); } operator PY_LONG_LONG() const { return as_long_long(); } unsigned PY_LONG_LONG as_unsigned_long_long() const { return PyLong_AsUnsignedLongLong( ptr() ); } operator unsigned PY_LONG_LONG() const { return as_unsigned_long_long(); } #endif // prefix ++ Long operator++() { set( PyNumber_Add( ptr(), *Long( 1 ) ) ); return *this; } // postfix ++ Long operator++( int ) { Long a = *this; set( PyNumber_Add( ptr(), *Long( 1 ) ) ); return a; } // prefix -- Long operator--() { set( PyNumber_Subtract( ptr(), *Long( 1 ) ) ); return *this; } // postfix -- Long operator--( int ) { Long a = *this; set( PyNumber_Subtract( ptr(), *Long( 1 ) ) ); return a; } }; #ifdef PYCXX_PYTHON_2TO3 // PyCXX for Python2 had an Int and LongLong classes typedef Long Int; #ifdef HAVE_LONG_LONG typedef Long LongLong; #endif #endif #if 1 //------------------------------------------------------------ // compare operators bool operator!=( const Long &a, const Long &b ); bool operator!=( const Long &a, int b ); bool operator!=( const Long &a, long b ); bool operator!=( int a, const Long &b ); bool operator!=( long a, const Long &b ); //------------------------------ bool operator==( const Long &a, const Long &b ); bool operator==( const Long &a, int b ); bool operator==( const Long &a, long b ); bool operator==( int a, const Long &b ); bool operator==( long a, const Long &b ); //------------------------------ bool operator>( const Long &a, const Long &b ); bool operator>( const Long &a, int b ); bool operator>( const Long &a, long b ); bool operator>( int a, const Long &b ); bool operator>( long a, const Long &b ); //------------------------------ bool operator>=( const Long &a, const Long &b ); bool operator>=( const Long &a, int b ); bool operator>=( const Long &a, long b ); bool operator>=( int a, const Long &b ); bool operator>=( long a, const Long &b ); //------------------------------ bool operator<( const Long &a, const Long &b ); bool operator<( const Long &a, int b ); bool operator<( const Long &a, long b ); bool operator<( int a, const Long &b ); bool operator<( long a, const Long &b ); //------------------------------ bool operator<=( const Long &a, const Long &b ); bool operator<=( int a, const Long &b ); bool operator<=( long a, const Long &b ); bool operator<=( const Long &a, int b ); bool operator<=( const Long &a, long b ); #ifdef HAVE_LONG_LONG //------------------------------ bool operator!=( const Long &a, PY_LONG_LONG b ); bool operator!=( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator==( const Long &a, PY_LONG_LONG b ); bool operator==( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator>( const Long &a, PY_LONG_LONG b ); bool operator>( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator>=( const Long &a, PY_LONG_LONG b ); bool operator>=( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator<( const Long &a, PY_LONG_LONG b ); bool operator<( PY_LONG_LONG a, const Long &b ); //------------------------------ bool operator<=( const Long &a, PY_LONG_LONG b ); bool operator<=( PY_LONG_LONG a, const Long &b ); #endif #endif // =============================================== // class Float // class Float: public Object { public: // Constructor explicit Float( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Float( const Float &f ) : Object( f ) { validate(); } // make from double explicit Float( double v=0.0 ) : Object( PyFloat_FromDouble( v ), true ) { validate(); } // try to make from any object Float( const Object &ob ) : Object( PyNumber_Float( *ob ), true ) { validate(); } Float &operator=( const Object &rhs ) { return *this = *rhs; } Float &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( PyNumber_Float( rhsp ), true ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Float_Check( pyob ); } double as_double() const { return PyFloat_AsDouble( ptr() ); } // convert to double operator double() const { return as_double(); } // assign from a double Float &operator=( double v ) { set( PyFloat_FromDouble( v ), true ); return *this; } // assign from an int Float &operator=( int v ) { set( PyFloat_FromDouble( double( v ) ), true ); return *this; } // assign from long Float &operator=( long v ) { set( PyFloat_FromDouble( double( v ) ), true ); return *this; } // assign from an Long Float &operator=( const Long &iob ) { set( PyFloat_FromDouble( double( iob.as_long() ) ), true ); return *this; } }; //------------------------------------------------------------ // compare operators bool operator!=( const Float &a, const Float &b ); bool operator!=( const Float &a, double b ); bool operator!=( double a, const Float &b ); //------------------------------ bool operator==( const Float &a, const Float &b ); bool operator==( const Float &a, double b ); bool operator==( double a, const Float &b ); //------------------------------ bool operator>( const Float &a, const Float &b ); bool operator>( const Float &a, double b ); bool operator>( double a, const Float &b ); //------------------------------ bool operator>=( const Float &a, const Float &b ); bool operator>=( const Float &a, double b ); bool operator>=( double a, const Float &b ); //------------------------------ bool operator<( const Float &a, const Float &b ); bool operator<( const Float &a, double b ); bool operator<( double a, const Float &b ); //------------------------------ bool operator<=( const Float &a, const Float &b ); bool operator<=( double a, const Float &b ); bool operator<=( const Float &a, double b ); // =============================================== // class Complex class Complex: public Object { public: // Constructor explicit Complex( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Complex( const Complex &f ) : Object( f ) { validate(); } // make from double explicit Complex( double v=0.0, double w=0.0 ) :Object( PyComplex_FromDoubles( v, w ), true ) { validate(); } Complex &operator=( const Object &rhs ) { return *this = *rhs; } Complex &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Complex_Check( pyob ); } #if !defined( Py_LIMITED_API ) // convert to Py_complex operator Py_complex() const { return PyComplex_AsCComplex( ptr() ); } // assign from a Py_complex Complex &operator=( const Py_complex &v ) { set( PyComplex_FromCComplex( v ), true ); return *this; } #endif // Py_LIMITED_API // assign from a double Complex &operator=( double v ) { set( PyComplex_FromDoubles( v, 0.0 ), true ); return *this; } // assign from an int Complex &operator=( int v ) { set( PyComplex_FromDoubles( double( v ), 0.0 ), true ); return *this; } // assign from long Complex &operator=( long v ) { set( PyComplex_FromDoubles( double( v ), 0.0 ), true ); return *this; } // assign from an Long Complex &operator=( const Long &iob ) { set( PyComplex_FromDoubles( double( iob.as_long() ), 0.0 ), true ); return *this; } double real() const { return PyComplex_RealAsDouble( ptr() ); } double imag() const { return PyComplex_ImagAsDouble( ptr() ); } }; // Sequences // Sequences are here represented as sequences of items of type T. // The base class SeqBase represents that. // In basic Python T is always "Object". // seqref is what you get if you get elements from a non-const SeqBase. // Note: seqref could probably be a nested class in SeqBase but that might stress // some compilers needlessly. Simlarly for mapref later. // While this class is not intended for enduser use, it needs some public // constructors for the benefit of the STL. // See Scott Meyer's More Essential C++ for a description of proxies. // This application is even more complicated. We are doing an unusual thing // in having a double proxy. If we want the STL to work // properly we have to compromise by storing the rvalue inside. The // entire Object API is repeated so that things like s[i].isList() will // work properly. // Still, once in a while a weird compiler message may occur using expressions like x[i] // Changing them to Object( x[i] ) helps the compiler to understand that the // conversion of a seqref to an Object is wanted. template class seqref { protected: SeqBase &s; // the sequence sequence_index_type offset; // item number T the_item; // lvalue public: seqref( SeqBase &seq, sequence_index_type j ) : s( seq ) , offset( j ) , the_item( s.getItem( j ) ) {} seqref( const seqref &range ) : s( range.s ) , offset( range.offset ) , the_item( range.the_item ) {} // TMM: added this seqref ctor for use with STL algorithms seqref( Object &obj ) : s( dynamic_cast< SeqBase&>( obj ) ) , offset( 0 ) , the_item( s.getItem( offset ) ) {} ~seqref() {} operator T() const { // rvalue return the_item; } seqref &operator=( const seqref &rhs ) { //used as lvalue the_item = rhs.the_item; s.setItem( offset, the_item ); return *this; } seqref &operator=( const T &ob ) { // used as lvalue the_item = ob; s.setItem( offset, ob ); return *this; } // forward everything else to the item PyObject *ptr() const { return the_item.ptr(); } int reference_count() const { // the reference count return the_item.reference_count(); } Type type() const { return the_item.type(); } String str() const; String repr() const; bool hasAttr( const std::string &attr_name ) const { return the_item.hasAttr( attr_name ); } Object getAttr( const std::string &attr_name ) const { return the_item.getAttr( attr_name ); } Object getItem( const Object &key ) const { return the_item.getItem( key ); } long hashValue() const { return the_item.hashValue(); } bool isCallable() const { return the_item.isCallable(); } bool isInstance() const { return the_item.isInstance(); } bool isDict() const { return the_item.isDict(); } bool isList() const { return the_item.isList(); } bool isMapping() const { return the_item.isMapping(); } bool isNumeric() const { return the_item.isNumeric(); } bool isSequence() const { return the_item.isSequence(); } bool isTrue() const { return the_item.isTrue(); } bool isType( const Type &t ) const { return the_item.isType( t ); } bool isTuple() const { return the_item.isTuple(); } bool isString() const { return the_item.isString(); } // Commands void setAttr( const std::string &attr_name, const Object &value ) { the_item.setAttr( attr_name, value ); } void delAttr( const std::string &attr_name ) { the_item.delAttr( attr_name ); } void delItem( const Object &key ) { the_item.delItem( key ); } bool operator==( const Object &o2 ) const { return the_item == o2; } bool operator!=( const Object &o2 ) const { return the_item != o2; } bool operator>=( const Object &o2 ) const { return the_item >= o2; } bool operator<=( const Object &o2 ) const { return the_item <= o2; } bool operator<( const Object &o2 ) const { return the_item < o2; } bool operator>( const Object &o2 ) const { return the_item > o2; } }; // end of seqref // class SeqBase // ...the base class for all sequence types template class SeqBase: public Object { public: // STL definitions typedef PyCxx_ssize_t size_type; typedef seqref reference; typedef T const_reference; typedef seqref *pointer; typedef int difference_type; typedef T value_type; // TMM: 26Jun'01 virtual size_type max_size() const { return static_cast( std::string::npos ); // why this constant its not from python } virtual size_type capacity() const { return size(); } virtual void swap( SeqBase &c ) { SeqBase temp = c; c = ptr(); set( temp.ptr() ); } virtual size_type size() const { return PySequence_Length( ptr() ); } explicit SeqBase() :Object( PyTuple_New( 0 ), true ) { validate(); } explicit SeqBase( PyObject *pyob, bool owned=false ) : Object( pyob, owned ) { validate(); } SeqBase( const Object &ob ) : Object( ob ) { validate(); } // Assignment acquires new ownership of pointer SeqBase &operator=( const Object &rhs ) { return *this = *rhs; } SeqBase &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return pyob && PySequence_Check( pyob ); } size_type length() const { return PySequence_Length( ptr() ); } // Element access const T operator[]( sequence_index_type index ) const { return getItem( index ); } seqref operator[]( sequence_index_type index ) { return seqref( *this, index ); } virtual T getItem( sequence_index_type i ) const { return T( asObject( PySequence_GetItem( ptr(), i ) ) ); } virtual void setItem( sequence_index_type i, const T &ob ) { if( PySequence_SetItem( ptr(), i, *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } SeqBase repeat( int count ) const { return SeqBase( PySequence_Repeat( ptr(), count ), true ); } SeqBase concat( const SeqBase &other ) const { return SeqBase( PySequence_Concat( ptr(), *other ), true ); } // more STL compatability const T front() const { return getItem( 0 ); } seqref front() { return seqref( *this, 0 ); } const T back() const { return getItem( size()-1 ); } seqref back() { return seqref( *this, size()-1 ); } void verify_length( size_type required_size ) const { if( size() != required_size ) { throw IndexError( "Unexpected SeqBase length." ); } } void verify_length( size_type min_size, size_type max_size ) const { size_type n = size(); if( n < min_size || n > max_size ) { throw IndexError( "Unexpected SeqBase length." ); } } class iterator: public random_access_iterator_parent( seqref ) { protected: friend class SeqBase; SeqBase *seq; sequence_index_type count; public: ~iterator() {} iterator() : seq( 0 ) , count( 0 ) {} iterator( SeqBase *s, Py_ssize_t where ) : seq( s ) , count( where ) {} iterator( const iterator &other ) : seq( other.seq ) , count( other.count ) {} bool eql( const iterator &other ) const { return seq->ptr() == other.seq->ptr() && count == other.count; } bool neq( const iterator &other ) const { return seq->ptr() != other.seq->ptr() || count != other.count; } bool lss( const iterator &other ) const { return count < other.count; } bool gtr( const iterator &other ) const { return count > other.count; } bool leq( const iterator &other ) const { return count <= other.count; } bool geq( const iterator &other ) const { return count >= other.count; } seqref operator*() { return seqref( *seq, count ); } seqref operator[]( sequence_index_type i ) { return seqref( *seq, count + i ); } iterator &operator=( const iterator &other ) { if( this != &other ) { seq = other.seq; count = other.count; } return *this; } iterator operator+( sequence_index_type n ) const { return iterator( seq, count + n ); } iterator operator-( sequence_index_type n ) const { return iterator( seq, count - n ); } iterator &operator+=( sequence_index_type n ) { count = count + n; return *this; } iterator &operator-=( sequence_index_type n ) { count = count - n; return *this; } sequence_index_type operator-( const iterator &other ) const { if( seq->ptr() != other.seq->ptr() ) { throw RuntimeError( "SeqBase::iterator comparison error" ); } return count - other.count; } // prefix ++ iterator &operator++() { count++; return *this; } // postfix ++ iterator operator++( int ) { return iterator( seq, count++ ); } // prefix -- iterator &operator--() { count--; return *this; } // postfix -- iterator operator--( int ) { return iterator( seq, count-- ); } std::string diagnose() const { std::OSTRSTREAM oss; oss << "iterator diagnosis " << seq << ", " << count << std::ends; return std::string( oss.str() ); } }; // end of class SeqBase::iterator iterator begin() { return iterator( this, 0 ); } iterator end() { return iterator( this, length() ); } class const_iterator : public random_access_iterator_parent( const Object ) { protected: friend class SeqBase; const SeqBase *seq; sequence_index_type count; public: ~const_iterator() {} const_iterator() : seq( 0 ) , count( 0 ) {} const_iterator( const SeqBase *s, sequence_index_type where ) : seq( s ) , count( where ) {} const_iterator( const const_iterator &other ) : seq( other.seq ) , count( other.count ) {} const T operator*() const { return seq->getItem( count ); } const T operator[]( sequence_index_type i ) const { return seq->getItem( count + i ); } const_iterator &operator=( const const_iterator &other ) { if( this != &other ) { seq = other.seq; count = other.count; } return *this; } const_iterator operator+( sequence_index_type n ) const { return const_iterator( seq, count + n ); } bool eql( const const_iterator &other ) const { return seq->ptr() == other.seq->ptr() && count == other.count; } bool neq( const const_iterator &other ) const { return seq->ptr() != other.seq->ptr() || count != other.count; } bool lss( const const_iterator &other ) const { return count < other.count; } bool gtr( const const_iterator &other ) const { return count > other.count; } bool leq( const const_iterator &other ) const { return count <= other.count; } bool geq( const const_iterator &other ) const { return count >= other.count; } const_iterator operator-( sequence_index_type n ) { return const_iterator( seq, count - n ); } const_iterator &operator+=( sequence_index_type n ) { count = count + n; return *this; } const_iterator &operator-=( sequence_index_type n ) { count = count - n; return *this; } int operator-( const const_iterator &other ) const { if( *seq != *other.seq ) { throw RuntimeError( "SeqBase::const_iterator::- error" ); } return count - other.count; } // prefix ++ const_iterator &operator++() { count++; return *this; } // postfix ++ const_iterator operator++( int ) { return const_iterator( seq, count++ ); } // prefix -- const_iterator &operator--() { count--; return *this; } // postfix -- const_iterator operator--( int ) { return const_iterator( seq, count-- ); } }; // end of class SeqBase::const_iterator const_iterator begin() const { return const_iterator( this, 0 ); } const_iterator end() const { return const_iterator( this, length() ); } }; // Here's an important typedef you might miss if reading too fast... typedef SeqBase Sequence; template bool operator==( const EXPLICIT_TYPENAME SeqBase::iterator &left, const EXPLICIT_TYPENAME SeqBase::iterator &right ); template bool operator!=( const EXPLICIT_TYPENAME SeqBase::iterator &left, const EXPLICIT_TYPENAME SeqBase::iterator &right ); template bool operator< ( const EXPLICIT_TYPENAME SeqBase::iterator &left, const EXPLICIT_TYPENAME SeqBase::iterator &right ); template bool operator> ( const EXPLICIT_TYPENAME SeqBase::iterator &left, const EXPLICIT_TYPENAME SeqBase::iterator &right ); template bool operator<=( const EXPLICIT_TYPENAME SeqBase::iterator &left, const EXPLICIT_TYPENAME SeqBase::iterator &right ); template bool operator>=( const EXPLICIT_TYPENAME SeqBase::iterator &left, const EXPLICIT_TYPENAME SeqBase::iterator &right ); template bool operator==( const EXPLICIT_TYPENAME SeqBase::const_iterator &left, const EXPLICIT_TYPENAME SeqBase::const_iterator &right ); template bool operator!=( const EXPLICIT_TYPENAME SeqBase::const_iterator &left, const EXPLICIT_TYPENAME SeqBase::const_iterator &right ); template bool operator< ( const EXPLICIT_TYPENAME SeqBase::const_iterator &left, const EXPLICIT_TYPENAME SeqBase::const_iterator &right ); template bool operator> ( const EXPLICIT_TYPENAME SeqBase::const_iterator &left, const EXPLICIT_TYPENAME SeqBase::const_iterator &right ); template bool operator<=( const EXPLICIT_TYPENAME SeqBase::const_iterator &left, const EXPLICIT_TYPENAME SeqBase::const_iterator &right ); template bool operator>=( const EXPLICIT_TYPENAME SeqBase::const_iterator &left, const EXPLICIT_TYPENAME SeqBase::const_iterator &right ); extern bool operator==( const Sequence::iterator &left, const Sequence::iterator &right ); extern bool operator!=( const Sequence::iterator &left, const Sequence::iterator &right ); extern bool operator< ( const Sequence::iterator &left, const Sequence::iterator &right ); extern bool operator> ( const Sequence::iterator &left, const Sequence::iterator &right ); extern bool operator<=( const Sequence::iterator &left, const Sequence::iterator &right ); extern bool operator>=( const Sequence::iterator &left, const Sequence::iterator &right ); extern bool operator==( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); extern bool operator!=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); extern bool operator< ( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); extern bool operator> ( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); extern bool operator<=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); extern bool operator>=( const Sequence::const_iterator &left, const Sequence::const_iterator &right ); // ================================================== // class Char // Python strings return strings as individual elements. // I'll try having a class Char which is a String of length 1 // #if !defined(Py_LIMITED_API) typedef std::basic_string unicodestring; extern Py_UNICODE unicode_null_string[1]; #endif typedef std::basic_string ucs4string; extern Py_UCS4 ucs4_null_string[1]; class Byte: public Object { public: // Membership virtual bool accepts( PyObject *pyob ) const { return pyob != NULL && Py::_Bytes_Check( pyob ) && PySequence_Length( pyob ) == 1; } explicit Byte( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Byte( const Object &ob ) : Object( ob ) { validate(); } Byte( const std::string &v = "" ) : Object( PyBytes_FromStringAndSize( const_cast( v.c_str() ), 1 ), true ) { validate(); } Byte( char v ) : Object( PyBytes_FromStringAndSize( &v, 1 ), true ) { validate(); } // Assignment acquires new ownership of pointer Byte &operator=( const Object &rhs ) { return *this = *rhs; } Byte &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Assignment from C string Byte &operator=( const std::string &v ) { set( PyBytes_FromStringAndSize( const_cast( v.c_str() ), 1 ), true ); return *this; } Byte &operator=( char v ) { set( PyUnicode_FromStringAndSize( &v, 1 ), true ); return *this; } // Conversion operator Bytes() const; }; class Bytes: public SeqBase { public: // Membership virtual bool accepts( PyObject *pyob ) const { return pyob != NULL && Py::_Bytes_Check( pyob ); } virtual size_type capacity() const { return max_size(); } explicit Bytes( PyObject *pyob, bool owned = false ) : SeqBase( pyob, owned ) { validate(); } Bytes( const Object &ob ) : SeqBase( ob ) { validate(); } Bytes() : SeqBase( PyBytes_FromStringAndSize( "", 0 ), true ) { validate(); } Bytes( const std::string &v ) : SeqBase( PyBytes_FromStringAndSize( const_cast( v.data() ), v.length() ), true ) { validate(); } Bytes( const std::string &v, Py_ssize_t vsize ) : SeqBase( PyBytes_FromStringAndSize( const_cast( v.data() ), vsize ), true ) { validate(); } Bytes( const char *v ) : SeqBase( PyBytes_FromString( v ), true ) { validate(); } Bytes( const char *v, Py_ssize_t vsize ) : SeqBase( PyBytes_FromStringAndSize( const_cast( v ), vsize ), true ) { validate(); } // Assignment acquires new ownership of pointer Bytes &operator=( const Object &rhs ) { return *this = *rhs; } Bytes &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Assignment from C string Bytes &operator=( const std::string &v ) { set( PyBytes_FromStringAndSize( const_cast( v.data() ), v.length() ), true ); return *this; } String decode( const char *encoding, const char *error="strict" ); // Queries virtual size_type size() const { return PyBytes_Size( ptr() ); } operator std::string() const { return as_std_string(); } std::string as_std_string() const { return std::string( PyBytes_AsString( ptr() ), static_cast( PyBytes_Size( ptr() ) ) ); } }; class Char: public Object { public: // Membership virtual bool accepts( PyObject *pyob ) const { return (pyob != 0 && Py::_Unicode_Check( pyob ) && PySequence_Length( pyob ) == 1); } explicit Char( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Char( const Object &ob ) : Object( ob ) { validate(); } Char( int v ) : Object( PyUnicode_FromOrdinal( v ), true ) { validate(); } #if !defined( Py_LIMITED_API ) Char( Py_UNICODE v ) : Object( PyUnicode_FromOrdinal( v ), true ) { validate(); } #endif #if !defined( Py_LIMITED_API ) Char( const unicodestring &v ) : Object( PyUnicode_FromUnicode( const_cast( v.data() ),1 ), true ) { validate(); } #endif // Assignment acquires new ownership of pointer Char &operator=( const Object &rhs ) { return *this = *rhs; } Char &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } #if !defined( Py_LIMITED_API ) Char &operator=( const unicodestring &v ) { set( PyUnicode_FromUnicode( const_cast( v.data() ), 1 ), true ); return *this; } #endif #if !defined( Py_LIMITED_API ) Char &operator=( int v_ ) { Py_UNICODE v( static_cast( v_ ) ); set( PyUnicode_FromUnicode( &v, 1 ), true ); return *this; } #endif #if !defined( Py_LIMITED_API ) Char &operator=( Py_UNICODE v ) { set( PyUnicode_FromUnicode( &v, 1 ), true ); return *this; } #endif long ord() { #if !defined( Py_LIMITED_API ) return static_cast( PyUnicode_ReadChar( ptr(), 0 ) ); #else // we know that a Char() is 1 unicode code point // that fits in 2 wchar_t on windows at worst wchar_t buf[2]; Py_ssize_t num_elements = PyUnicode_AsWideChar( ptr(), buf, 2 ); // just one wchar_t that easy if( num_elements == 1 ) { return static_cast( buf[0] ); } // must be a pair of utf-16 surragates - convert to a code point if( num_elements == 2 ) { // convert from utf-16 to a code-point return static_cast( ((buf[0]-0xd800)*0x400) + (buf[1]-0xdc00) + 0x10000); } return 0; #endif } // Conversion operator String() const; }; class String: public SeqBase { public: virtual size_type capacity() const { return max_size(); } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob != NULL && Py::_Unicode_Check( pyob ); } explicit String( PyObject *pyob, bool owned = false ) : SeqBase( pyob, owned ) { validate(); } String( const Object &ob ) : SeqBase( ob ) { validate(); } String() : SeqBase( PyUnicode_FromString( "" ), true ) { validate(); } String( const char *latin1 ) : SeqBase( PyUnicode_FromString( latin1 ), true ) { validate(); } String( const std::string &latin1 ) : SeqBase( PyUnicode_FromStringAndSize( latin1.c_str(), latin1.size() ), true ) { validate(); } String( const char *latin1, Py_ssize_t size ) : SeqBase( PyUnicode_FromStringAndSize( latin1, size ), true ) { validate(); } /* [Taken from Pythons's unicode.h] Many of these APIs take two arguments encoding and errors. These parameters encoding and errors have the same semantics as the ones of the builtin unicode() API. Setting encoding to NULL causes the default encoding to be used. Error handling is set by errors which may also be set to NULL meaning to use the default handling defined for the codec. Default error handling for all builtin codecs is "strict" (ValueErrors are raised). The codecs all use a similar interface. Only deviation from the generic ones are documented. */ String( const std::string &s, const char *encoding, const char *errors=NULL ) : SeqBase( PyUnicode_Decode( s.c_str(), s.size(), encoding, errors ), true ) { validate(); } String( const char *s, const char *encoding, const char *errors=NULL ) : SeqBase( PyUnicode_Decode( s, strlen(s), encoding, errors ), true ) { validate(); } String( const char *s, Py_ssize_t size, const char *encoding, const char *errors=NULL ) : SeqBase( PyUnicode_Decode( s, size, encoding, errors ), true ) { validate(); } #if !defined( Py_LIMITED_API ) && !defined( Py_UNICODE_WIDE ) // Need these c'tors becuase Py_UNICODE is 2 bytes // User may use "int" or "unsigned int" as the unicode type String( const unsigned int *s, int length ) : SeqBase( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, reinterpret_cast( s ), length ), true ) { validate(); } String( const int *s, int length ) : SeqBase( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, reinterpret_cast( s ), length ), true ) { validate(); } #endif #if !defined( Py_LIMITED_API ) String( const Py_UNICODE *s, int length ) : SeqBase( PyUnicode_FromUnicode( s, length ), true ) { validate(); } #endif // Assignment acquires new ownership of pointer String &operator=( const Object &rhs ) { return *this = *rhs; } String &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } #if !defined( Py_LIMITED_API ) String &operator=( const unicodestring &v ) { set( PyUnicode_FromUnicode( const_cast( v.data() ), v.length() ), true ); return *this; } #endif #if !defined( Py_UNICODE_WIDE ) && !defined( Py_LIMITED_API ) String &operator=( const ucs4string &v ) { set( PyUnicode_FromKindAndData( PyUnicode_4BYTE_KIND, reinterpret_cast( v.data() ), v.length() ), true ); return *this; } #endif // Encode Bytes encode( const char *encoding, const char *error="strict" ) const { return Bytes( PyUnicode_AsEncodedString( ptr(), encoding, error ), true ); } #if !defined( Py_LIMITED_API ) // Queries virtual size_type size() const { return PyUnicode_GetLength( ptr() ); } #endif #if !defined( Py_LIMITED_API ) const Py_UNICODE *unicode_data() const { return PyUnicode_AS_UNICODE( ptr() ); } #endif #if !defined( Py_LIMITED_API ) unicodestring as_unicodestring() const { return unicodestring( unicode_data(), PyUnicode_GetLength( ptr() ) ); } #endif ucs4string as_ucs4string() const { Py_UCS4 *buf = new Py_UCS4[ size() ]; if( PyUnicode_AsUCS4( ptr(), buf, size(), 0 ) == NULL ) { ifPyErrorThrowCxxException(); } ucs4string ucs4( buf, size() ); delete[] buf; return ucs4; } operator std::string() const { // use the default encoding return as_std_string( NULL ); } std::string as_std_string( const char *encoding=NULL, const char *error="strict" ) const { Bytes b( encode( encoding, error ) ); return b.as_std_string(); } }; // ================================================== // class Tuple class Tuple: public Sequence { public: virtual void setItem( sequence_index_type offset, const Object&ob ) { // note PyTuple_SetItem is a thief... if( PyTuple_SetItem( ptr(), offset, new_reference_to( ob ) ) == -1 ) { ifPyErrorThrowCxxException(); } } // Constructor explicit Tuple( PyObject *pyob, bool owned = false ) : Sequence( pyob, owned ) { validate(); } Tuple( const Object &ob ) : Sequence( ob ) { validate(); } // New tuple of a given size explicit Tuple( int size=0 ) { set( PyTuple_New( size ), true ); validate(); for( sequence_index_type i=0; i < size; i++ ) { if( PyTuple_SetItem( ptr(), i, new_reference_to( Py::_None() ) ) == -1 ) { ifPyErrorThrowCxxException(); } } } // Tuple from any sequence explicit Tuple( const Sequence &s ) { sequence_index_type limit( sequence_index_type( s.length() ) ); set( PyTuple_New( limit ), true ); validate(); for( sequence_index_type i=0; i < limit; i++ ) { if( PyTuple_SetItem( ptr(), i, new_reference_to( s[i] ) ) == -1 ) { ifPyErrorThrowCxxException(); } } } // Assignment acquires new ownership of pointer Tuple &operator=( const Object &rhs ) { return *this = *rhs; } Tuple &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Tuple_Check( pyob ); } Tuple getSlice( int i, int j ) const { return Tuple( PySequence_GetSlice( ptr(), i, j ), true ); } }; class TupleN: public Tuple { public: TupleN() : Tuple( 0 ) { } TupleN( const Object &obj1 ) : Tuple( 1 ) { setItem( 0, obj1 ); } TupleN( const Object &obj1, const Object &obj2 ) : Tuple( 2 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3 ) : Tuple( 3 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4 ) : Tuple( 4 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5 ) : Tuple( 5 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6 ) : Tuple( 6 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6, const Object &obj7 ) : Tuple( 7 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); setItem( 6, obj7 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6, const Object &obj7, const Object &obj8 ) : Tuple( 8 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); setItem( 6, obj7 ); setItem( 7, obj8 ); } TupleN( const Object &obj1, const Object &obj2, const Object &obj3, const Object &obj4, const Object &obj5, const Object &obj6, const Object &obj7, const Object &obj8, const Object &obj9 ) : Tuple( 9 ) { setItem( 0, obj1 ); setItem( 1, obj2 ); setItem( 2, obj3 ); setItem( 3, obj4 ); setItem( 4, obj5 ); setItem( 5, obj6 ); setItem( 6, obj7 ); setItem( 7, obj8 ); setItem( 8, obj9 ); } virtual ~TupleN() { } }; // ================================================== // class List class List: public Sequence { public: // Constructor explicit List( PyObject *pyob, bool owned = false ) : Sequence( pyob, owned ) { validate(); } List( const Object &ob ) : Sequence( ob ) { validate(); } // Creation at a fixed size List( size_type size = 0 ) { set( PyList_New( size ), true ); validate(); for( sequence_index_type i=0; i < size; i++ ) { if( PyList_SetItem( ptr(), i, new_reference_to( Py::_None() ) ) == -1 ) { ifPyErrorThrowCxxException(); } } } // List from a sequence List( const Sequence &s ) : Sequence() { size_type n = s.length(); set( PyList_New( n ), true ); validate(); for( sequence_index_type i=0; i < n; i++ ) { if( PyList_SetItem( ptr(), i, new_reference_to( s[i] ) ) == -1 ) { ifPyErrorThrowCxxException(); } } } virtual size_type capacity() const { return max_size(); } // Assignment acquires new ownership of pointer List &operator=( const Object &rhs ) { return *this = *rhs; } List &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_List_Check( pyob ); } List getSlice( int i, int j ) const { return List( PyList_GetSlice( ptr(), i, j ), true ); } void setSlice( Py_ssize_t i, Py_ssize_t j, const Object &v ) { if( PyList_SetSlice( ptr(), i, j, *v ) == -1 ) { ifPyErrorThrowCxxException(); } } void append( const Object &ob ) { if( PyList_Append( ptr(), *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } void extend( const Object &ob ) { setSlice( size(), size(), ob ); } void insert( int i, const Object &ob ) { if( PyList_Insert( ptr(), i, *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } void sort() { if( PyList_Sort( ptr() ) == -1 ) { ifPyErrorThrowCxxException(); } } void reverse() { if( PyList_Reverse( ptr() ) == -1 ) { ifPyErrorThrowCxxException(); } } }; // Mappings // ================================================== template class mapref { protected: MapBase &s; // the map Object key; // item key T the_item; public: mapref( MapBase &map, const std::string &k ) : s( map ), the_item() { key = String( k ); if( map.hasKey( key ) ) the_item = map.getItem( key ); } mapref( MapBase &map, const Object &k ) : s( map ), key( k ), the_item() { if( map.hasKey( key ) ) the_item = map.getItem( key ); } virtual ~mapref() {} // MapBase stuff // lvalue mapref &operator=( const mapref &other ) { if( this != &other ) { the_item = other.the_item; s.setItem( key, other.the_item ); } return *this; } mapref &operator=( const T &ob ) { the_item = ob; s.setItem( key, ob ); return *this; } // rvalue operator T() const { return the_item; } // forward everything else to the_item PyObject *ptr() const { return the_item.ptr(); } int reference_count() const { // the mapref count return the_item.reference_count(); } Type type() const { return the_item.type(); } String str() const { return the_item.str(); } String repr() const { return the_item.repr(); } bool hasAttr( const std::string &attr_name ) const { return the_item.hasAttr( attr_name ); } Object getAttr( const std::string &attr_name ) const { return the_item.getAttr( attr_name ); } Object getItem( const Object &k ) const { return the_item.getItem( k ); } long hashValue() const { return the_item.hashValue(); } bool isCallable() const { return the_item.isCallable(); } bool isInstance() const { return the_item.isInstance(); } bool isList() const { return the_item.isList(); } bool isMapping() const { return the_item.isMapping(); } bool isNumeric() const { return the_item.isNumeric(); } bool isSequence() const { return the_item.isSequence(); } bool isTrue() const { return the_item.isTrue(); } bool isType( const Type &t ) const { return the_item.isType( t ); } bool isTuple() const { return the_item.isTuple(); } bool isString() const { return the_item.isString(); } // Commands void setAttr( const std::string &attr_name, const Object &value ) { the_item.setAttr( attr_name, value ); } void delAttr( const std::string &attr_name ) { the_item.delAttr( attr_name ); } void delItem( const Object &k ) { the_item.delItem( k ); } }; // end of mapref #if 0 // TMM: now for mapref template< class T > bool operator==( const mapref &left, const mapref &right ) { return true; // NOT completed. } template< class T > bool operator!=( const mapref &left, const mapref &right ) { return true; // not completed. } #endif template class MapBase: public Object { protected: explicit MapBase() {} public: // reference: proxy class for implementing [] // TMM: 26Jun'01 - the types // If you assume that Python mapping is a hash_map... // hash_map::value_type is not assignable, but //( *it ).second = data must be a valid expression typedef PyCxx_ssize_t size_type; typedef Object key_type; typedef mapref data_type; typedef std::pair< const T, T > value_type; typedef std::pair< const T, mapref > reference; typedef const std::pair< const T, const T > const_reference; typedef std::pair< const T, mapref > pointer; // Constructor explicit MapBase( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } // TMM: 02Jul'01 - changed MapBase to Object in next line MapBase( const Object &ob ) : Object( ob ) { validate(); } // Assignment acquires new ownership of pointer MapBase &operator=( const Object &rhs ) { return *this = *rhs; } MapBase &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && PyMapping_Check( pyob ); } // Clear -- PyMapping Clear is missing // void clear() { List k = keys(); for( List::iterator i = k.begin(); i != k.end(); i++ ) { delItem( *i ); } } virtual Py_ssize_t size() const { return PyMapping_Length( ptr() ); } // Element Access T operator[]( const std::string &key ) const { return getItem( key ); } T operator[]( const Object &key ) const { return getItem( key ); } mapref operator[]( const char *key ) { return mapref( *this, key ); } mapref operator[]( const std::string &key ) { return mapref( *this, key ); } mapref operator[]( const Object &key ) { return mapref( *this, key ); } Py_ssize_t length() const { return PyMapping_Length( ptr() ); } bool hasKey( const std::string &s ) const { return PyMapping_HasKeyString( ptr(),const_cast( s.c_str() ) ) != 0; } bool hasKey( const Object &s ) const { return PyMapping_HasKey( ptr(), s.ptr() ) != 0; } T getItem( const std::string &s ) const { return T( asObject( PyMapping_GetItemString( ptr(), const_cast( s.c_str() ) ) ) ); } T getItem( const Object &s ) const { return T( asObject( PyObject_GetItem( ptr(), s.ptr() ) ) ); } virtual void setItem( const char *s, const Object &ob ) { if( PyMapping_SetItemString( ptr(), const_cast( s ), *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } virtual void setItem( const std::string &s, const Object &ob ) { if( PyMapping_SetItemString( ptr(), const_cast( s.c_str() ), *ob ) == -1 ) { ifPyErrorThrowCxxException(); } } virtual void setItem( const Object &s, const Object &ob ) { if( PyObject_SetItem( ptr(), s.ptr(), ob.ptr() ) == -1 ) { ifPyErrorThrowCxxException(); } } void delItem( const std::string &s ) { if( PyMapping_DelItemString( ptr(), const_cast( s.c_str() ) ) == -1 ) { ifPyErrorThrowCxxException(); } } void delItem( const Object &s ) { if( PyMapping_DelItem( ptr(), *s ) == -1 ) { ifPyErrorThrowCxxException(); } } // Queries List keys() const { return List( PyMapping_Keys( ptr() ), true ); } List values() const { // each returned item is a (key, value) pair return List( PyMapping_Values( ptr() ), true ); } List items() const { return List( PyMapping_Items( ptr() ), true ); } class iterator { // : public forward_iterator_parent( std::pair ) { protected: typedef std::forward_iterator_tag iterator_category; typedef std::pair< const T, T > value_type; typedef int difference_type; typedef std::pair< const T, mapref > pointer; typedef std::pair< const T, mapref > reference; friend class MapBase; // MapBase *map; List keys; // for iterating over the map sequence_index_type pos; // index into the keys public: ~iterator() {} iterator() : map( 0 ) , keys() , pos( 0 ) {} iterator( MapBase *m, bool end = false ) : map( m ) , keys( m->keys() ) , pos( end ? keys.length() : 0 ) {} iterator( const iterator &other ) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} iterator( MapBase *map_, List keys_, int pos_ ) : map( map_ ) , keys( keys_ ) , pos( pos_ ) {} reference operator*() { Object key = keys[ pos ]; return std::make_pair( key, mapref( *map, key ) ); } iterator &operator=( const iterator &other ) { if( this != &other ) { map = other.map; keys = other.keys; pos = other.pos; } return *this; } bool eql( const iterator &other ) const { return map->ptr() == other.map->ptr() && pos == other.pos; } bool neq( const iterator &other ) const { return map->ptr() != other.map->ptr() || pos != other.pos; } // pointer operator->() { // return ; // } // prefix ++ iterator &operator++() { pos++; return *this; } // postfix ++ iterator operator++( int ) { return iterator( map, keys, pos++ ); } // prefix -- iterator &operator--() { pos--; return *this; } // postfix -- iterator operator--( int ) { return iterator( map, keys, pos-- ); } std::string diagnose() const { std::OSTRSTREAM oss; oss << "iterator diagnosis " << map << ", " << pos << std::ends; return std::string( oss.str() ); } }; // end of class MapBase::iterator iterator begin() { return iterator( this, false ); } iterator end() { return iterator( this, true ); } class const_iterator { protected: typedef std::forward_iterator_tag iterator_category; typedef const std::pair< const T, T > value_type; typedef int difference_type; typedef const std::pair< const T, T > pointer; typedef const std::pair< const T, T > reference; friend class MapBase; const MapBase *map; List keys; // for iterating over the map Py_ssize_t pos; // index into the keys public: ~const_iterator() {} const_iterator() : map( 0 ) , keys() , pos() {} const_iterator( const MapBase *m, List k, Py_ssize_t p ) : map( m ) , keys( k ) , pos( p ) {} const_iterator( const const_iterator &other ) : map( other.map ) , keys( other.keys ) , pos( other.pos ) {} bool eql( const const_iterator &other ) const { return map->ptr() == other.map->ptr() && pos == other.pos; } bool neq( const const_iterator &other ) const { return map->ptr() != other.map->ptr() || pos != other.pos; } // const_reference operator*() { // Object key = *pos; // return std::make_pair( key, map->[key] ); // GCC < 3 barfes on this line at the '['. // } const_reference operator*() { Object key = keys[ pos ]; return std::make_pair( key, mapref( *map, key ) ); } const_iterator &operator=( const const_iterator &other ) { if( this != &other ) { map = other.map; keys = other.keys; pos = other.pos; } return *this; } // prefix ++ const_iterator &operator++() { pos++; return *this; } // postfix ++ const_iterator operator++( int ) { return const_iterator( map, keys, pos++ ); } // prefix -- const_iterator &operator--() { pos--; return *this; } // postfix -- const_iterator operator--( int ) { return const_iterator( map, keys, pos-- ); } }; // end of class MapBase::const_iterator const_iterator begin() const { return const_iterator( this, keys(), 0 ); } const_iterator end() const { return const_iterator( this, keys(), length() ); } }; // end of MapBase typedef MapBase Mapping; template bool operator==( const EXPLICIT_TYPENAME MapBase::iterator &left, const EXPLICIT_TYPENAME MapBase::iterator &right ); template bool operator!=( const EXPLICIT_TYPENAME MapBase::iterator &left, const EXPLICIT_TYPENAME MapBase::iterator &right ); template bool operator==( const EXPLICIT_TYPENAME MapBase::const_iterator &left, const EXPLICIT_TYPENAME MapBase::const_iterator &right ); template bool operator!=( const EXPLICIT_TYPENAME MapBase::const_iterator &left, const EXPLICIT_TYPENAME MapBase::const_iterator &right ); extern bool operator==( const Mapping::iterator &left, const Mapping::iterator &right ); extern bool operator!=( const Mapping::iterator &left, const Mapping::iterator &right ); extern bool operator==( const Mapping::const_iterator &left, const Mapping::const_iterator &right ); extern bool operator!=( const Mapping::const_iterator &left, const Mapping::const_iterator &right ); // ================================================== // class Dict class Dict: public Mapping { public: // Constructor explicit Dict( PyObject *pyob, bool owned=false ) : Mapping( pyob, owned ) { validate(); } Dict( const Object &ob ) : Mapping( ob ) { validate(); } // Creation Dict() { set( PyDict_New(), true ); validate(); } // Assignment acquires new ownership of pointer Dict &operator=( const Object &rhs ) { return *this = *rhs; } Dict &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && Py::_Dict_Check( pyob ); } }; class Callable: public Object { public: // Constructor explicit Callable() : Object() {} explicit Callable( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } Callable( const Object &ob ) : Object( ob ) { validate(); } // Assignment acquires new ownership of pointer Callable &operator=( const Object &rhs ) { return *this = *rhs; } Callable &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) { set( rhsp ); } return *this; } // Membership virtual bool accepts( PyObject *pyob ) const { return pyob && PyCallable_Check( pyob ); } // Call Object apply( const Tuple &args ) const { PyObject *result = PyObject_CallObject( ptr(), args.ptr() ); if( result == NULL ) { ifPyErrorThrowCxxException(); } return asObject( result ); } // Call with keywords Object apply( const Tuple &args, const Dict &kw ) const { #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9 PyObject *result = PyObject_Call( ptr(), args.ptr(), kw.ptr() ); #else PyObject *result = PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ); #endif if( result == NULL ) { ifPyErrorThrowCxxException(); } return asObject( result ); } #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9 Object apply() const { PyObject *result = PyObject_CallNoArgs( ptr() ); return asObject( result ); } Object apply( PyObject *pargs ) const { if( pargs == 0 ) { return apply( Tuple() ); } else { return apply( Tuple( pargs ) ); } } #else Object apply( PyObject *pargs = 0 ) const { if( pargs == 0 ) { return apply( Tuple() ); } else { return apply( Tuple( pargs ) ); } } #endif }; class Module: public Object { public: explicit Module( PyObject *pyob, bool owned = false ) : Object( pyob, owned ) { validate(); } // Construct from module name explicit Module( const std::string &s ) : Object() { PyObject *m = PyImport_AddModule( const_cast( s.c_str() ) ); set( m, false ); validate(); } // Copy constructor acquires new ownership of pointer Module( const Module &ob ) : Object( *ob ) { validate(); } Module &operator=( const Object &rhs ) { return *this = *rhs; } Module &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } Dict getDict() const { return Dict( PyModule_GetDict( ptr() ) ); // Caution -- PyModule_GetDict returns borrowed reference! } }; // Call function helper inline Object Object::callMemberFunction( const std::string &function_name ) const { Callable target( getAttr( function_name ) ); return target.apply(); } inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args ) const { Callable target( getAttr( function_name ) ); return target.apply( args ); } inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const { Callable target( getAttr( function_name ) ); return target.apply( args, kw ); } // Numeric interface inline Object operator+( const Object &a ) { return asObject( PyNumber_Positive( *a ) ); } inline Object operator-( const Object &a ) { return asObject( PyNumber_Negative( *a ) ); } inline Object abs( const Object &a ) { return asObject( PyNumber_Absolute( *a ) ); } //------------------------------------------------------------ // operator + inline Object operator+( const Object &a, const Object &b ) { return asObject( PyNumber_Add( *a, *b ) ); } inline Object operator+( const Object &a, int j ) { return asObject( PyNumber_Add( *a, *Long( j ) ) ); } inline Object operator+( const Object &a, long j ) { return asObject( PyNumber_Add( *a, *Long( j ) ) ); } inline Object operator+( const Object &a, double v ) { return asObject( PyNumber_Add( *a, *Float( v ) ) ); } inline Object operator+( int j, const Object &b ) { return asObject( PyNumber_Add( *Long( j ), *b ) ); } inline Object operator+( long j, const Object &b ) { return asObject( PyNumber_Add( *Long( j ), *b ) ); } inline Object operator+( double v, const Object &b ) { return asObject( PyNumber_Add( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator - inline Object operator-( const Object &a, const Object &b ) { return asObject( PyNumber_Subtract( *a, *b ) ); } inline Object operator-( const Object &a, int j ) { return asObject( PyNumber_Subtract( *a, *Long( j ) ) ); } inline Object operator-( const Object &a, double v ) { return asObject( PyNumber_Subtract( *a, *Float( v ) ) ); } inline Object operator-( int j, const Object &b ) { return asObject( PyNumber_Subtract( *Long( j ), *b ) ); } inline Object operator-( double v, const Object &b ) { return asObject( PyNumber_Subtract( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator * inline Object operator*( const Object &a, const Object &b ) { return asObject( PyNumber_Multiply( *a, *b ) ); } inline Object operator*( const Object &a, int j ) { return asObject( PyNumber_Multiply( *a, *Long( j ) ) ); } inline Object operator*( const Object &a, double v ) { return asObject( PyNumber_Multiply( *a, *Float( v ) ) ); } inline Object operator*( int j, const Object &b ) { return asObject( PyNumber_Multiply( *Long( j ), *b ) ); } inline Object operator*( double v, const Object &b ) { return asObject( PyNumber_Multiply( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator / inline Object operator/( const Object &a, const Object &b ) { return asObject( PyNumber_TrueDivide( *a, *b ) ); } inline Object operator/( const Object &a, int j ) { return asObject( PyNumber_TrueDivide( *a, *Long( j ) ) ); } inline Object operator/( const Object &a, double v ) { return asObject( PyNumber_TrueDivide( *a, *Float( v ) ) ); } inline Object operator/( int j, const Object &b ) { return asObject( PyNumber_TrueDivide( *Long( j ), *b ) ); } inline Object operator/( double v, const Object &b ) { return asObject( PyNumber_TrueDivide( *Float( v ), *b ) ); } //------------------------------------------------------------ // operator % inline Object operator%( const Object &a, const Object &b ) { return asObject( PyNumber_Remainder( *a, *b ) ); } inline Object operator%( const Object &a, int j ) { return asObject( PyNumber_Remainder( *a, *Long( j ) ) ); } inline Object operator%( const Object &a, double v ) { return asObject( PyNumber_Remainder( *a, *Float( v ) ) ); } inline Object operator%( int j, const Object &b ) { return asObject( PyNumber_Remainder( *Long( j ), *b ) ); } inline Object operator%( double v, const Object &b ) { return asObject( PyNumber_Remainder( *Float( v ), *b ) ); } //------------------------------------------------------------ // type inline Object type( const BaseException & ) // return the type of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch( &ptype, &pvalue, &ptrace ); Object result; if( ptype ) result = ptype; PyErr_Restore( ptype, pvalue, ptrace ); return result; } inline Object value( const BaseException & ) // return the value of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch( &ptype, &pvalue, &ptrace ); Object result; if( pvalue ) result = pvalue; PyErr_Restore( ptype, pvalue, ptrace ); return result; } inline Object trace( const BaseException & ) // return the traceback of the error { PyObject *ptype, *pvalue, *ptrace; PyErr_Fetch( &ptype, &pvalue, &ptrace ); Object result; if( ptrace ) result = ptrace; PyErr_Restore( ptype, pvalue, ptrace ); return result; } template String seqref::str() const { return the_item.str(); } template String seqref::repr() const { return the_item.repr(); } } // namespace Py #endif // __CXX_Objects__h pycxx-7.1.4/CXX/Python3/Config.hxx000644 000765 000024 00000010217 13662724004 017131 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __PyCXX_config_hh__ #define __PyCXX_config_hh__ #if defined( Py_LIMITED_API ) && Py_LIMITED_API+0 < 0x03040000 #error "PyCXX support for Python limited API requires version 3.4 or newer. Py_LIMITED_API=0x03040000" #endif // // Microsoft VC++ 6.0 has no traits // #if defined( _MSC_VER ) # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 #elif defined( __GNUC__ ) # if __GNUC__ >= 3 # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 # else # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 0 #endif // // Assume all other compilers do // #else // Macros to deal with deficiencies in compilers # define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1 #endif #if STANDARD_LIBRARY_HAS_ITERATOR_TRAITS # define random_access_iterator_parent(itemtype) std::iterator #else # define random_access_iterator_parent(itemtype) std::random_access_iterator #endif // // Which C++ standard is in use? // #if defined( _MSC_VER ) # if _MSC_VER <= 1200 // MSVC++ 6.0 # define PYCXX_ISO_CPP_LIB 0 # define STR_STREAM # define TEMPLATE_TYPENAME class # else # define PYCXX_ISO_CPP_LIB 1 # define STR_STREAM # define TEMPLATE_TYPENAME typename # endif #elif defined( __GNUC__ ) # if __GNUC__ >= 3 # define PYCXX_ISO_CPP_LIB 1 # define STR_STREAM # define TEMPLATE_TYPENAME typename # else # define PYCXX_ISO_CPP_LIB 0 # define STR_STREAM # define TEMPLATE_TYPENAME class # endif #endif #if PYCXX_ISO_CPP_LIB # define STR_STREAM # define OSTRSTREAM ostringstream # define EXPLICIT_TYPENAME typename # define EXPLICIT_CLASS class # define TEMPLATE_TYPENAME typename #else # define STR_STREAM # define OSTRSTREAM ostrstream # define EXPLICIT_TYPENAME # define EXPLICIT_CLASS # define TEMPLATE_TYPENAME class #endif // before 3.2 Py_hash_t was missing #ifndef PY_MAJOR_VERSION #error not defined PY_MAJOR_VERSION #endif #if PY_MINOR_VERSION < 2 typedef long int Py_hash_t; #endif #endif // __PyCXX_config_hh__ pycxx-7.1.4/CXX/Python3/cxx_standard_exceptions.hxx000644 000765 000024 00000012212 13330412771 022641 0ustar00barrystaff000000 000000 #if !defined( PYCXX_STANDARD_EXCEPTION ) #pragma error( "define PYCXX_STANDARD_EXCEPTION before including" ) #endif // taken for python3.5 documentation // EnvironmentError and IOError are not used in Python3 //PYCXX_STANDARD_EXCEPTION( EnvironmentError, QQQ ) //PYCXX_STANDARD_EXCEPTION( IOError, QQQ ) // 5.4 Exception hierarchy PYCXX_STANDARD_EXCEPTION( SystemExit, BaseException ) PYCXX_STANDARD_EXCEPTION( KeyboardInterrupt, BaseException ) PYCXX_STANDARD_EXCEPTION( GeneratorExit, BaseException ) #if !defined( PYCXX_6_2_COMPATIBILITY ) PYCXX_STANDARD_EXCEPTION( Exception, BaseException ) #endif PYCXX_STANDARD_EXCEPTION( StopIteration, Exception ) #if !defined(MS_WINDOWS) && ((defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x03050000 && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5) || (!defined( Py_LIMITED_API ) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5)) PYCXX_STANDARD_EXCEPTION( StopAsyncIteration, Exception ) #endif // Windows builds of python 3.5 do not export the symbol PyExc_StopAsyncIteration - need atleast 3.6 #if defined(MS_WINDOWS) && ((defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x03050000 && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6) || (!defined( Py_LIMITED_API ) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5)) PYCXX_STANDARD_EXCEPTION( StopAsyncIteration, Exception ) #endif PYCXX_STANDARD_EXCEPTION( ArithmeticError, Exception ) PYCXX_STANDARD_EXCEPTION( FloatingPointError, ArithmeticError ) PYCXX_STANDARD_EXCEPTION( OverflowError, ArithmeticError ) PYCXX_STANDARD_EXCEPTION( ZeroDivisionError, ArithmeticError ) PYCXX_STANDARD_EXCEPTION( AssertionError, Exception ) PYCXX_STANDARD_EXCEPTION( AttributeError, Exception ) PYCXX_STANDARD_EXCEPTION( BufferError, Exception ) PYCXX_STANDARD_EXCEPTION( EOFError, Exception ) PYCXX_STANDARD_EXCEPTION( ImportError, Exception ) PYCXX_STANDARD_EXCEPTION( LookupError, Exception ) PYCXX_STANDARD_EXCEPTION( IndexError, LookupError ) PYCXX_STANDARD_EXCEPTION( KeyError, LookupError ) PYCXX_STANDARD_EXCEPTION( MemoryError, Exception ) PYCXX_STANDARD_EXCEPTION( NameError, Exception ) PYCXX_STANDARD_EXCEPTION( UnboundLocalError, NameError ) PYCXX_STANDARD_EXCEPTION( OSError, Exception ) #if (defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x03060000 && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6) || (!defined( Py_LIMITED_API ) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4) PYCXX_STANDARD_EXCEPTION( BlockingIOError, OSError ) PYCXX_STANDARD_EXCEPTION( ChildProcessError,OSError ) PYCXX_STANDARD_EXCEPTION( ConnectionError, OSError ) PYCXX_STANDARD_EXCEPTION( BrokenPipeError, ConnectionError ) PYCXX_STANDARD_EXCEPTION( ConnectionAbortedError, ConnectionError ) PYCXX_STANDARD_EXCEPTION( ConnectionRefusedError, ConnectionError ) PYCXX_STANDARD_EXCEPTION( ConnectionResetError, ConnectionError ) PYCXX_STANDARD_EXCEPTION( FileExistsError, OSError ) PYCXX_STANDARD_EXCEPTION( FileNotFoundError, OSError ) PYCXX_STANDARD_EXCEPTION( InterruptedError, OSError ) PYCXX_STANDARD_EXCEPTION( IsADirectoryError, OSError ) PYCXX_STANDARD_EXCEPTION( NotADirectoryError, OSError ) PYCXX_STANDARD_EXCEPTION( PermissionError, OSError ) PYCXX_STANDARD_EXCEPTION( ProcessLookupError, OSError ) PYCXX_STANDARD_EXCEPTION( TimeoutError, OSError ) #endif PYCXX_STANDARD_EXCEPTION( ReferenceError, Exception ) PYCXX_STANDARD_EXCEPTION( RuntimeError, Exception ) PYCXX_STANDARD_EXCEPTION( NotImplementedError, RuntimeError ) #if !defined(MS_WINDOWS) && ((defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x03050000 && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5) || (!defined( Py_LIMITED_API ) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5)) PYCXX_STANDARD_EXCEPTION( RecursionError, RuntimeError ) #endif // Windows builds of python 3.5 do not export the symbol PyExc_RecursionError - need atleast 3.6 #if defined(MS_WINDOWS) && ((defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x03050000 && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6) || (!defined( Py_LIMITED_API ) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5)) PYCXX_STANDARD_EXCEPTION( RecursionError, RuntimeError ) #endif PYCXX_STANDARD_EXCEPTION( SyntaxError, Exception ) PYCXX_STANDARD_EXCEPTION( IndentationError, SyntaxError ) PYCXX_STANDARD_EXCEPTION( TabError, IndentationError ) PYCXX_STANDARD_EXCEPTION( SystemError, Exception ) PYCXX_STANDARD_EXCEPTION( TypeError, Exception ) PYCXX_STANDARD_EXCEPTION( ValueError, Exception ) PYCXX_STANDARD_EXCEPTION( UnicodeError, ValueError ) PYCXX_STANDARD_EXCEPTION( UnicodeDecodeError, UnicodeError ) PYCXX_STANDARD_EXCEPTION( UnicodeEncodeError, UnicodeError ) PYCXX_STANDARD_EXCEPTION( UnicodeTranslateError,UnicodeError ) pycxx-7.1.4/CXX/Python3/CxxDebug.hxx000644 000765 000024 00000000402 11146615306 017427 0ustar00barrystaff000000 000000 // // CxxDebug.hxx // // Copyright (c) 2008 Barry A. Scott // #ifndef __CXX_Debug_hxx #define __CXX_Debug_hxx // // Functions useful when debugging PyCXX // #ifdef PYCXX_DEBUG extern void bpt(); extern void printRefCount( PyObject *obj ); #endif #endif pycxx-7.1.4/CXX/Python3/ExtensionOldType.hxx000644 000765 000024 00000031764 13305260623 021207 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionOldType__h #define __CXX_ExtensionOldType__h namespace Py { template class PythonExtension : public PythonExtensionBase { public: static PyTypeObject *type_object() { return behaviors().type_object(); } static bool check( PyObject *p ) { // is p like me? return p->ob_type == type_object(); } static bool check( const Object &ob ) { return check( ob.ptr() ); } // // every object needs getattr implemented // to support methods // virtual Object getattr( const char *name ) { return getattr_methods( name ); } PyObject *selfPtr() { return this; } Object self() { return asObject( this ); } protected: explicit PythonExtension() : PythonExtensionBase() { PyObject_Init( this, type_object() ); // every object must support getattr behaviors().supportGetattr(); } virtual ~PythonExtension() {} static PythonType &behaviors() { static PythonType* p; if( p == NULL ) { #if defined( _CPPRTTI ) || defined( __GNUG__ ) const char *default_name =( typeid( T ) ).name(); #else const char *default_name = "unknown"; #endif p = new PythonType( sizeof( T ), 0, default_name ); p->set_tp_dealloc( extension_object_deallocator ); } return *p; } typedef Object (T::*method_noargs_function_t)(); typedef Object (T::*method_varargs_function_t)( const Tuple &args ); typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); typedef std::map *> method_map_t; // support the default attributes, __name__, __doc__ and methods virtual Object getattr_default( const char *_name ) { std::string name( _name ); #if !defined( Py_LIMITED_API ) if( name == "__name__" && type_object()->tp_name != NULL ) { return Py::String( type_object()->tp_name ); } #endif #if !defined( Py_LIMITED_API ) if( name == "__doc__" && type_object()->tp_doc != NULL ) { return Py::String( type_object()->tp_doc ); } #endif // trying to fake out being a class for help() // else if( name == "__bases__" ) // { // return Py::Tuple( 0 ); // } // else if( name == "__module__" ) // { // return Py::Nothing(); // } // else if( name == "__dict__" ) // { // return Py::Dict(); // } return getattr_methods( _name ); } // turn a name into function object virtual Object getattr_methods( const char *_name ) { std::string name( _name ); method_map_t &mm = methods(); // see if name exists and get entry with method EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.find( name ); if( i == mm.end() ) { if( name == "__methods__" ) { List methods; i = mm.begin(); EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); for( ; i != i_end; ++i ) methods.append( String( (*i).first ) ); return methods; } throw AttributeError( name ); } MethodDefExt *method_def = i->second; Tuple self( 2 ); self[0] = Object( this ); self[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); PyObject *func = PyCFunction_NewEx( &method_def->ext_meth_def, self.ptr(), NULL ); return Object(func, true); } // check that all methods added are unique static void check_unique_method_name( const char *name ) { method_map_t &mm = methods(); EXPLICIT_TYPENAME method_map_t::const_iterator i; i = mm.find( name ); if( i != mm.end() ) throw AttributeError( name ); } static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) { check_unique_method_name( name ); method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_noargs_call_handler, doc ); } static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) { check_unique_method_name( name ); method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_varargs_call_handler, doc ); } static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) { check_unique_method_name( name ); method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_keyword_call_handler, doc ); } private: static method_map_t &methods( void ) { static method_map_t *map_of_methods = NULL; if( map_of_methods == NULL ) map_of_methods = new method_map_t; return *map_of_methods; } // Note: Python calls noargs as varargs buts args==NULL static PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ); Object result; // Adding try & catch in case of STL debug-mode exceptions. #ifdef _STLP_DEBUG try { result = (self->*meth_def->ext_noargs_function)(); } catch( std::__stl_debug_exception ) { // throw cxx::RuntimeError( sErrMsg ); throw RuntimeError( "Error message not set yet." ); } #else result = (self->*meth_def->ext_noargs_function)(); #endif // _STLP_DEBUG return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } static PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ); Tuple args( _args ); Object result; // Adding try & catch in case of STL debug-mode exceptions. #ifdef _STLP_DEBUG try { result = (self->*meth_def->ext_varargs_function)( args ); } catch( std::__stl_debug_exception ) { throw RuntimeError( "Error message not set yet." ); } #else result = (self->*meth_def->ext_varargs_function)( args ); #endif // _STLP_DEBUG return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } static PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ) { try { Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ); Tuple args( _args ); // _keywords may be NULL so be careful about the way the dict is created Dict keywords; if( _keywords != NULL ) keywords = Dict( _keywords ); Object result( ( self->*meth_def->ext_keyword_function )( args, keywords ) ); return new_reference_to( result.ptr() ); } catch( BaseException & ) { return 0; } } static void extension_object_deallocator( PyObject* t ) { delete (T *)( t ); } // // prevent the compiler generating these unwanted functions // explicit PythonExtension( const PythonExtension &other ); void operator=( const PythonExtension &rhs ); }; // // ExtensionObject is an Object that will accept only T's. // template class ExtensionObject: public Object { public: explicit ExtensionObject( PyObject *pyob ) : Object( pyob ) { validate(); } ExtensionObject( const ExtensionObject &other ) : Object( *other ) { validate(); } ExtensionObject( const Object &other ) : Object( *other ) { validate(); } ExtensionObject &operator=( const Object &rhs ) { return( *this = *rhs ); } ExtensionObject &operator=( PyObject *rhsp ) { if( ptr() != rhsp ) set( rhsp ); return *this; } virtual bool accepts( PyObject *pyob ) const { return( pyob && T::check( pyob ) ); } // // Obtain a pointer to the PythonExtension object // T *extensionObject( void ) { return static_cast( ptr() ); } }; } // Namespace Py // End of __CXX_ExtensionOldType__h #endif pycxx-7.1.4/CXX/Python3/PythonType.hxx000644 000765 000024 00000022343 13662723705 020061 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_PythonType__h #define __CXX_PythonType__h #if defined( Py_LIMITED_API ) #include #endif namespace Py { class PythonType { public: // if you define one sequence method you must define // all of them except the assigns PythonType( size_t base_size, int itemsize, const char *default_name ); virtual ~PythonType(); const char *getName() const; const char *getDoc() const; PyTypeObject *type_object() const; PythonType &name( const char *nam ); PythonType &doc( const char *d ); PythonType &supportClass( void ); #if defined( PYCXX_PYTHON_2TO3 ) && !defined( Py_LIMITED_API ) && PY_MINOR_VERSION <= 7 PythonType &supportPrint( void ); #endif PythonType &supportGetattr( void ); PythonType &supportSetattr( void ); PythonType &supportGetattro( void ); PythonType &supportSetattro( void ); #ifdef PYCXX_PYTHON_2TO3 PythonType &supportCompare( void ); #endif PythonType &supportRichCompare( void ); PythonType &supportRepr( void ); PythonType &supportStr( void ); PythonType &supportHash( void ); PythonType &supportCall( void ); #define B( n ) (1<<(n)) enum { support_iter_iter = B(0), support_iter_iternext = B(1) }; PythonType &supportIter( int methods_to_support= support_iter_iter | support_iter_iternext ); enum { support_sequence_length = B(0), support_sequence_repeat = B(1), support_sequence_item = B(2), support_sequence_slice = B(3), support_sequence_concat = B(4), support_sequence_ass_item = B(5), support_sequence_ass_slice = B(6), support_sequence_inplace_concat = B(7), support_sequence_inplace_repeat = B(8), support_sequence_contains = B(9) }; PythonType &supportSequenceType( int methods_to_support= support_sequence_length | support_sequence_repeat | support_sequence_item | support_sequence_slice | support_sequence_concat ); enum { support_mapping_length = B(0), support_mapping_subscript = B(1), support_mapping_ass_subscript = B(2) }; PythonType &supportMappingType( int methods_to_support= support_mapping_length | support_mapping_subscript ); enum { support_number_add = B(0), support_number_subtract = B(1), support_number_multiply = B(2), support_number_remainder = B(3), support_number_divmod = B(4), support_number_power = B(5), support_number_negative = B(6), support_number_positive = B(7), support_number_absolute = B(8), support_number_invert = B(9), support_number_lshift = B(10), support_number_rshift = B(11), support_number_and = B(12), support_number_xor = B(13), support_number_or = B(14), support_number_int = B(15), support_number_float = B(16), support_number_floor_divide = B(17), support_number_true_divide = B(18), support_number_index = B(19), #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 support_number_matrix_multiply = B(20), #endif // start a new bit mask for inplace that avoid using more then 32 bits in methods_to_support support_number_inplace_floor_divide = B(0), support_number_inplace_true_divide = B(1), support_number_inplace_add = B(2), support_number_inplace_subtract = B(3), support_number_inplace_multiply = B(4), support_number_inplace_remainder = B(5), support_number_inplace_power = B(6), support_number_inplace_lshift = B(7), support_number_inplace_rshift = B(8), support_number_inplace_and = B(9), support_number_inplace_xor = B(10), support_number_inplace_or = B(11) #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5 , support_number_inplace_matrix_multiply = B(12) #endif }; PythonType &supportNumberType( int methods_to_support= support_number_add | support_number_subtract | support_number_multiply | support_number_remainder | support_number_divmod | support_number_power | support_number_negative | support_number_positive | support_number_absolute | support_number_invert | support_number_lshift | support_number_rshift | support_number_and | support_number_xor | support_number_or | support_number_int | support_number_float, int inplace_methods_to_support=0 ); #if !defined( Py_LIMITED_API ) enum { support_buffer_getbuffer = B(0), support_buffer_releasebuffer = B(1) }; PythonType &supportBufferType( int methods_to_support= support_buffer_getbuffer | support_buffer_releasebuffer ); #endif #undef B PythonType &set_tp_dealloc( void (*tp_dealloc)( PyObject * ) ); PythonType &set_tp_init( int (*tp_init)( PyObject *self, PyObject *args, PyObject *kwds ) ); PythonType &set_tp_new( PyObject *(*tp_new)( PyTypeObject *subtype, PyObject *args, PyObject *kwds ) ); PythonType &set_methods( PyMethodDef *methods ); // call once all support functions have been called to ready the type bool readyType(); protected: #if defined( Py_LIMITED_API ) std::unordered_map slots; PyType_Spec *spec; PyTypeObject *tp_object; #else PyTypeObject *table; PySequenceMethods *sequence_table; PyMappingMethods *mapping_table; PyNumberMethods *number_table; PyBufferProcs *buffer_table; #endif private: // // prevent the compiler generating these unwanted functions // PythonType( const PythonType &tb ); // unimplemented void operator=( const PythonType &t ); // unimplemented }; } // Namespace Py // End of __CXX_PythonType__h #endif pycxx-7.1.4/CXX/Python3/ExtensionModule.hxx000644 000765 000024 00000021127 12733537475 021064 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __CXX_ExtensionModule__h #define __CXX_ExtensionModule__h namespace Py { class ExtensionModuleBase { public: ExtensionModuleBase( const char *name ); virtual ~ExtensionModuleBase(); Module module( void ) const; // only valid after initialize() has been called Dict moduleDictionary( void ) const; // only valid after initialize() has been called virtual Object invoke_method_noargs( void *method_def ) = 0; virtual Object invoke_method_keyword( void *method_def, const Tuple &_args, const Dict &_keywords ) = 0; virtual Object invoke_method_varargs( void *method_def, const Tuple &_args ) = 0; const std::string &name() const; const std::string &fullName() const; // what is returned from PyInit_ function Object moduleObject( void ) const; protected: // Initialize the module void initialize( const char *module_doc ); const std::string m_module_name; const std::string m_full_module_name; MethodTable m_method_table; PyModuleDef m_module_def; PyObject *m_module; private: // // prevent the compiler generating these unwanted functions // ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented void operator=( const ExtensionModuleBase & ); //unimplemented }; // Note: Python calls noargs as varargs buts args==NULL extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * ); extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ); extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ); template class ExtensionModule : public ExtensionModuleBase { public: ExtensionModule( const char *name ) : ExtensionModuleBase( name ) {} virtual ~ExtensionModule() {} protected: typedef Object (T::*method_noargs_function_t)(); typedef Object (T::*method_varargs_function_t)( const Tuple &args ); typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws ); typedef std::map *> method_map_t; static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" ) { method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_noargs_call_handler, doc ); } static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" ) { method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_varargs_call_handler, doc ); } static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" ) { method_map_t &mm = methods(); mm[ std::string( name ) ] = new MethodDefExt( name, function, method_keyword_call_handler, doc ); } void initialize( const char *module_doc="" ) { ExtensionModuleBase::initialize( module_doc ); Dict dict( moduleDictionary() ); // // put each of the methods into the modules dictionary // so that we get called back at the function in T. // method_map_t &mm = methods(); EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.begin(); EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end(); for ( ; i != i_end; ++i ) { MethodDefExt *method_def = (*i).second; static PyObject *self = PyCapsule_New( this, NULL, NULL ); Tuple args( 2 ); args[0] = Object( self, true ); args[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); assert( m_module != NULL ); PyObject *func = PyCFunction_NewEx ( &method_def->ext_meth_def, new_reference_to( args ), m_module ); method_def->py_method = Object( func, true ); dict[ (*i).first ] = method_def->py_method; } } protected: // Tom Malcolmson reports that derived classes need access to these static method_map_t &methods( void ) { static method_map_t *map_of_methods = NULL; if( map_of_methods == NULL ) map_of_methods = new method_map_t; return *map_of_methods; } // this invoke function must be called from within a try catch block virtual Object invoke_method_noargs( void *method_def ) { // cast up to the derived class, method_def and call T *self = static_cast( this ); MethodDefExt *meth_def = reinterpret_cast *>( method_def ); return (self->*meth_def->ext_noargs_function)(); } // this invoke function must be called from within a try catch block virtual Object invoke_method_varargs( void *method_def, const Tuple &args ) { // cast up to the derived class, method_def and call T *self = static_cast( this ); MethodDefExt *meth_def = reinterpret_cast *>( method_def ); return (self->*meth_def->ext_varargs_function)( args ); } // this invoke function must be called from within a try catch block virtual Object invoke_method_keyword( void *method_def, const Tuple &args, const Dict &keywords ) { // cast up to the derived class, method_def and call T *self = static_cast( this ); MethodDefExt *meth_def = reinterpret_cast *>( method_def ); return (self->*meth_def->ext_keyword_function)( args, keywords ); } private: // // prevent the compiler generating these unwanted functions // ExtensionModule( const ExtensionModule & ); //unimplemented void operator=( const ExtensionModule & ); //unimplemented }; } // Namespace Py // End of __CXX_ExtensionModule__h #endif pycxx-7.1.4/Demo/Python3/000755 000765 000024 00000000000 13664720516 015422 5ustar00barrystaff000000 000000 pycxx-7.1.4/Demo/Python2/000755 000765 000024 00000000000 13664720516 015421 5ustar00barrystaff000000 000000 pycxx-7.1.4/Demo/Python2/python.cxx000644 000765 000024 00000004776 11146616710 017475 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- /* Minimal main program -- everything is loaded from the library */ #include "CXX/WrapPython.h" #include extern "C" int Py_Main(int argc, char** argv); extern "C" void initexample(); extern "C" void Py_Initialize(); int main(int argc, char** argv) { std::cout << "Greetings. Type from example import *; test()" << std::endl; Py_Initialize(); initexample(); return Py_Main(argc, argv); } pycxx-7.1.4/Demo/Python2/rangetest.cxx000644 000765 000024 00000010735 13662723705 020150 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "CXX/Extensions.hxx" #include "range.hxx" // This test also illustrates using the Py namespace explicitly extern void debug_check_ref_queue(); std::string test_extension_object() { debug_check_ref_queue(); Py::Tuple a; // just something that isn't an range... Py::ExtensionObject r1( new range(1, 20, 3) ); if(range::check(a)) std::cout << "range::check failed (1)."; if(!range::check(r1)) return "r::check failed (2)."; debug_check_ref_queue(); RangeSequence r2(1, 10, 2); if(r2[1] != Py::Int(3)) return "RangeSequence check failed. "; debug_check_ref_queue(); // calling an extension object method using getattr Py::Callable w(r2.getAttr("amethod")); Py::Tuple args(1); Py::Int j(3); args[0]=j; Py::List answer(w.apply(args)); if(answer[0] != r2) return ("Extension object test failed (1)"); if(answer[1] != args[0]) return ("Extension object test failed (2)"); // calling an extension object method using callMemberFunction Py::List answer2( r2.callMemberFunction( "amethod", args ) ); if(answer2[0] != r2) return ("Extension object test failed (3)"); if(answer2[1] != args[0]) return ("Extension object test failed (4)"); debug_check_ref_queue(); Py::Tuple nv(3); nv[0] = Py::Int(1); nv[1] = Py::Int(20); nv[2] = Py::Int(3); Py::Tuple unused; Py::List r2value; r2.assign(unused, nv); r2value = r2.value(unused); if(r2value[1] != Py::Int(4)) return("Extension object test failed (5)"); debug_check_ref_queue(); // repeat using getattr w = r2.getAttr("assign"); Py::Tuple the_arguments(2); the_arguments[0] = unused; the_arguments[1] = nv; w.apply(the_arguments); debug_check_ref_queue(); w = r2.getAttr("value"); Py::Tuple one_arg(1); one_arg[0] = unused; r2value = w.apply(one_arg); if(r2value[1] != Py::Int(4)) return("Extension object test failed. (6)"); debug_check_ref_queue(); { Py::ExtensionObject rheap( new range(1, 10, 2) ); debug_check_ref_queue(); // delete rheap } debug_check_ref_queue(); return "ok."; } pycxx-7.1.4/Demo/Python2/range.hxx000644 000765 000024 00000012733 13662723705 017255 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __r__h #define __r__h #include "CXX/Extensions.hxx" #include STR_STREAM // Making an extension object class range: public Py::PythonExtension { public: long start; long stop; long step; range(long start_, long stop_, long step_ = 1L) { start = start_; stop = stop_; step = step_; std::cout << "range object created " << this << std::endl; } virtual ~range() { std::cout << "range object destroyed " << this << std::endl; } static void init_type(void); long length() const { return (stop - start + 1)/step; } long item(int i) const { if( i >= length() ) // this exception stops a Python for loop over range. throw Py::IndexError("index too large"); return start + i * step; } range *slice( int i, int j ) const { int first = start + i * step; int last = start + j * step; return new range(first, last, step); } range* extend(int k) const { return new range(start, stop + k, step); } std::string asString() const { std::OSTRSTREAM s; s << "range(" << start << ", " << stop << ", " << step << ")" << std::ends; return std::string(s.str()); } // override functions from PythonExtension virtual Py::Object repr(); virtual Py::Object getattr( const char *name ); virtual Py_ssize_t sequence_length(); virtual Py::Object sequence_item( Py_ssize_t i ); virtual Py::Object sequence_concat( const Py::Object &j ); virtual Py::Object sequence_slice( Py_ssize_t i, Py_ssize_t j ); // define python methods of this object Py::Object amethod (const Py::Tuple& args); Py::Object value (const Py::Tuple& args); Py::Object assign (const Py::Tuple& args); Py::Object reference_count (const Py::Tuple& /*args*/) { return Py::LongLong(this->ob_refcnt); } Py::Object c_value(const Py::Tuple&) const { Py::List result; for(int i = start; i <= stop; i += step) { result.append(Py::Int(i)); } return result; } void c_assign(const Py::Tuple&, const Py::Object& rhs) { Py::Tuple w(rhs); w.verify_length(3); start = long(Py::Int(w[0])); stop = long(Py::Int(w[1])); step = long(Py::Int(w[2])); } }; class RangeSequence: public Py::SeqBase { public: explicit RangeSequence (PyObject *pyob, bool owned = false): Py::SeqBase(pyob, owned) { validate(); } explicit RangeSequence(int start, int stop, int step = 1) { set (new range(start, stop, step), true); } RangeSequence(const RangeSequence& other): Py::SeqBase(*other) { validate(); } RangeSequence& operator= (const Py::Object& rhs) { return (*this = *rhs); } RangeSequence& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set(rhsp); return *this; } virtual bool accepts(PyObject *pyob) const { return pyob && range::check(pyob); } Py::Object value(const Py::Tuple& t) const { return static_cast(ptr())->c_value(t); } void assign(const Py::Tuple& t, const Py::Object& rhs) { static_cast(ptr())->c_assign(t, rhs); } }; #endif pycxx-7.1.4/Demo/Python2/pycxx_iter.hxx000644 000765 000024 00000003604 13662723705 020354 0ustar00barrystaff000000 000000 #include "CXX/Extensions.hxx" #include #include #include class IterT : public Py::PythonExtension { int from, count, last; int fwd_iter; bool do_it_reversed; public: static void init_type(void); // announce properties and methods IterT(int _from, int _last) : from(_from) , last(_last) , fwd_iter(0) , do_it_reversed(false) {} Py::Object repr() { std::string s; std::ostringstream s_out; s_out << "IterT count(" << count << ")"; return Py::String(s_out.str()); } Py::Object reversed(const Py::Tuple&) { do_it_reversed= true; // indicate backward iteration return Py::Object(this,false); // increment the refcount } Py::Object iter() { if( do_it_reversed ) { fwd_iter = -1; do_it_reversed=false; } else fwd_iter = 1; // indicate forward iteration return Py::Object(this,false); // increment the refcount } PyObject* iternext() { int ct; if( ! fwd_iter ) return NULL; // signal StopIteration if( fwd_iter > 0 ) { if( fwd_iter == 1 ) { ct = from; count = from+1; fwd_iter=2; } else if( count <= last ) ct= count++; else return NULL; // signal StopIteration } else if( fwd_iter == -1 ) { ct = last; count = last-1; fwd_iter=-2; } else if( count >= from ) ct= count--; else return NULL; // signal StopIteration Py::Int Result(ct); Result.increment_reference_count(); return Result.ptr(); } }; pycxx-7.1.4/Demo/Python2/test_simple.py000644 000765 000024 00000003753 12740663530 020327 0ustar00barrystaff000000 000000 import sys import simple print( '--- module func ---' ) simple.mod_func_noargs() simple.mod_func_varargs( 6, 7 ) simple.mod_func_keyword() simple.mod_func_keyword( 4, 5 ) simple.mod_func_keyword( 4, 5, name=6, value=7 ) print( '--- old_style_class func ---' ) old_style_class = simple.old_style_class() old_style_class.old_style_class_func_noargs() old_style_class.old_style_class_func_varargs() old_style_class.old_style_class_func_varargs( 4 ) old_style_class.old_style_class_func_keyword() old_style_class.old_style_class_func_keyword( name=6, value=7 ) old_style_class.old_style_class_func_keyword( 4, 5 ) old_style_class.old_style_class_func_keyword( 4, 5, name=6, value=7 ) print( '--- Derived func ---' ) class Derived(simple.new_style_class): def __init__( self ): simple.new_style_class.__init__( self ) def derived_func( self ): print( 'derived_func' ) super( Derived, self ).func_noargs() def func_noargs( self ): print( 'derived func_noargs' ) d = Derived() print( dir( d ) ) d.derived_func() d.func_noargs() d.func_varargs() d.func_varargs( 4 ) d.func_keyword() d.func_keyword( name=6, value=7 ) d.func_keyword( 4, 5 ) d.func_keyword( 4, 5, name=6, value=7 ) print( d.value ) d.value = "a string" print( d.value ) d.new_var = 99 print( 'TEST: pass derived class to C++ world' ) result = simple.derived_class_test( d, 5, 9 ) print( 'derived_class_test result %r' % (result,) ) print( '--- new_style_class func ---' ) new_style_class = simple.new_style_class() print( dir( new_style_class ) ) new_style_class.func_noargs() new_style_class.func_varargs() new_style_class.func_varargs( 4 ) new_style_class.func_keyword() new_style_class.func_keyword( name=6, value=7 ) new_style_class.func_keyword( 4, 5 ) new_style_class.func_keyword( 4, 5, name=6, value=7 ) try: new_style_class.func_noargs_raise_exception() print 'Error: did not raised RuntimeError' sys.exit( 1 ) except RuntimeError, e: print 'Raised %r' % (str(e),) new_style_class = None pycxx-7.1.4/Demo/Python2/pycxx_iter.cxx000644 000765 000024 00000002613 13662723705 020346 0ustar00barrystaff000000 000000 #include "pycxx_iter.hxx" #include "CXX/Objects.hxx" void IterT::init_type() { behaviors().name("IterT"); behaviors().doc("IterT(ini_count)"); // you must have overwritten the virtual functions // Py::Object iter() and Py::Object iternext() behaviors().supportIter(); // set entries in the Type Table behaviors().supportRepr(); add_varargs_method("reversed",&IterT::reversed,"reversed()"); behaviors().readyType(); } class MyIterModule : public Py::ExtensionModule { public: MyIterModule() : Py::ExtensionModule("pycxx_iter") { IterT::init_type(); add_varargs_method("IterT",&MyIterModule::new_IterT,"IterT(from,last)"); initialize("MyIterModule documentation"); // register with Python } virtual ~MyIterModule() {} private: Py::Object new_IterT(const Py::Tuple& args) { if (args.length() != 2) { throw Py::RuntimeError("Incorrect # of args to IterT(from,to)."); } return Py::asObject(new IterT(Py::Int(args[0]),Py::Int(args[1]))); } }; #if defined( _WIN32 ) #define EXPORT_SYMBOL __declspec( dllexport ) #else #define EXPORT_SYMBOL #endif extern "C" EXPORT_SYMBOL void initpycxx_iter() { // the following constructor call registers our extension module // with the Python runtime system static MyIterModule* IterTest = new MyIterModule; } pycxx-7.1.4/Demo/Python2/test_pycxx_iter.py000644 000765 000024 00000000323 13305260623 021214 0ustar00barrystaff000000 000000 import sys sys.path.insert( 0, 'pyds%d%d' % (sys.version_info[0], sys.version_info[1]) ) import pycxx_iter IT=pycxx_iter.IterT(5,7) for i in IT: print i, IT print "refcount of IT:",sys.getrefcount(IT) pycxx-7.1.4/Demo/Python2/setup.py000644 000765 000024 00000006431 13074106026 017124 0ustar00barrystaff000000 000000 #----------------------------------------------------------------------------- # # Copyright (c) 1998 - 2007, The Regents of the University of California # Produced at the Lawrence Livermore National Laboratory # All rights reserved. # # This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The # full copyright notice is contained in the file COPYRIGHT located at the root # of the PyCXX distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the disclaimer below. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the disclaimer (as noted below) in the # documentation and/or materials provided with the distribution. # - Neither the name of the UC/LLNL nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF # CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # #----------------------------------------------------------------------------- import os, sys from distutils.core import setup, Extension support_dir = os.path.normpath( os.path.join( sys.prefix, 'share', 'python%d.%d' % (sys.version_info[0],sys.version_info[1]), 'CXX') ) if os.name == 'posix': CXX_libraries = ['stdc++','m'] else: CXX_libraries = [] setup( name = "CXXDemo", version = "7.0", maintainer = "Barry Scott", maintainer_email = "barry-scott@users.sourceforge.net", description = "Demo of facility for extending Python with C++", url = "http://cxx.sourceforge.net", packages = ['CXX'], package_dir = {'CXX': '.'}, ext_modules = [ Extension( 'CXX.example', sources = ['example.cxx', 'range.cxx', 'rangetest.cxx', os.path.join(support_dir,'cxxsupport.cxx'), os.path.join(support_dir,'cxx_extensions.cxx'), os.path.join(support_dir,'cxx_exceptions.cxx'), os.path.join(support_dir,'IndirectPythonInterface.cxx'), os.path.join(support_dir,'cxxextensions.c') ] )] ) pycxx-7.1.4/Demo/Python2/example.def000644 000765 000024 00000000026 11146616710 017523 0ustar00barrystaff000000 000000 EXPORTS initexample pycxx-7.1.4/Demo/Python2/simple.cxx000644 000765 000024 00000026305 13662723705 017445 0ustar00barrystaff000000 000000 // // Copyright (c) 2008-2010 Barry A. Scott // // // simple_moduile.cxx // // This module defines a single function. // #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "CXX/Objects.hxx" #include "CXX/Extensions.hxx" #include class new_style_class: public Py::PythonClass< new_style_class > { public: new_style_class( Py::PythonClassInstance *self, Py::Tuple &args, Py::Dict &kwds ) : Py::PythonClass< new_style_class >::PythonClass( self, args, kwds ) , m_value( "default value" ) { std::cout << "new_style_class c'tor Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } } virtual ~new_style_class() { std::cout << "~new_style_class." << std::endl; } long cxx_method( long a, long b ) { return a * b + 3; } static void init_type(void) { behaviors().name( "new_style_class" ); behaviors().doc( "documentation for new_style_class class" ); behaviors().supportGetattro(); behaviors().supportSetattro(); PYCXX_ADD_NOARGS_METHOD( func_noargs, new_style_class_func_noargs, "docs for new_style_class_func_noargs" ); PYCXX_ADD_VARARGS_METHOD( func_varargs, new_style_class_func_varargs, "docs for new_style_class_func_varargs" ); PYCXX_ADD_KEYWORDS_METHOD( func_keyword, new_style_class_func_keyword, "docs for new_style_class_func_keyword" ); PYCXX_ADD_NOARGS_METHOD( func_noargs_raise_exception, new_style_class_func_noargs_raise_exception, "docs for new_style_class_func_noargs_raise_exception" ); // Call to make the type ready for use behaviors().readyType(); } Py::Object new_style_class_func_noargs( void ) { std::cout << "new_style_class_func_noargs Called." << std::endl; std::cout << "value ref count " << m_value.reference_count() << std::endl; return Py::None(); } PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs ) Py::Object new_style_class_func_varargs( const Py::Tuple &args ) { std::cout << "new_style_class_func_varargs Called with " << args.length() << " normal arguments." << std::endl; return Py::None(); } PYCXX_VARARGS_METHOD_DECL( new_style_class, new_style_class_func_varargs ) Py::Object new_style_class_func_keyword( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "new_style_class_func_keyword Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::None(); } PYCXX_KEYWORDS_METHOD_DECL( new_style_class, new_style_class_func_keyword ) Py::Object new_style_class_func_noargs_raise_exception( void ) { std::cout << "new_style_class_func_noargs_raise_exception Called." << std::endl; throw Py::RuntimeError( "its an error" ); } PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs_raise_exception ) Py::Object getattro( const Py::String &name_ ) { std::string name( name_.as_std_string( "utf-8" ) ); if( name == "value" ) { return m_value; } else { return genericGetAttro( name_ ); } } int setattro( const Py::String &name_, const Py::Object &value ) { std::string name( name_.as_std_string( "utf-8" ) ); if( name == "value" ) { m_value = value; return 0; } else { return genericSetAttro( name_, value ); } } Py::String m_value; }; class old_style_class: public Py::PythonExtension< old_style_class > { public: old_style_class() { } virtual ~old_style_class() { } static void init_type(void) { behaviors().name( "old_style_class" ); behaviors().doc( "documentation for old_style_class class" ); behaviors().supportGetattr(); add_noargs_method( "old_style_class_func_noargs", &old_style_class::old_style_class_func_noargs ); add_varargs_method( "old_style_class_func_varargs", &old_style_class::old_style_class_func_varargs ); add_keyword_method( "old_style_class_func_keyword", &old_style_class::old_style_class_func_keyword ); } // override functions from PythonExtension virtual Py::Object getattr( const char *name ) { return getattr_methods( name ); } Py::Object old_style_class_func_noargs( void ) { std::cout << "old_style_class_func_noargs Called." << std::endl; return Py::None(); } Py::Object old_style_class_func_varargs( const Py::Tuple &args ) { std::cout << "old_style_class_func_varargs Called with " << args.length() << " normal arguments." << std::endl; return Py::None(); } Py::Object old_style_class_func_keyword( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "old_style_class_func_keyword Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::None(); } }; class simple_module : public Py::ExtensionModule { public: simple_module() : Py::ExtensionModule( "simple" ) // this must be name of the file on disk e.g. simple.so or simple.pyd { old_style_class::init_type(); new_style_class::init_type(); add_noargs_method( "mod_func_noargs", &simple_module::mod_func_noargs, "documentation for mod_func_noargs()" ); add_varargs_method( "mod_func_varargs", &simple_module::mod_func_varargs, "documentation for mod_func_varargs()" ); add_keyword_method( "mod_func_keyword", &simple_module::mod_func_keyword, "documentation for mod_func_keyword()" ); add_varargs_method("old_style_class", &simple_module::factory_old_style_class, "documentation for old_style_class()"); add_keyword_method("make_instance", &simple_module::make_instance, "documentation for make_instance()"); add_keyword_method("decode_test", &simple_module::decode_test, "documentation for decode_test()"); add_keyword_method("encode_test", &simple_module::encode_test, "documentation for encode_test()"); add_keyword_method("derived_class_test", &simple_module::derived_class_test, "documentation for derived_class_test()"); // after initialize the moduleDictionary will exist initialize( "documentation for the simple module" ); Py::Dict d( moduleDictionary() ); d["var"] = Py::String( "var value" ); Py::Object x( new_style_class::type() ); d["new_style_class"] = x; } virtual ~simple_module() {} private: Py::Object decode_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::String s( args[0] ); return s.decode("utf-8"); } Py::Object encode_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::String s( args[0] ); return s.encode("utf-8"); } Py::Object derived_class_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::PythonClassObject py_nsc( args[0] ); new_style_class *cxx_nsc = py_nsc.getCxxObject(); Py::Long a( args[1] ); Py::Long b( args[2] ); long result = cxx_nsc->cxx_method( a, b ); return Py::Long( result ); } Py::Object mod_func_noargs() { std::cout << "mod_func_noargs Called." << std::endl; return Py::None(); } Py::Object mod_func_varargs( const Py::Tuple &args ) { std::cout << "mod_func_varargs Called with " << args.length() << " normal arguments." << std::endl; return Py::None(); } Py::Object mod_func_keyword( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "mod_func_varargs Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } if( args.length() > 0 ) { Py::Object x( args[0] ); try { Py::PythonClassObject x2( x ); std::cout << "C++ pointer " << x2.getCxxObject() << std::endl; } catch( Py::TypeError &e ) { // must clear the error e.clear(); std::cout << "arg 1 is not a new_style_class" << std::endl; } } return Py::None(); } Py::Object make_instance( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "make_instance Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } Py::Callable class_type( new_style_class::type() ); Py::PythonClassObject new_style_obj( class_type.apply( args, kwds ) ); return new_style_obj; } Py::Object factory_old_style_class( const Py::Tuple &/*args*/ ) { Py::Object obj = Py::asObject( new old_style_class ); return obj; } }; #if defined( _WIN32 ) #define EXPORT_SYMBOL __declspec( dllexport ) #else #define EXPORT_SYMBOL #endif #if PY_MAJOR_VERSION == 3 static simple_module *simple; extern "C" EXPORT_SYMBOL PyObject *PyInit_simple() { #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) Py::InitialisePythonIndirectPy::Interface(); #endif simple = new simple_module; return simple->module().ptr(); } // symbol required for the debug version extern "C" EXPORT_SYMBOL PyObject *PyInit_simple_d() { return PyInit_simple(); } #else static simple_module *simple; extern "C" EXPORT_SYMBOL void initsimple() { #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) Py::InitialisePythonIndirectPy::Interface(); #endif simple = new simple_module; } // symbol required for the debug version extern "C" EXPORT_SYMBOL void initsimple_d() { initsimple(); } #endif pycxx-7.1.4/Demo/Python2/test_example.py000644 000765 000024 00000004257 11146616710 020466 0ustar00barrystaff000000 000000 #----------------------------------------------------------------------------- # # Copyright (c) 1998 - 2007, The Regents of the University of California # Produced at the Lawrence Livermore National Laboratory # All rights reserved. # # This file is part of PyCXX. For details,see http:#cxx.sourceforge.net/. The # full copyright notice is contained in the file COPYRIGHT located at the root # of the PyCXX distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the disclaimer below. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the disclaimer (as noted below) in the # documentation and/or materials provided with the distribution. # - Neither the name of the UC/LLNL nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF # CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # #----------------------------------------------------------------------------- import sys sys.path.insert( 0, 'pyds%d%d' % (sys.version_info[0], sys.version_info[1]) ) import example example.test() pycxx-7.1.4/Demo/Python2/example.cxx000644 000765 000024 00000050626 13662723705 017612 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details, see http://cxx.sourceforge.net. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "CXX/Objects.hxx" #include "CXX/Extensions.hxx" #include #include "range.hxx" // Extension object extern std::string test_extension_object(); #include static std::string test_String() { Py::String s("hello"); Py::Char blank = ' '; Py::String r1("world in brief", 5); s = s + blank + r1; s = s * 2; if(std::string(s) != "hello worldhello world") { return "failed (1) '" + std::string(s) + "'"; } // test conversion std::string w = static_cast(s); std::string w2 = (std::string) s; if(w != w2) { return "failed (2)"; } Py::String r2("12345 789"); Py::Char c6 = r2[5]; if(c6 != blank) { std::cout << "|" << c6 << "|" << std::endl; return "failed (3)"; } // ord tests Py::Char c3 = r2[2]; long v3 = c3.ord(); if( v3 != '3' ) { std::cout << "string ord value < 2^7 " << v3 << " vs. " << '3' << std::endl; return "failed (4)"; } std::cout << "sizeof( Py_UNICODE ) " << sizeof( Py_UNICODE ) << std::endl; // python2 only handles unicode < 2^16. Py_UNICODE u4( 0x20ac ); Py::Char c4( u4 ); long v4 = c4.ord(); if( v4 != 0x20ac ) { std::cout << "string ord value > 2^16 " << v4 << " vs. " << 0x20ac << std::endl; return "failed (5)"; } Py::Char c5( '\xd5' ); long v5 = c5.ord(); if( v5 != 0xd5 ) { std::cout << "string ord value < 2^8 " << v5 << " vs. " << 0xd5 << std::endl; return "failed (6)"; } // convert tests Py::Char c7 = r2.front(); Py::Char c8 = r2.back(); return "ok"; } static std::string test_boolean() { bool passed = true; Py::Object o; Py::Boolean pb1; Py::Boolean pb2; bool b1; o = Py::True(); if( o.isTrue() ) { std::cout << "OK: T1: True" << std::endl; } else { std::cout << "Bad: T1: False" << std::endl; passed = false; } pb1 = o; if( pb1 ) { std::cout << "OK: T2: True" << std::endl; } else { std::cout << "Bad: T2: False" << std::endl; passed = false; } b1 = pb1; if( b1 ) { std::cout << "OK: T3: True" << std::endl; } else { std::cout << "Bad: T3: False" << std::endl; passed = false; } pb2 = pb1; if( pb2 ) { std::cout << "OK: T4: True" << std::endl; } else { std::cout << "Bad: T4: False" << std::endl; passed = false; } pb2 = true; if( pb2 ) { std::cout << "OK: T5: True" << std::endl; } else { std::cout << "Bad: T5: False" << std::endl; passed = false; } o = Py::False(); if( o.isTrue() ) { std::cout << "Bad: F1: True" << std::endl; passed = false; } else { std::cout << "OK: F1: False" << std::endl; } pb1 = o; if( pb1 ) { std::cout << "Bad: F2: True" << std::endl; passed = false; } else { std::cout << "OK: F2: False" << std::endl; } b1 = pb1; if( b1 ) { std::cout << "Bad: F3: True" << std::endl; passed = false; } else { std::cout << "OK: F3: False" << std::endl; } pb2 = pb1; if( pb2 ) { std::cout << "Bad: F4: True" << std::endl; passed = false; } else { std::cout << "OK: F4: False" << std::endl; } pb2 = false; if( pb2 ) { std::cout << "Bad: F5: True" << std::endl; passed = false; } else { std::cout << "OK: F5: False" << std::endl; } if( passed ) return "ok"; else return "failed"; } static std::string test_numbers() { // test the basic numerical classes Py::Int i; Py::Int j(2); Py::Int k = Py::Int(3); if (! (j < k)) return "failed (1)"; if (! (j == j)) return "failed (2)" ; if (! (j != k)) return "failed (3)"; if (! (j <= k)) return "failed (4)"; if (! (k >= j)) return "failed (5)"; if (! (k > j)) return "failed (6)"; if (! (j <= j)) return "failed (7)"; if (! (j >= Py::Int(2))) return "failed (8)"; i = 2; Py::Float a; a = 3 + i; //5.0 Py::Float b(4.0); a = (1.0 + 2*a + (b*3.0)/2.0 + k)/Py::Float(5); // 4.0 i = a - 1.0; // 3 if(i != k) { return "failed 9"; } #ifdef HAVE_LONG_LONG long long cxx_long_long11 = 1152921504616856976ll; long long cxx_long_long12 = 6152921504616856976ll; Py::Long py_long11( cxx_long_long11 ); Py::Long py_long12( 100 ); if( !(cxx_long_long11 == py_long11.as_long_long() )) return "failed (100)"; if( !(1152921504616856976ll == py_long11.as_long_long() )) return "failed (101)"; if( !(100ll == py_long12.as_long_long() )) return "failed (101)"; py_long12 = cxx_long_long12; if( !(cxx_long_long12 == py_long12.as_long_long() )) return "failed (101)"; #endif return "ok"; } static std::string test_List_iterators (const Py::List& x, Py::List& y) { std::vector v; Py::Sequence::iterator j; int k = 0; for(Py::Sequence::const_iterator i = x.begin(); i != x.end(); ++i) { if ((*i).isList()) { ++k; } } if(k!=1) return "failed List iterators (1)"; k = 0; for(j = y.begin(); j != y.end(); ++j) { *j = Py::Int(k++); v.push_back (*j); } k = 0; for(j = y.begin(); j != y.end(); j++) { if(*j != Py::Int(k)) return "failed List iterators (2)"; if(v[k] != Py::Int(k)) return "failed List iterators (3)"; ++k; } Py::String o1("Howdy"); Py::Int o2(1); int caught_it = 0; try { std::cout << "About to raise exception int(\"Howdy\")" << std::endl; o2 = o1; } catch (Py::BaseException &e) { std::cout << "Catch o.k." << std::endl; caught_it = 1; e.clear(); } if(!caught_it) return "failed exception catch (4)."; return "ok"; } static Py::List test_List_references (Py::List& x) { Py::List y; for(Py::List::size_type i=0; i < x.length(); ++i) { if (x[i].isList()) { y = x[i]; } } return y; } static std::string test_List() { // test the Py::List class Py::List a; Py::List ans, aux; aux.append(Py::Int(3)); aux.append(Py::Float(6.0)); Py::Object b; Py::Int i(3); Py::Float x(6.0); Py::Float c(10.0), d(20.0); a.append(i); a.append(x); a.append(Py::Float(0.0)); b = a[0]; a[2] = b; a.append(c+d); a.append(aux); // a is now [3, 6.0, 3, 30.0, aux] ans.append(Py::Int(3)); ans.append(Py::Float(6.0)); ans.append(Py::Int(3)); ans.append(Py::Float(30.0)); ans.append(aux); Py::List::iterator l1, l2; for(l1= a.begin(), l2 = ans.begin(); l1 != a.end() && l2 != ans.end(); ++l1, ++l2) { if(*l1 != *l2) return "failed 1" + a.as_string(); } if (test_List_references (a)!= aux) { return "failed 2" + test_List_references(a).as_string(); } return test_List_iterators(ans, a); } static std::string test_Dict() { // test the Dict class Py::Dict a,b; Py::List v; Py::String s("two"); a["one"] = Py::Int(1); a[s] = Py::Int(2); a["three"] = Py::Int(3); if(Py::Int(a["one"]) != Py::Int(1)) return "failed 1a " + a.as_string(); if(Py::Int(a[s]) != Py::Int(2)) return "failed 1b " + a.as_string(); v = a.values(); #if 0 std::sort(v.begin(), v.end()); for(int k = 1; k < 4; ++k) { if(v[k-1] != Py::Int(k)) return "failed 2 " + v.as_string(); } #endif b = a; b.clear(); if(b.keys().length() != 0) { return "failed 3 " + b.as_string(); } const Py::Dict c; for (Py::Dict::const_iterator it = c.begin(); it != c.end(); ++it) { } return "ok"; } static std::string test_Tuple() { // test the Tuple class Py::Tuple a(3); Py::Tuple t; Py::Float f1(1.0), f2(2.0), f3(3.0); a[0] = f1; // should be ok since no other reference owned a[1] = f2; a[2] = f3; Py::Tuple b(a); int k = 0; for(Py::Tuple::iterator i = b.begin(); i != b.end(); ++i) { if(*i != Py::Float(++k)) return "failed 1 " + b.as_string(); } t = a; try { t[0] = Py::Int(1); // should fail, tuple has multiple references return "failed 2"; } catch (Py::BaseException& e) { e.clear(); } Py::TupleN t0; Py::TupleN t1( Py::Int( 1 ) ); Py::TupleN t2( Py::Int( 1 ), Py::Int( 2 ) ); Py::TupleN t3( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ) ); Py::TupleN t4( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ), Py::Int( 4 ) ); Py::TupleN t5( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ), Py::Int( 4 ), Py::Int( 5 ) ); Py::TupleN t6( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ), Py::Int( 4 ), Py::Int( 5 ), Py::Int( 6 ) ); Py::TupleN t7( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ), Py::Int( 4 ), Py::Int( 5 ), Py::Int( 6 ), Py::Int( 7 ) ); Py::TupleN t8( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ), Py::Int( 4 ), Py::Int( 5 ), Py::Int( 6 ), Py::Int( 7 ), Py::Int( 8 ) ); Py::TupleN t9( Py::Int( 1 ), Py::Int( 2 ), Py::Int( 3 ), Py::Int( 4 ), Py::Int( 5 ), Py::Int( 6 ), Py::Int( 7 ), Py::Int( 8 ), Py::Int( 9 ) ); return "ok"; } static std::string test_STL() { int ans1; Py::List w; Py::List wans; wans.append(Py::Int(1)); wans.append(Py::Int(1)); wans.append(Py::Int(2)); wans.append(Py::Int(3)); wans.append(Py::Int(4)); wans.append(Py::Int(5)); w.append(Py::Int(5)); w.append(Py::Int(1)); w.append(Py::Int(4)); w.append(Py::Int(2)); w.append(Py::Int(3)); w.append(Py::Int(1)); ans1 = std::count(w.begin(), w.end(), Py::Float(1.0)); if (ans1 != 2) { return "failed count test"; } #if 0 std::sort(w.begin(), w.end()); if (w != wans) { return "failed sort test"; } #endif Py::Dict d; Py::String s1("blah"); Py::String s2("gorf"); d[ "one" ] = s1; d[ "two" ] = s1; d[ "three" ] = s2; d[ "four" ] = s2; Py::Dict::iterator it = d.begin(); for( ; it != d.end(); ++it ) { Py::Dict::value_type vt( *it ); Py::String rs = vt.second.repr(); std::string ls = rs.operator std::string(); std::cout << "dict value " << ls.c_str() << std::endl; } return "ok"; } void debug_check_ref_queue() { #ifdef Py_TRACE_REFS // create an element to find the queue Py::Int list_element; PyObject *p_slow = list_element.ptr(); PyObject *p_fast = p_slow; do { assert( p_slow->_ob_next->_ob_prev == p_slow ); assert( p_slow->_ob_prev->_ob_next == p_slow ); p_slow = p_slow->_ob_next; p_fast = p_slow->_ob_next->_ob_next; assert( p_slow != p_fast ); } while( p_slow != list_element.ptr() ); #endif } class example_module : public Py::ExtensionModule { public: example_module() : Py::ExtensionModule( "example" ) { range::init_type(); add_varargs_method("string", &example_module::ex_string, "string( s ) = return string"); add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments"); add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite"); add_varargs_method("range", &example_module::new_r, "range(start,stop,stride)"); add_keyword_method("kw", &example_module::ex_keyword, "kw()"); initialize( "documentation for the example module" ); Py::Dict d( moduleDictionary() ); Py::Object b(Py::asObject(new range(1,10,2))); d["a_constant"] = b.getAttr("c"); } virtual ~example_module() {} private: Py::Object ex_keyword( const Py::Tuple &args, const Py::Dict &kws ) { std::cout << "Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kws.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::Int(0); } Py::Object new_r (const Py::Tuple &rargs) { if (rargs.length() < 2 || rargs.length() > 3) { throw Py::RuntimeError("Incorrect # of args to range(start,stop [,step])."); } Py::Int start(rargs[0]); Py::Int stop(rargs[1]); Py::Int step(1); if (rargs.length() == 3) { step = rargs[2]; } if (long(start) > long(stop) + 1 || long(step) == 0) { throw Py::RuntimeError("Bad arguments to range(start,stop [,step])."); } return Py::asObject(new range(start, stop, step)); } Py::Object ex_string (const Py::Tuple &a) { std::cout << "ex_std::string: s1 is first arg" << std::endl; Py::String s1( a[0] ); std::cout << "ex_string: s1.isString() " << s1.isString() << std::endl; std::cout << "ex_string: s1.isUnicode() " << s1.isUnicode() << std::endl; std::cout << "ex_string: s1.size() " << s1.size() << std::endl; if( s1.isUnicode() ) { std::cout << "ex_string: s2 is s1.encode( utf-8 )" << std::endl; Py::String s2( s1.encode( "utf-8" ) ); std::cout << "ex_string: s2.isString() " << s2.isString() << std::endl; std::cout << "ex_string: s2.isUnicode() " << s2.isUnicode() << std::endl; std::cout << "ex_string: s2.size() " << s2.size() << std::endl; return s2; } else { std::cout << "ex_string: s2 is s1.decode( utf-8 )" << std::endl; Py::String s2( s1.decode( "utf-8" ) ); std::cout << "ex_string: s2.isString() " << s2.isString() << std::endl; std::cout << "ex_string: s2.isUnicode() " << s2.isUnicode() << std::endl; std::cout << "ex_string: s2.size() " << s2.size() << std::endl; return s2; } } Py::Object ex_sum (const Py::Tuple &a) { // this is just to test the function verify_length: try { a.verify_length(0); std::cout << "I see that you refuse to give me any work to do." << std::endl; } catch (Py::BaseException& e) { e.clear(); std::cout << "I will now add up your elements, oh great one." << std::endl; } Py::Float f(0.0); for( Py::Sequence::size_type i = 0; i < a.length(); i++ ) { Py::Float g (a[i]); f = f + g; } return f; } Py::Object ex_test( const Py::Tuple &a) { debug_check_ref_queue(); std::cout << "Example Test starting" << std::endl; try { // cannot create from NULL Py::Object obj( NULL ); std::cout << "FAILED Py::Object( NULL )" << std::endl; } catch (Py::TypeError& e) { std::cout << "Correctly caught " << Py::type(e) << std::endl; std::cout << " Py::BaseException value: " << Py::value(e) << std::endl; std::cout << " Py::BaseException traceback: " << Py::trace(e) << std::endl; e.clear(); } try { PyObject *p = NULL; std::cout << "Trying to convert a NULL to an Py::Int" << std::endl; Py::Int k( p ); std::cout << "Failed to raise error" << std::endl; } catch (Py::TypeError& e) { std::cout << "Correctly caught " << Py::type(e) << std::endl; std::cout << " Py::BaseException value: " << Py::value(e) << std::endl; std::cout << " Py::BaseException traceback: " << Py::trace(e) << std::endl; e.clear(); } try { Py::String s("this should fail"); PyObject *p = s.ptr(); std::cout << "Trying to convert a Py::String to an Py::Int" << std::endl; Py::Int k( p ); std::cout << "Failed to raise error" << std::endl; } catch (Py::TypeError& e) { std::cout << "Correctly caught " << Py::type(e) << std::endl; std::cout << " Py::BaseException value: " << Py::value(e) << std::endl; std::cout << " Py::BaseException traceback: " << Py::trace(e) << std::endl; e.clear(); } debug_check_ref_queue(); std::string result = test_boolean(); std::cout << "Py::Boolean: " << result << std::endl; debug_check_ref_queue(); std::cout << "Numbers: " << test_numbers() << std::endl; debug_check_ref_queue(); std::cout << "Py::String: " << test_String() << std::endl; debug_check_ref_queue(); std::cout << "Py::List: " << test_List() << std::endl; debug_check_ref_queue(); std::cout << "Py::Dict: " << test_Dict() << std::endl; debug_check_ref_queue(); std::cout << "Py::Tuple: " << test_Tuple() << std::endl; debug_check_ref_queue(); std::cout << "STL test: " << test_STL() << std::endl; debug_check_ref_queue(); std::cout << "Extension object test: " << test_extension_object() << std::endl; debug_check_ref_queue(); Py::List b(a); Py::Tuple c(b); if( c != a) { std::cout << "Py::Tuple/list conversion failed.\n"; } Py::Module m("sys"); Py::Object s = m.getAttr("stdout"); Py::Object nun; nun = PyObject_CallMethod(s.ptr(), "write", "s", "Module test ok.\n"); return Py::None(); } }; #if defined( _WIN32 ) #define EXPORT_SYMBOL __declspec( dllexport ) #else #define EXPORT_SYMBOL #endif extern "C" EXPORT_SYMBOL void initexample() { #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) Py::InitialisePythonIndirectPy::Interface(); #endif static example_module* example = new example_module; } // symbol required for the debug version extern "C" EXPORT_SYMBOL void initexample_d() { initexample(); } pycxx-7.1.4/Demo/Python2/range.cxx000644 000765 000024 00000007761 13662723705 017255 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "range.hxx" // Connect range objects to Python Py::Object range::repr() { return Py::String(asString()); } Py_ssize_t range::sequence_length() { return length(); } Py::Object range::sequence_item( Py_ssize_t i ) { return Py::Int( item( static_cast( i ) ) ); } Py::Object range::sequence_concat( const Py::Object &j ) { Py::Int k(j); return Py::asObject(extend(int(k))); } Py::Object range::sequence_slice( Py_ssize_t i, Py_ssize_t j ) { return Py::asObject( slice( static_cast( i ), static_cast( j ) ) ); } Py::Object range::getattr( const char *name ) { if(std::string(name) == "c") return Py::Float(300.0); if(std::string(name) == "start") return Py::Int(start); return getattr_methods( name ); } // "regular" methods... Py::Object range::amethod( const Py::Tuple &t ) { t.verify_length(1); Py::List result; result.append(Py::Object(this)); result.append(t[0]); return result; } Py::Object range::value( const Py::Tuple &t ) { return c_value(t); } Py::Object range::assign( const Py::Tuple &t ) { t.verify_length(2); Py::Tuple t1(t[0]); // subscripts Py::Object o2(t[1]); // rhs; c_assign (t1, o2); return Py::Nothing(); } void range::init_type() { behaviors().name("range"); behaviors().doc("range objects: start, stop, step"); behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSequenceType(); add_varargs_method("amethod", &range::amethod, "demonstrate how to document amethod"); add_varargs_method("assign", &range::assign); add_varargs_method("value", &range::value); add_varargs_method("reference_count", &range::reference_count); behaviors().readyType(); } pycxx-7.1.4/Demo/Python3/python.cxx000644 000765 000024 00000004776 11146616710 017476 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- /* Minimal main program -- everything is loaded from the library */ #include "CXX/WrapPython.h" #include extern "C" int Py_Main(int argc, char** argv); extern "C" void initexample(); extern "C" void Py_Initialize(); int main(int argc, char** argv) { std::cout << "Greetings. Type from example import *; test()" << std::endl; Py_Initialize(); initexample(); return Py_Main(argc, argv); } pycxx-7.1.4/Demo/Python3/rangetest.cxx000644 000765 000024 00000010377 13662723705 020153 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning( disable: 4786 ) #endif #include "CXX/Extensions.hxx" #include "range.hxx" #include "test_assert.hxx" // This test also illustrates using the Py namespace explicitly void test_extension_object() { Py::List a; // just something that is not a range... Py::ExtensionObject r1( new range( 1, 20, 3 ) ); test_assert( "extension object check() incompatible", false, range::check( a ) ); test_assert( "extension object check() incompatible", true, range::check( r1 ) ); RangeSequence r2( 1, 10, 2 ); test_assert( "extension object index", r2[ 1 ], Py::Long( 3 ) ); // calling an extension object method using getattr Py::Callable w( r2.getAttr( "amethod" ) ); { Py::Tuple args( 1 ); Py::Long j( 3 ); args[0] = j; Py::List answer( w.apply( args ) ); test_assert( "extension object amethod 1 q1", answer[0], r2 ); test_assert( "extension object amethod 1q2", answer[1], args[0] ); } { // calling an extension object method using callMemberFunction Py::Tuple args( 1 ); Py::Long j( 3 ); args[0] = j; Py::List answer( r2.callMemberFunction( "amethod", args ) ); test_assert( "extension object amethod 2 q1", answer[0], r2 ); test_assert( "extension object amethod 2 q2", answer[1], args[0] ); } Py::Tuple nv( 3 ); nv[0] = Py::Long( 1 ); nv[1] = Py::Long( 20 ); nv[2] = Py::Long( 3 ); Py::Tuple unused; Py::List r2value; r2.assign( unused, nv ); r2value = r2.value( unused ); test_assert( "extension object q3", r2value[1], Py::Long( 4 ) ); // repeat using getattr w = r2.getAttr( "assign" ); Py::Tuple the_arguments( 2 ); the_arguments[0] = unused; the_arguments[1] = nv; w.apply( the_arguments ); { Py::ExtensionObject rheap( new range( 1, 10, 2 ) ); // delete rheap } w = r2.getAttr( "value" ); Py::Tuple one_arg( 1 ); one_arg[0] = unused; r2value = w.apply( one_arg ); test_assert( "extension object q4", r2value[1], Py::Long( 4 ) ); } pycxx-7.1.4/Demo/Python3/range.hxx000644 000765 000024 00000010514 13662723705 017251 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifndef __r__h #define __r__h #include "CXX/Extensions.hxx" #include STR_STREAM // Making an extension object class range: public Py::PythonExtension { public: range( long start, long stop, long step = 1L ); virtual ~range(); static void init_type(void); Py_ssize_t length() const; int item( long i ) const; range *slice( Py_ssize_t i, Py_ssize_t j ) const; range *extend( Py_ssize_t k ) const; std::string asString() const; // override functions from PythonExtension virtual Py::Object repr(); virtual Py::Object getattr( const char *name ); virtual Py_ssize_t sequence_length(); virtual Py::Object sequence_item( Py_ssize_t i ); virtual Py::Object sequence_concat( const Py::Object &j ); virtual Py::Object sequence_slice( Py_ssize_t i, Py_ssize_t j ); // define python methods of this object Py::Object amethod( const Py::Tuple &args ); Py::Object value( const Py::Tuple &args ); Py::Object assign( const Py::Tuple &args ); Py::Object reference_count( const Py::Tuple &args ); Py::Object c_value( const Py::Tuple & ) const; void c_assign( const Py::Tuple &, const Py::Object &rhs ); private: long m_start; long m_stop; long m_step; }; class RangeSequence: public Py::SeqBase { public: explicit RangeSequence (PyObject *pyob, bool owned = false): Py::SeqBase(pyob, owned) { validate(); } explicit RangeSequence(long start, long stop, long step = 1) { set (new range(start, stop, step), true); } RangeSequence(const RangeSequence& other): Py::SeqBase(*other) { validate(); } RangeSequence& operator= (const Py::Object& rhs) { return (*this = *rhs); } RangeSequence& operator= (PyObject* rhsp) { if(ptr() == rhsp) return *this; set(rhsp); return *this; } virtual bool accepts(PyObject *pyob) const { return pyob && range::check(pyob); } Py::Object value(const Py::Tuple& t) const { return static_cast(ptr())->c_value(t); } void assign(const Py::Tuple& t, const Py::Object& rhs) { static_cast(ptr())->c_assign(t, rhs); } }; #endif pycxx-7.1.4/Demo/Python3/simple2.cxx000644 000765 000024 00000021171 13662723705 017524 0ustar00barrystaff000000 000000 // // Copyright (c) 2008 Barry A. Scott // // // simple2_moduile.cxx // // This module defines a single function. // #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "CXX/Objects.hxx" #include "CXX/Extensions.hxx" #include #include template class EnumString { public: EnumString(); ~EnumString() {} const std::string &toTypeName( T ) { return m_type_name; } const std::string &toString( T value ) { static std::string not_found( "-unknown-" ); EXPLICIT_TYPENAME std::map::iterator it = m_enum_to_string.find( value ); if( it != m_enum_to_string.end() ) return (*it).second; not_found = "-unknown ("; int u1000 = value/1000 % 10; int u100 = value/100 % 10; int u10 = value/10 % 10; int u1 = value % 10; not_found += char( '0' + u1000 ); not_found += char( '0' + u100 ); not_found += char( '0' + u10 ); not_found += char( '0' + u1 ); not_found += ")-"; return not_found; } bool toEnum( const std::string &string, T &value ) { EXPLICIT_TYPENAME std::map::iterator it = m_string_to_enum.find( string ); if( it != m_string_to_enum.end() ) { value = (*it).second; return true; } return false; } EXPLICIT_TYPENAME std::map::iterator begin() { return m_string_to_enum.begin(); } EXPLICIT_TYPENAME std::map::iterator end() { return m_string_to_enum.end(); } private: void add( T value, std::string string ) { m_string_to_enum[string] = value; m_enum_to_string[value] = string; } std::string m_type_name; std::map m_string_to_enum; std::map m_enum_to_string; }; template class pysvn_enum_value : public Py::PythonExtension< EXPLICIT_CLASS pysvn_enum_value > { public: pysvn_enum_value( T _value) : Py::PythonExtension() , m_value( _value ) { } virtual ~pysvn_enum_value() { } virtual int compare( const Py::Object &other ) { if( pysvn_enum_value::check( other ) ) { pysvn_enum_value *other_value = static_cast( other.ptr() ); if( m_value == other_value->m_value ) return 0; if( m_value > other_value->m_value ) return 1; else return -1; } else { std::string msg( "expecting " ); msg += toTypeName( m_value ); msg += " object for compare "; throw Py::AttributeError( msg ); } } virtual Py::Object repr() { std::string s("<"); s += toTypeName( m_value ); s += "."; s += toString( m_value ); s += ">"; return Py::String( s ); } virtual Py::Object str() { return Py::String( toString( m_value ) ); } // need a hash so that the enums can go into a map virtual long hash() { static Py::String type_name( toTypeName( m_value ) ); // use the m_value plus the hash of the type name return long( m_value ) + type_name.hashValue(); } static void init_type(void); public: T m_value; }; //------------------------------------------------------------ template class pysvn_enum : public Py::PythonExtension< EXPLICIT_CLASS pysvn_enum > { public: pysvn_enum() : Py::PythonExtension() { } virtual ~pysvn_enum() { } virtual Py::Object getattr( const char *_name ) { std::string name( _name ); T value; if( name == "__methods__" ) { return Py::List(); } if( name == "__members__" ) { return memberList( static_cast( 0 ) ); } if( toEnum( name, value ) ) { return Py::asObject( new pysvn_enum_value( value ) ); } return this->getattr_methods( _name ); } static void init_type(void); }; template const std::string &toTypeName( T value ) { static EnumString< T > enum_map; return enum_map.toTypeName( value ); } template const std::string &toString( T value ) { static EnumString< T > enum_map; return enum_map.toString( value ); } template bool toEnum( const std::string &string, T &value ) { static EnumString< T > enum_map; return enum_map.toEnum( string, value ); } template Py::List memberList( T value ) { static EnumString< T > enum_map; Py::List members; EXPLICIT_TYPENAME std::map::iterator it = enum_map.begin(); while( it != enum_map.end() ) { members.append( Py::String( (*it).first ) ); ++it; } return members; } typedef enum { xxx_first = 1, xxx_second, xxx_third } xxx_t; template <> EnumString< xxx_t >::EnumString() : m_type_name( "xxx" ) { add( xxx_first, "first" ); add( xxx_second, "second" ); add( xxx_third, "third" ); } template <> void pysvn_enum< xxx_t >::init_type(void) { behaviors().name("xxx"); behaviors().doc("xxx enumeration"); behaviors().supportGetattr(); } template <> void pysvn_enum_value< xxx_t >::init_type(void) { behaviors().name("xxx"); behaviors().doc("xxx value"); behaviors().supportRepr(); behaviors().supportStr(); behaviors().supportHash(); } class cls: public Py::PythonExtension< cls > { public: cls() { } virtual ~cls() { } static void init_type(void) { behaviors().name( "cls" ); behaviors().doc( "documentation for cls class" ); behaviors().supportGetattr(); add_noargs_method( "cls_func_noargs", &cls::cls_func_noargs ); add_varargs_method( "cls_func_varargs", &cls::cls_func_varargs ); add_keyword_method( "cls_func_keyword", &cls::cls_func_keyword ); } // override functions from PythonExtension virtual Py::Object getattr( const char *name ) { return getattr_methods( name ); } Py::Object cls_func_noargs( void ) { std::cout << "cls_func_noargs Called." << std::endl; return Py::None(); } Py::Object cls_func_varargs( const Py::Tuple &args ) { std::cout << "cls_func_varargs Called with " << args.length() << " normal arguments." << std::endl; return Py::None(); } Py::Object cls_func_keyword( const Py::Tuple &args, const Py::Dict &kws ) { std::cout << "cls_func_keyword Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kws.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::None(); } }; class simple2_module : public Py::ExtensionModule { public: simple2_module() : Py::ExtensionModule( "simple2" ) // this must be name of the file on disk e.g. simple2.so or simple2.pyd { cls::init_type(); pysvn_enum< xxx_t >::init_type(); pysvn_enum_value< xxx_t >::init_type(); add_varargs_method("cls", &simple2_module::factory_cls, "documentation for cls()"); add_keyword_method("func", &simple2_module::func, "documentation for func()"); // after initialize the moduleDictionary with exist initialize( "documentation for the simple2 module" ); Py::Dict d( moduleDictionary() ); d["xxx"] = Py::asObject( new pysvn_enum< xxx_t >() ); d["var"] = Py::String( "var value" ); } virtual ~simple2_module() {} private: Py::Object func( const Py::Tuple &args, const Py::Dict &kws ) { return Py::None(); } Py::Object factory_cls( const Py::Tuple &rargs ) { return Py::asObject( new cls ); } }; extern "C" PyObject *PyInit_simple2() { #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) Py::InitialisePythonIndirectPy::Interface(); #endif static simple2_module* simple2 = new simple2_module; return simple2->module().ptr(); } // symbol required for the debug version extern "C" PyObject *PyInit_simple2_d() { return PyInit_simple2(); } pycxx-7.1.4/Demo/Python3/test_assert.hxx000644 000765 000024 00000006017 13662723705 020520 0ustar00barrystaff000000 000000 // // Copyright (c) 2008-2009 Barry A. Scott // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // // test_assert.hxx // class TestError { public: TestError( const std::string &description ) : m_description( description ) {} ~TestError() {} std::string m_description; }; template static void test_assert_scaler( const char *description, const char *type, T benchmark, T value ) { std::ostringstream full_description; full_description << description << ": " << type << " benchmark=" << benchmark << " " << type << " value=" << value; if( benchmark != value ) { throw TestError( full_description.str() ); } else { std::cout << "PASSED: " << full_description.str() << std::endl; } } static void test_assert( const char *description, bool benchmark, bool value ) { test_assert_scaler( description, "bool", benchmark, value ); } static void test_assert( const char *description, int benchmark, int value ) { test_assert_scaler( description, "int", benchmark, value ); } #ifdef HAVE_LONG_LONG static void test_assert( const char *description, long long benchmark, long long value ) { test_assert_scaler( description, "long long", benchmark, value ); } #endif static void test_assert( const char *description, double benchmark, double value ) { test_assert_scaler( description, "double", benchmark, value ); } #if SIZEOF_INT != SIZEOF_SIZE_T && SIZEOF_LONG_LONG != SIZEOF_SIZE_T static void test_assert( const char *description, Py_ssize_t benchmark, Py_ssize_t value ) { test_assert_scaler( description, "Py_ssize_t", benchmark, value ); } #endif #if SIZEOF_INT != SIZEOF_SIZE_T static void test_assert( const char *description, int benchmark, Py_ssize_t value ) { test_assert_scaler( description, "Py_ssize_t", Py_ssize_t( benchmark ), value ); } #endif static void test_assert( const char *description, const std::string &benchmark, const std::string &value ) { test_assert_scaler( description, "std::string", benchmark, value ); } static void test_assert( const char *description, const Py::Object &benchmark, const Py::Object &value ) { test_assert_scaler( description, "Py::Object", benchmark, value ); } pycxx-7.1.4/Demo/Python3/pycxx_iter.hxx000644 000765 000024 00000003605 13662723705 020356 0ustar00barrystaff000000 000000 #include "CXX/Extensions.hxx" #include #include #include class IterT : public Py::PythonExtension { int from, count, last; int fwd_iter; bool do_it_reversed; public: static void init_type(void); // announce properties and methods IterT(int _from, int _last) : from(_from) , last(_last) , fwd_iter(0) , do_it_reversed(false) {} Py::Object repr() { std::string s; std::ostringstream s_out; s_out << "IterT count(" << count << ")"; return Py::String(s_out.str()); } Py::Object reversed(const Py::Tuple&) { do_it_reversed= true; // indicate backward iteration return Py::Object(this,false); // increment the refcount } Py::Object iter() { if( do_it_reversed ) { fwd_iter = -1; do_it_reversed=false; } else fwd_iter = 1; // indicate forward iteration return Py::Object(this,false); // increment the refcount } PyObject* iternext() { int ct; if( ! fwd_iter ) return NULL; // signal StopIteration if( fwd_iter > 0 ) { if( fwd_iter == 1 ) { ct = from; count = from+1; fwd_iter=2; } else if( count <= last ) ct= count++; else return NULL; // signal StopIteration } else if( fwd_iter == -1 ) { ct = last; count = last-1; fwd_iter=-2; } else if( count >= from ) ct= count--; else return NULL; // signal StopIteration Py::Long Result(ct); Result.increment_reference_count(); return Result.ptr(); } }; pycxx-7.1.4/Demo/Python3/pickle_test.py000644 000765 000024 00000001064 13474531342 020277 0ustar00barrystaff000000 000000 import simple import copyreg import pickle import pprint class can_be_pickled(simple.new_style_class): def __init__( self, value ): super().__init__() self.value = value def __reduce__( self ): return (simple.new_style_class, (self.value,)) #n = can_be_pickled( 'QQQZZZQQQ' ) n = simple.new_style_class( 'QQQZZZQQQ' ) print( 'n.value:', n.value ) print( 'pickle.dumps' ) s = pickle.dumps( n ) print( 'dumps:', repr(s) ) print( 'pickle.loads' ) n2 = pickle.loads( s ) print( 'loads:', repr(n2) ) print( 'n2.value:', n2.value ) pycxx-7.1.4/Demo/Python3/test_simple.py000644 000765 000024 00000010400 13305260623 020305 0ustar00barrystaff000000 000000 import sys def message( msg ): sys.stdout.write( msg ) sys.stdout.write( '\n' ) sys.stdout.flush() message( 'Info: ---- %s ----' % (sys.argv[0],) ) message( 'TEST: import simple' ) import simple message( 'TEST: call module functions' ) simple.func() simple.func( 4, 5 ) simple.func( 4, 5, name=6, value=7 ) def callback_good( arg ): message( 'callback_good with %r' % (arg,) ) return 'good result' message( 'TEST: raise user defined exception' ) try: raise simple.SimpleError( 'Testing simple error' ) except simple.SimpleError as e: message( 'PASS SimpleError %s' % (e,) ) def callback_bad( arg ): message( 'callback_bad with %r' % (arg,) ) raise ValueError( 'callback_bad error' ) def callback_raise_simple_error( arg ): message( 'callback_bad with %r' % (arg,) ) raise simple.SimpleError( 'callback_raise_simple_error' ) message( 'TEST: call C++ with Python callback_good' ) answer = simple.func_with_callback( callback_good, 'fred' ) message( 'PASS callback_good returned %r' % (answer,) ) message( 'TEST: call C++ with Python callback_bad' ) try: answer = simple.func_with_callback( callback_bad, 'fred' ) message( 'FAILED callback_bad %r' % (answer,) ) except Exception as e: message( 'PASS callback_bad: error %s' % (e,) ) message( 'TEST: call C++ with Python callback_raise_simple_error' ) try: answer = simple.func_with_callback( callback_raise_simple_error, 'fred' ) message( 'FAIL callback_raise_simple_error returned %r' % (answer,) ) except simple.SimpleError as e: message( 'PASS callback_raise_simple_error: %s' % (e,) ) message( 'TEST: call C++ that will catch SimpleError' ) try: answer = simple.func_with_callback_catch_simple_error( callback_raise_simple_error, 'fred' ) message( 'PASS func_with_callback_catch_simple_error returned %r' % (answer,) ) except simple.SimpleError as e: message( 'FAIL func_with_callback_catch_simple_error: %s' % (e,) ) message( 'TEST: raise SimpleError' ) try: raise simple.SimpleError( 'Hello!' ) except simple.SimpleError as e: message( 'PASS caught SimpleError - %s' % (e,) ) message( 'TEST: call old style class functions' ) old_style_class = simple.old_style_class() old_style_class.old_style_class_func_noargs() old_style_class.old_style_class_func_varargs() old_style_class.old_style_class_func_varargs( 4 ) old_style_class.old_style_class_func_keyword() old_style_class.old_style_class_func_keyword( name=6, value=7 ) old_style_class.old_style_class_func_keyword( 4, 5 ) old_style_class.old_style_class_func_keyword( 4, 5, name=6, value=7 ) message( 'TEST: Derived class functions' ) class Derived(simple.new_style_class): def __init__( self ): simple.new_style_class.__init__( self ) def derived_func( self, arg ): message( 'derived_func' ) super().func_noargs() def derived_func_bad( self, arg ): message( 'derived_func_bad' ) raise ValueError( 'derived_func_bad value error' ) def func_noargs( self ): message( 'derived func_noargs' ) d = Derived() message( repr(dir( d )) ) d.derived_func( "arg" ) d.func_noargs() d.func_varargs() d.func_varargs( 4 ) d.func_keyword() d.func_keyword( name=6, value=7 ) d.func_keyword( 4, 5 ) d.func_keyword( 4, 5, name=6, value=7 ) message( d.value ) d.value = "a string" message( d.value ) d.new_var = 99 d.func_varargs_call_member( "derived_func" ) result = d.func_varargs_call_member( "derived_func_bad" ) message( 'derived_func_bad caught error: %r' % (result,) ) message( 'TEST: pass derived class to C++ world' ) result = simple.derived_class_test( d, 5, 9 ) message( 'derived_class_test result %r' % (result,) ) message( 'TEST: new_style_class functions' ) new_style_class = simple.new_style_class() message( repr(dir( new_style_class )) ) new_style_class.func_noargs() new_style_class.func_varargs() new_style_class.func_varargs( 4 ) new_style_class.func_keyword() new_style_class.func_keyword( name=6, value=7 ) new_style_class.func_keyword( 4, 5 ) new_style_class.func_keyword( 4, 5, name=6, value=7 ) try: new_style_class.func_noargs_raise_exception() message( 'Error: did not raised RuntimeError' ) sys.exit( 1 ) except RuntimeError as e: message( 'Raised %r' % (str(e),) ) message( 'TEST: dereference new style class' ) new_style_class = None pycxx-7.1.4/Demo/Python3/pycxx_iter.cxx000644 000765 000024 00000002765 13305260623 020344 0ustar00barrystaff000000 000000 #include "pycxx_iter.hxx" #include "CXX/Objects.hxx" void IterT::init_type() { behaviors().name( "pycxx_iter.IterT" ); behaviors().doc( "IterT( ini_count )" ); // you must have overwritten the virtual functions // Py::Object iter() and Py::Object iternext() behaviors().supportIter(); // set entries in the Type Table behaviors().supportRepr(); add_varargs_method( "reversed", &IterT::reversed, "reversed()" ); behaviors().readyType(); } class MyIterModule : public Py::ExtensionModule { public: MyIterModule() : Py::ExtensionModule( "pycxx_iter" ) { IterT::init_type(); add_varargs_method( "IterT", &MyIterModule::new_IterT, "IterT(from,last)" ); initialize( "MyIterModule documentation" ); // register with Python } virtual ~MyIterModule() {} private: Py::Object new_IterT( const Py::Tuple &args ) { if( args.length() != 2 ) { throw Py::RuntimeError( "Incorrect # of args to IterT(from,to)." ); } return Py::asObject( new IterT( Py::Long( args[0] ).as_long(), Py::Long( args[1] ).as_long() ) ); } }; #if defined( _WIN32 ) #define EXPORT_SYMBOL __declspec( dllexport ) #else #define EXPORT_SYMBOL #endif extern "C" EXPORT_SYMBOL PyObject *PyInit_pycxx_iter() { // the following constructor call registers our extension module // with the Python runtime system static MyIterModule *iter = new MyIterModule; return iter->module().ptr(); } pycxx-7.1.4/Demo/Python3/test_pycxx_iter.py000644 000765 000024 00000000616 13305260623 021222 0ustar00barrystaff000000 000000 import sys def message( msg ): sys.stdout.write( msg ) sys.stdout.write( '\n' ) sys.stdout.flush() message( 'Info: ---- %s ----' % (sys.argv[0],) ) sys.path.insert( 0, 'pyds%d%d' % (sys.version_info[0], sys.version_info[1]) ) import pycxx_iter it = pycxx_iter.IterT( 5, 7 ) for i in it: message( '%r %r' % (i, it) ) message( 'refcount of it: %d' % (sys.getrefcount( it ),) ) pycxx-7.1.4/Demo/Python3/setup.py000644 000765 000024 00000006413 13074106026 017125 0ustar00barrystaff000000 000000 #----------------------------------------------------------------------------- # # Copyright (c) 1998 - 2007, The Regents of the University of California # Produced at the Lawrence Livermore National Laboratory # All rights reserved. # # This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The # full copyright notice is contained in the file COPYRIGHT located at the root # of the PyCXX distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the disclaimer below. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the disclaimer (as noted below) in the # documentation and/or materials provided with the distribution. # - Neither the name of the UC/LLNL nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF # CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # #----------------------------------------------------------------------------- import os, sys from distutils.core import setup, Extension support_dir = os.path.normpath( os.path.join( sys.prefix, 'share', 'python%d.%d' % (sys.version_info[0],sys.version_info[1]), 'CXX' ) ) if os.name == 'posix': CXX_libraries = ['stdc++','m'] else: CXX_libraries = [] setup( name = "CXXDemo", version = "7.0", maintainer = "Barry Scott", maintainer_email = "barry-scott@users.sourceforge.net", description = "Demo of facility for extending Python with C++", url = "http://cxx.sourceforge.net", packages = ['CXX'], package_dir = {'CXX': '.'}, ext_modules = [ Extension( 'CXX.example', sources = ['example.cxx', 'range.cxx', 'rangetest.cxx', os.path.join(support_dir,'cxxsupport.cxx'), os.path.join(support_dir,'cxx_extensions.cxx'), os.path.join(support_dir,'cxx_exceptions.cxx'), os.path.join(support_dir,'IndirectPythonInterface.cxx'), os.path.join(support_dir,'cxxextensions.c') ] )] ) pycxx-7.1.4/Demo/Python3/example.def000644 000765 000024 00000000026 11146616710 017524 0ustar00barrystaff000000 000000 EXPORTS initexample pycxx-7.1.4/Demo/Python3/simple.cxx000644 000765 000024 00000034253 13662743201 017440 0ustar00barrystaff000000 000000 // // Copyright (c) 2008-2010 Barry A. Scott // // // simple_moduile.cxx // // This module defines a single function. // #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "CXX/Objects.hxx" #include "CXX/Extensions.hxx" #include class new_style_class: public Py::PythonClass< new_style_class > { public: new_style_class( Py::PythonClassInstance *self, Py::Tuple &args, Py::Dict &kwds ) : Py::PythonClass< new_style_class >::PythonClass( self, args, kwds ) , m_value( "default value" ) { std::cout << "new_style_class c'tor Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } if( args.length() >= 1 ) { m_value = args[0]; } } virtual ~new_style_class() { std::cout << "~new_style_class." << std::endl; } int cxx_method( int a, int b ) { return a * b + 3; } static void init_type(void) { behaviors().name( "simple.new_style_class" ); behaviors().doc( "documentation for new_style_class class" ); behaviors().supportGetattro(); behaviors().supportSetattro(); behaviors().supportNumberType( Py::PythonType::support_number_add, Py::PythonType::support_number_inplace_add ); PYCXX_ADD_NOARGS_METHOD( func_noargs, new_style_class_func_noargs, "docs for func_noargs" ); PYCXX_ADD_VARARGS_METHOD( func_varargs, new_style_class_func_varargs, "docs for func_varargs" ); PYCXX_ADD_KEYWORDS_METHOD( func_keyword, new_style_class_func_keyword, "docs for func_keyword" ); PYCXX_ADD_NOARGS_METHOD( func_noargs_raise_exception, new_style_class_func_noargs_raise_exception, "docs for func_noargs_raise_exception" ); PYCXX_ADD_VARARGS_METHOD( func_varargs_call_member, new_style_class_call_member, "docs for func_varargs_call_member" ); PYCXX_ADD_NOARGS_METHOD( __reduce__, reduce_func, "__reduce__ function" ); // Call to make the type ready for use behaviors().readyType(); } Py::Object number_add( const Py::Object &other ) { std::cout << "new_style_class.number_add called" << std::endl; Py::Long num_to_add( other ); return Py::Long( 5 + num_to_add ); } Py::Object number_inplace_add( const Py::Object &other ) { std::cout << "new_style_class.number_inplace_add called..." << std::endl; Py::Long num_to_add( other ); std::cout << "... with " << num_to_add << std::endl; return self(); } Py::Object reduce_func( void ) { Py::TupleN ctor_args( m_value ); Py::TupleN result( new_style_class::type(), ctor_args ); return result; } PYCXX_NOARGS_METHOD_DECL( new_style_class, reduce_func ) Py::Object new_style_class_func_noargs( void ) { std::cout << "new_style_class_func_noargs Called." << std::endl; std::cout << "value ref count " << m_value.reference_count() << std::endl; return Py::None(); } PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs ) Py::Object new_style_class_func_varargs( const Py::Tuple &args ) { std::cout << "new_style_class_func_varargs Called with " << args.length() << " normal arguments." << std::endl; return Py::None(); } PYCXX_VARARGS_METHOD_DECL( new_style_class, new_style_class_func_varargs ) Py::Object new_style_class_call_member( const Py::Tuple &args ) { std::cout << "new_style_class_call_member Called with " << args.length() << " normal arguments." << std::endl; Py::String member_func_name( args[0] ); #ifdef PYCXX_DEBUG bpt(); #endif Py::Object _self = self(); try { Py::Object result( _self.callMemberFunction( member_func_name.as_std_string(), args ) ); return result; } catch( Py::BaseException &e ) { e.clear(); return Py::String( "new_style_class_call_member error when calling member" ); } } PYCXX_VARARGS_METHOD_DECL( new_style_class, new_style_class_call_member ) Py::Object new_style_class_func_keyword( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "new_style_class_func_keyword Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::None(); } PYCXX_KEYWORDS_METHOD_DECL( new_style_class, new_style_class_func_keyword ) Py::Object new_style_class_func_noargs_raise_exception( void ) { std::cout << "new_style_class_func_noargs_raise_exception Called." << std::endl; throw Py::RuntimeError( "its an error" ); } PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs_raise_exception ) Py::Object getattro( const Py::String &name_ ) { std::string name( name_.as_std_string( "utf-8" ) ); if( name == "value" ) { return m_value; } else { return genericGetAttro( name_ ); } } int setattro( const Py::String &name_, const Py::Object &value ) { std::string name( name_.as_std_string( "utf-8" ) ); if( name == "value" ) { m_value = value; return 0; } else { return genericSetAttro( name_, value ); } } Py::String m_value; }; class old_style_class: public Py::PythonExtension< old_style_class > { public: old_style_class() { } virtual ~old_style_class() { } static void init_type(void) { behaviors().name( "simple.old_style_class" ); behaviors().doc( "documentation for old_style_class class" ); behaviors().supportGetattr(); add_noargs_method( "old_style_class_func_noargs", &old_style_class::old_style_class_func_noargs ); add_varargs_method( "old_style_class_func_varargs", &old_style_class::old_style_class_func_varargs ); add_keyword_method( "old_style_class_func_keyword", &old_style_class::old_style_class_func_keyword ); behaviors().readyType(); } // override functions from PythonExtension virtual Py::Object getattr( const char *name ) { return getattr_methods( name ); } Py::Object old_style_class_func_noargs( void ) { std::cout << "old_style_class_func_noargs Called." << std::endl; return Py::None(); } Py::Object old_style_class_func_varargs( const Py::Tuple &args ) { std::cout << "old_style_class_func_varargs Called with " << args.length() << " normal arguments." << std::endl; return Py::None(); } Py::Object old_style_class_func_keyword( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "old_style_class_func_keyword Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::None(); } }; PYCXX_USER_EXCEPTION_STR_ARG( SimpleError ) class simple_module : public Py::ExtensionModule { public: simple_module() : Py::ExtensionModule( "simple" ) // this must be name of the file on disk e.g. simple.so or simple.pyd { old_style_class::init_type(); new_style_class::init_type(); add_varargs_method("old_style_class", &simple_module::factory_old_style_class, "documentation for old_style_class()"); add_keyword_method("func", &simple_module::func, "documentation for func()"); add_keyword_method("func_with_callback", &simple_module::func_with_callback, "documentation for func_with_callback()"); add_keyword_method("func_with_callback_catch_simple_error", &simple_module::func_with_callback_catch_simple_error, "documentation for func_with_callback_catch_simple_error()"); add_keyword_method("make_instance", &simple_module::make_instance, "documentation for make_instance()"); add_keyword_method("str_test", &simple_module::str_test, "documentation for str_test()"); add_keyword_method("decode_test", &simple_module::decode_test, "documentation for decode_test()"); add_keyword_method("encode_test", &simple_module::encode_test, "documentation for encode_test()"); add_keyword_method("derived_class_test", &simple_module::derived_class_test, "documentation for derived_class_test()"); // after initialize the moduleDictionary will exist initialize( "documentation for the simple module" ); Py::Dict d( moduleDictionary() ); d["var"] = Py::String( "var value" ); Py::Object x( new_style_class::type() ); d["new_style_class"] = x; SimpleError::init( *this ); } virtual ~simple_module() {} private: Py::Object decode_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::Bytes s( args[0] ); return s.decode("utf-8"); } Py::Object encode_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::String s( args[0] ); return s.encode("utf-8"); } Py::Object str_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { char buffer[64*1024+1]; memset( &buffer, ' ', sizeof( buffer )-1 ); buffer[sizeof( buffer )-1] = 0; return Py::String( buffer ); } Py::Object derived_class_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::PythonClassObject py_nsc( args[0] ); new_style_class *cxx_nsc = py_nsc.getCxxObject(); Py::Long a( args[1] ); Py::Long b( args[2] ); int result = cxx_nsc->cxx_method( a, b ); return Py::Long( result ); } Py::Object func( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "func Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } #ifdef PYCXX_DEBUG if( args.length() > 0 ) { Py::Object x( args[0] ); PyObject *x_p = x.ptr(); std::cout << "func( self=0x" << std::hex << reinterpret_cast< unsigned long >( x_p ) << std::dec << " )" << std::endl; Py::PythonClassInstance *instance_wrapper = reinterpret_cast< Py::PythonClassInstance * >( x_p ); new_style_class *instance = static_cast( instance_wrapper->m_pycxx_object ); std::cout << " self->cxx_object=0x" << std::hex << reinterpret_cast< unsigned long >( instance ) << std::dec << std::endl; } bpt(); #endif return Py::None(); } Py::Object func_with_callback( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::Callable callback_func( args[0] ); Py::Tuple callback_args( 1 ); callback_args[0] = Py::String( "callback_args string" ); return callback_func.apply( callback_args ); } Py::Object func_with_callback_catch_simple_error( const Py::Tuple &args, const Py::Dict &/*kwds*/ ) { Py::Callable callback_func( args[0] ); Py::Tuple callback_args( 1 ); callback_args[0] = Py::String( "callback_args string" ); try { std::cout << "func_with_callback_catch_simple_error calling arg[0]" << std::endl; return callback_func.apply( callback_args ); } catch( SimpleError &e ) { Py::Object value = e.errorValue(); e.clear(); std::cout << "PASS caught SimpleError( \"" << value.repr() << "\"" << std::endl; return Py::String("Error"); } } Py::Object make_instance( const Py::Tuple &args, const Py::Dict &kwds ) { std::cout << "make_instance Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kwds.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } Py::Callable class_type( new_style_class::type() ); Py::PythonClassObject new_style_obj( class_type.apply( args, kwds ) ); return new_style_obj; } Py::Object factory_old_style_class( const Py::Tuple &/*args*/ ) { Py::Object obj = Py::asObject( new old_style_class ); return obj; } }; #if defined( _WIN32 ) #define EXPORT_SYMBOL __declspec( dllexport ) #else #define EXPORT_SYMBOL #endif extern "C" EXPORT_SYMBOL PyObject *PyInit_simple() { #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) Py::InitialisePythonIndirectPy::Interface(); #endif std::cout << "sizeof(int) " << sizeof(int) << std::endl; std::cout << "sizeof(long) " << sizeof(long) << std::endl; std::cout << "sizeof(Py_hash_t) " << sizeof(Py_hash_t) << std::endl; std::cout << "sizeof(Py_ssize_t) " << sizeof(Py_ssize_t) << std::endl; static simple_module* simple = new simple_module; return simple->module().ptr(); } // symbol required for the debug version extern "C" EXPORT_SYMBOL PyObject *PyInit_simple_d() { return PyInit_simple(); } pycxx-7.1.4/Demo/Python3/test_simple2.py000644 000765 000024 00000000216 11146066410 020372 0ustar00barrystaff000000 000000 import simple2 m = { simple2.xxx.first: 1, simple2.xxx.second: 2, simple2.xxx.third: 3 } v = m[ simple2.xxx.second ] print( v ) pycxx-7.1.4/Demo/Python3/test_example.py000644 000765 000024 00000004375 13305260623 020465 0ustar00barrystaff000000 000000 #----------------------------------------------------------------------------- # # Copyright (c) 1998 - 2007, The Regents of the University of California # Produced at the Lawrence Livermore National Laboratory # All rights reserved. # # This file is part of PyCXX. For details,see http:#cxx.sourceforge.net/. The # full copyright notice is contained in the file COPYRIGHT located at the root # of the PyCXX distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # - Redistributions of source code must retain the above copyright notice, # this list of conditions and the disclaimer below. # - Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the disclaimer (as noted below) in the # documentation and/or materials provided with the distribution. # - Neither the name of the UC/LLNL nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF # CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # #----------------------------------------------------------------------------- import sys sys.path.insert( 0, 'pyds%d%d' % (sys.version_info[0], sys.version_info[1]) ) sys.stdout.write( 'Info: ---- %s ----' % (sys.argv[0],) ) sys.stdout.flush() import example example.test() pycxx-7.1.4/Demo/Python3/example.cxx000644 000765 000024 00000104242 13662723705 017605 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details, see http://cxx.sourceforge.net. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning(disable: 4786) #endif #include "CXX/Objects.hxx" #include "CXX/Extensions.hxx" #include #include "range.hxx" // Extension object #include "test_assert.hxx" extern void test_extension_object(); #include void test_compare() { test_assert( "compare == true", true, Py::Long( 100 ) == Py::Long( 100 ) ); test_assert( "compare == false", false, Py::Long( 100 ) == Py::Long( 101 ) ); test_assert( "compare != true", true, Py::Long( 100 ) != Py::Long( 101 ) ); test_assert( "compare != false", false, Py::Long( 100 ) != Py::Long( 100 ) ); test_assert( "compare < true", true, Py::Long( 100 ) < Py::Long( 101 ) ); test_assert( "compare < false", false, Py::Long( 100 ) < Py::Long( 99 ) ); test_assert( "compare <= true", true, Py::Long( 100 ) <= Py::Long( 101 ) ); test_assert( "compare <= true", true, Py::Long( 100 ) <= Py::Long( 100 ) ); test_assert( "compare <= false", false, Py::Long( 100 ) <= Py::Long( 99 ) ); test_assert( "compare > true", true, Py::Long( 100 ) > Py::Long( 99 ) ); test_assert( "compare > false", false, Py::Long( 100 ) > Py::Long( 101 ) ); test_assert( "compare >= true", true, Py::Long( 100 ) >= Py::Long( 99 ) ); test_assert( "compare >= true", true, Py::Long( 100 ) >= Py::Long( 100 ) ); test_assert( "compare >= false", false, Py::Long( 100 ) >= Py::Long( 101 ) ); test_assert( "compare == true", true, Py::Float( 100 ) == Py::Float( 100 ) ); test_assert( "compare == false", false, Py::Float( 100 ) == Py::Float( 101 ) ); test_assert( "compare != true", true, Py::Float( 100 ) != Py::Float( 101 ) ); test_assert( "compare != false", false, Py::Float( 100 ) != Py::Float( 100 ) ); test_assert( "compare < true", true, Py::Float( 100 ) < Py::Float( 101 ) ); test_assert( "compare < false", false, Py::Float( 100 ) < Py::Float( 99 ) ); test_assert( "compare <= true", true, Py::Float( 100 ) <= Py::Float( 101 ) ); test_assert( "compare <= true", true, Py::Float( 100 ) <= Py::Float( 100 ) ); test_assert( "compare <= false", false, Py::Float( 100 ) <= Py::Float( 99 ) ); test_assert( "compare > true", true, Py::Float( 100 ) > Py::Float( 99 ) ); test_assert( "compare > false", false, Py::Float( 100 ) > Py::Float( 101 ) ); test_assert( "compare >= true", true, Py::Float( 100 ) >= Py::Float( 99 ) ); test_assert( "compare >= true", true, Py::Float( 100 ) >= Py::Float( 100 ) ); test_assert( "compare >= false", false, Py::Float( 100 ) >= Py::Float( 101 ) ); } void test_String() { Py::String s( "hello" ); Py::Char blank = ' '; Py::String r1( "world in brief", 5 ); s = s + blank + r1; test_assert( "string concat", s, "hello world" ); s = s * 2; test_assert( "string multiple", s, "hello worldhello world" ); // test conversion std::string w = static_cast( s ); std::string w2 = s; test_assert( "string convert to std::string", w, w2 ); Py::String r2( "12345 789" ); // ord tests Py::Char c3 = r2[2]; long v3 = c3.ord(); test_assert( "string ord value < 2^7", v3, long( 0x33 ) ); Py::Char c4( 0xd5 ); long v4 = c4.ord(); test_assert( "string ord value < 2^8", v4, long( 0xd5 ) ); Py::Char c5( 0x10437 ); long v5 = c5.ord(); test_assert( "string ord value > 2^16", v5, long( 0x10437 ) ); Py::Char c6( 0x10ff00 ); long v6 = c6.ord(); test_assert( "string ord value > 2^16", v6, long( 0x10ff00 ) ); // convert tests Py::Char c7 = r2[5]; test_assert( "string convert to std::string", c7, blank ); Py::Char c8 = r2.front(); Py::Char c9 = r2.back(); } void test_boolean() { Py::Object o; Py::Boolean pb1; Py::Boolean pb2; Py::String st1; Py::Long int1; bool b1; // True tests o = Py::True(); test_assert( "boolean Py::True", o.isTrue(), true ); pb1 = o; test_assert( "boolean true pybool var ", pb1 ? true : false, true ); b1 = pb1; test_assert( "boolean true bool = pybool", b1, true ); pb2 = pb1; test_assert( "boolean true pybool = pybool", pb2 ? true : false, true ); pb2 = true; test_assert( "boolean true pybool = true", pb2 ? true : false, true ); test_assert( "boolean operator bool true", true, bool( pb2 ) ); // False tests o = Py::False(); test_assert( "boolean Py::False", o.isTrue(), false ); pb1 = o; test_assert( "boolean false pybool var ", pb1 ? true : false, false ); b1 = pb1; test_assert( "boolean false bool = pybool", b1, false ); pb2 = pb1; test_assert( "boolean false pybool = pybool", pb2 ? true : false, false ); pb2 = false; test_assert( "boolean false pybool = false", pb2 ? true : false, false ); test_assert( "boolean operator bool false", false, bool( pb2 ) ); // conversion tests int1 = 0; pb1 = int1; test_assert( "boolean int 0", pb1 ? true : false, false ); int1 = 99; pb1 = int1; test_assert( "boolean int 99", pb1 ? true : false, true ); st1 = ""; pb1 = st1; test_assert( "boolean string \"\"", pb1 ? true : false, false ); st1 = "x"; pb1 = st1; test_assert( "boolean string \"x\"", pb1 ? true : false, true ); } void test_long() { long cxx_long1( 100 ); long cxx_long2( 0 ); long cxx_long3( 0 ); Py::Long py_long1( 100 ); Py::Long py_long2( 0 ); Py::Long py_long3( 0 ); test_assert( "long constructor", cxx_long1, py_long1.as_long() ); cxx_long2 = cxx_long1++; py_long2 = py_long1++; test_assert( "long num++", cxx_long2, py_long2.as_long() ); cxx_long2 = ++cxx_long1; py_long2 = ++py_long1; test_assert( "long ++num", cxx_long2, py_long2.as_long() ); cxx_long2 = cxx_long1--; py_long2 = py_long1--; test_assert( "long num--", cxx_long2, py_long2.as_long() ); cxx_long2 = --cxx_long1; py_long2 = --py_long1; test_assert( "long --num", cxx_long2, py_long2.as_long() ); cxx_long1 = 1000; py_long1 = 1000; test_assert( "long num =", cxx_long1, py_long1.as_long() ); // comparison tests cxx_long1 = 2; cxx_long2 = 3; cxx_long3 = 3; py_long1 = cxx_long1; py_long2 = cxx_long2; py_long3 = cxx_long3; // ------------------------------------------------------------ test_assert( "long operator ==", cxx_long2 == cxx_long3, py_long2 == py_long3 ); test_assert( "long operator ==", cxx_long2 == cxx_long3, cxx_long2 == py_long3 ); test_assert( "long operator ==", cxx_long2 == cxx_long3, py_long2 == cxx_long3 ); test_assert( "long operator ==", cxx_long1 == cxx_long3, py_long1 == py_long3 ); test_assert( "long operator ==", cxx_long1 == cxx_long3, cxx_long1 == py_long3 ); test_assert( "long operator ==", cxx_long1 == cxx_long3, py_long1 == cxx_long3 ); // ------------------------------------------------------------ test_assert( "long operator !=", cxx_long1 != cxx_long2, py_long1 != py_long2 ); test_assert( "long operator !=", cxx_long1 != cxx_long2, cxx_long1 != py_long2 ); test_assert( "long operator !=", cxx_long1 != cxx_long2, py_long1 != cxx_long2 ); test_assert( "long operator !=", cxx_long2 != cxx_long3, py_long2 != py_long3 ); test_assert( "long operator !=", cxx_long2 != cxx_long3, cxx_long2 != py_long3 ); test_assert( "long operator !=", cxx_long2 != cxx_long3, py_long2 != cxx_long3 ); // ------------------------------------------------------------ test_assert( "long operator < ", cxx_long1 < cxx_long2, py_long1 < py_long2 ); test_assert( "long operator < ", cxx_long1 < cxx_long2, cxx_long1 < py_long2 ); test_assert( "long operator < ", cxx_long1 < cxx_long2, py_long1 < cxx_long2 ); test_assert( "long operator < ", cxx_long2 < cxx_long1, py_long2 < py_long1 ); test_assert( "long operator < ", cxx_long2 < cxx_long1, cxx_long2 < py_long1 ); test_assert( "long operator < ", cxx_long2 < cxx_long1, py_long2 < cxx_long1 ); // ------------------------------------------------------------ test_assert( "long operator > ", cxx_long2 > cxx_long1, py_long2 > py_long1 ); test_assert( "long operator > ", cxx_long2 > cxx_long1, cxx_long2 > py_long1 ); test_assert( "long operator > ", cxx_long2 > cxx_long1, py_long2 > cxx_long1 ); test_assert( "long operator > ", cxx_long1 > cxx_long2, py_long1 > py_long2 ); test_assert( "long operator > ", cxx_long1 > cxx_long2, cxx_long1 > py_long2 ); test_assert( "long operator > ", cxx_long1 > cxx_long2, py_long1 > cxx_long2 ); // ------------------------------------------------------------ test_assert( "long operator <=", cxx_long1 <= cxx_long2, py_long1 <= py_long2 ); test_assert( "long operator <=", cxx_long1 <= cxx_long2, cxx_long1 <= py_long2 ); test_assert( "long operator <=", cxx_long1 <= cxx_long2, py_long1 <= cxx_long2 ); test_assert( "long operator <=", cxx_long2 <= cxx_long3, py_long2 <= py_long3 ); test_assert( "long operator <=", cxx_long2 <= cxx_long3, cxx_long2 <= py_long3 ); test_assert( "long operator <=", cxx_long2 <= cxx_long3, py_long2 <= cxx_long3 ); test_assert( "long operator <=", cxx_long2 <= cxx_long1, py_long2 <= py_long1 ); test_assert( "long operator <=", cxx_long2 <= cxx_long1, cxx_long2 <= py_long1 ); test_assert( "long operator <=", cxx_long2 <= cxx_long1, py_long2 <= cxx_long1 ); // ------------------------------------------------------------ test_assert( "long operator >=", cxx_long2 >= cxx_long1, py_long2 >= py_long1 ); test_assert( "long operator >=", cxx_long2 >= cxx_long1, cxx_long2 >= py_long1 ); test_assert( "long operator >=", cxx_long2 >= cxx_long1, py_long2 >= cxx_long1 ); test_assert( "long operator >=", cxx_long2 >= cxx_long3, py_long2 >= py_long3 ); test_assert( "long operator >=", cxx_long2 >= cxx_long3, cxx_long2 >= py_long3 ); test_assert( "long operator >=", cxx_long2 >= cxx_long3, py_long2 >= cxx_long3 ); test_assert( "long operator >=", cxx_long1 >= cxx_long2, py_long1 >= py_long2 ); test_assert( "long operator >=", cxx_long1 >= cxx_long2, cxx_long1 >= py_long2 ); test_assert( "long operator >=", cxx_long1 >= cxx_long2, py_long1 >= cxx_long2 ); // ------------------------------------------------------------ test_assert( "long operator long", cxx_long2, long( py_long2 ) ); test_assert( "long operator int", int( cxx_long2 ), int( py_long2 ) ); #ifdef HAVE_LONG_LONG long long cxx_long_long11 = 1152921504616856976ll; long long cxx_long_long12 = 6152921504616856976ll; Py::Long py_long11( cxx_long_long11 ); Py::Long py_long12( 100 ); test_assert( "long long constructor 1", cxx_long_long11, py_long11.as_long_long() ); test_assert( "long long constructor 2", 1152921504616856976ll, py_long11.as_long_long() ); test_assert( "long long constructor 4", 100ll, py_long12.as_long_long() ); py_long12 = cxx_long_long12; test_assert( "long long operator=", cxx_long_long12, py_long12.as_long_long() ); #endif } void test_float() { double cxx_float1( 100 ); double cxx_float2( 0 ); double cxx_float3( 0 ); Py::Float py_float1( 100.0 ); Py::Float py_float2( 0.0 ); Py::Float py_float3( 0.0 ); test_assert( "float constructor", cxx_float1, py_float1.as_double() ); cxx_float1 = 1000; py_float1 = 1000; test_assert( "float num =", cxx_float1, py_float1.as_double() ); // comparison tests cxx_float1 = 2; cxx_float2 = 3; cxx_float3 = 3; py_float1 = cxx_float1; py_float2 = cxx_float2; py_float3 = cxx_float3; //------------------------------------------------------------ test_assert( "float operator ==", cxx_float2 == cxx_float3, py_float2 == py_float3 ); test_assert( "float operator ==", cxx_float2 == cxx_float3, cxx_float2 == py_float3 ); test_assert( "float operator ==", cxx_float2 == cxx_float3, py_float2 == cxx_float3 ); test_assert( "float operator ==", cxx_float1 == cxx_float3, py_float1 == py_float3 ); test_assert( "float operator ==", cxx_float1 == cxx_float3, cxx_float1 == py_float3 ); test_assert( "float operator ==", cxx_float1 == cxx_float3, py_float1 == cxx_float3 ); //------------------------------------------------------------ test_assert( "float operator !=", cxx_float1 != cxx_float2, py_float1 != py_float2 ); test_assert( "float operator !=", cxx_float1 != cxx_float2, cxx_float1 != py_float2 ); test_assert( "float operator !=", cxx_float1 != cxx_float2, py_float1 != cxx_float2 ); test_assert( "float operator !=", cxx_float2 != cxx_float3, py_float2 != py_float3 ); test_assert( "float operator !=", cxx_float2 != cxx_float3, cxx_float2 != py_float3 ); test_assert( "float operator !=", cxx_float2 != cxx_float3, py_float2 != cxx_float3 ); //------------------------------------------------------------ test_assert( "float operator < ", cxx_float1 < cxx_float2, py_float1 < py_float2 ); test_assert( "float operator < ", cxx_float1 < cxx_float2, cxx_float1 < py_float2 ); test_assert( "float operator < ", cxx_float1 < cxx_float2, py_float1 < cxx_float2 ); test_assert( "float operator < ", cxx_float2 < cxx_float1, py_float2 < py_float1 ); test_assert( "float operator < ", cxx_float2 < cxx_float1, cxx_float2 < py_float1 ); test_assert( "float operator < ", cxx_float2 < cxx_float1, py_float2 < cxx_float1 ); //------------------------------------------------------------ test_assert( "float operator > ", cxx_float2 > cxx_float1, py_float2 > py_float1 ); test_assert( "float operator > ", cxx_float2 > cxx_float1, cxx_float2 > py_float1 ); test_assert( "float operator > ", cxx_float2 > cxx_float1, py_float2 > cxx_float1 ); test_assert( "float operator > ", cxx_float1 > cxx_float2, py_float1 > py_float2 ); test_assert( "float operator > ", cxx_float1 > cxx_float2, cxx_float1 > py_float2 ); test_assert( "float operator > ", cxx_float1 > cxx_float2, py_float1 > cxx_float2 ); //------------------------------------------------------------ test_assert( "float operator <=", cxx_float1 <= cxx_float2, py_float1 <= py_float2 ); test_assert( "float operator <=", cxx_float1 <= cxx_float2, cxx_float2 <= py_float2 ); test_assert( "float operator <=", cxx_float1 <= cxx_float2, py_float1 <= cxx_float2 ); test_assert( "float operator <=", cxx_float2 <= cxx_float3, py_float2 <= py_float3 ); test_assert( "float operator <=", cxx_float2 <= cxx_float3, cxx_float2 <= py_float3 ); test_assert( "float operator <=", cxx_float2 <= cxx_float3, py_float2 <= cxx_float3 ); test_assert( "float operator <=", cxx_float2 <= cxx_float1, py_float2 <= py_float1 ); test_assert( "float operator <=", cxx_float2 <= cxx_float1, cxx_float2 <= py_float1 ); test_assert( "float operator <=", cxx_float2 <= cxx_float1, py_float2 <= cxx_float1 ); //------------------------------------------------------------ test_assert( "float operator >=", cxx_float2 >= cxx_float1, py_float2 >= py_float1 ); test_assert( "float operator >=", cxx_float2 >= cxx_float1, cxx_float2 >= py_float1 ); test_assert( "float operator >=", cxx_float2 >= cxx_float1, py_float2 >= cxx_float1 ); test_assert( "float operator >=", cxx_float2 >= cxx_float3, py_float2 >= py_float3 ); test_assert( "float operator >=", cxx_float2 >= cxx_float3, cxx_float2 >= py_float3 ); test_assert( "float operator >=", cxx_float2 >= cxx_float3, py_float2 >= cxx_float3 ); test_assert( "float operator >=", cxx_float1 >= cxx_float2, py_float1 >= py_float2 ); test_assert( "float operator >=", cxx_float1 >= cxx_float2, cxx_float1 >= py_float2 ); test_assert( "float operator >=", cxx_float1 >= cxx_float2, py_float1 >= cxx_float2 ); //------------------------------------------------------------ test_assert( "float operator float", cxx_float2, float( py_float2 ) ); } void test_numbers() { test_long(); test_float(); // test the basic numerical classes Py::Long i; Py::Long j(2); Py::Long k = Py::Long(3); i = 2; Py::Float a; a = 3 + i; //5.0 Py::Float b( 4.0 ); a = (1.0 + 2*a + (b*3.0)/2.0 + k)/Py::Float(5); // 4.0 i = a - 1.0; // 3 test_assert( "number calculation", i.as_long(), k.as_long() ); } void test_List() { // test the Py::List class Py::List list1; Py::List list2; test_assert( "list empty len()", list1.size(), static_cast( 0 ) ); list2.append( Py::String( "list2 index 0" ) ); list2.append( Py::String( "list2 index 1" ) ); list1.append( Py::Long( 3 ) ); list1.append( Py::Float( 6.0 ) ); list1.append( list2 ); list1.append( Py::String( "world" ) ); test_assert( "list len()", static_cast( 4 ), list1.size() ); test_assert( "list index[0]", Py::Long( 3 ), list1[0] ); test_assert( "list index[1]", Py::Float( 6.0 ), list1[1] ); test_assert( "list index[-1]", Py::String( "world" ), list1[-1] ); Py::List::iterator it1 = list1.begin(); test_assert( "list iterator not end != [0]", true, it1 != list1.end() ); test_assert( "list iterator not end == [0]", false, it1 == list1.end() ); test_assert( "list iterator compare [0]", Py::Long( 3 ), *it1 ); ++it1; test_assert( "list iterator not end != [1]", true, it1 != list1.end() ); test_assert( "list iterator not end == [1]", false, it1 == list1.end() ); test_assert( "list iterator compare [1]", Py::Float( 6.0 ), *it1 ); ++it1; test_assert( "list iterator not end != [2]", true, it1 != list1.end() ); test_assert( "list iterator not end == [2]", false, it1 == list1.end() ); test_assert( "list iterator compare [2]", list2, *it1 ); ++it1; Py::List::iterator it2 = list1.end(); test_assert( "list iterator not end != [3]", true, it1 != list1.end() ); test_assert( "list iterator not end == [3]", false, it1 == list1.end() ); test_assert( "list iterator compare [3]", Py::String( "world" ), *it1 ); ++it1; test_assert( "list iterator at end != [4]", false, it1 != list1.end() ); test_assert( "list iterator at end == [4]", true, it1 == list1.end() ); list1[ 3 ] = Py::String( "hello" ); test_assert( "list index assign", list1[ 3 ], Py::String( "hello" ) ); Py::List list3; list3 = list1 + list2; test_assert( "list operator+ count", static_cast( 6 ), list3.size() ); Py::Tuple tuple1( list1 ); test_assert( "list construct from tuple", list1.size(), tuple1.size() ); } void test_Tuple() { // test the Tuple class Py::Float f1( 1.0 ); Py::Float f2( 2.0 ); Py::Float f3( 3.0 ); Py::Tuple tuple1( 3 ); tuple1[0] = f1; // should be ok since no other reference owned tuple1[1] = f2; tuple1[2] = f3; Py::Tuple tuple2( tuple1 ); Py::Tuple::iterator it2 = tuple2.begin(); test_assert( "tuple iterator not end [0]", true, it2 != tuple2.end() ); test_assert( "tuple iterator compare [0]", Py::Float( 1.0 ), *it2 ); ++it2; test_assert( "tuple iterator not end [1]", true, it2 != tuple2.end() ); test_assert( "tuple iterator compare [1]", Py::Float( 2.0 ), *it2 ); ++it2; test_assert( "tuple iterator not end [2]", true, it2 != tuple2.end() ); test_assert( "tuple iterator compare [2]", Py::Float( 3.0 ), *it2 ); ++it2; test_assert( "tuple iterator at end [3]", true, it2 == tuple2.end() ); bool test_passed = false; Py::Tuple tuple3 = tuple1; try { tuple3[0] = Py::Long( 1 ); // should fail, tuple has multiple references } catch( Py::BaseException &e ) { e.clear(); test_passed = true; } test_assert( "tuple assign exception with multiple referencese", test_passed, true ); Py::List list1( tuple1 ); test_assert( "tuple construct from list", list1.size(), tuple1.size() ); Py::TupleN t0; test_assert( "TupleN construction", 0, t0.size() ); Py::TupleN t1( Py::Long( 1 ) ); test_assert( "TupleN construction", 1, t1.size() ); Py::TupleN t2( Py::Long( 1 ), Py::Long( 2 ) ); test_assert( "TupleN construction", 2, t2.size() ); Py::TupleN t3( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ) ); test_assert( "TupleN construction", 3, t3.size() ); Py::TupleN t4( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ), Py::Long( 4 ) ); test_assert( "TupleN construction", 4, t4.size() ); Py::TupleN t5( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ), Py::Long( 4 ), Py::Long( 5 ) ); test_assert( "TupleN construction", 5, t5.size() ); Py::TupleN t6( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ), Py::Long( 4 ), Py::Long( 5 ), Py::Long( 6 ) ); test_assert( "TupleN construction", 6, t6.size() ); Py::TupleN t7( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ), Py::Long( 4 ), Py::Long( 5 ), Py::Long( 6 ), Py::Long( 7 ) ); test_assert( "TupleN construction", 7, t7.size() ); Py::TupleN t8( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ), Py::Long( 4 ), Py::Long( 5 ), Py::Long( 6 ), Py::Long( 7 ), Py::Long( 8 ) ); test_assert( "TupleN construction", 8, t8.size() ); Py::TupleN t9( Py::Long( 1 ), Py::Long( 2 ), Py::Long( 3 ), Py::Long( 4 ), Py::Long( 5 ), Py::Long( 6 ), Py::Long( 7 ), Py::Long( 8 ), Py::Long( 9 ) ); test_assert( "TupleN construction", 9, t9.size() ); } void test_Dict() { // test the Dict class Py::Dict dict1; Py::List list1; Py::String str1( "two" ); dict1[ "one" ] = Py::Long( 1 ); dict1[ str1 ] = Py::Long( 2 ); dict1[ "three" ] = Py::Long( 3 ); test_assert( "dict index[char *]", dict1[ "one" ], Py::Long( 1 ) ); test_assert( "dict index[std::string]", dict1[ std::string("one") ], Py::Long( 1 ) ); test_assert( "dict index[Py::String]", dict1[ str1 ], Py::Long( 2 ) ); test_assert( "dict keys()", dict1.keys().size(), static_cast( 3 ) ); test_assert( "dict values()", dict1.values().size(), static_cast( 3 ) ); Py::Dict::iterator it1 = dict1.begin(); test_assert( "dict iterator not end != [0]", true, it1 != dict1.end() ); test_assert( "dict iterator not end == [0]", false, it1 == dict1.end() ); ++it1; test_assert( "dict iterator not end != [1]", true, it1 != dict1.end() ); test_assert( "dict iterator not end == [1]", false, it1 == dict1.end() ); ++it1; test_assert( "dict iterator not end != [2]", true, it1 != dict1.end() ); test_assert( "dict iterator not end == [2]", false, it1 == dict1.end() ); ++it1; Py::Dict::iterator it2 = dict1.end(); bool x = it1 != it2; test_assert( "x", false, x ); test_assert( "dict iterator at end != [3]", false, it1 != dict1.end() ); test_assert( "dict iterator at end == [3]", true, it1 == dict1.end() ); list1 = dict1.values(); list1.sort(); for( long k = 1; k < 4; ++k ) { test_assert( "dict values as expected", Py::Long( list1[ k-1 ] ).as_long(), k ); } Py::Dict dict2 = dict1; dict2.clear(); test_assert( "dict clear()", dict2.keys().length(), Py_ssize_t( 0 ) ); const Py::Dict c; for (Py::Dict::const_iterator it = c.begin(); it != c.end(); ++it) { } } void test_STL() { Py::List list1; list1.append( Py::Long(5) ); list1.append( Py::Long(1) ); list1.append( Py::Long(4) ); list1.append( Py::Long(2) ); list1.append( Py::Long(3) ); list1.append( Py::Long(1) ); test_assert( "STL count", 2, std::count( list1.begin(), list1.end(), Py::Long( 1 ) ) ); Py::Dict dict1; Py::String s1( "blah" ); Py::String s2( "gorf" ); dict1[ "one" ] = s1; dict1[ "two" ] = s1; dict1[ "three" ] = s2; dict1[ "four" ] = s2; Py::Dict::iterator it( dict1.begin() ); test_assert( "STL ad hoc", true, it != dict1.end() ); while( it != dict1.end() ) { Py::Dict::value_type vt( *it ); Py::String rs = vt.second.repr(); Py::Bytes bs = rs.encode( "utf-8" ); std::string ls = bs.as_std_string(); std::cout << "STL test: " << ls << std::endl; ++it; } } void debug_check_ref_queue() { #ifdef Py_TRACE_REFS // create an element to find the queue Py::Long list_element; PyObject *p_slow = list_element.ptr(); PyObject *p_fast = p_slow; do { assert( p_slow->_ob_next->_ob_prev == p_slow ); assert( p_slow->_ob_prev->_ob_next == p_slow ); p_slow = p_slow->_ob_next; p_fast = p_slow->_ob_next->_ob_next; assert( p_slow != p_fast ); } while( p_slow != list_element.ptr() ); #endif } class example_module : public Py::ExtensionModule { public: example_module() : Py::ExtensionModule( "example" ) { range::init_type(); add_varargs_method( "string", &example_module::ex_string, "string( s ) = return string" ); add_varargs_method( "sum", &example_module::ex_sum, "sum( arglist ) = sum of arguments" ); add_varargs_method( "test", &example_module::ex_test, "test( arglist ) runs a test suite" ); add_varargs_method( "range", &example_module::new_r, "range( start, stop, step )" ); add_varargs_method( "return_arg", &example_module::ex_return_arg, "return_arg( arg )" ); add_keyword_method( "kw", &example_module::ex_keyword, "kw()" ); initialize( "documentation for the example module" ); Py::Dict d( moduleDictionary() ); Py::Object b( Py::asObject( new range( 1, 10, 2 ) ) ); d["a_constant"] = b.getAttr("c"); d["a_range"] = b; } virtual ~example_module() {} private: Py::Object ex_keyword( const Py::Tuple &args, const Py::Dict &kws ) { std::cout << "Called with " << args.length() << " normal arguments." << std::endl; Py::List names( kws.keys() ); std::cout << "and with " << names.length() << " keyword arguments:" << std::endl; for( Py::List::size_type i=0; i< names.length(); i++ ) { Py::String name( names[i] ); std::cout << " " << name << std::endl; } return Py::Long(0); } Py::Object new_r( const Py::Tuple &rargs ) { if( rargs.length() < 2 || rargs.length() > 3 ) { throw Py::RuntimeError("Incorrect # of args to range(start,stop [,step])."); } Py::Long start( rargs[0] ); Py::Long stop( rargs[1] ); Py::Long step( 1 ); if (rargs.length() == 3) { step = rargs[2]; } std::cout << "new_r" << " start: " << start.as_long() << " stop: " << stop.as_long() << " step: " << step.as_long() << std::endl; if( start.as_long() > stop.as_long() + 1 || step.as_long() == 0 ) { throw Py::RuntimeError("Bad arguments to range( start, stop [,step] )"); } return Py::asObject( new range( start.as_long(), stop.as_long(), step.as_long() ) ); } Py::Object ex_string( const Py::Tuple &a ) { std::cout << "ex_std::string: s1 is first arg" << std::endl; Py::Object o1( a[0] ); std::cout << "ex_string: s1.isString() " << o1.isString() << std::endl; if( o1.isString() ) { Py::String s1( o1 ); std::cout << "ex_string: s1.size() " << s1.size() << std::endl; std::cout << "ex_string: s2 is s1.encode( utf-8 )" << std::endl; Py::Bytes b1( s1.encode( "utf-8" ) ); std::cout << "ex_string: s1.isString() " << b1.isString() << std::endl; std::cout << "ex_string: s1.size() " << b1.size() << std::endl; return b1; } else { Py::Bytes b1( o1 ); std::cout << "ex_string: s1 is b1.decode( utf-8 )" << std::endl; Py::String s1( b1.decode( "utf-8" ) ); std::cout << "ex_string: s1.isString() " << s1.isString() << std::endl; std::cout << "ex_string: s1.size() " << s1.size() << std::endl; return s1; } } Py::Object ex_return_arg( const Py::Tuple &a ) { return a[0]; } Py::Object ex_sum( const Py::Tuple &a ) { // this is just to test the function verify_length: try { a.verify_length(0); std::cout << "I see that you refuse to give me any work to do." << std::endl; } catch (Py::BaseException& e) { e.clear(); std::cout << "I will now add up your elements, oh great one." << std::endl; } Py::Float f(0.0); for( Py::Sequence::size_type i = 0; i < a.length(); i++ ) { Py::Float g (a[i]); f = f + g; } return f; } void test_apply() { Py::Module m("example"); Py::Callable fn = m.getAttr("return_arg"); Py::String s("test_apply string"); int start_ref = s.reference_count(); for( int i=0; i<10; ++i ) { Py::String result = fn.apply( Py::TupleN( s ) ); } int end_ref = s.reference_count(); test_assert( "apply ref check", start_ref, end_ref ); } Py::Object ex_test( const Py::Tuple &/*args*/ ) { debug_check_ref_queue(); std::cout << "Example Test starting" << std::endl; try { Py::String s("this should fail"); Py::Long k( s.ptr() ); throw TestError( "convert a Py::String to an Py::Long must not succeed" ); } catch( Py::TypeError &e ) { e.clear(); std::cout << "PASSED: Correctly caught " << Py::type(e) << std::endl; std::cout << "PASSED: Py::BaseException value: " << Py::value(e) << std::endl; std::cout << "PASSED: Py::BaseException traceback: " << Py::trace(e) << std::endl; } try { debug_check_ref_queue(); std::cout << "Start: test_compare" << std::endl; test_compare(); debug_check_ref_queue(); std::cout << "Start: test_boolean" << std::endl; test_boolean(); debug_check_ref_queue(); std::cout << "Start: test_numbers" << std::endl; test_numbers(); debug_check_ref_queue(); std::cout << "Start: test_String" << std::endl; test_String(); debug_check_ref_queue(); std::cout << "Start: test_List" << std::endl; test_List(); debug_check_ref_queue(); std::cout << "Start: test_Dict" << std::endl; test_Dict(); debug_check_ref_queue(); std::cout << "Start: test_Tuple" << std::endl; test_Tuple(); debug_check_ref_queue(); std::cout << "Start: test_STL" << std::endl; test_STL(); std::cout << "Done: test_STL" << std::endl; debug_check_ref_queue(); std::cout << "Start: test_extension_object" << std::endl; test_extension_object(); debug_check_ref_queue(); std::cout << "Start: test_apply" << std::endl; test_apply(); debug_check_ref_queue(); } catch( TestError &e ) { std::cout << "FAILED: Test error - " << e.m_description << std::endl; } Py::Module m("sys"); Py::Object s = m.getAttr("stdout"); Py::Object fd = s.callMemberFunction( "fileno" ); test_assert( "stdout fileno() is 1", fd, Py::Long( 1 ) ); Py::Object num = s.callMemberFunction( "write", Py::TupleN( Py::String("PASS: Module test ok.\n") ) ); return Py::None(); } }; #if defined( _WIN32 ) #define EXPORT_SYMBOL __declspec( dllexport ) #else #define EXPORT_SYMBOL #endif extern "C" EXPORT_SYMBOL PyObject *PyInit_example() { #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) Py::InitialisePythonIndirectPy::Interface(); #endif static example_module *example = new example_module; return example->module().ptr(); } // symbol required for the debug version extern "C" EXPORT_SYMBOL PyObject *PyInit_example_d() { return PyInit_example(); } pycxx-7.1.4/Demo/Python3/range.cxx000644 000765 000024 00000013254 13662723705 017250 0ustar00barrystaff000000 000000 //----------------------------------------------------------------------------- // // Copyright (c) 1998 - 2007, The Regents of the University of California // Produced at the Lawrence Livermore National Laboratory // All rights reserved. // // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The // full copyright notice is contained in the file COPYRIGHT located at the root // of the PyCXX distribution. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the disclaimer below. // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the disclaimer (as noted below) in the // documentation and/or materials provided with the distribution. // - Neither the name of the UC/LLNL nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. // //----------------------------------------------------------------------------- #ifdef _MSC_VER // disable warning C4786: symbol greater than 255 character, // nessesary to ignore as causes lots of warning #pragma warning( disable: 4786 ) #endif #include "range.hxx" // Connect range objects to Python range::range( long start, long stop, long step ) : Py::PythonExtension() , m_start( start ) , m_stop( stop ) , m_step( step ) { std::cout << "range object created " << this << " " << asString() << std::endl; } range::~range() { std::cout << "range object destroyed " << this << std::endl; } Py_ssize_t range::length() const { return (m_stop - m_start + 1)/m_step; } int range::item( long i ) const { if( i >= length() ) // this exception stops a Python for loop over range. throw Py::IndexError("index too large"); return m_start + i * m_step; } range *range::slice( Py_ssize_t i, Py_ssize_t j ) const { long first = m_start + static_cast( i ) * m_step; long last = m_start + static_cast( j ) * m_step; return new range( first, last, m_step ); } range *range::extend( Py_ssize_t k ) const { return new range( m_start, m_stop + static_cast( k ), m_step); } std::string range::asString() const { std::OSTRSTREAM s; s << "range(" << m_start << ", " << m_stop << ", " << m_step << ")"; return std::string( s.str() ); } Py::Object range::reference_count( const Py::Tuple &/*args*/ ) { return Py::Long( ob_refcnt ); } Py::Object range::c_value(const Py::Tuple&) const { Py::List result; for( int i = m_start; i <= m_stop; i += m_step ) { result.append( Py::Long(i) ); } return result; } void range::c_assign( const Py::Tuple &, const Py::Object &rhs ) { Py::Tuple w( rhs ); w.verify_length( 3 ); m_start = Py::Long( w[0] ).as_long(); m_stop = Py::Long( w[1] ).as_long(); m_step = Py::Long( w[2] ).as_long(); } Py::Object range::repr() { return Py::String( asString() ); } Py_ssize_t range::sequence_length() { return static_cast( length() ); } Py::Object range::sequence_item( Py_ssize_t i ) { return Py::Long( item( static_cast( i ) ) ); } Py::Object range::sequence_concat( const Py::Object &j ) { Py::Long k( j ); return Py::asObject( extend( k.as_long() ) ); } Py::Object range::sequence_slice( Py_ssize_t i, Py_ssize_t j ) { return Py::asObject( slice( i, j ) ); } Py::Object range::getattr( const char *name ) { if( std::string( name ) == "c" ) return Py::Float( 300.0 ); if( std::string( name ) == "start" ) return Py::Long( m_start ); return getattr_methods( name ); } // "regular" methods... Py::Object range::amethod( const Py::Tuple &t ) { t.verify_length( 1 ); Py::List result; result.append( Py::Object( this ) ); result.append( t[0] ); return result; } Py::Object range::value( const Py::Tuple &t ) { return c_value( t ); } Py::Object range::assign( const Py::Tuple &t ) { t.verify_length( 2 ); Py::Tuple t1( t[0] ); // subscripts Py::Object o2( t[1] ); // rhs; c_assign ( t1, o2 ); return Py::None(); } void range::init_type() { behaviors().name( "example.range" ); behaviors().doc( "range objects: start, stop, step" ); behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSequenceType(); add_varargs_method( "amethod", &range::amethod, "demonstrate how to document amethod" ); add_varargs_method( "assign", &range::assign ); add_varargs_method( "value", &range::value ); add_varargs_method( "reference_count", &range::reference_count ); behaviors().readyType(); }