#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Modeling Framework: an Object-Relational Bridge for python
#
# Copyright (c) 2001-2004 Sbastien Bigaret <sbigaret@users.sourceforge.net>
# All rights reserved.
#
# This file is part of the Modeling Framework.
#
# This code is distributed under a "3-clause BSD"-style license;
# see the LICENSE file for details.
#-----------------------------------------------------------------------------
"""
Builds the python-code templates for the supplied model
CVS information
$Id: mdl_generate_python_code.py 961 2004-11-30 17:25:35Z sbigaret $
"""
__version__='$Revision: 961 $'[11:-2]
import getopt, sys
class TargetDirectoryAlreadyExists(IOError):
pass
def log(msg):
sys.stderr.write(msg+'\n')
def tracebackInfoFromStack(exc_traceback):
from traceback import extract_tb,format_list
from Modeling.utils import isListOrTuple
tb=None
str='%s\n%s\n'%sys.exc_info()[:2]
try:
tb=sys.exc_info()[-1]
str+=reduce(lambda a,b: a+b, format_list(extract_tb(tb)))
return str
finally:
del tb
def build_python_code(model, pymodel_path, generation_scheme, rootPath=None,
typeOfCode='python', verbose_mode=0, fake_mode=0):
"""
Builds the python-code templates for the supplied model
:Parameters:
- `model`: an instance of Modeling.Model
- `pymodel_path`: the detected type, as returned by `Model._loadModel()`
- `generation_scheme`:
- `rootPath`: where the files should be dropped
- `typeOfCode`: (do not use) only 'python' is available for the moment ;
future dev. will probably include generation of zope products.
- `verbose_mode`: if set to true, the building process logs some
informational message onto sys.stderr while building the files. Default
is false.
- `fake_mode`: if true, do not create or change any file, just report what
would be done
Raises TargetDirectoryAlreadyExists if 'overwrite' is false and the target
directory already exists.
"""
if not rootPath:
raise ValueError, 'Error: A path must be specified'
if typeOfCode=='python':
from Modeling.ModelMasons.PyModelMason import PyModelMason
mason = PyModelMason(model, pymodel_path, rootPath,
verbose_mode=verbose_mode,
generation_scheme=generation_scheme,
fake_mode=fake_mode)
mason.build()
def usage(prgName):
"Writes usage on sys.stderr"
_usage="""
%s [options] model.(xml|py) [directory]
Generates python code from a model, either a xml-model file or a PyModel.
Parameter:
----------
[directory] The directory in which the generated python modules should be
dropped. If not provided, it defaults to the current directory.
General options:
----------------
-h --help gives this help
-n --dry-run do not create or change any file, just report what would
be done
-q --quiet quiet mode
-v --verbose verbose mode (default)
-f --force By default, the script stops if the model has errors.
Setting this flag makes the script ignores the errors: use
at your own risks and expect errors to happen!
Generation options:
-------------------
For an explanation on generation schemes, see below
-B --base-generation-scheme use the 'base' scheme
-C --compact-generation-scheme use the 'compact' scheme (default)
-g<scheme>
--generation_scheme=<scheme> use <scheme> as the generation scheme
(either 'base' or 'compact')
'compact' scheme: puts all generated file in the same directory (the package
for the model). When re-generating the files, only the two files
containing the model are overwritten, every other file that already exists
is never overwritten
'base' scheme: adds a sub-module 'MDL' within the generated package. All files
within MDL/ are ALWAYS overwritten when the python code is regenerated,
while others (in the root package) are never overwritten if they exist.
This is probably the one you want to use if your model changes often.
Note: this can be used if and only if there is no entity sharing the same
module with one of its (direct or indirect) subentities. If this is
not the case, the generation will raise and indicate the problem.
""" % prgName
sys.stderr.write(_usage)
# Global variables
verbose=1
def main(args):
me=args[0]
try: options, args = getopt.getopt(sys.argv[1:],
'BCfg:hnqv',
["help", "quiet", "verbose",
"force", "generation_scheme=",
"compact-generation-scheme",
"base-generation-scheme",
"dry-run"])
except: usage(me); return 1
global verbose
generation_scheme='compact'
fake_mode=force_flag=0
for k, v in options:
if k in ('-h', '--help'): usage(me); return 0
if k in ('-q', '--quiet'): verbose=0; continue
if k in ('-g', '--generation-scheme'): generation_scheme=v; continue
if k in ('-C', '--compact-generation-scheme'): generation_scheme='compact'; continue
if k in ('-B', '--base-generation-scheme'): generation_scheme='base'; continue
if k in ('-n', '--dry-run'): fake_mode=1; continue
if k in ('-f', '--force'): force_flag=1; continue
if len(args) not in (1,2): usage(me) ; return 1
model_file=args[0]
rootPath=len(args)==2 and args[1] or './'
pymodel_path=None
# load the model
if verbose: log("Loading the model...")
try:
from Modeling import Model
model,model_type=Model._loadModel(model_file)
if model_type=="pymodel":
import os
pymodel_path=os.path.abspath(model_file)
if not model:
raise RuntimeError, "Abnormal: got no exception but Model is None"
Model.updateModelWithCFG(model)
except Exception, exc:
if verbose: log(tracebackInfoFromStack(exc))
else: log('(-v will give you the traceback)')
return 1
from Modeling import ModelValidation
from Modeling.ModelValidation import NOT_SUPPORTED,ERROR,WARNING,INFO,DEBUG
errors=MV.ModelValidationException(ignore_levels=[DEBUG,INFO,WARNING])
MV.validateModel(model, errors)
if errors:
log("Error: model has errors")
if verbose: log(str(errors))
else: log("(-v for details)")
if not force_flag:
log("Aborting")
return 2
else:
log("Option --force set, continuing anyway...\n")
try:
build_python_code(model, pymodel_path, generation_scheme, rootPath,
verbose_mode=verbose, fake_mode=fake_mode)
except TargetDirectoryAlreadyExists, exc:
sys.stderr.write(str(sys.exc_info()[1])+'\n')
return 1
return 0
if __name__ == "__main__":
errs = main(sys.argv)
sys.exit(errs and 1 or 0)
|