Forum: Poser Python Scripting


Subject: Useful Code Snippets

structure opened this issue on Jun 27, 2019 · 94 posts


structure posted Thu, 27 June 2019 at 4:56 PM Forum Coordinator

So I think with the advent of a new dawn for poser, this forum could use a sticky thread where snakeheads can supply snippets of poser python code that others may find useful, or indeed, be able to improve upon. Let me start the ball Rolling - the following is a complete library that I have built / collected over the years ( there are more to follow ) Some of the code was written by others, edited by myself and is now here - for the use of all of you fellow coders should you choose to.


# -*- coding: UTF8 -*-
# Dialog Library

import os
import wx
import wx.lib.imagebrowser as imagebrowser


class dialogs:
    def choose(self, title="", prompt="", OptionList=[], parent=None):
        # prepare the dialog
        dialog = wx.SingleChoiceDialog(parent, prompt, title, OptionList)
        # ensure the list is not empty
        if not OptionList == []:
            # check the dialog response
            return dialog.GetStringSelection() if dialog.ShowModal() == wx.ID_OK else None

    def choosemulti(self, title="", prompt="", OptionList=[], parent=None):
        # prepare the dialog
        dialog = wx.MultiChoiceDialog(parent, prompt, title, OptionList)
        # check the dialog response
        if dialog.ShowModal() == wx.ID_OK:
            # get the selections indices
            selections = dialog.GetSelections()
            # get the selections strings
            strings = [OptionList[x] for x in selections]
            dialog.Destroy()
            return (selections, strings)
        else:
            return (False, False)

    def colordialog(self, event=None):
        dialog = wx.ColourDialog(None)
        dialog.GetColourData().SetChooseFull(True)
        return dialog.GetColourData() if dialog.ShowModal() == wx.ID_OK else False

    def getfile(self, start="", filemustexist=True, parent=None):
        styles = [(wx.FD_OPEN | wx.FD_FILE_MUST_EXIST), (wx.FD_OPEN)]
        style = styles[0] if filemustexist else styles[1]
        types = "Camera         (*.cm2 , *.cmz)|*.cm2; *.cmz|"                                     \
            "Figure         (*.cr2 , *.crz)|*.cr2; *.crz|"                                    \
            "Expression     (*.fc2 , *.fcz)|*.fc2; *.fcz|"                                    \
            "Hand           (*.hd2 , *.hdz)|*.hd2; *.hdz|"                                    \
            "Hair           (*.hr2 , *.hrz)|*.hr2; *.hrz|"                                    \
            "Light          (*.lt2 , *.ltz)|*.lt2; *.ltz|"                                    \
            "Material       (*.mt5 , *.mtz , *.mc6 , *.mcz)|*.mt5; *.mtz; *.mc6; *.mcz|"      \
            "Object         (*.obj , *.obz)|*.obj; *.obz|"                                    \
            "Pose           (*.pz2 , *.p2z)|*.pz2; *.p2z|"                                    \
            "Prop           (*.pp2 , *.ppz)|*.pp2; *.ppz|"                                    \
            "Python Script  (*.py , *.pyc , *.pyd)|*.py; *.pyc; *.pyd|"                       \
            "Scene          (*.pz3 , *.pzz)|*.pz3; *.pzz|"                                    \
            "all files        (*.*)|*.*|"                                             # File Types

        # prepare dialog
        dialog = wx.FileDialog(parent, "Select a File",
                               start, "", types, style)
        # test dialog response
        return dialog.GetPath() if dialog.ShowModal() == wx.ID_OK else False

    def getfolder(self, start="", newdirbutton=True, parent=None):
        styles = [(wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON),
                  (wx.DD_DEFAULT_STYLE)]
        style = styles[0] if newdirbutton else styles[1]
        # prepare dialog
        dialog = wx.DirDialog(None, 'Select a Folder ', start, style)
        # test dialog response
        return dialog.GetPath() if dialog.ShowModal() == wx.ID_OK else False

    def get_desktop_path(self, event=None):
        import re
        # create variable
        D_paths = list()
        try:
            fs = open(os.sep.join((os.path.expanduser("~"),
                      ".config", "user-dirs.dirs")), 'r')
            data = fs.read()
            fs.close()
        except:
            data = ""

        D_paths = re.findall(r'XDG_DESKTOP_DIR="([^"]*)', data)

        if len(D_paths) == 1:
            D_path = D_paths[0]
            D_path = re.sub(r'$HOME', os.path.expanduser("~"), D_path)
        else:
            D_path = os.sep.join((os.path.expanduser("~"), 'Desktop'))

        return D_path if os.path.isdir(D_path) else None

    def getfont(self, f):
        fontdialog = wx.FontDialog(self, wx.FontData())

        if fontdialog.ShowModal() == wx.ID_OK:
            data = fontdialog.GetFontData()
            font = data.GetChosenFont()
            # self.text.SetFont(font)
            fontdialog.Destroy()
            return font
        fontdialog.Destroy()

    def getnumberentry(self, alertmessage, prompt, caption, value, min, max, pos=wx.DefaultPosition):
        NE_dialog = wx.NumberEntryDialog(
            None, alertmessage, prompt, caption, value, min, max, pos)
        return NE_dialog.GetValue() if NE_dialog.ShowModal() == wx.ID_OK else False

    def gettextentry(self, title="", message="", parent=None):
        TE_dialog = wx.TextEntryDialog(
            parent, message, title, "", style=wx.OK)                 # none=parent
        TE_dialog.SetValue("")
        return TE_dialog.GetValue() if TE_dialog.ShowModal() == wx.ID_OK else False

    def imageviewer(self, parent=None):
        dialog = imagebrowser.ImageDialog(parent)
        if dialog.ShowModal() == wx.ID_OK:
            print("You Selected File: ")+dialog.GetFile()

    def okcancel(self, title="", alertmessage="", okonly=False, parent=None):
        styles = [(wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP),
                  (wx.OK | wx.CANCEL | wx.ICON_INFORMATION | wx.STAY_ON_TOP)]
        style = styles[0] if okonly else styles[1]
        ok_dialog = wx.MessageDialog(parent, alertmessage, title, style)
        return True if ok_dialog.ShowModal() == wx.ID_OK else False

    def showalert(self, title="", alertmessage="", icon=0, Btype=0, bType=0, parent=None):
        icons = {
            0:  wx.ICON_ERROR,
            1:  wx.ICON_EXCLAMATION,
            2:  wx.ICON_HAND,
            3:  wx.ICON_QUESTION,
            4:  wx.ICON_INFORMATION,
            5:  wx.ICON_NONE
        }                                                                             # set up icons

        buttonType = {
            0:  wx.OK,
            # Must be combined with either OK or YES_NO
            1:  wx.CANCEL,
            2:  wx.YES_NO,
            3:  wx.HELP,
            # Can only be used with YES_NO
            4:  wx.NO_DEFAULT,
            # This style is currently not supported (and ignored) in wxOSX.
            5:  wx.CANCEL_DEFAULT,
            # Can only be used with YES_NO
            6:  wx.YES_DEFAULT,
            7:  wx.OK_DEFAULT
        }                                                                     # set up buttons

        behaviourType = {
            0:  wx.STAY_ON_TOP,
            1:  wx.CENTRE
        }                                                                     # set up behaviour

        # select icon to display
        icon = icons[icon]
        # select buttons to display
        atype = buttonType[Btype]
        # select behaviour
        btype = behaviourType[bType]

        wx.MessageDialog(parent, alertmessage, title, style=atype |
                         icon | btype).ShowModal()  # Show alert message

    def yesno(self, title="", message="", parent=None):
        style = (wx.YES | wx.NO)
        # prepare dialog
        YN_dialog = wx.MessageDialog(parent, message, title, style)
        # test dialog response
        return True if YN_dialog.ShowModal() == wx.ID_YES else False

    def onBusy(self,  message):
        busyDialog = wx.BusyInfo(message)
        busyDialog = None

Locked Out


FVerbaas posted Thu, 25 July 2019 at 2:31 PM Forum Coordinator

Also do not forget the examples that come with Poser. They could do with more documentation but are a great reference.


FVerbaas posted Tue, 30 July 2019 at 9:44 AM Forum Coordinator

A simple function to copy matrerial collections between figures and props. if the target (a prop or a figure) has a material defined with a name that also appears in the materials list of the source, that material definition (shader) in the target will be overwritten by the material of the source.

def copyMaterialDefinitions(source, target):
    srcmats = source.Materials()
    tgtmats = target.Materials()
    for srcmat in srcmats:
        matnam = srcmat.Name()
        srcmat.SaveMaterialSet(matnam)
        try:
            target.Material(matnam).LoadMaterialSet(matnam)
        except:
            pass

structure posted Sun, 01 September 2019 at 8:35 AM Forum Coordinator

Nice routine! thanks

Locked Out


FVerbaas posted Mon, 06 January 2020 at 12:04 PM Forum Coordinator

I tried some of the dialogs class yesterday because I needed some of the functions. I assume the site formatting has ironed some things away here and there:

D_paths = re.findall(r'XDG_DESKTOP_DIR="([^"]*)', data)

structure posted Mon, 06 January 2020 at 12:07 PM Forum Coordinator

FVerbaas posted at 6:07PM Mon, 06 January 2020 - #4375651

I tried some of the dialogs class yesterday because I needed some of the functions. I assume the site formatting has ironed some things away here and there:

D_paths = re.findall(r'XDG_DESKTOP_DIR="([^"]*)', data)

add

Import re

Locked Out


structure posted Mon, 06 January 2020 at 4:21 PM Forum Coordinator

the backslashes were not showing ( I forget about that in this forum ) so I have added a double backslash to enable them to be visible

Locked Out


structure posted Tue, 07 January 2020 at 9:42 PM Forum Coordinator

A dictionary of poser Figures by geometry:


# -*- coding: UTF8 -*-
# ©2001 - 2018 structure

