forked from pabigot/pyxb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.py
executable file
·278 lines (236 loc) · 10.7 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#!/usr/bin/env python
from __future__ import print_function
import sys
# The current version of the system. Format is #.#.#[-DEV].
version = '1.2.7-DEV'
# Require Python 2.6 or higher or Python 3.1 or higher
if (sys.version_info[:2] < (2, 6)) or ((sys.version_info[0] == 3) and sys.version_info[:2] < (3, 1)):
raise ValueError('''PyXB requires:
Python2 version 2.6 or later; or
Python3 version 3.1 or later
(You have %s.)''' % (sys.version,))
import os
import stat
import re
import datetime
import logging
from distutils.core import setup, Command
# Stupid little command to automatically update the version number
# where it needs to be updated.
class update_version (Command):
# Brief (40-50 characters) description of the command
description = "Substitute @VERSION@ in relevant files"
# List of option tuples: long name, short name (None if no short
# name), and help string.
user_options = [ ]
boolean_options = [ ]
# Files in the distribution that need to be rewritten when the
# version number changes
files = ( 'README.txt', 'pyxb/__init__.py', 'doc/conf.py' )
# The substitutions (key braced by @ signs)
substitutions = { 'VERSION' : version,
'THIS_YEAR' : datetime.date.today().strftime('%Y'),
'SHORTVERSION' : '.'.join(version.split('.')[:2]) }
def initialize_options (self):
pass
def finalize_options (self):
pass
def run (self):
for f in self.files:
text = open('%s.in' % (f,)).read()
for (k, v) in self.substitutions.items():
text = text.replace('@%s@' % (k,), v)
os.chmod(f, os.stat(f)[stat.ST_MODE] | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
open(f,'w').write(text)
os.chmod(f, os.stat(f)[stat.ST_MODE] & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH))
class test (Command):
# Brief (40-50 characters) description of the command
description = "Run all unit tests found in testdirs"
# List of option tuples: long name, short name (None if no short
# name), and help string.
user_options = [ ( 'testdirs=', None, 'colon separated list of directories to search for tests' ),
( 'trace-tests', 'v', 'trace search for tests' ),
( 'inhibit-output', 'q', 'inhibit test output' ),
]
boolean_options = [ 'trace-tests', 'inhibit-output' ]
def initialize_options (self):
self.trace_tests = None
self.inhibit_output = None
self.testdirs = 'tests'
def finalize_options (self):
pass
# Regular expression that matches unittest sources
__TestFile_re = re.compile('^test.*\.py$')
def run (self):
# Make sure log messages are supported
logging.basicConfig()
# Walk the tests hierarchy looking for tests
dirs = self.testdirs.split(':')
tests = [ ]
while dirs:
dir = dirs.pop(0)
if self.trace_tests:
print('Searching for tests in %s' % (dir,))
for f in os.listdir(dir):
fn = os.path.join(dir, f)
statb = os.stat(fn)
if stat.S_ISDIR(statb[0]):
dirs.append(fn)
elif self.__TestFile_re.match(f):
tests.append(fn)
number = 0
import sys
import traceback
import unittest
import types
# Import each test into its own module, then add the test
# cases in it to a complete suite.
loader = unittest.defaultTestLoader
suite = unittest.TestSuite()
used_names = set()
for fn in tests:
stage = 'compile'
try:
# Assign a unique name for this test
test_name = os.path.basename(fn).split('.')[0]
test_name = test_name.replace('-', '_')
number = 2
base_name = test_name
while test_name in used_names:
test_name = '%s%d' % (base_name, number)
number += 1
# Read the test source in and compile it
rv = compile(open(fn).read(), test_name, 'exec')
state = 'evaluate'
# Make a copy of the globals array so we don't
# contaminate this environment.
g = globals().copy()
# The test cases use __file__ to determine the path to
# the schemas
g['__file__'] = fn
# Create a module into which the test will be evaluated.
module = types.ModuleType(test_name)
# The generated code uses __name__ to look up the
# containing module in sys.modules.
g['__name__'] = test_name
sys.modules[test_name] = module
# Import the test into the module, making sure the created globals look like they're in the module.
eval(rv, g)
module.__dict__.update(g)
# Find all subclasses of unittest.TestCase that were
# in the test source and add them to the suite.
for (nm, obj) in g.items():
if (type == type(obj)) and issubclass(obj, unittest.TestCase):
suite.addTest(loader.loadTestsFromTestCase(obj))
if self.trace_tests:
print('%s imported' % (fn,))
except Exception as e:
print('%s failed in %s: %s' % (fn, stage, e))
raise
# Run everything
verbosity = 1
if self.trace_tests:
verbosity = 2
elif self.inhibit_output:
# Don't know how to do this for real
verbosity = 0
runner = unittest.TextTestRunner(verbosity=verbosity)
runner.run(suite)
import glob
import sys
import pyxb.utils.utility
packages = [
'pyxb', 'pyxb.namespace', 'pyxb.binding', 'pyxb.utils', 'pyxb.xmlschema',
"pyxb.bundles"
]
package_data = {}
init_re = re.compile('^__init__\.py$')
wxs_re = re.compile('^.*\.wxs$')
setup_path = os.path.dirname(__file__)
bundle_base = os.path.join(setup_path, 'pyxb', 'bundles')
possible_bundles = []
try:
possible_bundles.extend(os.listdir(bundle_base))
except OSError as e:
print("Directory %s bundle search failed: %s" % (bundle_base, e))
for possible_bundle in possible_bundles:
bundle_root = os.path.join(bundle_base, possible_bundle)
if not os.path.isdir(bundle_root):
continue
b_packages = []
b_data = { }
for fp in pyxb.utils.utility.GetMatchingFiles('%s//' % (bundle_root,), init_re):
bundle_path = os.path.dirname(os.path.normpath(fp))
try:
package_relpath = os.path.relpath(bundle_path, setup_path)
except AttributeError as e:
package_relpath = bundle_path
if setup_path and '.' != setup_path:
prefix_path = setup_path + os.path.sep
if not package_relpath.startswith(prefix_path):
print("Unable to determine relative path from %s to %s installation" % (setup_path, bundle_path))
sys.exit(1)
package_relpath = package_relpath[len(prefix_path):]
package = package_relpath.replace(os.path.sep, '.')
b_packages.append(package)
wxs_files = [os.path.basename(_f) for _f in pyxb.utils.utility.GetMatchingFiles(bundle_path, wxs_re) ]
if wxs_files:
b_data[package] = wxs_files
if 0 < len(b_data):
print('Found bundle in %s' % (bundle_root,))
packages.extend(b_packages)
package_data.update(b_data)
setup(name='PyXB',
description = 'PyXB ("pixbee") is a pure Python package that generates Python source code for classes that correspond to data structures defined by XMLSchema.',
author='Peter A. Bigot',
author_email='[email protected]',
url='http://pyxb.sourceforge.net',
# Also change in README.TXT, pyxb/__init__.py, and doc/conf.py
version=version,
license='Apache License 2.0',
long_description='''PyXB is a pure `Python <http://www.python.org>`_ package that generates
Python code for classes that correspond to data structures defined by
`XMLSchema <http://www.w3.org/XML/Schema>`_. In concept it is similar to
`JAXB <http://en.wikipedia.org/wiki/JAXB>`_ for Java and `CodeSynthesis XSD
<http://www.codesynthesis.com/products/xsd/>`_ for C++.
The major goals of PyXB are:
* Provide a generated Python interface that is "Pythonic", meaning similar
to one that would have been hand-written:
+ Attributes and elements are Python properties, with name conflicts
resolved in favor of elements
+ Elements with maxOccurs larger than 1 are stored as Python lists
+ Bindings for type extensions inherit from the binding for the base type
+ Enumeration constraints are exposed as class (constant) variables
* Support bi-directional conversion (document to Python and back)
* Allow easy customization of the generated bindings to provide
functionality along with content
* Support all XMLSchema features that are in common use, including:
+ complex content models (nested all/choice/sequence)
+ cross-namespace dependencies
+ include and import directives
+ constraints on simple types
''',
provides=[ 'PyXB' ],
packages=packages,
package_data=package_data,
# I normally keep these in $purelib, but distutils won't tell me where that is.
# We don't need them in the installation anyway.
#data_files= [ ('pyxb/standard/schemas', glob.glob(os.path.join(*'pyxb/standard/schemas/*.xsd'.split('/'))) ) ],
scripts=[ 'scripts/pyxbgen', 'scripts/pyxbwsdl', 'scripts/pyxbdump' ],
cmdclass = { 'test' : test,
'update_version' : update_version },
classifiers = [ 'Development Status :: 5 - Production/Stable'
, 'Intended Audience :: Developers'
, 'License :: OSI Approved :: Apache Software License'
, 'Topic :: Software Development :: Code Generators'
, 'Topic :: Text Processing :: Markup :: XML'
, 'Programming Language :: Python :: 2'
, 'Programming Language :: Python :: 2.6'
, 'Programming Language :: Python :: 2.7'
, 'Programming Language :: Python :: 3'
# Skip 3.0 because it doesn't know how to be built with hashlib support
, 'Programming Language :: Python :: 3.1'
, 'Programming Language :: Python :: 3.2'
, 'Programming Language :: Python :: 3.3'
, 'Programming Language :: Python :: 3.4'
] )