Fake_poser3.py
from __future__ import print_function

import inspect
import os
import re
import sys
import traceback
from collections import namedtuple

try:
    import poser
except ImportError:
    poser = None

PARMS = namedtuple("PARMS", "Name args doc")
classnames = set()

sc = poser.Scene()


def debug(*args):
    print(*args, file=sys.stderr)


def analyze(obj2analyze):
    container = dict(
            classes=list(),
            builtins=list(),
            consts=list()
    )

    members = inspect.getmembers(obj2analyze)
    if members:
        for name, obj in members:
            if name.startswith("_"):
                continue
            doc = obj.__doc__.replace("  ", "\n").split("\n") if obj.__doc__ else None
            if name.startswith("k"):
                #if isinstance(obj, basestring):
                #    obj = "'{}'".format(obj)
                container["consts"].append(PARMS(name, obj, ""))
            elif inspect.isclass(obj):
                container["classes"].append(PARMS(name, None, doc))
                classnames.add(name.strip().lower())
            elif inspect.isbuiltin(obj):
                container["builtins"].append(PARMS(name, None, doc))
    else:
        t = getattr(poser, obj2analyze.__class__.__name__ + "Type")
        if t:
            for name in dir(t):
                if name.startswith("_"):
                    continue
                obj = getattr(obj2analyze, name)
                doc = obj.__doc__.replace("  ", "\n").split("\n") if obj.__doc__ else None
                container["builtins"].append(PARMS(name, None, doc))

    return container


def print_obj(container, tabs=0):
    if not container:
        debug(">>>>>>>>>EMPTY")
        return
    t = "\t" * tabs
    for _entry in sorted(container["consts"]):
        if _entry.doc:
            print(t + "# ".join(_entry.doc))
        frmt = "{}{} = '{}'" if isinstance(_entry.args, basestring) \
            else "{}{} = {}"
        print(frmt.format(t, _entry.Name, _entry.args))
    if tabs == 0:
        print("#", "-" * 70)

    for _entry in sorted(container["classes"]):
        print("\n{}class {}:".format(t, _entry.Name))
        if _entry.doc:
            doc = ("\n" + t + "\t").join(_entry.doc)
            print('{}"""\n{}\n{}"""'.format(t, doc, t))
        if _entry.args is not None:
            print("{}\tdef __init__({}):".format(t, _entry.args))
            print("{}\t\tpass".format(t))

        try:
            if _entry.Name == "SceneType":
                print_obj(analyze(poser.Scene()), tabs + 1)
            elif _entry.Name == "CredManagerType":
                print_obj(analyze(CredManager), tabs + 1)
            elif _entry.Name == "ClothSimulatorType" and cloth_simulator:
                print_obj(analyze(cloth_simulator), tabs + 1)
            elif _entry.Name == "ActorType" and Actor:
                print_obj(analyze(Actor), tabs + 1)
            elif _entry.Name == "ParmType" and Parameter:
                print_obj(analyze(Parameter), tabs + 1)
            elif _entry.Name == "GeomType" and Geometry:
                print_obj(analyze(Geometry), tabs + 1)
            elif _entry.Name == "PolygonType" and Geometry:
                print_obj(analyze(Geometry.Polygons()[0]), tabs + 1)
            elif _entry.Name == "TexPolygonType" and Geometry:
                print_obj(analyze(Geometry.TexPolygons()[0]), tabs + 1)
            elif _entry.Name == "VertType" and Geometry:
                print_obj(analyze(Geometry.Vertices()[0]), tabs + 1)
            elif _entry.Name == "TexVertType" and Geometry:
                print_obj(analyze(Geometry.TexVertices()[0]), tabs + 1)
            elif _entry.Name == "FigureType" and Figure:
                print_obj(analyze(Figure), tabs + 1)
            elif _entry.Name == "MaterialType" and Material:
                print_obj(analyze(Material), tabs + 1)
            elif _entry.Name == "ShaderTreeType" and Shadertree:
                print_obj(analyze(Shadertree), tabs + 1)
            elif _entry.Name == "ShaderNodeType" and Node:
                print_obj(analyze(Node), tabs + 1)
            elif _entry.Name == "ShaderNodeInputType" and Node:
                print_obj(analyze(Node.Inputs()[0]), tabs + 1)
            elif _entry.Name == "ImExporterType" and Imexporter:
                print_obj(analyze(Imexporter), tabs + 1)
            elif _entry.Name == "MovieMakerType" and Moviemaker:
                print_obj(analyze(Moviemaker), tabs + 1)
            elif _entry.Name == "MotionNodeType" and Motionrig:
                print_obj(analyze(Motionrig), tabs + 1)
            elif _entry.Name == "SuperFlyOptionsType" and Superfly:
                print_obj(analyze(Superfly), tabs + 1)
            elif _entry.Name == "FireFlyOptionsType" and Firefly:
                print_obj(analyze(Firefly), tabs + 1)
            elif _entry.Name == "Dialog":
                dlg = poser.Dialog()
                print_obj(analyze(dlg), tabs + 1)
                del dlg
            elif _entry.Name == "DialogDirChooser":
                dlg = poser.DialogDirChooser()
                print_obj(analyze(dlg), tabs + 1)
                del dlg
            elif _entry.Name == "DialogFileChooser":
                dlg = poser.DialogFileChooser(2)
                print_obj(analyze(dlg), tabs + 1)
                del dlg
            elif _entry.Name == "DialogTextEntry":
                dlg = poser.DialogTextEntry()
                print_obj(analyze(dlg), tabs + 1)
                del dlg
            else:
                print("{}\tpass".format(t))
        except poser.error as err:
            debug(err)
            print("{}\tpass".format(t))

        print()

    for _entry in sorted(container["builtins"]):
        args = _entry.args or "*args"
        if tabs > 0:
            args = "self, {}".format(_entry.args or "*args")
        print("\n{}def {}({}):".format(t, _entry.Name, args))
        if _entry.doc:
            doc = ("\n" + t + "\t").join(_entry.doc)
            print('{}\t"""\n{}\t{}\n{}\t"""'.format(t, t, doc, t))

            is_list = False
            return_str = None
            last_line = _entry.doc[-1].strip()
            res = re.match(r"[\(\[]\s*[\(\[].*?[\)\]]\s*[\]\)]", last_line)
            if res:
                # return type is tuple or list of tuples
                res_str = res.string[res.regs[0][0] + 1:res.regs[0][1] - 1].strip()
                res_str = [s for s in re.split(r"([\(\[][^\)]*[\)\[]),", res_str) if s.strip()]
                for idx, _entry in enumerate(res_str):
                    for _r in re.findall(r"<((\w+)\s*type)>", _entry, flags=re.IGNORECASE):
                        if _r[1].lower() in "int float list tuple":
                            _entry = re.sub("<"+_r[0]+">", _r[1].lower()+"(0)", _entry, flags=re.IGNORECASE)
                        else:
                            _entry = re.sub("<"+_r[0]+">", _r[0]+"()", _entry, flags=re.IGNORECASE)
                    res_str[idx] = _entry.strip()

                return_str = "list({})" if last_line.startswith("[") else "tuple({})"
                return_str = return_str.format(", ".join(res_str))

            if return_str is None:
                res = re.match(r"\(?<([^>]+)>", last_line)
                if res:
                    return_type = res.groups(1)[0].strip()
                    is_list = False
                    if return_type.endswith("List") or return_type.endswith("list"):
                        return_type = return_type.split()[0]
                        is_list = True

                    if return_type.lower() in classnames:
                        return_str = return_type + "()"
                    elif return_str == "NoneType":
                        return_str = ""
                    elif return_type == "IntType":
                        return_str = "int(1)"
                    elif return_type == "FloatType":
                        return_str = "float(1.0)"
                    elif return_type == "StringType":
                        return_str = "str('{}()')".format(_entry.Name)
                    elif return_type == "DictType":
                        return_str = 'dict()'
                    elif return_type == "HairType":
                        return_str = "HairType()"

            if return_str is None:
                if "FloatType 4x4 Tuple" in last_line:
                    return_str = "(float(0), float(0), float(0), float(0))"

            elif return_str is None and _entry.Name == "WxAuiManager":
                return_str = "wx.AuiManager()"

            elif return_str is None and _entry.Name == "WxApp":
                return_str = "poser.WxApp()"

            if is_list:
                return_str = "list({})".format(return_str)

            if return_str is not None:
                print("{}\treturn {}".format(t, return_str))
            else:
                print("{}\treturn".format(t))
        else:
            print("{}\tpass".format(t))