def FigureTypes():
return {
'!!!!TEO_PUR' : 'Teo Pur' ,
'!!!Kali_And_Kelm' : 'Kali_Kelm' ,
'!!AyanaDoll' : 'AyanaDoll' ,
'!!Eepo_Kobee' : 'EEpo' ,
'!Chip' : 'Cookie-Chip' ,
'3duSkye' : '!skye' ,
'3DrmLO_LO' : 'Little One' ,
'3DUDennis' : '3DUDennis' ,
'3duGramps' : '3duGramps' ,
'3duSadie' : 'Sadie' ,
'3duSam' : '3DUSam' ,
'AfrElephant' : 'Mammoth / African Elephant' ,
'Alexa21' : 'Alexa' ,
'Allosaurus' : 'Allosaurus' ,
'Alyson2_HR' : 'Alyson' ,
'AMSilver' : 'AlphaMan' ,
'Anceata_Semil' : 'Anceata-Semil' ,
'Andrea' : 'Andy' ,
'Andrewsarchus' : 'Andrewsarchus' ,
'Andy' : 'Andy' ,
'Andy2' : 'Andy' ,
'Angela' : 'Angela' ,
'Antonia-1.2' : 'Antonia' ,
'Antonia-1.2WM' : 'Antonia' ,
'ApolloMaximus2005' : 'Apollo' ,
'AucasaurusDR' : 'Aucasaurus' ,
'BabyLuna' : 'BabyLuna' ,
'Barney' : 'Barney' ,
'Barney2' : 'Barney' ,
'Ben' : 'Ben' ,
'BenP7' : 'Ben' ,
'Bertha' : 'Bertha' ,
'Bertha2' : 'Bertha' ,
'Betaboy' : 'BetaBoy' ,
'blAiko3' : 'Aiko 3' ,
'blBear' : 'Bear' ,
'blBizMan' : 'Biz Man' ,
'blBizWom' : 'Biz Woman' ,
'blDavid' : 'David 3' ,
'blDavidGEN' : 'David 3 Genitals' ,
'blDemon' : 'DAZ Demon' ,
'blFREAK' : 'Freak 3' ,
'blGhost' : 'Ghost' ,
'blGirl' : 'The Girl' ,
'blGirl_v3UV' : 'The Girl' ,
'blHiro' : 'Hiro 3' ,
'blHiro_Dv' : 'Hiro 3' ,
'blKid' : 'DeeDee / Sammy' ,
'blMilBaby' : 'Millennium Baby' ,
'blMilBaby_2' : 'Chubblies / Millennium Baby 3' ,
'blMilBigCat' : 'Millennium Big Cat' ,
'blMilCat' : 'Millennium Cat' ,
'blMilDog' : 'Millennium Dog' ,
'blMilDragon' : 'Millennium Dragon' ,
'blMilDragon2' : 'Millennium Dragon' ,
'blMilFoal' : 'Millennium Foal' ,
'blMilGirl' : 'Millennium Girl' ,
'blMilGirlPS' : 'Pre-School Boy / Girl' ,
'blMilGirlPT' : 'Pre-Teen Boy / Girl' ,
'blMilHorse' : 'Millennium Horse' ,
'blMilKid_k4b' : 'Kids 4' ,
'blMilMan' : 'Frank / Orc' ,
'blMilMan_m3' : 'Michael 3' ,
'blMilMan_m3GEN' : 'Michael 3 Genitals' ,
'blMilMan_m4b' : 'Michael 4' ,
'blMilMan_m4GEN' : 'Generation 4 Genitals' ,
'blMilPup' : 'Millennium Puppy' ,
'blMilWomLoNG' : 'Millennium Woman Low Res No Genitals' ,
'blMilWom_v3' : 'Victoria 3' ,
'blMilWom_v4' : 'Victoria4' ,
'blMilWom_v4b' : 'Victoria4' ,
'blMilWom_V4_V3b' : 'Victoria4 to Victoria 3' ,
'blPSBoy' : 'Matt' ,
'blPSBoyPS' : 'Matt' ,
'blPSGirl' : 'Maddie' ,
'blPSGirlPS' : 'Maddie' ,
'blPython' : 'Python' ,
'blSkeleton_m3' : 'Michael 3 Skeleton' ,
'blSkeleton_m4' : 'Michael 4 Skeleton' ,
'blSkeleton_v3' : 'Victoria 3 Skeleton' ,
'blSkeleton_v4' : 'Victoria4 Skeleton' ,
'blSnowman' : 'Snowman' ,
'blStephanie' : 'Stephanie' ,
'blStephaniePetite' : 'Stephanie Petite' ,
'blSubDragon' : 'SubDragon' ,
'blTriceratops' : 'Triceratops' ,
'blTroll' : 'Troll' ,
'blVickiP4' : 'Vicki Poser 4' ,
'blVittorio' : 'Vittorio' ,
'blWalter' : 'Walter' ,
'blWolf' : 'Zygote Wolf' ,
'blWyvern' : 'Wyvern' ,
'blYTBoy' : 'Luke' ,
'blYTGirl' : 'Laura' ,
'blYTGirlPT' : 'Laura Pre-Teen / Luke Pre-Teen' ,
'BrachiosaurusDR' : 'Brachiosaurus' ,
'BrachiosaurusDRnospikes' : 'Brachiosaurus' ,
'Butterfly' : 'Butterfly' ,
'Campestergum' : 'Campestergum' ,
'Cloud' : 'Butterfly Cloud' ,
'Creech' : 'Creech' ,
'Dawn' : 'Dawn' ,
'DI-D-O-Burden' : 'Dragon of Burden' ,
'Diego' : 'Diego' ,
'Dinohyus' : 'Dinohyus' ,
'DI_Biguana' : 'Biguana' ,
'DocPitterbill' : 'Doc Pitterbill' ,
'Dragon' : 'Dragon' ,
'DragonFlySID' : 'SID Dragonfly' ,
'DragonSkeleton' : 'Dragon Skeleton' ,
'Drossel' : 'Drossel2' ,
'DRSnDragon' : 'Snake Dragon' ,
'Dusk' : 'Dusk' ,
'Dylan' : 'CubedBabies' ,
'EasternDragon' : 'Eastern Dragon' ,
'Edgar' : 'Edgar' ,
'Edgar2' : 'Edgar' ,
'EiniosaurusDR' : 'Einiosaurus' ,
'FemaleMusculature' : 'Female Muscules' ,
'Fon' : 'Fon' ,
'Freddie' : 'Freddie' ,
'gallicu-2' : 'Gallimimus' ,
'GammaGirl' : 'GammaGirl' ,
'GenitalsG2' : 'G2 Genitals' ,
'Ginger' : 'Ginger' ,
'Ginger2' : 'Ginger' ,
'Glyptodon' : 'Glyptodon' ,
'GodfreyFinal_V07' : 'Godfrey' ,
'Goblin' : 'Goblin 2' ,
'Gosha' : 'Gosha' ,
'Gramps' : 'Gramps' ,
'Gramps2' : 'Gramps' ,
'GreyAlien2-5' : 'GreyAlien' ,
'Haru' : 'Haru' ,
'Hatchling' : 'Hatchling' ,
'Hein' : 'Hein' ,
'HummingBird' : 'HummingBird' ,
'Hydra' : 'Hydra' ,
'Ichiro2' : 'Ichiro' ,
'Ictiosaur' : 'Ictiosaur' ,
'Indricotherium' : 'Indricotherium' ,
'Izumi' : 'Izumi' ,
'James' : 'James' ,
'JamesCasual' : 'James' ,
'JamesG2' : 'James' ,
'JamesHiRes' : 'James' ,
'JamesLoRes' : 'James' ,
'JamesLoRes' : 'James' ,
'Jenny' : 'CubedBabies' ,
'Jessi' : 'Jessi' ,
'JessiCasual' : 'Jessi' ,
'JessiG2' : 'Jessi' ,
'JessiHires' : 'Jessi' ,
'JessiHiRes' : 'Jessi' ,
'JessiLores' : 'Jessi' ,
'Kate' : 'Kate' ,
'KateP7' : 'Kate' ,
'Kelvin' : 'Kelvin' ,
'KelvinG2' : 'Kelvin' ,
'KentrosaurusDR' : 'Kentrosaurus' ,
'Kiki' : 'Kiki' ,
'Kit' : 'LittleFox' ,
'Koji' : 'James' ,
'KojiG2' : 'Koji' ,
'kon' : 'Kon' ,
'Koshini2' : 'Koshini' ,
'Krystal' : 'Krystal' ,
'LaFemme1' : 'La Femme' ,
'L\'Homme1' : 'L\'Homme' ,
'LaRoo2' : 'LaRoo' ,
'LLF-Cookie' : 'Cookie-Chip' ,
'LLF-Star_Base3' : 'Star' ,
'Loik' : 'Loik' ,
'Lusitana' : 'Lusitana' ,
'Macrauchenia' : 'Macrauchenia' ,
'Majestic Dragon' : 'Majestic Dragon' ,
'MaleMusculature' : 'Male Muscles' ,
'Malik' : 'Malik' ,
'Mannequin' : 'mannequin' ,
'Marcus' : 'Marcus' ,
'Mavka' : 'Mavka' ,
'MDP_ANIME\\MDP-F202' : 'MDP Anime' ,
'Michelle' : 'Michelle' ,
'Mick' : 'Mick' ,
'Miki' : 'Miki' ,
'Miki2' : 'Miki' ,
'Miki3' : 'Miki' ,
'Miki4' : 'Miki' ,
'Minnie' : 'Minnie' ,
'Minnie2' : 'Minnie' ,
'MonolophosaurusDR' : 'Monolophosaurus' ,
'Natu2' : 'Natu' ,
'Natu3' : 'Natu' ,
'near_me' : 'Near Me' ,
'Nea_2_n2_4' : 'Nea 2' ,
'NogChick' : 'Noggins Chick' ,
'NogCockerel' : 'Noggins Cockerel' ,
'NogHen' : 'Noggins Hen' ,
'NogOwl' : 'Noggins Owl' ,
'NogOwl Perched' : 'Noggins Owl' ,
'nwsNetherGirl' : 'Phoebe' ,
'okcNadyaB' : 'Nadya' ,
'okcSenyaV1bW' : 'Senya' ,
'okcVini' : 'Vini' ,
'OliviaG2' : 'Olivia' ,
'P3DA_Goblin_HR' : 'Goblin' ,
'P3DA_Goblin_LR' : 'Goblin' ,
'P3DA_LoREZ_Crow' : 'P3DA Crow' ,
'P3DA_TrogGenital_HR' : 'Trog Genitals' ,
'P3DA_TrogGenital_LR' : 'Trog Genitals' ,
'P3DA_Trog_HR' : 'Trog' ,
'P3DA_Trog_LR' : 'Trog' ,
'P5CasualMan' : 'P5Casual' ,
'P5CasualWoman' : 'P5Casual' ,
'P5NudeBoy' : 'P5Nude' ,
'P5NudeGirl' : 'P5Nude' ,
'P5NudeMan' : 'P5Nude' ,
'P5NudeWoman' : 'P5Nude' ,
'P8Alyson' : 'Alyson' ,
'P8Alyson_Casual' : 'Alyson' ,
'P8Alyson_HR' : 'Alyson' ,
'P8Alyson_LR' : 'Alyson' ,
'P8Ryan' : 'Ryan' ,
'P8Ryan_Genitals_HR' : 'Ryan Genitals' ,
'P10Rex' : 'Rex' ,
'P10Rex1.1' : 'Rex' ,
'P10RexGenitals' : 'Rex Genitals' ,
'P10Roxie' : 'Roxie' ,
'P10Roxie1.1' : 'Roxie' ,
'PHFemale' : 'Project Human Female' ,
'PHMale' : 'Project Human Male' ,
'PolarBear' : 'Polar Bear' ,
'PosetteV3' : 'Posette' ,
'PPro_LR_Fem' : 'Poser Low Res Female' ,
'PPro_MR_Fem' : 'Poser Medium Res Female' ,
'PuntikKaalkopje' : 'Puntik' ,
'R-lina' : 'RLina' ,
'RIKI_A01' : 'Rikishi' ,
'RIKI_A01H' : 'Rikishi' ,
'Ryan2_HR' : 'Ryan' ,
'sbrm3' : 'Songbird Remix' ,
'sbrm3_g' : 'Songbird Remix' ,
'sbrm3_wf1' : 'Songbird Remix' ,
'sbrm3_wf4' : 'Songbird Remix' ,
'sbrm3_wf5' : 'Songbird Remix' ,
'sbrm3_wf7' : 'Songbird Remix' ,
'sbrm3_wf10' : 'Songbird Remix' ,
'sbrm_vulture' : 'Condor' ,
'SeaDragon' : 'Sea Dragon' ,
'Seq_orc' : 'Orc' ,
'serpent' : 'Serpent' ,
'SharkDR' : 'Shark' ,
'SimonG2' : 'Simon' ,
'Skywyrm' : 'Skywyrm' ,
'Slon' : 'Slon' ,
'Smilodon' : 'Smilodon' ,
'SpinosaurusDR' : 'Spinosaurus' ,
'Squeaker' : 'Squeaker' ,
'StorybookDragon' : 'Storybook Dragon' ,
'Suchomimus' : 'Suchomimus' ,
'SydneyG2' : 'Sydney' ,
'tawhak' : 'Tawhak' ,
'TeraiYuki2' : 'Terai Yuki 2' ,
'thanator gruppe3' : 'Thanator' ,
'Trex' : 'T-Rex' ,
'Troll' : 'Ragbesh' ,
'udadultd' : 'Adult Dragon' ,
'udhatchlingd' : 'Hatchling Dragon' ,
'Vila' : 'Vila' ,
'waterelemental2' : 'Water Elemental' ,
'Wolf' : 'Wolf' ,
'WoollyMammoth' : 'Wooly Mammoth' ,
'WWSal' : '3DWW' ,
'Yweeb' : 'Yweeb' ,
'Zot' : 'Zot' ,
'Zuniceratops' : 'Zuniceratops' ,
}

