genwrapper.py :  » Development » PyObjC » trunk » pyobjc » pyobjc-metadata » Lib » PyObjCMetaData » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » PyObjC 
PyObjC » trunk » pyobjc » pyobjc metadata » Lib » PyObjCMetaData » genwrapper.py
"""
This is a script for generating a framework wrapping project.

usage: genwrapper.py [options]

options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -f FRAMEWORK, --framework=FRAMEWORK
                        Generate wrapper for the named framework
  -o DIR, --output=DIR  Name of the output directory (default: '.')
  -p NAME, --project-name=NAME
                        Name of the python project, defaults to 'pyobjc-
                        framework-FRAMEWORK'
"""
import subprocess
import optparse
import sys
import os
import textwrap
import plistlib
import objc

#
# Templates for the various files in a new framework wrapper:
#

SETUP_TMPL=textwrap.dedent("""\
    ''' 
    Wrappers for framework '%(framework)s'. 

    These wrappers don't include documentation, please check Apple's documention
    for information on how to use this framework and PyObjC's documentation
    for general tips and tricks regarding the translation between Python
    and (Objective-)C frameworks
    '''
    import ez_setup
    ez_setup.use_setuptools()

    from setuptools import setup
    try:
        from PyObjCMetaData.commands import extra_cmdclass, extra_options
    except ImportError:
        extra_cmdclass = {}
        extra_options = lambda name: {}

    setup(
        name=%(project)r,
        version=%(pyobjc_version)r,
        description = "Wrappers for the framework %(framework)s on Mac OS X",
        long_description = __doc__,
        author='Ronald Oussoren',
        author_email='pyobjc-dev@lists.sourceforge.net',
        url='http://pyobjc.sourceforge.net',
        platforms = [ "MacOS X" ],
        packages = [ "%(framework)s" ],
        package_dir = { 
            '': 'Lib/' 
        },
        setup_requires = [ 
            'bdist_mpkg>=0.4.2',
        ],
        install_requires = [ 
            'pyobjc-core>=%(pyobjc_version)s',
            %(dependencyList)s
        ],
        dependency_links = [],
        package_data = { 
            '': ['*.xml'] 
        },
        test_suite='%(framework)s.test',
        cmdclass = extra_cmdclass,
        options = extra_options('%(framework)s'),

        # The package is actually zip-safe, but py2app isn't zip-aware yet.
        zip_safe = False,
    )
""")

README_TMPL=textwrap.dedent("""\
    Wrappers for framework '%(framework)s'. 

    These wrappers don't include documentation, please check Apple's documention
    for information on how to use this framework and PyObjC's documentation
    for general tips and tricks regarding the translation between Python
    and (Objective-)C frameworks
""")

LICENSE_TMPL=textwrap.dedent("""\
    (This is the MIT license)

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
""")

INIT_TMPL=textwrap.dedent("""\
    '''
    Python mapping for the %(framework)s framework.

    This module does not contain docstrings for the wrapped code, check Apple's
    documentation for details on how to use these functions and classes. 
    '''

    import objc as _objc
    %(frameworkDepends)s

    __bundle__ = _objc.initFrameworkWrapper("%(framework)s",
        frameworkIdentifier="%(bundleIdentifier)s",
        frameworkPath=_objc.pathForFramework(
            "%(frameworkPath)s"),
        globals=globals())
""")