# temp_dir = poser.TempLocation()
temp_dir = os.path.dirname(sys.argv[0])
fname = os.path.join(temp_dir, "POSER_FAKE.py")

_stdout = sys.stdout
errmsg = None

Actor = poser.Scene().CurrentActor()
Figure = poser.Scene().CurrentFigure()
if Figure and Actor:
    Geometry = Actor.Geometry()
    Parameter = Actor.Parameters()[0]
    Material = Actor.Materials()[0]
    if Material:
        Shadertree = Material.ShaderTree()
        if Shadertree:
            Node = Shadertree.Nodes()[0]

    if sc.NumClothSimulators() == 0:
        cloth_simulator = sc.CreateClothSimulator()
    else:
        cloth_simulator = sc.ClothSimulator(0)

    Imexporter = sc.ImExporter()
    Moviemaker = sc.MovieMaker()
    CredManager = poser.CredManager()
    Motionrig = poser.NewMotionRig()
    Superfly = sc.CurrentSuperFlyOptions()
    Firefly = sc.CurrentFireFlyOptions()

    try:
        Hair = Actor.HairGroup(0)
    except:
        Hair = None

    try:
        with open(fname, "w") as fh:
            sys.stdout = fh
            print_obj(analyze(poser))
            if Hair:
                print("\nclass HairType:")
                print_obj(analyze(Hair), 1)

    except Exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print(traceback.format_exception(exc_type, exc_value, exc_traceback), file=_stdout)
    finally:
        sys.stdout = _stdout

    print(errmsg or "Written to: {}".format(fname))

else:
    print("Can not work with an empty scene.")