a short script to get the figure type.
import poser, os
figure=poser.Scene().CurrentFigure()
print(FigureTypes(os.path.splitext(os.path.basename(geomName))[0]))

Locked Out


structure posted Sun, 05 April 2020 at 11:11 PM Forum Coordinator

replacing all backslashes in a list of paths


def replaceBackslashinList( Thislist, bs, fs ):
    return list(map(lambda x: x.replace( bs, fs), Thislist) )

myList = replaceBackslashinList(myList, "\\", "/")

Locked Out


structure posted Fri, 10 April 2020 at 7:04 PM Forum Coordinator

Copy to Clipboard

import wx
def copytoclipboard( item  = None ):
    clipboard = wx.TheClipboard
    if not clipboard.IsOpened():
        clipboard.Open()
        data = wx.TextDataObject()
        data.SetText( item )
        clipboard.SetData(data)
    clipboard.Close()

without wx :

from subprocess import check_call
class clipboard:
    def copy2clip(self, txt):
        cmd='echo '+txt.strip()+'|clip'
        return check_call(cmd, shell=True)

Locked Out


adp001 posted Thu, 14 May 2020 at 9:36 AM

Simple method to save some typing while dealing with dicts:

class MyDict(dict):
    def __getattr__(self, item):
        if not item.startswith("_"):
            return self.get(item)
        return super(self.__class__, self).__getattribute__(item)

Instead of MyDict["keyword"]you can simplly write MyDict.keyword.




adp001 posted Thu, 14 May 2020 at 9:41 AM

Above dict replacement delivers None for not existent elements. If you want original behaviour, use this a bit slower class:

class MyDict(dict):
    def __getattr__(self, item):
        if not item.startswith("_") and item in self:
            return self.get(item)
        return super(self.__class__, self).__getattribute__(item)



adp001 posted Sat, 16 May 2020 at 8:41 AM

I often use the following little function if I have to script something with Poser meshes. I do that outside of Poser, because I often need a debugger to follow what the script is doing step by step in critical parts.

With Poser-Python:

import numpy as NP

try:
    import poser

    INSIDEPOSER = True
except ImportError:
    # "POSER_FAKE" is a Python lib to allow your editor to know about Poser
    # for scripting outsite of Poser (code completition, type checking, highlighting).
    # Author: adp001
    # Direct download: http://adp.spdns.org/FakePoserLib3.zip
    import POSER_FAKE as poser

    INSIDEPOSER = False

# Pickle is used to save|load the complete geometry instead of a slow obj loader.
try:
    import cPickle as pickle
except ImportError:
    import pickle


# Returns python list (assume given poly is tri or quad):
f_forcequad = lambda _poly: list(_poly) if len(_poly) == QUAD else list(_poly) + [_poly[-1]]

VERSION = float(poser.Version()) if poser.Version()[0].isdigit() else 11
NP_PRECISION = NP.float32 if int(VERSION) <= 11 else NP.float

def save_figure(fig, filename):
    """
        Saves verts, tverts, polys (4 vertices as float), polysets (4 indices crossreferencing verts),
        tpolys (2 vertices as float), tpolysets (2 indices creossreferencing tverts), material names
        and a material indexlist for cross-reference.
        All collected arrays from current figure are pickled into a file.

        :param fig: Poser figure
        :param filename: Path and filename
        :type fig: poser.FigureType
        :type filename: basestring
    """
    if INSIDEPOSER:
        # Get unimesh of current figure (unmorphed, unposed)
        poser_geom = fig.UnimeshInfo()[0]
        assert isinstance(poser_geom, poser.GeomType)
        geom = MyGeom(
                verts=NP.array([[v.X(), v.Y(), v.Z()] for v in poser_geom.Vertices()], NP_PRECISION),
                tverts=NP.array([[v.U(), v.V()] for v in poser_geom.TexVertices()], NP_PRECISION),
                polys=NP.array([f_forcequad([[v.X(), v.Y(), v.Z()] for v in p.Vertices()])
                                for p in poser_geom.Polygons()], NP_PRECISION),
                polysets=NP.array([f_forcequad(poser_geom.Sets[p.Start():p.Start() + p.NumVertices()])
                                   for p in poser_geom.Polygons()], NP.int32),
                tpolys=NP.array([f_forcequad([[v.U(), v.V()]
                                              for v in p.TexVertices()]) for p in poser_geom.TexPolygons()],
                                NP_PRECISION),
                tpolysets=NP.array([f_forcequad(poser_geom.Sets[p.Start():p.Start() + p.NumVertices()])
                                    for p in poser_geom.TexPolygons()], NP.int32),
                matindex=NP.array([p.MaterialIndex() for p in poser_geom.Polygons()], NP.int32),
                matnames=[m.Name() for m in poser_geom.Materials()]
        )
        p = poser.TexPolygonType()

        with open(filename, "wb") as fh:
            pickle.dump(geom, fh, pickle.HIGHEST_PROTOCOL)

        return geom
    return None

This saves all those collected data in a file (pickled).




adp001 posted Sat, 16 May 2020 at 8:45 AM

Class "MyGeom" is actually a dict. But in my case it is what I mentioned before:

class MyGeom(dict):
    def __getattr__(self, item):
        if not item.startswith("_") and item in self:
            return self.get(item)
        return super(self.__class__, self).__getattribute__(item)




adp001 posted Sat, 16 May 2020 at 8:50 AM

To load the data back if you are scripting outside of Poser:

try:
    import cPickle as pickle
except ImportError:
    import pickle

with open(filename, "rb") as fh:
    geom = pickle.load(fh)

(Make sure there is access to the class you saved the file with – maybe it's better to use plain dict in the Poser script part)

Now you can get from the dict what you need and ignore/discard the rest.




adp001 posted Sat, 16 May 2020 at 8:54 AM

I extraced the Poser part from a whole script and forgot to copy 2 declarations:

TRI, QUAD = 3, 4

Sorry for that.




adp001 posted Sat, 16 May 2020 at 9:03 AM

Something useful when dealing with Numpy:

try:
    # Try to make Numpy show numbers in this format:
    float_formatter = "{:.4f}".format
    NP.set_printoptions(formatter={'float_kind': float_formatter})
except TypeError as err:
    # Numpy to old. But "precision" should work.
    NP.set_printoptions(precision=4)




adp001 posted Sat, 16 May 2020 at 9:06 AM

Some "constants" I often use:

# Poser <= version 11 seems to work with 32-bit float precision (Numpy standard is 64-bit)
VERSION = float(poser.Version()) if poser.Version()[0].isdigit() else 11
NP_PRECISION = NP.float32 if int(VERSION) <= 11 else NP.float
NP_VERT_ZERO = NP.array((0, 0, 0), NP_PRECISION)

# Simplification to deal with some names used as indices
X, Y, Z = range(3)
A, B, C, D = range(4)
QUAD = 4
TRI = 3

(Because Poser does not know constants, I write them in Uppercase to remember)




adp001 posted Sat, 16 May 2020 at 9:13 AM

Polys can have 3 or 4 vertices (TRI or QUAD). Numpy arrays must have a constant length. So it is common behaviour to set the 4th entry for a TRI equal to the third entry (isTri == (p[3] == p[4]) )




adp001 posted Sat, 16 May 2020 at 9:15 AM

And a real fast function to compute the distance between 2 verts:

def distance_e(v, u):
    # Distance with Numpy "einsum"
    # https://semantive.com/blog/high-performance-computation-in-python-numpy-2/
    z = v - u
    return NP.sqrt(NP.einsum('i,i->', z, z))



adp001 posted Sat, 16 May 2020 at 3:10 PM

The function to save the figure is pretty slow, because a whole lot of function calls to Poser are needed when collecting the indices. Use the following and it is pretty fast:

        vsets = poser_geom.Sets()
        tsets = poser_geom.TexSets()
        geom = MyGeom(
                verts=NP.array([[v.X(), v.Y(), v.Z()] for v in poser_geom.Vertices()], NP_PRECISION),
                tverts=NP.array([[v.U(), v.V()] for v in poser_geom.TexVertices()], NP_PRECISION),
                polys=NP.array([f_forcequad([[v.X(), v.Y(), v.Z()] for v in p.Vertices()])
                                for p in poser_geom.Polygons()], NP_PRECISION),
                polysets=NP.array([f_forcequad(vsets[p.Start():p.Start() + p.NumVertices()])
                                   for p in poser_geom.Polygons()], NP.int32),
                tpolys=NP.array([f_forcequad([[v.U(), v.V()]
                                              for v in p.TexVertices()]) for p in poser_geom.TexPolygons()],
                                NP_PRECISION),
                tpolysets=NP.array([f_forcequad(tsets[p.Start():p.Start() + p.NumTexVertices()])
                                    for p in poser_geom.TexPolygons()], NP.int32),
                matindex=NP.array([p.MaterialIndex() for p in poser_geom.Polygons()], NP.int32),
                matnames=[m.Name() for m in poser_geom.Materials()]
        )




VedaDalsette posted Tue, 16 June 2020 at 9:29 AM

I''m no snakehead, and I'm not sure if this is even a good thing to do, but I'm always changing the shadow strength for lights, so I modified someone's script (can't remember whose). This script is useful to me, because, when there are a lot of lights, the displayed log tells me what I've changed already.

# Change Shadow Intensity of Selected Lights
#

import poser scene = poser.Scene() actor = scene.CurrentActor()

def doIt(): dialog = None dialog2 = None actor = scene.CurrentActor("GROUND") dialog = poser.DialogSimple.AskActor("Please select a light.") actor = scene.CurrentActor(dialog) if actor.IsLight(): print "n ",actor.Name() dialog2 = poser.DialogSimple.AskFloat("Type a value from 0 to 1.") if dialog2 == None: print "n Please type in a value from 0 to 1." doIt() else: if float(dialog2) < 0: print "n Please type in a value from 0 to 1." doIt() elif float(dialog2) > 1: print "n Please type in a value from 0 to 1." doIt() else: print "n You want ",dialog2," shadow intensity for ",actor.Name() actor.ParameterByCode(poser.kParmCodeDEPTHMAPSTRENGTH).SetValue(float(dialog2)) print "n Update done." scene.SelectActor(scene.Actor("GROUND")) another() else: print "n You didn't select a light." doIt()