# Note: the test template doesn't define tests, but only contains a template
# for some tests. This is because it would be rather pointless to check if 
# the generated wrapper is correct by using information generated by the 
# metadata tool: if that were absolutely reliable we wouldn't need tests in
# the first place.
TEST_TMPL=textwrap.dedent("""\
    '''
    Some simple tests to check that the framework is properly wrapped.
    '''
    import objc
    import unittest
    import %(framework)s

    class Test%(framework)s (unittest.TestCase):
        def testClasses(self):
            pass
            # self.assert_( hasattr(%(framework)s, 'CLASSNAME') )
            # self.assert_( isinstance(%(framework)s.CLASSNAME, objc.objc_class) )
            # Tollfree CF-type:
            # self.assert_( hasattr(%(framework)s, 'CLASSNAMERef') )
            # self.assert_( %(framework)s.CLASSNAMERef is %(framework)s.CLASSNAME )

            # Not-tollfree CF-type:
            # self.assert_( hasattr(%(framework)s, 'CLASSNAMERef') )
            # self.assert_( issubclass(%(framework)s.CLASSNAMERef, objc.lookUpClass('NSCFType')) )
            # self.assert_( %(framework)s.CLASSNAMERef is not objc.lookUpClass('NSCFType') )

        def testValues(self):
            # Use this to test for a number of enum and #define values
            pass

            # Integer values:
            # self.assert_( hasattr(%(framework)s, 'CONSTANT') )
            # self.assert_( isinstance(%(framework)s.CONSTANT, (int, long)) )
            # self.assertEquals(%(framework)s.CONSTANT, 7)

            # String values:
            # self.assert_( hasattr(%(framework)s, 'CONSTANT') )
            # self.assert_( isinstance(%(framework)s.CONSTANT, (str, unicode)) )
            # self.assertEquals(%(framework)s.CONSTANT, 'value')

        def testVariables(self):
            # Use this to test for global variables, (NSString*'s and the like)
            pass

            # self.assert_( hasattr(%(framework)s, 'CONSTANT') )
            # self.assert_( isinstance(%(framework)s.CONSTANT, unicode) )

        def testFunctions(self):
            # Use this to test for functions
            pass

            # self.assert_( hasattr(%(framework)s, 'FUNCTION') )

        def testOpaque(self):
            # Use this to test for opaque pointers
            pass

            # self.assert_( hasattr(%(framework)s, 'OPAQUE') )

        def testProtocols(self):
            # Use this to test if informal protocols  are present
            pass

            # self.assert_( hasattr(%(framework)s, 'protocols') )

            # self.assert_( hasattr(%(framework)s.protocols, 'PROTOCOL') )
            # self.assert_( isinstance(%(framework)s.protocols.PROTOCOL, objc.informal_protocol) )

        def test_structs(self):
            # Use this to test struct wrappers
            pass

            # self.assert_( hasattr(%(framework)s, 'STRUCT') )
            # o = %(framework)s.STRUCT()
            # self.assert_( hasattr(o, 'FIELD_NAME') )



    if __name__ == "__main__":
        unittest.main()

""")

def getBundleIdentifier(frameworkPath):
    infoPlist = os.path.join(frameworkPath, "Resources", "Info.plist")
    if not os.path.exists(infoPlist):
        infoPlist = os.path.join(frameworkPath, "Resources", "Info-macos.plist")
    if not os.path.exists(infoPlist):
        raise RuntimeError, "Framework at %s has no Info.plist?"%(frameworkPath,)

    try:
        pl = plistlib.readPlist(infoPlist)
    except:
        # Some frameworks contain a binary plist file, which plistlib doesn't
        # like at all.
        r = subprocess.call(
            ['plutil', '-convert', 'xml1', '-o', 'Info.plist', infoPlist])
        if r != 0:
            raise RuntimeError, "plutil failed"
        pl = plistlib.readPlist('Info.plist')
        os.unlink('Info.plist')
    return pl['CFBundleIdentifier']

def getFrameworkPath(framework):

    # Normal frameworks:
    for basedir in ('/Library/Frameworks', '/System/Library/Frameworks'):
        path = os.path.join(basedir, framework + '.framework')
        if os.path.exists(path):
            return path

    # Frameworks in an umbrella framework:
    subpath = 'Frameworks/%s.framework'%(framework,)
    for basedir in '/Library/Frameworks', '/System/Library/Frameworks':
        for dn in os.listdir(basedir):
            possibleMatch = os.path.join(basedir, dn, subpath)
            if os.path.exists(possibleMatch):
                return possibleMatch


    raise RuntimeError, "Cannot find framework: %s"%(framework)


