]> SALOME platform Git repositories - modules/kernel.git/commitdiff
Salome HOME
PAL6952: Documentation of geompy.py. Add script for conversion of python files in...
authorjfa <jfa@opencascade.com>
Thu, 13 Jan 2005 13:54:47 +0000 (13:54 +0000)
committerjfa <jfa@opencascade.com>
Thu, 13 Jan 2005 13:54:47 +0000 (13:54 +0000)
doc/salome/tui/Makefile.in
doc/salome/tui/pythfilter.py [new file with mode: 0644]

index 5949e81b8cac33d3bf5573d098c90c7e25974d46..436bef0cb50e0767d0b9c02329af80ba7a95fa8a 100644 (file)
@@ -17,6 +17,7 @@ doxygen=@DOXYGEN@
 @COMMENCE@
 
 docs:
+       cp -f $(srcdir)/pythfilter.py ./
        cp -fr $(srcdir)/KERNEL ./INPUT; \
        cd INPUT; \
        sed 's|../../../share/salome|$(root_srcdir)|' ./doxyfile > ./doxyfile1; \
diff --git a/doc/salome/tui/pythfilter.py b/doc/salome/tui/pythfilter.py
new file mode 100644 (file)
index 0000000..ee72cd8
--- /dev/null
@@ -0,0 +1,547 @@
+#!/usr/bin/env python
+
+import getopt
+import glob
+import os.path
+import shutil
+import string
+import sys
+import token
+import tokenize
+
+from stat import *
+
+OUTSIDE          = 0
+BUILD_COMMENT    = 1
+BUILD_CLASS_DECL = 2
+BUILD_CLASS_BODY = 3
+BUILD_DEF_DECL   = 4
+BUILD_DEF_BODY   = 5
+IMPORT           = 6
+IMPORT_OP        = 7
+IMPORT_APPEND    = 8
+
+# Output file stream
+outfile = sys.stdout
+
+# Output buffer
+outbuffer = []
+
+out_row = 0
+out_col = 0
+
+# Variables used by rec_name_n_param()
+name         = ""
+param        = ""
+doc_string   = ""
+record_state = 0
+bracket_counter = 0
+
+# Tuple: (row,column)
+class_spos  = (0,0)
+def_spos    = (0,0)
+import_spos = (0,0)
+
+# Which import was used? ("import" or "from")
+import_token = ""
+
+# Comment block buffer
+comment_block = []
+comment_finished = 0
+
+# Imported modules
+modules = []
+
+# Program state
+stateStack = [OUTSIDE]
+
+# Keep track of whether module has a docstring
+module_has_docstring = False
+
+# Keep track of member protection
+protection_level = "public"
+private_member = False
+
+# Keep track of the module namespace
+namespace = ""
+
+######################################################################
+# Output string s. '\n' may only be at the end of the string (not
+# somewhere in the middle).
+#
+# In: s    - String
+#     spos - Startpos
+######################################################################
+def output(s,spos, immediate=0):
+    global outbuffer, out_row, out_col, outfile
+
+    os = string.rjust(s,spos[1]-out_col+len(s))
+    if immediate:
+        outfile.write(os)
+    else:
+        outbuffer.append(os)
+    if (s[-1:]=="\n"):
+        out_row = out_row+1
+        out_col = 0
+    else:
+        out_col = spos[1]+len(s)
+
+
+######################################################################
+# Records a name and parameters. The name is either a class name or
+# a function name. Then the parameter is either the base class or
+# the function parameters.
+# The name is stored in the global variable "name", the parameters
+# in "param".
+# The variable "record_state" holds the current state of this internal
+# state machine.
+# The recording is started by calling start_recording().
+#
+# In: type, tok
+######################################################################
+def rec_name_n_param(type, tok):
+    global record_state,name,param,doc_string,bracket_counter
+    s = record_state
+    # State 0: Do nothing.
+    if   (s==0):
+         return
+    # State 1: Remember name.
+    elif (s==1):
+        name = tok
+        record_state = 2
+    # State 2: Wait for opening bracket or colon
+    elif (s==2):
+        if (tok=='('):
+            bracket_counter = 1
+            record_state=3
+        if (tok==':'): record_state=4
+    # State 3: Store parameter (or base class) and wait for an ending bracket
+    elif (s==3):
+        if (tok=='*' or tok=='**'):
+            tok=''
+        if (tok=='('):
+            bracket_counter = bracket_counter+1
+        if (tok==')'):
+            bracket_counter = bracket_counter-1
+        if bracket_counter==0:
+            record_state=4
+        else:
+            param=param+tok
+    # State 4: Look for doc string
+    elif (s==4):
+        if (type==token.NEWLINE or type==token.INDENT or type==token.SLASHEQUAL):
+            return
+        elif (tok==":"):
+            return
+        elif (type==token.STRING):
+            while tok[:1]=='r' or tok[:1]=='u':
+                tok=tok[1:]
+            while tok[:1]=='"':
+                tok=tok[1:]
+            while tok[-1:]=='"':
+                tok=tok[:-1]
+            doc_string=tok
+        record_state=0
+
+######################################################################
+# Starts the recording of a name & param part.
+# The function rec_name_n_param() has to be fed with tokens. After
+# the necessary tokens are fed the name and parameters can be found
+# in the global variables "name" und "param".
+######################################################################
+def start_recording():
+    global record_state,param,name, doc_string
+    record_state=1
+    name=""
+    param=""
+    doc_string=""
+
+######################################################################
+# Test if recording is finished
+######################################################################
+def is_recording_finished():
+    global record_state
+    return record_state==0
+
+######################################################################
+## Gather comment block
+######################################################################
+def gather_comment(type,tok,spos):
+    global comment_block,comment_finished
+    if (type!=tokenize.COMMENT):
+        comment_finished = 1
+    else:
+        # Output old comment block if a new one is started.
+        if (comment_finished):
+            print_comment(spos)
+            comment_finished=0
+        if (tok[0:2]=="##" and tok[0:3]!="###"):
+            comment_block.append(tok[2:])
+
+######################################################################
+## Output comment block and empty buffer.
+######################################################################
+def print_comment(spos):
+    global comment_block,comment_finished
+    if (comment_block!=[]):
+        output("/**\n",spos)
+        for c in comment_block:
+            output(c,spos)
+        output("*/\n",spos)
+    comment_block    = []
+    comment_finished = 0
+
+######################################################################
+def set_state(s):
+    global stateStack
+    stateStack[len(stateStack)-1]=s
+
+######################################################################
+def get_state():
+    global stateStack
+    return stateStack[len(stateStack)-1]
+
+######################################################################
+def push_state(s):
+    global stateStack
+    stateStack.append(s)
+
+######################################################################
+def pop_state():
+    global stateStack
+    stateStack.pop()
+
+
+######################################################################
+def tok_eater(type, tok, spos, epos, line):
+    global stateStack,name,param,class_spos,def_spos,import_spos
+    global doc_string, modules, import_token, module_has_docstring
+    global protection_level, private_member
+
+    rec_name_n_param(type,tok)
+    if (string.replace(string.strip(tok)," ","")=="##private:"):
+         protection_level = "private"
+         output("private:\n",spos)
+    elif (string.replace(string.strip(tok)," ","")=="##protected:"):
+         protection_level = "protected"
+         output("protected:\n",spos)
+    elif (string.replace(string.strip(tok)," ","")=="##public:"):
+         protection_level = "public"
+         output("public:\n",spos)
+    else:
+         gather_comment(type,tok,spos)
+
+    state = get_state()
+
+#    sys.stderr.write("%d: %s\n"%(state, tok))
+
+    # OUTSIDE
+    if   (state==OUTSIDE):
+        if  (tok=="class"):
+            start_recording()
+            class_spos = spos
+            push_state(BUILD_CLASS_DECL)
+        elif (tok=="def"):
+            start_recording()
+            def_spos = spos
+            push_state(BUILD_DEF_DECL)
+        elif (tok=="import") or (tok=="from"):
+            import_token = tok
+            import_spos = spos
+            modules     = []
+            push_state(IMPORT)
+        elif (spos[1] == 0 and tok[:3] == '"""'):
+            # Capture module docstring as namespace documentation
+            module_has_docstring = True
+            #comment_block.append("\\namespace %s\n" % namespace)
+            comment_block.append(tok[3:-3])
+            print_comment(spos)
+
+    # IMPORT
+    elif (state==IMPORT):
+        if (type==token.NAME):
+            modules.append(tok)
+            set_state(IMPORT_OP)
+    # IMPORT_OP
+    elif (state==IMPORT_OP):
+        if (tok=="."):
+            set_state(IMPORT_APPEND)
+        elif (tok==","):
+            set_state(IMPORT)
+        else:
+            for m in modules:
+                output('#include "'+m.replace('.',os.sep)+'.py"\n', import_spos, immediate=1)
+                if import_token=="from":
+                    output('using namespace '+m.replace('.', '::')+';\n', import_spos)
+            pop_state()
+    # IMPORT_APPEND
+    elif (state==IMPORT_APPEND):
+        if (type==token.NAME):
+            modules[len(modules)-1]+="."+tok
+            set_state(IMPORT_OP)
+    # BUILD_CLASS_DECL
+    elif (state==BUILD_CLASS_DECL):
+        if (is_recording_finished()):
+            s = "class "+name
+            if (param!=""): s = s+" : public "+param.replace('.','::')
+            if (doc_string!=""): comment_block.append(doc_string)
+            print_comment(class_spos)
+            output(s+"\n",class_spos)
+            output("{\n",(class_spos[0]+1,class_spos[1]))
+            protection_level = "public"
+            output("  public:\n",(class_spos[0]+2,class_spos[1]))
+            set_state(BUILD_CLASS_BODY)
+    # BUILD_CLASS_BODY
+    elif (state==BUILD_CLASS_BODY):
+        if (type!=token.INDENT and type!=token.NEWLINE and type!=40 and
+            type!=tokenize.NL and type!=tokenize.COMMENT and
+            (spos[1]<=class_spos[1])):
+            output("}; // end of class\n",(out_row+1,class_spos[1]))
+            pop_state()
+        elif (tok=="def"):
+            start_recording()
+            def_spos = spos
+            push_state(BUILD_DEF_DECL)
+    # BUILD_DEF_DECL
+    elif (state==BUILD_DEF_DECL):
+        if (is_recording_finished()):
+            s = ''
+            # Do we document a class method? then remove the 'self' parameter
+            if BUILD_CLASS_BODY in stateStack:
+                params = param.split(",")
+                if params[0] == 'self':
+                    param = string.join(params[1:], ",")
+                else:
+                    s = 'static '
+                    if params[0] == 'cls':
+                        param = string.join(params[1:], ",")
+               s = s+name+"("+param+");\n"
+                if len(name) > 1 \
+                   and name[0:2] == '__' \
+                   and name[len(name)-2:len(name)] != '__' \
+                   and protection_level != 'private':
+                       private_member = True
+                       output("  private:\n",(def_spos[0]+2,def_spos[1]))
+            else:
+               s = name+"("+param+");\n"
+            if (doc_string!=""): comment_block.append(doc_string)
+            print_comment(def_spos)
+            output(s,def_spos)
+#       output("{\n",(def_spos[0]+1,def_spos[1]))
+            set_state(BUILD_DEF_BODY)
+    # BUILD_DEF_BODY
+    elif (state==BUILD_DEF_BODY):
+        if (type!=token.INDENT and type!=token.NEWLINE \
+            and type!=40 and type!=tokenize.NL \
+            and (spos[1]<=def_spos[1])):
+#            output("} // end of method/function\n",(out_row+1,def_spos[1]))
+            if private_member and protection_level != 'private':
+                private_member = False
+                output("  " + protection_level + ":\n",(def_spos[0]+2,def_spos[1]))
+            pop_state()
+#       else:
+#            output(tok,spos)
+
+
+def dump(filename):
+    f = open(filename)
+    r = f.readlines()
+    for s in r:
+        sys.stdout.write(s)
+
+def filter(filename):
+    global name, module_has_docstring
+    global namespace,outbuffer
+    outbuffer=[]
+
+    path,name = os.path.split(filename)
+    root,ext  = os.path.splitext(name)
+
+
+    if namespace:
+       if root == "__init__":
+          root=namespace
+       else:
+          root=namespace+"::"+root 
+    else:
+       root=root 
+
+    output("namespace "+root+" {\n",(0,0))
+
+    # set module name for tok_eater to use if there's a module doc string
+    package=namespace
+    name = root
+    namespace = root
+
+    sys.stderr.write("namespace: "+namespace+'\n')
+    sys.stderr.write("root: "+root+'\n')
+    sys.stderr.write('Filtering "'+filename+'"...')
+
+    f = open(filename)
+    tokenize.tokenize(f.readline, tok_eater)
+    f.close()
+    print_comment((0,0))
+
+    output("\n",(0,0))
+    output("}  // end of namespace\n",(0,0))
+
+    if not module_has_docstring:
+        # Put in default namespace documentation
+        output('/** \\namespace '+root+' \n',(0,0))
+        output('    \\brief Module "%s" */\n'%(root),(0,0))
+
+    for s in outbuffer:
+        outfile.write(s)
+    namespace=package
+    module_has_docstring = False
+
+
+def filterFile(filename, out=sys.stdout):
+    global outfile
+
+    outfile = out
+
+    try:
+        root,ext  = os.path.splitext(filename)
+
+        if ext==".py":
+            filter(filename)
+        else:
+            dump(filename)
+
+        sys.stderr.write("OK\n")
+    except IOError,e:
+        sys.stderr.write(e[1]+"\n")
+
+
+######################################################################
+
+# preparePath
+def preparePath(path):
+    """Prepare a path.
+
+    Checks if the path exists and creates it if it does not exist.
+    """
+    if not os.path.exists(path):
+        parent = os.path.dirname(path)
+        if parent!="":
+            preparePath(parent)
+        os.mkdir(path)
+
+# isNewer
+def isNewer(file1,file2):
+    """Check if file1 is newer than file2.
+
+    file1 must be an existing file.
+    """
+    if not os.path.exists(file2):
+        return True
+    return os.stat(file1)[ST_MTIME]>os.stat(file2)[ST_MTIME]
+
+# convert
+def convert(srcpath, destpath):
+    """Convert a Python source tree into a C+ stub tree.
+
+    All *.py files in srcpath (including sub-directories) are filtered
+    and written to destpath. If destpath exists, only the files
+    that have been modified are filtered again. Files that were deleted
+    from srcpath are also deleted in destpath if they are still present.
+    The function returns the number of processed *.py files.
+    """
+    global namespace
+    count=0
+    l=os.listdir(srcpath)
+    if "__init__.py" in l:
+       if namespace:
+         namespace=namespace+"::"+os.path.split(srcpath)[1]
+       else:
+         namespace=os.path.split(srcpath)[1]
+       print "It's a package:",namespace
+    sp = os.path.join(srcpath,"*")
+    sfiles = glob.glob(sp)
+    dp = os.path.join(destpath,"*")
+    dfiles = glob.glob(dp)
+    leftovers={}
+    for df in dfiles:
+        leftovers[os.path.basename(df)]=1
+
+    for srcfile in sfiles:
+        basename = os.path.basename(srcfile)
+        if basename in leftovers:
+            del leftovers[basename]
+
+        # Is it a subdirectory?
+        if os.path.isdir(srcfile):
+            package=namespace
+            sdir = os.path.join(srcpath,basename)
+            ddir = os.path.join(destpath,basename)
+            count+=convert(sdir, ddir)
+            namespace=package
+            continue
+        # Check the extension (only *.py will be converted)
+        root, ext = os.path.splitext(srcfile)
+        if ext.lower()!=".py":
+            continue
+
+        destfile = os.path.join(destpath,basename)
+        if destfile==srcfile:
+            print "WARNING: Input and output names are identical!"
+            sys.exit(1)
+
+        count+=1
+#        sys.stdout.write("%s\015"%(srcfile))
+
+        if isNewer(srcfile, destfile):
+            preparePath(os.path.dirname(destfile))
+            out=open(destfile,"w")
+            filterFile(srcfile, out)
+            out.close()
+#            os.system("python %s -f %s>%s"%(sys.argv[0],srcfile,destfile))
+
+    # Delete obsolete files in destpath
+    for df in leftovers:
+        dname=os.path.join(destpath,df)
+        if os.path.isdir(dname):
+            try:
+                shutil.rmtree(dname)
+            except:
+                print "Can't remove obsolete directory '%s'"%dname
+        else:
+            try:
+                os.remove(dname)
+            except:
+                print "Can't remove obsolete file '%s'"%dname
+
+    return count
+
+
+######################################################################
+######################################################################
+######################################################################
+
+filter_file = False
+
+try:
+    opts, args = getopt.getopt(sys.argv[1:], "hf", ["help"])
+except getopt.GetoptError,e:
+    print e
+    sys.exit(1)
+
+for o,a in opts:
+    if o=="-f":
+        filter_file = True
+
+if filter_file:
+    # Filter the specified file and print the result to stdout
+    filename = string.join(args)
+    filterFile(filename)
+else:
+
+    if len(args)!=2:
+        sys.stderr.write("%s options input output\n"%(os.path.basename(sys.argv[0])))
+        sys.exit(1)
+
+    # Filter an entire Python source tree
+    print '"%s" -> "%s"\n'%(args[0],args[1])
+    c=convert(args[0],args[1])
+    print "%d files"%(c)