def another(): message = "Select another light?" dialog = None dialog = poser.DialogSimple.YesNo(message) if dialog == 1: print "n Yes, another light." doIt() else: print "n No, no more lights." return

doIt()



W11,Intel i9-14900KF @ 3.20GHz, 64.0 GB RAM, 64-bit, GeForce GTX 4070 Ti SUPER, 16GB. 

Old lady hobbyist. All visual art or fiction is "playing with dolls."

VISIT MY ALBUMSFOR COMICS: https://www.renderosity.com/users/VedaDalsette/gallery/albums

You can also get to my comics from my book website: https://www.vdbooks.com.


structure posted Sun, 19 July 2020 at 9:47 PM Forum Coordinator

Updated version of the above code

# -*- coding: utf-8 -*- 
# Change Shadow Intensity of Selected Lights

import poser
import wx
scene = poser.Scene()
title = "Shadow Intensity Editor"

def chooselights( title = "", prompt = "", OptionList = [], parent = None ):
    if OptionList == []: return False
    dialog = wx.MultiChoiceDialog( parent, prompt, title, OptionList )

    if dialog.ShowModal() == wx.ID_OK:
        selections = dialog.GetSelections()
        strings = [OptionList[x] for x in selections]
        if selections == []:
            selections = False
        return ( selections )

    else:
        return ( False )
    
    dialog.Destroy()

def gettextentry( title = "", message = "", parent = None ):

    TE_dialog = wx.TextEntryDialog( parent, message, title, "", style=wx.OK)
    TE_dialog.SetValue("")

    return TE_dialog.GetValue() if TE_dialog.ShowModal() == wx.ID_OK else False

def okcancel( title = "", alertmessage = "", okonly = False, parent = None ):

    if okonly:
        style = ( wx.OK|wx.ICON_INFORMATION|wx.STAY_ON_TOP )
    else:
        style = ( wx.OK|wx.CANCEL|wx.ICON_INFORMATION|wx.STAY_ON_TOP )      

    ok_dialog = wx.MessageDialog( parent, alertmessage, title, style )
    
    return True if ok_dialog.ShowModal() == wx.ID_OK else False

lights = []

for light in scene.Lights():
    lights.append( light.Name() )

lights = chooselights( title, "Please select which lights to edit.", lights )
if lights:
    try:
        value = float( gettextentry( title, "Please enter your value ( 0 - 1 )" ) )
    except:
        value = 0

    for light in lights:
        scene.Lights()[light].ParameterByCode( poser.kParmCodeDEPTHMAPSTRENGTH ).SetValue( value )

if you wish to edit each light individually, change the script to the following :


lights = []
for light in scene.Lights():
    lights.append( light.Name() )

lights = chooselights( title, "Please select which lights to edit.", lights )
if lights:
    for light in lights:
        try:
            value = float( gettextentry( title, "Please enter your value ( 0 - 1 )" ) )
        except:
            value = scene.Lights()[light].Value()
        scene.Lights()[light].ParameterByCode( poser.kParmCodeDEPTHMAPSTRENGTH ).SetValue( value )

Locked Out


structure posted Wed, 12 August 2020 at 8:28 AM Forum Coordinator

A simple lights class

class poserlights:
    def processlights( self, code = 0 ):
        if not isinstance( code, int):
            return

        lights = scene.Lights()
    
        if not code > 1:
            # LightsOnOff
            [light.SetLightOn(code) for light in lights]
        
        elif code == 2:
            # toggle lights
            [light.SetLightOn(not light.LightOn()) for light in lights]
    
        else:
            # Delete Lights
            [light.Delete() for light in lights]

        scene.DrawAll()

import poser
scene = poser.Scene()
l = poserlights()

# turn lights off
l.processlights(0)

# turn lights on
l.processlights(1)

# toggle lights
l.processlights(2)

# delete lights
l.processlights(3) (any number above 2)

Locked Out


structure posted Wed, 12 August 2020 at 7:16 PM Forum Coordinator

Dealing with figure IK

class IK:
    def SetIK( self, figure = None , status = 0 , parts = 2 ):
        # status    : 0 = off, 1 = on , 2 = toggle
        # setup parts dictionary (ikrange)
        ikrange =   {
                        0   :   (0,1),          # legs
                        1   :   (2,3),          # arms
                        2   :   (0,1,2,3),      # all
                        3   :   (0,None),       # left leg
                        4   :   (1,None),       # Right leg
                        5   :   (2,None),       # left arm
                        6   :   (3,None),       # right arm
                        7   :   (0,2),          # left leg + left arm
                        8   :   (1,3),          # right leg + right arm
                        9   :   (0,3),          # left leg + right arm
                        10  :   (1,2)           # right leg + left arm
                    }
        if figure:
            IkNames=figure.IkNames()
            if status==0 or status ==1:             # turn off / on
                [figure.SetIkStatus(ik,status) for ik in ikrange[parts] if not ik==None]
            elif status==2:                         # toggle
                [figure.SetIkStatus(ik,not figure.IkStatus(ik)) for ik in ikrange[parts] if not ik==None]
        else:
            return False

Locked Out


structure posted Wed, 12 August 2020 at 7:49 PM Forum Coordinator

Use a tuple as a dictionary key

theDict = { (0,1,2,3) : "This is a test" }
print(theDict[ tuple(range(0,4))])

which gives this output
This is a test

keys=theDict.keys()
test=(0,3)
for item in test:
    for key in keys:
        if item in key:
        print(theDict[tuple(key)])


which also gives this output
This is a test

Locked Out


structure posted Fri, 14 August 2020 at 12:35 PM Forum Coordinator

call a function using a string as a variable.

for i in range( 0, 5 ):
    FUNCTIONNAME = str( i )
    getattr(globals()['CLASSNAME'](), FUNCTIONNAME )( args )
example script


from __future__ import print_function
import inspect
functionlist = []

class stringclass:
    def stripstring( self, i ):
        i=str(i).split(",")[0]
        return i.translate(None, "()'")

class materialclass:
    def get_all_scene_materials( self, item = None ):
        print("You are in the {} function".format( item ) )
        return

    def get_item_materials( self, item = None ):
        print("You are in the {} function".format( item ) )
        return

for i in (inspect.getmembers(materialclass, predicate=inspect.ismethod ) ):
    i = stringclass().stripstring( i )
    functionlist.append( i )

for f in functionlist:
    getattr(globals()['materialclass'](), f )( f ) # the 2nd f can be any argument


output

You are in the get_all_scene_materials function

You are in the get_item_materials function

Locked Out


structure posted Sun, 23 August 2020 at 1:18 PM Forum Coordinator

create your UI with no stay_on_top style

use the following to make it stay on top - or cancel stay on top as you need

def set_style( self, event = None ):
    self.old_style = self.GetWindowStyle()

def stay_on_top( self, event=None ):
    self.SetWindowStyle(self.old_style | wx.STAY_ON_TOP)

def cancel_on_top( self, event = None ):
    self.SetWindowStyle(self.old_style)

Locked Out


structure posted Sat, 29 August 2020 at 2:34 PM Forum Coordinator

apply a material ( not a pose ) to an unparented prop

import os
import poser                                                # get poser
reset = False                                               # set reparent variable
scene = poser.Scene()                                       # define scene
actor = scene.CurrentActor()                                # get the actor

if len( actor.Materials() ) > 0:                            # make sure the actor has materials
    if actor.IsProp():                                      # is this actor a prop?
        if actor.Parent().Name() == "UNIVERSE":             # is this actor parented?
            actor.SetParent( scene.Actor("GROUND") )        # set actor parent
            reset = True                                    # inform script we need to reparent prop

    material = actor.Materials()[0]                         # get actors preview material
    material.LoadMaterialSet(
        os.path.join(poser.TempLocation(), "test.mt5" ))    # load material
    if reset:
        actor.SetParent( scene.Actor( "UNIVERSE") )         # if we need to reparent - do so

    scene.DrawAll()

Locked Out


structure posted Sun, 08 November 2020 at 10:23 AM Forum Coordinator

convert bytes to kb, mb. gb etc :

class conversions:
    def convert_bytes( self, size_bytes ):
        if size_bytes == 0:
            return "0B"
        size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
        i = int(math.floor(math.log(size_bytes, 1024)))
        p = math.pow(1024, i)
        s = round(size_bytes / p, 2)
        return "%s %s" % (s, size_name[i])

Locked Out


adp001 posted Sat, 05 December 2020 at 3:23 PM

Or in short (and without the use of a library):

has_ext = lambda path: path.rfind(".") != -1

hasext("myown/directory/file")
# says: False
hasext("myown/directory/file.txt")
# says: True



adp001 posted Sat, 05 December 2020 at 3:57 PM

Or, to make a simplyfied version of what os.path.splitext() does (needs os imported because we need the path seperator):

hasext = lambda path: path[path.rfind(os.sep) if os.sep in path else 0:].rfind(".") != -1

P.s.: I love it fast and dirty ;)




adp001 posted Sat, 05 December 2020 at 4:37 PM

In real life I assume no extension is more than 5 characters (not where it matters for my scripts). So I simply use:


if "." in path[-5:]...

or as a function:

hasext = lambda path: "." in path[-5:]

I assume this is the faster possible form and fine for 99.9% of cases a script has to handle files.




structure posted Tue, 08 December 2020 at 3:56 PM Forum Coordinator

adp001 posted at 3:55PM Tue, 08 December 2020 - #4406505

Or in short (and without the use of a library):

has_ext = lambda path: path.rfind(".") != -1

hasext("myown/directory/file")
# says: False
hasext("myown/directory/file.txt")
# says: True

this is awesome, I always forget about lambda, thanks.

Locked Out


adp001 posted Tue, 08 December 2020 at 8:21 PM

structure posted at 8:18PM Tue, 08 December 2020 - #4406737

this is awesome, I always forget about lambda, thanks.

Keep in mind that this version can give a false response if you have pathes with an "." in it. This is why I prefer "." in path[-5:].




structure posted Mon, 21 December 2020 at 6:37 AM Forum Coordinator

list the contents of a folder in date order - new to old or old to new ( dealers choice )

import platform
class file_times:
    def creation_date(self, path_to_file):
        """
        Try to get the date that a file was created, falling back to when it was
        last modified if that isn't possible.
        See http://stackoverflow.com/a/39501288/1709587 for explanation.
        """
        if platform.system() == 'Windows':
            timestamp = (os.path.getctime(path_to_file))
            return timestamp
        else:
            stat = os.stat(path_to_file)
            try:
                return stat.st_birthtime
            except AttributeError:
                # We're probably on Linux. No easy way to get creation dates here,
                # so we'll settle for when its content was last modified.
                return stat.st_mtime



Locked Out


structure posted Fri, 25 December 2020 at 9:13 AM Forum Coordinator

get Poser's install directory from the windows registry While this is actually mostly redundant
thanks to Poser's AppLocation() it does show how to access the registry to read keys / data.

import winreg as reg


class _REGISTRY:
    def _find_poser_win(self, version):
        poser = r"SOFTWARE\\Poser Software\\Poser\\Poser %d" % version
        with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, poser) as key:
            if poser.endswith(str(version)) and key:
                return(reg.QueryValueEx(key, "InstallDir")[0])

# example code