def main():
    parser = optparse.OptionParser(version="%prog 0.5")    
    parser.add_option("-f", "--framework", dest="framework",        
        metavar="FRAMEWORK",        
        help="Generate wrapper for the named framework")    
    parser.add_option("-o", "--output", dest="output", metavar="DIR",        
            help="Name of the output directory (default: '.')", default=".")    
    parser.add_option("-p", "--project-name", dest="project", metavar="NAME",
        help="Name of the python project, defaults to 'pyobjc-framework-FRAMEWORK'")

    options, args = parser.parse_args()
    if args:
        parser.error("incorrect number of arguments")

    if options.framework is None:
        parser.error("you must specify a framework to wrap")

    if options.project is None:
        options.project = "pyobjc-framework-%s"%(options.framework,)

    try:
        frameworkPath = getFrameworkPath(options.framework)
    except RuntimeError, msg:
        parser.error(msg)

    bundleIdentifier = getBundleIdentifier(frameworkPath)
    
    if not os.path.exists(options.output):
        os.makedirs(options.output)

    if os.path.exists(os.path.join(options.output, options.project)):
        parser.error("framework wrapper already exists")

    framework = options.framework
    project = options.project
    pyobjc_version = objc.__version__

    basedir = os.path.join(options.output, options.project)
    os.mkdir(basedir)
    os.mkdir(os.path.join(basedir, "Lib"))
    os.mkdir(os.path.join(basedir, "Lib", options.framework))
    os.mkdir(os.path.join(basedir, "Lib", options.framework, "test"))
    os.mkdir(os.path.join(basedir, "Examples"))
    os.mkdir(os.path.join(basedir, "Exceptions"))

    fp = open(os.path.join(basedir, 'README.txt'), 'w')
    fp.write(README_TMPL % locals())
    fp.close()

    fp = open(os.path.join(basedir, 'LICENSE.txt'), 'w')
    fp.write(LICENSE_TMPL % locals())
    fp.close()


    import __main__
    bindir = os.path.dirname(os.path.abspath(__main__.__file__))

    proc =  subprocess.Popen([
            os.path.join(bindir, 'pyobjc-metadata-gen'),
            '-f', framework,
            '-F', 'final-md',
            '-o', os.path.join(basedir, 'Lib', framework, 'PyObjC.bridgesupport'),
            '-d', '-'
            ], stdout=subprocess.PIPE)
    lines = proc.communicate()[0]

    result = proc.returncode
    if result != 0:
        print >>sys.stderr, "Generating metadata failed"
        sys.exit(1)

    result = subprocess.call([
            os.path.join(bindir, 'pyobjc-metadata-gen'),
            '-f', framework,
            '-F', 'excp-templ-md',
            '-o', os.path.join(basedir, 'Exceptions', framework + '.bridgesupport'),
            ])
    if result != 0:
        print >>sys.stderr, "Generating exceptions template failed"
        sys.exit(1)


    importList = []
    dependencyList = []
    for ln in lines.splitlines():
        importList.append('from %s import *'%(ln.strip(),))
        dependencyList.append('\'pyobjc-framework-%s>=%s\','%(ln.strip(), pyobjc_version))

    dependencyList = '\n        '.join(dependencyList)
    fp = open(os.path.join(basedir, 'setup.py'), 'w')
    fp.write(SETUP_TMPL % locals())
    fp.close()

    frameworkDepends = '\n'.join(importList)
        
    fp = open(
        os.path.join(basedir, "Lib", framework, '__init__.py'), 'w')
    fp.write(INIT_TMPL % locals())
    fp.close()

    fp = open(
        os.path.join(basedir, "Lib", framework, 'test', '__init__.py'), 'w')
    fp.close()

    fp = open(
        os.path.join(basedir, "Lib", framework, 'test', 'test_%s.py'%(framework.lower(),)), 'w')
    fp.write(TEST_TMPL % locals())
    fp.close()

    result = subprocess.call([
            'svn', 'export', 'svn://svn.eby-sarna.com/svnroot/ez_setup'],
            cwd=basedir)
    if result != 0:
        print >>sys.stderr, "Couldn't extract the required 'ez_setup' files"
        sys.exit(1)

    print textwrap.dedent('''\
        Generated framework wrappers for %(framework)s.
        
        Please check and adjust setup.py, License.txt and ReadMe.txt to tast.
        Also check and update the metadata exceptions (and if you make changes
        there update the actual metadata) before releasing this package.

        There is a skeleton for  unittests in Lib/%(framework)s/test, please 
        add some real tests to that file.

        You'd do well to add some examples as well :-)

        Note: if you use subversion: remove ez_setup.py and add the following
        svn:externals defintion::

           ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup

        ''') % locals()
    sys.exit(0)


if __name__ == "__main__":
    main()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.