Forum: Poser Python Scripting


Subject: Python For Poser by PhilC

OberonRex opened this issue on Sep 14, 2023 ยท 20 posts


HartyBart posted Mon, 18 September 2023 at 3:20 AM

As you mention Visual Studio Code, ADP's Fake_poser3a.py may be a useful assistant. His site/page appears to have been unavailable for some months, and the Wayback Machine hasn't saved his .ZIP files (though some of the code insets still display). But here is his Fake_poser3a.py (latest version) for use with Visual Studio Code etc. I've added an expanded header.


# Fake_poser3a.py Class and Method headers to support editors while writing Python scripts.
# Works in Visual Studio Code
#
# Updated: 04/17/2020
#
# Updated: 08/25/2022
# More types for P12 version added
#
# Updated: 07/23/2022
# Some bugfixes for P12. Ready to go lib for Poser 12 included as "POSER_FAKE_12.py".

# Source: https://web.archive.org/web/20200805051440/https://adp.spdns.org/
# All possible Poser keywords should be covered.
# Contains a ready to go lib for Poser 11. Insert file "POSER_FAKE.py" into a path
# where your editor can find it. In your script insert the line:
#
#                import POSER_FAKE as poser
#
# Or, as a better solution:
#                try:
#                    import poser
#                except ImportError:
#                    import POSER_FAKE as poser
#
# For use with other Poser versions than 11, run the script once inside your own Poser and copy the resulting file "POSER_FAKE.py" where you need it.

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

if sys.version_info.major > 2:
    basestring = str
    xrange = range
else:
    range = xrange

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

sc = poser.Scene()


DONT_CALL_FILE = None
DONT_CALL = set()

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


#def dont_call(funcstr):
#    if DONT_CALL_FILE:
#        print(funcstr, file=DONT_CALL_FILE)


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(containertabs=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, _subentry in enumerate(res_str):
                    for _r in re.findall(r"<((\w+)\s*type)>", _subentry, flags=re.IGNORECASE):
                        if _r[1].lower() in "int float list tuple":
                            _subentry = re.sub("<"+_r[0]+">", _r[1].lower()+"(0)", _subentry, flags=re.IGNORECASE)
                        else:
                            _subentry = re.sub("<"+_r[0]+">", _r[0]+"()", _subentry, flags=re.IGNORECASE)
                    res_str[idx] = _subentry.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 not return_str.strip():
                        DONT_CALL.add(_entry.Name)

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

                if _entry.Name == "WxAuiManager":
                    return_str = "wx.AuiManager()"

                elif _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))
            DONT_CALL.add(_entry.Name)

# 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

        with open(os.path.join(temp_dir, "DONT_CALL.txt"), "w"as fh:
            for entry in DONT_CALL:
                print(entry, file=fh)

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

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



Learn the Secrets of Poser 11 and Line-art Filters.