installdirs = []
for version in (10, 11, 12):
    print(f"testing Poser {version}")
    try:
        installdir = _REGISTRY()._find_poser_win(version)
    except:
        installdir = "Not Installed"
    if not installdir in installdirs:
        installdirs.append(installdir)
    print(installdir)

Locked Out


structure posted Mon, 04 January 2021 at 8:58 AM Forum Coordinator

Check if a module exists before trying to import it.

from pkgutil import iter_modules


class basic_functions:
    def module_exists( self, module_name):
        return module_name in (name for loader, name, ispkg in iter_modules())

if basic_functions().module_exists( "poser" ):
    import poser
else:
    if basic_functions().module_exists( "POSER_FAKE"):
        import POSER_FAKE as poser

Locked Out


structure posted Mon, 25 October 2021 at 3:35 AM Forum Coordinator

store dictionary names in a list, and retrieve them as a printable string 

def varname(var):
    import inspect
    frame = inspect.currentframe()
    var_id = id(var)
    for name in frame.f_back.f_locals.keys():
        try:
            if id(eval(name)) == var_id:return(name)
        except:return var

cmra_data,char_data, face_data, hand_data = {}, {}, {}, {}
hair_data, lite_data, mtrl_data, pose_data = {}, {}, {}, {}
prop_data =  {}

alldicts = [cmra_data, char_data, face_data, hand_data,
            hair_data, lite_data, mtrl_data, pose_data,
            prop_data,]

count = 0
for dictionary in alldicts:
    print(f"Dictionary {count} Name : {varname(dictionary)}")
    count += 1

output : 
Dictionary 0 Name : cmra_data
Dictionary 1 Name : char_data
Dictionary 2 Name : face_data
Dictionary 3 Name : hand_data
Dictionary 4 Name : hair_data
Dictionary 5 Name : lite_data
Dictionary 6 Name : mtrl_data
Dictionary 7 Name : pose_data
Dictionary 8 Name : prop_data

This script allows you to store dictionary names as strings :
useful if you need to print the dictionary name for debugging
or just to let the user know which dictionary is being accessed.

** NOTE @ it does not work for :
    alldicts = [{} for _ in range(9)]
    since alldicts has no named dictionaries inside

For which; the output becomes :
Dictionary 0 Name : dictionary
Dictionary 1 Name : dictionary
Dictionary 2 Name : dictionary
Dictionary 3 Name : dictionary
Dictionary 4 Name : dictionary
Dictionary 5 Name : dictionary
Dictionary 6 Name : dictionary
Dictionary 7 Name : dictionary
Dictionary 8 Name : dictionary

Locked Out


structure posted Mon, 25 October 2021 at 6:24 AM Forum Coordinator

Find a word / phrase in any file without loading the file into memory; 

import mmap
import os


class Dialogs:
    def get_folder( self, start = "" ):
        style = wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON
        dialog = wx.DirDialog( None, 'Select a Folder ', start , style )
        return dialog.GetPath() if dialog.ShowModal() == wx.ID_OK else None

    def get_text( self, title = "", message = "" ):
        style = wx.ID_OK|wx.ID_CANCEL
        TE_dialog = wx.TextEntryDialog( None, message, title, "", style )
        TE_dialog.SetValue("")
        return TE_dialog.GetValue() if TE_dialog.ShowModal() == wx.ID_OK else None


class File_Ops:
    def find_in_files( self, root, listoffiles, thing_to_find ):
        found_in_files = False
        thing_to_find = bytes( thing_to_find, encoding = 'utf8' )
        for file in listoffiles:
            file = os.path.join(root, file)
            with open(file) as f:
                s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
                if s.find( thing_to_find ) != -1:
                    print(f'{thing_to_find} found in {file}.')
                    found_in_files = True
                elif len(list_of_files) == 1 and s.find(thing_to_find) == -1:
                    print(f'{thing_to_find} not found in {file}.')
                else:
                    pass
        if not found_in_files:
            print(f'{thing_to_find} not found.')

title = "find in files"
root = Dialogs().get_folder()
list_of_files = os.listdir(root)
thing_to_find = Dialogs().Get_text(title, "Find What ?",  )
if root and list_of_files and thing_to_find:
    File_Ops().find_in_files(root, list_of_files, thing_to_find)

Locked Out


structure posted Tue, 26 October 2021 at 12:11 AM Forum Coordinator

get machine current ID and BIOS serial number

from subprocess import check_output
def get_details():
    current_machine_id = str(check_output('wmic csproduct get uuid'), 'utf-8').split('\n')[1].strip()
    current_machine_sn = str(check_output('wmic bios get serialnumber'), 'utf-8').split('\n')[1].strip()
    return current_machine_id, current_machine_sn

cid, csn = get_details()

Locked Out


structure posted Tue, 26 October 2021 at 2:24 AM Forum Coordinator

sort dictionary by value

from operator import itemgetter

def pTypes():
    return{ ('.pz3', '.pzz') : 'Scene',
            ('.pp2', '.ppz') : 'Prop',
            ('.cr2', '.crz') : 'Character',
            ('.pz2', '.p2z') : 'Pose',
            ('.hr2', '.hrz') : 'Hair',
            ('.fc2', '.fcz') : 'Expression',
            ('.hd2', '.hdz') : 'Hand',
            ('.lt2', '.ltz') : 'Light',
            ('.cm2', '.cmz') : 'Camera',
            ('.mt5', '.mz5') : 'Material',
            ('.mc6', '.mcz') : 'Material',
            ('.obj', '.obz') : 'Geometry',}

marklist= sorted(pTypes().items(), key=itemgetter(1))
pTypes=dict(marklist)
for item in pTypes:
    print(item, pTypes[item])


output:
('.cm2', '.cmz') Camera
('.cr2', '.crz') Character
('.fc2', '.fcz') Expression
('.obj', '.obz') Geometry
('.hr2', '.hrz') Hair
('.hd2', '.hdz') Hand
('.lt2', '.ltz') Light
('.mc6', '.mcz') Material
('.mt5', '.mz5') Material
('.pz2', '.p2z') Pose
('.pp2', '.ppz') Prop
('.pz3', '.pzz') Scene

Locked Out


structure posted Tue, 26 October 2021 at 2:11 PM Forum Coordinator

simple beep function

import sys

class OS_BEEP:
    def beep_macos(self, **kwargs):
        from AppKit import NSBeep
        NSBeep()
   
    def beep_windows(self, **kwargs):
        import winsound
        winsound.MessageBeep()

if sys.platform == "win32":
    OS_BEEP().beep_windows()
else:
    OS_BEEP().beep_macos()

Locked Out


structure posted Tue, 02 November 2021 at 12:27 PM Forum Coordinator

get libraries (outside of poser) : 

import os
import xml.etree.cElementTree as ElementTree

def PrefsLocation(version):
    if version > 10:
        return os.path.join(os.environ["APPDATA"], "poser", str(Version()))
    else:
        return os.path.join(os.environ["APPDATA"], "poser pro", str(Version()))

def get_libraries( xml_file ):
    try:
        tree = ElementTree.parse(xml_file)
    except Exception as inst:
        print( "Unexpected error opening %s: %s" % (xml_file, inst) )
        return None
   
    libraries = []
   
    if os.path.exists(xml_file):
        root=tree.getroot()
        for child in root:
            if child.tag=='ContentFolder':
                libraries.append(str(child.attrib['folder']))
   
    return libraries

def Version(): # edit to suit your needs
    # return 10
    return 12

def get_libraries( xml_file ):
    try:
        tree = ElementTree.parse(xml_file)
    except Exception as inst:
        print( "Unexpected error opening %s: %s" % (xml_file, inst) )
        return None
    libraries = []
   
    if os.path.exists(xml_file):
        root=tree.getroot()
        for child in root:
            if child.tag=='ContentFolder':
                libraries.append(str(child.attrib['folder']))
   
    return libraries

PrefsLocation = PrefsLocation(Version())
PrefsFile = "LibraryPrefs.xml"
xml_file = os.path.join(PrefsLocation, PrefsFile)
libraries = get_libraries( xml_file)

for library in libraries:
    print(library)

Locked Out


adp001 posted Tue, 02 November 2021 at 3:50 PM

A shorter and less complicated version:


import os
import re

def get_library_pathes():
    version = int(poser.Version().split(".")[0])
    fname = os.path.join(os.environ["APPDATA"],
                         "Poser" if version < 11 else "Poser Pro", str(version),
                         "LibraryPrefs.xml")
    re_libs = re.compile(r"<ContentFolder.*?folder=\"([^\"]+)\"")
    with open(fname, "r") as fh:
        for line in fh:
            res = re.search(re_libs, line)
            if res:
                yield res.group(1)


if __name__ == "__main__":
    for entry in get_library_pathes():
        print(entry)




adp001 posted Wed, 03 November 2021 at 2:31 AM

Not so seldom we have situations in which an occurring error is tollerable. Typically we wrap such a situation in a try/except clause.

But this can also be done differently, if we use an appropriate class:


class ignore_error(object):
def __init__(self):
pass

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
return True


Now we can write:


with ignore_error():
actor = poser.Scene().Actor("not existing actor")

without causing an error.

Note that the entire block after "ignore_error" is ignored in case of an error. Like the part that follows a "try".




adp001 posted Wed, 03 November 2021 at 2:44 AM

A slightly extended version prevents only allowed exceptions:


class ignore_error(object):
def __init__(self, *args):
self.tolerable = args

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
return exc_type in self.tolerable if len(self.tolerable) else True


with ignore_error(NameError, poser.error):
actor = poser.Scene().Actor("not existing actor")

(The construct is called "Context Manager", by the way).



adp001 posted Wed, 03 November 2021 at 2:49 AM

As you can see above, the editor still doesn't work properly. The indentations are completely off when they are displayed. When I bring the text back into the editor, it looks completely right again.

Here again inserted as standard text:


class ignore_error(object):
    def __init__(self, *args):
        self.tolerable = args

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else True


with ignore_error(NameError, poser.error):
    actor = poser.Scene().Actor("not existing actor")






structure posted Wed, 03 November 2021 at 2:59 AM Forum Coordinator

adp001 posted at 3:50 PM Tue, 2 November 2021 - #4429791

A shorter and less complicated version:


import os
import re

def get_library_pathes():
    version = int(poser.Version().split(".")[0])
    fname = os.path.join(os.environ["APPDATA"],
                         "Poser" if version < 11 else "Poser Pro", str(version),
                         "LibraryPrefs.xml")
    re_libs = re.compile(r"<ContentFolder.*?folder=\"([^\"]+)\"")
    with open(fname, "r") as fh:
        for line in fh:
            res = re.search(re_libs, line)
            if res:
                yield res.group(1)


if __name__ == "__main__":
    for entry in get_library_pathes():
        print(entry)

this line : 
    version = int(poser.Version().split(".")[0]) can be better written thus     
version = int(float(poser.Version())) and requires that poser or perhaps POSER_FAKE be imported.
better to include a dummy version function 
def Version():
    return 12 also this construct : 
    fname = os.path.join(os.environ["APPDATA"],
                         "Poser" if version < 11 else "Poser Pro", str(version),
                         "LibraryPrefs.xml") 

does not appear to working - I have set version to 12 - but it keeps using poser pro as the folder name .

    poserversion =  "Poser" if Version() < 11 else "Poser Pro"
    print(poserversion, Version()<11, Version())

output :
Poser Pro False 12

 


Locked Out


structure posted Wed, 03 November 2021 at 3:02 AM Forum Coordinator

adp001 posted at 2:49 AM Wed, 3 November 2021 - #4429830

As you can see above, the editor still doesn't work properly. The indentations are completely off when they are displayed. When I bring the text back into the editor, it looks completely right again.

Here again inserted as standard text:


class ignore_error(object):
    def __init__(self, *args):
        self.tolerable = args

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else True


with ignore_error(NameError, poser.error):
    actor = poser.Scene().Actor("not existing actor")



looking forward to trying this out


Locked Out


adp001 posted Wed, 03 November 2021 at 3:09 AM

version = int(poser.Version().split(".")[0]) if globals().get("poser", False) else 12

Should do the trick.



adp001 posted Wed, 03 November 2021 at 3:16 AM

Maybe this one is more robust:

fname = os.path.join(os.environ["APPDATA"], "Poser", str(version), "LibraryPrefs.xml")
if not os.path.exists(fname):
fname.replace("Poser", "Poser Pro")



structure posted Wed, 03 November 2021 at 3:37 AM Forum Coordinator

adp001 posted at 3:16 AM Wed, 3 November 2021 - #4429836

Maybe this one is more robust:

fname = os.path.join(os.environ["APPDATA"], "Poser", str(version), "LibraryPrefs.xml")
if not os.path.exists(fname):
fname.replace("Poser", "Poser Pro")
that works fine thank you 

How do we take into account, poser builds from 11.2 and poser builds past 12 - right now this is adequate for my needs, but do we just update it for every build?

do remember to edit the line
fname.replace("Poser", "Poser Pro") to read

fname = fname.replace("Poser", "Poser Pro")

Locked Out


adp001 posted Wed, 03 November 2021 at 3:55 AM

In my opinion, a version number should not be assumed to be a float. Version numbers can also look like this: "12.3.0.3". This is where "float" fails severely.

My method is something like Python's "sys.version_info.major", where Python's version number contains several decimal points.




adp001 posted Wed, 03 November 2021 at 3:59 AM

structure posted at 3:37 AM Wed, 3 November 2021 - #4429837

How do we take into account, poser builds from 11.2 and poser builds past 12 - right now this is adequate for my needs, but do we just update it for every build?

Since we can't guess which scheme Bondware will follow for the version numbers and the resulting file structure, there is nothing left to do but wait until the case occurs that it doesn't work as it is anymore :)





structure posted Wed, 03 November 2021 at 4:11 AM Forum Coordinator

adp001 posted at 3:55 AM Wed, 3 November 2021 - #4429838

In my opinion, a version number should not be assumed to be a float. Version numbers can also look like this: "12.3.0.3". This is where "float" fails severely.

My method is something like Python's "sys.version_info.major", where Python's version number contains several decimal points.

right - this would be a better method

Locked Out


adp001 posted Wed, 03 November 2021 at 5:27 AM

structure posted at 3:37 AM Wed, 3 November 2021 - #4429837

do remember to edit the line
fname.replace("Poser", "Poser Pro") to read

fname = fname.replace("Poser", "Poser Pro")

Ups!

Maybe post a complete and tested version. I'm working out of the blue at the moment because I don't have a working Poser version here anymore.



structure posted Wed, 03 November 2021 at 5:29 AM Forum Coordinator

ok - will do that soonly - why no working poser?

Locked Out


structure posted Wed, 03 November 2021 at 5:35 AM Forum Coordinator

tested and working :

def get_library_paths():
    version = int(poser.Version().split(".")[0]) if globals().get("poser", False) else 12
    fname = os.path.join(os.environ["APPDATA"], "Poser", str(int(version)), "LibraryPrefs.xml")
    if not os.path.exists(fname):
        fname = fname.replace("Poser", "Poser Pro")
    re_libs = re.compile(r"<ContentFolder.*?folder=\"([^\"]+)\"")
    if os.path.exists(fname):
        with open(fname, "r") as fh:
            for line in fh:
                res = re.search(re_libs, line)
                if res:
                    yield res.group(1)
if __name__ == "__main__":
    for entry in get_library_paths():
        print(entry)

Locked Out


adp001 posted Wed, 03 November 2021 at 6:29 AM

structure posted at 5:29 AM Wed, 3 November 2021 - #4429845

ok - will do that soonly - why no working poser?

Fine.

Rest: See sitemail.




adp001 posted Wed, 03 November 2021 at 4:01 PM

adp001 posted at 2:49 AM Wed, 3 November 2021 - #4429830

class ignore_error(object):
    def __init__(self, *args):
        self.tolerable = args

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else True


with ignore_error(NameError, poser.error):
    actor = poser.Scene().Actor("not existing actor")




Made a mistake in:

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else True

the default result must be False, not True:

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else False






structure posted Thu, 04 November 2021 at 4:38 AM Forum Coordinator

adp001 posted at 2:49 AM Wed, 3 November 2021 - #4429830


class ignore_error(object):
    def __init__(self, *args):
        self.tolerable = args

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else True


with ignore_error(NameError, poser.error):
    actor = poser.Scene().Actor("not existing actor")




Made a mistake in:

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else True

the default result must be False, not True:

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type in self.tolerable if len(self.tolerable) else False



nice addition,  this could be used in conjunction with contextlib.suppress
which captures all kinds of errors and ignores them.

in this simple example, I am trying to print a non-digit string as an integer,
and the output is suppressed. 


import contextlib

with contextlib.suppress(NameError, TypeError, WindowsError):
    def do_something(*args, **kwargs):
        try:
            print(int(message))
        except ValueError:
            raise TypeError("%s is invalid" %(message))

    message = "nothing to see here, move along"
    do_something()


without the contextlib.suppress in place the output is 
TypeError: nothing to see here, move along is invalid

In the following amended example the output is printed as
nothing to see here, move along

import contextlib

with contextlib.suppress(NameError, TypeError, WindowsError):
    def do_something(*args, **kwargs):
        try:
            print(message)
        except ValueError:
            raise TypeError("%s is invalid" %(message))

    message = "nothing to see here, move along"
    do_something()

            

I am unsure that I have found every type of python error, but here is an
almost comprehensive list of errors that contextlib.suppress can capture. 

errorlist = [ArithmeticError, AssertionError, BrokenPipeError, BufferError,
ChildProcessError, ConnectionAbortedError,  ConnectionError,
ConnectionRefusedError, ConnectionResetError, EOFError, FileExistsError,
FileNotFoundError, FloatingPointError, ImportError, IndentationError,
IndexError, InterruptedError, IsADirectoryError, KeyError, LookupError,
MemoryError, ModuleNotFoundError, NameError, NotADirectoryError,
NotImplementedError, OverflowError, ProcessLookupError, ReferenceError,
RuntimeError, SyntaxError, SystemError, TabError, TimeoutError, TypeError,
UnboundLocalError, UnicodeEncodeError, UnicodeError, UnicodeTranslateError,
ValueError, WindowsError, ZeroDivisionError, ]

Locked Out


structure posted Thu, 04 November 2021 at 5:45 AM Forum Coordinator

Get poser AppLocation outside of poser ( WINDOWS ONLY ) (you need to add this to POSER_FAKE by adp001, a separate file would be the best option probably. e.g. in the poser fake folder, add Applocation.py)

import winreg as reg
import POSER_FAKE as poser

class _REGISTRY:
    def _find_poser_win(self, version):
        # versions = ( 11, 12 ) # select version you want
        poser = r"SOFTWARE\Poser Software\Poser\Poser %d" %version
        with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, poser ) as key:
            if poser.endswith( str(version) ) and key:
                return(reg.QueryValueEx(key, "InstallDir" )[0])

def AppLocation(installdirs = []):
    installdir = _REGISTRY()._find_poser_win(Version())
    if not installdir in installdirs:
        installdirs.append( installdir )
    return os.path.join(installdir, "Poser.exe")
print(poser.AppLocation())


Locked Out


structure posted Thu, 04 November 2021 at 6:07 AM Forum Coordinator

get poser templocation / prefslocation outside of poser (you need to add these to POSER_FAKE by adp001, separate files would be the best option probably. e.g. in the poser fake folder, add Templocation.py and PrefsLocation.py)

import POSER_FAKE as poser

def TempLocation():
    return os.path.join(os.environ["TEMP"],"Poser")
def PrefsLocation():
    if Version() >= 11.2 or Version() < 11.2 and not IsPro():
        return os.path.join(os.environ["APPDATA"], "Poser", str(int(Version())))
    elif Version() < 11.2 and IsPro():
        return os.path.join(os.environ["APPDATA"], "Poser Pro", str(int(Version())))
    else:
        return None


def Version():
    return 12

def IsPro():
    return True

print(poser.TempLocation())
print(poser.PrefsLocation())


you should likely add checks to see if the actual location exists. 



Locked Out


adp001 posted Fri, 05 November 2021 at 6:37 PM

structure posted at 4:38 AM Thu, 4 November 2021 - #4429892

nice addition,  this could be used in conjunction with contextlib.suppress
which captures all kinds of errors and ignores them.


"contextlib.suppress" is not present in Python 2.7. And 2.7 is currently much more important than Python 3, because Poser 12 is only used by a few people.

Code that runs only under Python 3 should be explicitly marked. Otherwise beginners look for supposed errors where there are none.





adp001 posted Tue, 09 November 2021 at 6:11 AM

Function to trim/extend array, tuple,  bytes or string to a fixed number of elements:

def trimmed(arg, nr_of_elements, f=None):
return (arg + arg.__class__([f, ] * nr_of_elements)
if isinstance(arg, (tuple, list))
else (arg + arg.__class__((f or " ") * nr_of_elements)
if isinstance(arg, (str, bytes))
else [arg, ] + [f, ] * nr_of_elements))[:nr_of_elements]

("f" is what is used to fill missed elements; should be compatible with 'arg')


trimmed([1,2,3], 5) # returns list: [1, 2, 3, None, None]

trimmed((1,2,3), 5) # returns tuple: (1, 2, 3, None, None)

trimmed([1, 2, 3, 4, 5, 6, 7, 8, 9], 5) # returns list: [1, 2, 3, 4, 5]

trimmed("Sample", 10, ".") # returns string: "Sample...."

trimmed(b'123', 5, b'.') # returns bytes: b'123..'

trimmed(10, 5, 1) # returns [10, 1, 1, 1, 1]

trimmed(10, 5, [1, 2, 3]) # returns [10, [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]

trimmed([], 5, 1) # returns list: [1, 1, 1, 1, 1]

trimmed((), 5, 1) # returns tuple: (1, 1, 1, 1, 1)








adp001 posted Tue, 09 November 2021 at 7:03 AM

Some more about error handling. This time as decorator to "protect" functions:

def no_err(f):
def _f():
try:
f()
except Exception as err:
pass
return(_f)


@no_err
def test(*args, **kwargs):
a = 3
print(a) # ok
print(a + b) # generates error
print("unreachable because of error")





structure posted Sun, 14 November 2021 at 10:55 AM Forum Coordinator

Get the users Language (windows):

def Language():
    import locale
    import ctypes
    windll = ctypes.windll.kernel32
    return locale.windows_locale[windll.GetUserDefaultUILanguage()]

Locked Out


structure posted Sun, 14 November 2021 at 11:22 AM Forum Coordinator

possible alternative to ExecFile

import runpy
runpy.run_path(filepath)

Locked Out


Y-Phil posted Wed, 29 December 2021 at 12:46 PM

I don't know if this can help someone, but just in case...
These last months, I've been writing a toolbox with a few wxpython script to import, as the main script has more than 1100 lines. The problem with python is that once a module is imported, it remains in memory, and I've been searching a way to pop it out if there's an error in it, hence this method (I'm writing for Poser12):

import sys

try: sys.modules.pop('my_module')
except: pass
from my_module import MyClass


𝒫𝒽𝓎𝓁


(っ◔◡◔)っ

👿 Win11 on i9-13900K@5GHz, 64GB, RoG Strix B760F Gaming, Asus Tuf Gaming RTX 4070 OC Edition, 1+2 TB SSD's, 6+4TB HD
👿 Mac Mini M2, Tahoe 26.4.1.2.3.4.5.6.7...., 16GB, 500GB SSD
👿 Nas 10TB
👿 Poser 13 and 14 ❤️

𝑀𝓎 𝒢𝒶𝓁𝓁𝑒𝓇𝓎


vholf posted Thu, 10 February 2022 at 10:57 PM

How about opening a repo in github and upload stuff there?, you can upload/update your own scripts and contribute to an organized repository of scripts.


structure posted Sat, 26 February 2022 at 8:04 AM Forum Coordinator

Y-Phil posted at 12:46 PM Wed, 29 December 2021 - #4432576

I don't know if this can help someone, but just in case...
These last months, I've been writing a toolbox with a few wxpython script to import, as the main script has more than 1100 lines. The problem with python is that once a module is imported, it remains in memory, and I've been searching a way to pop it out if there's an error in it, hence this method (I'm writing for Poser12):

import sys

try: sys.modules.pop('my_module')
except: pass
from my_module import MyClass

nice, there is also another method : 


import importlib
import module
importlib.reload(module)


Locked Out


structure posted Sat, 26 February 2022 at 8:06 AM Forum Coordinator

vholf posted at 10:57 PM Thu, 10 February 2022 - #4434663

How about opening a repo in github and upload stuff there?, you can upload/update your own scripts and contribute to an organized repository of scripts.

If someone has the time to do this, I would be open to adding scripts there. 

Locked Out


Y-Phil posted Sat, 26 February 2022 at 11:15 AM

structure posted at 8:04 AM Sat, 26 February 2022 - #4435181

Y-Phil posted at 12:46 PM Wed, 29 December 2021 - #4432576

I don't know if this can help someone, but just in case...
These last months, I've been writing a toolbox with a few wxpython script to import, as the main script has more than 1100 lines. The problem with python is that once a module is imported, it remains in memory, and I've been searching a way to pop it out if there's an error in it, hence this method (I'm writing for Poser12):

import sys

try: sys.modules.pop('my_module')
except: pass
from my_module import MyClass

nice, there is also another method : 


import importlib
import module
importlib.reload(module)


Well... Thank you for that nice trick! 😁

𝒫𝒽𝓎𝓁


(っ◔◡◔)っ

👿 Win11 on i9-13900K@5GHz, 64GB, RoG Strix B760F Gaming, Asus Tuf Gaming RTX 4070 OC Edition, 1+2 TB SSD's, 6+4TB HD
👿 Mac Mini M2, Tahoe 26.4.1.2.3.4.5.6.7...., 16GB, 500GB SSD
👿 Nas 10TB
👿 Poser 13 and 14 ❤️

𝑀𝓎 𝒢𝒶𝓁𝓁𝑒𝓇𝓎


structure posted Fri, 11 March 2022 at 1:56 AM Forum Coordinator

example usage of casefold, Counter and count

# setup main tuple
items=("Extra-Terrestrial", "Alien", "Planet", "Star",
        "Galaxy", "Universe", "Black Hole", "White Hole",
        "Astronomy", "Dark-Matter", "Dark-Energy")

# setup comparison tuple
compare=("extra-terrestrial", "alien")

''' use casefold -py3(or upper / lower -py2)
for context insensitive comparison '''
for item in items:
    if any(i.casefold() in item.casefold() for i in compare):
        print(item)

''' use counter to count all words in tuple'''
print(f'\n{Counter(compare)}\n')

''' use count to count how many times comparative
    words appear in tuple'''
for c in compare:
    tense="time" if items.count(c.title())==1 else "times"
    print(f'{c.title()} appears {items.count(c.title())}

Output:

Extra-Terrestrial Alien

Counter({'extra-terrestrial': 1, 'alien': 1}) Extra-Terrestrial appears 1 time in ('Extra-Terrestrial', 'Alien', 'Planet', 'Star', 'Galaxy', 'Universe', 'Black Hole', 'White Hole', 'Astronomy', 'Dark-Matter', 'Dark-Energy', '') Alien appears 1 time in ('Extra-Terrestrial', 'Alien', 'Planet', 'Star', 'Galaxy', 'Universe', 'Black Hole', 'White Hole', 'Astronomy', 'Dark-Matter', 'Dark-Energy', '')

**note :
.count only takes into account the exact word - so words like
"alienesque" or "alien ship" would not be recognised as containing
the word alien.

Locked Out


structure posted Sat, 19 March 2022 at 9:32 AM Forum Coordinator

Wait for Keypress (windows)

from msvcrt import getch

def wait():
    getch()

Locked Out


structure posted Sun, 20 March 2022 at 8:30 PM Forum Coordinator

Convert bytes to Kb, Mb, Gb, or Tb

def formatSize(bytes):
    try:
        bytes = float(bytes)
        kb = bytes / 1024
    except:
        return "Error"
    if kb >= 1024:
        M = kb / 1024
        if M >= 1024:
            G = M / 1024
            if G >= 1024:
                T = G / 1024
                return "%.2f Tb" % (T)
            return "%.2f Gb" % (G)
        return "%.2f Mb" % (M)
    else:
        return "%.2f kb" % (kb)

Example Output:




Locked Out


structure posted Sun, 27 March 2022 at 9:38 AM Forum Coordinator

convert a string of digits to numeric and remove even or odd numbers



def returnDigits(my_string):
    x = re.findall(r'\b\d+\b', my_string)
    return [int(n) for n in x]


def removenumbers(numbers, even=True):
    return [n for n in numbers if n % 2 == 0] \
        if even == True else [n for n in numbers if n % 2 != 0]


my_string = "0 3 4 321 24 034, 1001, 2022, 1977, 1, 6"

stringed_numbers = returnDigits(my_string)
print(stringed_numbers)

evennumbers = sorted(removenumbers(stringed_numbers))
print(evennumbers)

oddnumbers = sorted(removenumbers(stringed_numbers, False))
print(oddnumbers)


Locked Out


structure posted Sun, 27 March 2022 at 11:22 AM Forum Coordinator

Install a missing module from inside a running python script, and rerun the script (using rich as an example )


class basic_functions:
    def module_exists(self, module_name):
        from pkgutil import iter_modules
        return module_name in (name for loader, name, ispkg in iter_modules())


if basic_functions().module_exists("rich"):
    from rich.align import Align
    from rich.console import Console
else:
    try:
        from subprocess import check_call
        import os
        import sys
        check_call([sys.executable, "-m", "pip", "install", 'rich'])
        import importlib
        from rich.align import Align
        from rich.console import Console
        importlib.reload(rich)
        os.execv(sys.argv[0], sys.argv)
    except:
        pass


rich allows you to create outputs like this :

Locked Out


EVargas posted Sat, 23 April 2022 at 7:42 PM

Hi guys, so here I go again trying to share something, hopefully not reinventing the wheel.

While learning (or trying) to use HDRI and setup scenes with cameras from multiple angles etc, I found myself accidentally moving the cameras a lot. I don't like saving cameras to the library, and I always missed a way to quickly lock/unlock its position/rotation. The native "object/lock" menu can do this, but the camera have to be selected in order for it to work. I want to simply lock/unlock the current ACTIVE camera, without worrying about selecting it in a list.

I searched G00gle and here but with no success I decided to go for it and, why not, learn some more python along the way. Here I share a few lines that help me a lot. These are two separate files that can be added to the python scripts window, or put in "(...)/Poser Software/Poser 12/Runtime/Python/poserScripts/ScriptsMenu/"

For some reason this only works with the user created cameras ("object/create camera"), but I don't bother with it since I always create a new camera for rendering anyway.

# Lock_Current_Cam.py

scene = poser.Scene()
cam = scene.CurrentCamera()

def lockCurrentCam():
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        camPar = cam.Parameter(parName)
        camPar.SetMinValue(camPar.MinValue() - 1 * camPar.MinValue() + camPar.Value())
        camPar.SetMaxValue(camPar.MaxValue() - 1 * camPar.MaxValue() + camPar.Value())

lockCurrentCam()

# ---------------------------------------

# Unlock_Current_Cam.py

scene = poser.Scene()
cam = scene.CurrentCamera()
 
def unlockCurrentCam():    
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        camPar = cam.Parameter(parName)
        camPar.SetMinValue(-10000)
        camPar.SetMaxValue(10000)

unlockCurrentCam()



Store | Website


EVargas posted Sun, 24 April 2022 at 11:53 AM

Update here, when translating to the "def" syntax I forgot the "Force Limits", fixed below. Another good tip is to set a keyboard shortcut for both, it makes life a lot easier!

# -- -- -- -- -- Lock_Current_Cam.py -- -- -- -- --

scene = poser.Scene()
cam = scene.CurrentCamera()

def lockCurrentCam():
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        camPar = cam.Parameter(parName)
        camPar.SetMinValue(camPar.MinValue() - 1 * camPar.MinValue() + camPar.Value())
        camPar.SetMaxValue(camPar.MaxValue() - 1 * camPar.MaxValue() + camPar.Value())
        camPar.SetForceLimits(1)

lockCurrentCam()

# -- -- -- -- -- Unlock_Current_Cam.py -- -- -- -- --

scene = poser.Scene()
cam = scene.CurrentCamera()
 
def unlockCurrentCam():    
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        camPar = cam.Parameter(parName)
        camPar.SetMinValue(-10000)
        camPar.SetMaxValue(10000)
        camPar.SetForceLimits(0)

unlockCurrentCam()



Store | Website


structure posted Mon, 25 April 2022 at 9:09 AM Forum Coordinator

evargas posted at 11:53 AM Sun, 24 April 2022 - #4437678

Update here, when translating to the "def" syntax I forgot the "Force Limits", fixed below. Another good tip is to set a keyboard shortcut for both, it makes life a lot easier!

# -- -- -- -- -- Lock_Current_Cam.py -- -- -- -- --

scene = poser.Scene()
cam = scene.CurrentCamera()

def lockCurrentCam():
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        camPar = cam.Parameter(parName)
        camPar.SetMinValue(camPar.MinValue() - 1 * camPar.MinValue() + camPar.Value())
        camPar.SetMaxValue(camPar.MaxValue() - 1 * camPar.MaxValue() + camPar.Value())
        camPar.SetForceLimits(1)

lockCurrentCam()

# -- -- -- -- -- Unlock_Current_Cam.py -- -- -- -- --

scene = poser.Scene()
cam = scene.CurrentCamera()
 
def unlockCurrentCam():    
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        camPar = cam.Parameter(parName)
        camPar.SetMinValue(-10000)
        camPar.SetMaxValue(10000)
        camPar.SetForceLimits(0)

unlockCurrentCam()


nice addition - thanks

a slightly shorter version

import poser
# -- -- -- -- -- (un)Lock_Current_Cam.py -- -- -- -- --

scene = poser.Scene()
cam = scene.CurrentCamera()

def lockCurrentCam(lock = True, camPar = None):
    for parName in ('xtran','ytran','ztran','xrot','yrot','zrot'):
        if lock:
            camPar = cam.Parameter(parName)
            camPar.SetMinValue(camPar.MinValue() - 1 * camPar.MinValue() + camPar.Value())
            camPar.SetMaxValue(camPar.MaxValue() - 1 * camPar.MaxValue() + camPar.Value())
            camPar.SetForceLimits(1)
        else:
            camPar = cam.Parameter(parName)
            camPar.SetMinValue(-10000)
            camPar.SetMaxValue(10000)
            camPar.SetForceLimits(0)
    return True if camPar.ForceLimits()==1 else False
           

camlocked = lockCurrentCam() # Lock the cam
camlocked = lockCurrentCam(False) # unlock the cam

Locked Out


structure posted Wed, 27 April 2022 at 4:57 AM Forum Coordinator

Added to dialog Library:


    def getnumberentry(self, alertmessage, prompt, caption, value, min, max, wx.DefaultPosition):
        NE_dialog = wx.NumberEntryDialog(None, alertmessage, prompt, caption, value, min, max, pos)
        return NE_dialog.GetValue() if NE_dialog.ShowModal() == wx.ID_OK else None
   
example Usage:
   
duplicate = (getnumberentry("How Many %s's ?" % item, "Select a number",
                            "Number Entry Dialog", 0, 0, 100))

Locked Out


structure posted Tue, 10 May 2022 at 4:35 AM Forum Coordinator

number outside chosen range? select the closest viable number to the chosen number.

from random import randint


def closest_value(value, iterable):
    storage = []

    for i in iterable:
        storage.append((abs(value - i), i))

    result = min(storage)
    return result[1]


for x in range(0, 10):
    variant = randint(-20, 20)
    if variant > 4 or variant < 1:
        # generate viable number
        v = variant
        variant = closest_value(variant, range(1, 5))
        print(f"Original {v} : New {variant}")


Output : 

Original 13 : New 4
Original -1 : New 1
Original -5 : New 1
Original -16 : New 1
Original 17 : New 4
Original -11 : New 1
Original 13 : New 4
Original 11 : New 4
Original 6 : New 4
Original 16 : New 4


Locked Out


structure posted Wed, 18 May 2022 at 2:57 PM Forum Coordinator

get screen resolution


import wx

def get_Screen_Resolution():
    try:
        # method to get screen size
        return wx.GetDisplaySize()
    except:
        # alternate method to get screen size
        return wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X), wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)

SCREENW, SCREENH = get_Screen_Resolution()
print((SCREENW, SCREENH))




Locked Out


structure posted Fri, 20 May 2022 at 2:25 AM Forum Coordinator

Mirror / reverse data:

INSTANCES for testing what your variable is. ( this is just for printing headings )

class INSTANCES:
    def test_instance(self, value):
        if isinstance(value, type(None)):
            return "NoneType"
        if isinstance(value, str):
            return "string"
        if isinstance(value, int):
            return "int"
        if isinstance(value, float):
            return "float"
        if isinstance(value, list):
            return "list"
        if isinstance(value, tuple):
            return "tuple"
        if isinstance(value, dict):
            return "dict"
        if isinstance(value, set):
            return "set"
        if isinstance(value, object):
            return "object"


Actual Mirror Code:
class MIRROR_DATA:
    def mirror(self, data):
        if isinstance(data, tuple):
            return tuple(map(self.mirror, reversed(data)))
        elif isinstance(data, list):
            return [ele for ele in reversed(data)]
        elif isinstance(data, str):
            return data[::-1]
        elif isinstance(data, dict):
            return dict(reversed(list(data.items())))
        elif isinstance(data, set):
            data = list(data)
            data = self.mirror(data)
            return data
        else:
            return data


example Code:
type(None) == None.__class__
types = (type(None), str, int, float, list, dict, tuple, set, object)
testdata = {0: (0, 1, 2, 3),
            1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ],
            2: "0,1,2,3,4,5,6,7,8,9,",
            3: {0: "0,1,2,3,4,5,6,7,8,9,", 1: 123, 2: "more bullsh*t!"},
            4: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }
            }


for t in testdata:
    nport = testdata[t]
    print(f"{'-'*5} With a {INSTANCES().test_instance(nport)} {'-'*5}")
    print(nport)
    rport = MIRROR_DATA().mirror(nport)
    if t == 4:
        print(f"before conversion back to a set {rport}")
        rport = set(rport)
        print(f"after conversion back to a set {rport}")
    print(rport)
    print(f"{'-'*24}")
    print()


Output:
····· With a tuple ·····
(0, 1, 2, 3)
(3, 2, 1, 0)
························

····· With a list ·····
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
························

····· With a string ·····
0,1,2,3,4,5,6,7,8,9,
,9,8,7,6,5,4,3,2,1,0
························

····· With a dict ·····
{0: '0,1,2,3,4,5,6,7,8,9,', 1: 123, 2: 'more bullsh*t!'}
{2: 'more bullsh*t!', 1: 123, 0: '0,1,2,3,4,5,6,7,8,9,'}
························

····· With a set ·····
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
before conversion back to a set [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
after conversion back to a set {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
························

Locked Out


adp001 posted Fri, 20 May 2022 at 3:03 PM

According to the motto: Why simple when you can make it complicated :)

test this:

d = dict(a=1, b=2, c=3)

print(d.__class__.__name__)




structure posted Sat, 21 May 2022 at 1:51 AM Forum Coordinator

adp001 posted at 3:03 PM Fri, 20 May 2022 - #4438875

According to the motto: Why simple when you can make it complicated :)

test this:

d = dict(a=1, b=2, c=3)

print(d.__class__.__name__)

nice - thanks

Locked Out


adp001 posted Sun, 22 May 2022 at 6:49 AM

Just for the records:

Python sets and dictionaries are unordered. So not sorted. For this reason there is no "reverse" for it. Because the order is random.

https://docs.python.org/3.8/library/stdtypes.html#set-types-set-frozenset

Exception for dictionaries: Class OrderedDict from lib collections.




adp001 posted Sun, 22 May 2022 at 7:00 AM

Another thing: Strings are arrays of characters.

So, list(reversed("abcdefg") ) returns ['g', 'f', 'e', 'd', 'c', 'b', 'a']. list(s[::-1]) returns the same.








structure posted Sun, 22 May 2022 at 12:19 PM Forum Coordinator

in python 3 - reversing "ABRACDABRA"

returns  : ARBADCARBA

Dictionaries are ordered and so can be reversed as is evidenced by 

····· With a dict ·····
{0: '0,1,2,3,4,5,6,7,8,9,', 1: 123, 2: 'more bullsh*t!'}
{2: 'more bullsh*t!', 1: 123, 0: '0,1,2,3,4,5,6,7,8,9,'}
························

sets must be converted to a list to get the data reversed. They also seem to be sorted low to high 

Locked Out


structure posted Tue, 31 May 2022 at 11:32 AM Forum Coordinator

creating a class for working with colors: (part I)

from matplotlib import colors as colours
from skimage import color as colour

class COLOR_SYSTEM:
    def random_hex(self):
        ''' Generate a random Hex String '''
        return str(["#"+''.join([choice(hex_string)
                                 for loop in range(6)])]).strip("\[\]\'")

    def hex2rgb(self, colorstring): # requires a HEX notated value
        ''' convert #RRGGBB to an (R, G, B) tuple '''
        colorstring = colorstring.lstrip('#')
        return tuple(int(colorstring[_hex:_hex+2], 16) for _hex in (0, 2, 4))

    def rgb2hsv(self, r, g, b):
        ''' convert (R, G, B) to (H, S, V) tuple '''
        (r, g, b) = self.rgb2posercol((r, g, b))
        return tuple(colours.rgb_to_hsv((r, g, b)))

    def rgb2posercol(self, rgb):
        ''' convert (R, G, B) to Poser Notation '''
        return tuple([x/255.0 for x in rgb])#

    def posercol2html(self, col_tuple):
        ''' convert Poser Notation to HEX '''
        return self.rgb2htmlcolor(col_tuple)

    def rgb2htmlcolor(self, rgb_tuple):
        ''' convert (R, G, B) to Hex '''
        return '#%02x%02x%02x'.upper() % rgb_tuple

Locked Out


structure posted Fri, 03 June 2022 at 12:19 PM Forum Coordinator

Toggle lock keys  * WINDOWS 

importable script: ( I saved this in lib/site-packages under folder _toggle_keys)

from ctypes import windll
from win32con import VK_CAPITAL, VK_NUMLOCK, VK_SCROLL
from win32api import GetKeyState


TEST_STATUS = False
# toggle status is binary 0/1 - on/off


class KEY_SYSTEM:
    def toggle_key(self, key, turn_on=0):
        '''
        toggle_key(int) ->  int

        Turns key on or off and returns whether
        it was originally on or off.        '''

        KEYEVENTF_KEYUP = 2
        KEYEVENTF_EXTENDEDKEY = 1
        KEYEVENTF_KEYUP = 2

        is_on = GetKeyState(key) & 1

        if is_on != turn_on:
            windll.user32.keybd_event(key,
                                      69,
                                      KEYEVENTF_EXTENDEDKEY | 0,
                                      0)
            windll.user32.keybd_event(key, 69,
                                      KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
                                      0)
        return is_on

    def get_key_status(self, key):
        # key must be one of the following integer values - 20, 144, 145
        return None if key not in [20, 144, 145] else GetKeyState(key)


script to import and run:

from _toggle_keys import KEY_SYSTEM as toggle
keys = {20: "CAPS",
        144: "NUM",
        145: "SCROLL", }

for k in keys:
    OFFON = toggle.get_key_status(None, k)

    toggle.toggle_key(None, k, not(OFFON))
    print(f"{keys[k]}_LOCK is off", end="\n\n") if OFFON else print(
        f"{keys[k]}_LOCK is on", end="\n\n")

if __name__ == "__main__":
    for k in (20, 144, 145):
        # turn off/on key lock 0 = off, 1 = on
        KEY_SYSTEM().toggle_key(k, not(KEY_SYSTEM().get_key_status(k)))

Locked Out


structure posted Fri, 03 June 2022 at 12:57 PM Forum Coordinator

getting single characters from keystrokes and building a string from them * WINDOWS

from msvcrt import getche
from _toggle_keys import KEY_SYSTEM as toggle
from importlib import util

FOUND = util.find_spec("rich") is not None
if FOUND:
    from rich import print

hex_string = '0123456789ABCDEF'
chars = "#"
if not toggle.get_key_status(None, 20) == 1:
    toggle.toggle_key(None, 20, 1)  # turn off/on caps lock 0 = off, 1 = on

# getche displays characters as they are typed, getch does not display them
print("Incorrect hex characters will be substituted with a zero (0).")
print(f"Enter Your Hex Value (from {hex_string}) {chars}", end=" : ")
for x in range(1, 7):
    char = str(getche().decode('utf-8')).upper()
    chars += "0" if not char in hex_string else char

if not toggle.get_key_status(None, 20) == 0:
    toggle.toggle_key(None, 20, 0)  # turn off/on caps lock 0 = off, 1 = on

ps = f"[{chars}]" if FOUND else ""

print(f"\n\nYour Selected Color : {ps}{chars}\n")

Locked Out