Sat, Nov 23, 12:49 PM CST

Renderosity Forums / Poser Python Scripting



Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Sep 18 2:50 am)

We now have a ProPack Section in the Poser FreeStuff.
Check out the new Poser Python Wish List thread. If you have an idea for a script, jot it down and maybe someone can write it. If you're looking to write a script, check out this thread for useful suggestions.

Also, check out the official Python site for interpreters, sample code, applications, cool links and debuggers. This is THE central site for Python.

You can now attach text files to your posts to pass around scripts. Just attach the script as a txt file like you would a jpg or gif. Since the forum will use a random name for the file in the link, you should give instructions on what the file name should be and where to install it. Its a good idea to usually put that info right in the script file as well.

Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: How to fetch the full os.path of a CurrentFigure ?


HartyBart ( ) posted Sun, 27 December 2020 at 3:32 PM · edited Thu, 21 November 2024 at 5:01 AM

I'm thinking of how to make a simple scripted variant of Poser's existing "Show in Explorer" Content Library functionality.

But in this case, instead of opening the Character path to the CR2, Explorer would instead open the relevant Pose folder path. The script would thus enable the user to quickly seek the figure's missing PZ2 MATs. An example vendor is 1971s, where many of his early models load without textures, and the user has to go seeking the MAT files over in the Poses folder.

How it might work:

  1. The script fetches the full os.path of the CurrentFigure in the scene.

  2. The CurrentFigure source is then known to be located at...

               "RuntimeLibrariesCharacterHouse on suburbHouse.cr2"
    
  3. Therefore, try to open the equivalent Pose folder in Explorer...

               "RuntimeLibrariesPoseHouse on suburb"
    

Is it possible for a script to fetch the full path of a Figure, once it is loaded to the Poser scene?



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


structure ( ) posted Sun, 27 December 2020 at 3:42 PM · edited Sun, 27 December 2020 at 3:46 PM
Forum Coordinator

to my knowledge, you would have to index your runtime folders and store a readable index file ( unless you want to index every time you load the script).

I find this is easiest using json as it dumps a dictionary structure to disk, so you could have the script build a dictionary:

something along the lines of

{ "suburbhouse" : ( "runtimelibrariesCharacterHousesuburbhouse.cr2", "runtimelibrariesPoseHousesuburbhouse.cr2" ) } 

this method will store an alias, the path to the aliased cr2 and the path to the pose folder.

{ "suburbhouse" : (  "runtimelibrariesPoseHousesuburbhouse.cr2" ) }

this method stores the alias and the pose, you would need a second dictionary for the alias and the cr2 and you would need to cross-reference them.

Locked Out


structure ( ) posted Sun, 27 December 2020 at 4:17 PM · edited Sun, 27 December 2020 at 4:22 PM
Forum Coordinator

something like this might work for creating your index


import json
import os.path
import poser

class _data_class:
    def save_data( self, file, db ):
        if file:
            if len( db )>0:
                with open( file, 'w') as f:
                    json.dump( db, f, indent=2 ) 

    def load_data( self, file ):
        if file:
            try:
                with open( file, 'r' ) as f:
                    return json.load( f )
            except:
                return None

exts = ( ".cr2",".crz" )
cross_ref_Dict = {}

for library in poser.Libraries():
    library = os.path.join( library, "Runtime", "Libraries" )
    for root, folders, files in os.walk( library ):
        for file in files:
            file = os.path.join( root, file ) 
            if "Character" in file.title():
                if file.endswith( exts ):
                    path1 = file
                    path2 = os.path.dirname(file.replace( "character".title(), "Pose" ))
                    alias = os.path.splitext(os.path.basename( file ))[0]
                    if alias and path1 and path2:
                        if not alias in list( cross_ref_Dict.keys() ):
                            cross_ref_Dict.update( { alias : (path1, path2) } )

if len(cross_ref_Dict.keys()) > 0:
    _data_class().save_data( database_filepath, cross_ref_Dict )

if os.path.exists( database_filepath ):
    cross_ref_Dict = _dataclass().load_data( database_filepath )

if len( cross_ref_Dict.keys() ) > 0:
    for key in cross_ref_Dict.keys():
        print( key, cross_ref_Dict[key] )

Locked Out


HartyBart ( ) posted Sun, 27 December 2020 at 4:26 PM

Thanks, so it sounds like it's not, at least not the way I had hoped. But further testing just now reveals a Utility script I assume ships with Poser. CollectSceneInventory.py can print a list of scene items with their full OS paths. In this test case, printed is:

      C:|.._blahblah_..|content|Runtime|Geometries|1971s|House on suburb|House.obj

It then seems like one might edit down this script to print out only the OBJ that has just been loaded (textureless) into the new scene. The script would then cut off the House.obj filename and in the path would switch...

      |Geometries|1971s| 

for

      |Libraries|Pose|

This, in 1971s's case at least, would then be a full working path for Explorer to open.



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


HartyBart ( ) posted Sun, 27 December 2020 at 5:49 PM

Here's my working cut-down of the much larger CollectSceneInventory.py - my testing shows it prints the full OS path for just the OBJ(s) in the current Poser scene.

workingcutdown.jpg

Now, how to constrain it to just the currently selected figure, and have the script operate on the path - and then launch Windows Explorer with that new path?



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


FVerbaas ( ) posted Wed, 30 December 2020 at 1:51 PM · edited Wed, 30 December 2020 at 1:57 PM
Forum Coordinator

You cannot find the .cr2 file (never understood why but that is Poser). You appear to be looking for the refrerenced geometry file.

A snippet from MDBridge for Poser, returning the geometry file of the currently setected figure. geomfile should be what you are looking for.

#
#------------------------------------------
# First check if the current actor is a body part or and actual figure
#------------------------------------------
if scene.CurrentActor().IsBodyPart(): 
   fig = scene.CurrentActor().ItsFigure()
elif scene.CurrentActor().IsFigure():
   fig = scene.CurrentFigure()
else:
   fig = None

if not fig is None: 
   geomfile = fig.GeomFileName()
   gf = os.path.basename(geomfile)


HartyBart ( ) posted Sat, 02 January 2021 at 7:08 AM · edited Sat, 02 January 2021 at 7:15 AM

Thanks, FVerbaas, you set me on the right path to making a working script that does what I want. Thanks also to Structure for the indexer. Here is my full script, a bit gnarly - but it works for many figures that come in without textures, and where the MATS or textures then need to be found. Any further advice is welcome. I assume it is not possible for a Python script to control the current location in the Poser Library? That would offer an alternative to launching Windows Explorer.

final-working.jpg



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


HartyBart ( ) posted Sun, 03 January 2021 at 12:00 PM

A better reworked version of the above script. I think I'm starting to understand how these mindbending if / else / elif chains work now! :) I've also made a working 'CR2 finder' for FVerbaas.

v2.jpg



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


HartyBart ( ) posted Sun, 03 January 2021 at 12:03 PM

A working 'CR2 finder' script for FVerbaas, who mentioned it was a gap in what Poser could do. Again, its 'early days' here, and any advice is welcome.

workingcr2.jpg



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


FVerbaas ( ) posted Tue, 05 January 2021 at 9:00 AM
Forum Coordinator

Thank you HartyBart.

Your script will be helpful in many cases.

My remark about Poser was mainly addressing the absence of a sort of log of library items opened. We now only have full deep copy even if we only do 'posing' and make no changes to content loaded. I sometimes would appreciate a small 'inventory' in the vein used in the descriptions in the gallery: "Project Evolution Shoona girl character, 70s Rockabilly Hair, BASHIR, EasyPumps" that I can save with my rendered image in case I ever want to make something similar. Yes I can do that manually but no I admit that may never happen.


HartyBart ( ) posted Sat, 16 January 2021 at 5:52 PM

My pleasure. If you've happy with the working (but not ideal) code, then I will try to bundle these into a package for the Renderosity Freestuff. With suitable warnings to users.

The saved filename for the scene seems to be the best option, for storing such useful library information. And in such a way as it cannot then be lost. Such as:

PE_Shoona_with_70s_Rockabilly_Hair_and_BASHIR_EasyPumps_posed_with_Gel004_light.pz3

Could not a script use some of the methods shown above, to pluck out the names of the items in the scene, combine these, and then save the scene with that combined super-name? Though, as you hint, it may be that the in-scene name is not always quite the same as the name used by the Library item.



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


FVerbaas ( ) posted Sun, 17 January 2021 at 11:33 AM · edited Sun, 17 January 2021 at 11:38 AM
Forum Coordinator

Length of paths is limited and I for example mostly do not save scene files. Could use this for rendered images of course, but then I prefer to name these by a sort of title appropriate to the image rather than by a list of the components used to make it. Could be stored in the exif data of the image files. Most image file formats have such facility.

I have been thinking more about a sort of metadata management system:

  • adding a StartUpScript to a scene that will open a .py file that imports a PoserLogger module and defines the directory of loaded library items
  • PoserLogger adding a callback function that will write that .py file when the scene is closed
  • PoserLogger adding a callback function that will add any loaded library files to the list (Info is already in the Poser log file but that info cannot be assessed from Python and it does not give the path names)

I concluded there would be a few problems though:

  • LoadLibrary Figure and its siblings do not even report if a load was successful, and the filename is not available unless I wrap scene.LoadLibraryFigure and find a way to ensure that my wrapper is called and not the original method.
  • This list would hold all library files loaded during the development of the scene. It would not automatically be pruned.
  • same holds for adding the metadata to the image files. Would have to wrap SaveImage()

Wrapping standard functions is a prescription for trouble of course. Guess this idea will have permanent residence in onedayland.


HartyBart ( ) posted Mon, 18 January 2021 at 8:04 PM

I'm told that Renderosity can now only test Freestuff Python scripts with Poser 12. This effectively means that no Poser 11 Python script will ever again pass Freestuff testing, if it is even slightly sophisticated. I assume the same will also apply to newly uploaded commercial Python scripts for the Store.

The alternative for both free and paid Poser 11 scripts is then ShareCG. I've thus uploaded the above bundle of scripts to ShareCG as 'Find It'. Between them, the three scripts cover the automated finding of OBJ, CR2 and MATS/Poses. 'Find It' is now showing in the main Poser category there.



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


HartyBart ( ) posted Mon, 18 January 2021 at 8:21 PM

FVerbaas, yes, it's a thorny problem. A step-by-step macro recorder might help, similar to Photoshop's record/replay Actions system. The resulting recording, if human-readable as a simple one-step-per-line text file, would at least be a memory-jogger - even if perhaps no longer practical as a 'do it again, this time automatically' replay script. But perhaps I'm actually describing the PoserLogger? I can find no trace of anything under that name. Is it internal in Poser and undocumented, or one of your own creations?



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


adp001 ( ) posted Tue, 19 January 2021 at 8:45 AM

HartyBart posted at 8:32AM Tue, 19 January 2021 - #4410678

I'm told that Renderosity can now only test Freestuff Python scripts with Poser 12. This effectively means that no Poser 11 Python script will ever again pass Freestuff testing, if it is even slightly sophisticated. I assume the same will also apply to newly uploaded commercial Python scripts for the Store.

What's the probem with this?

Python scripts can be written to run with P11 and P12. Python 2 scripts are dead. Relics of a bygone century.

Just write a few lines at the top of your script and you are good to go:

from __future__ import print_function, division

And if you use "basestring" (to avoid problems with utf-8 strings in Python 2.7, as I do):

import sys
if sys.version_info.major > 2:
    basestring = str

And use a modern Python editor able to notify you if you use libs or a syntax not compatible with Python 3. There is always a way around possible errors.




adp001 ( ) posted Tue, 19 January 2021 at 8:51 AM

I write all my code with an editor with enabled syntax checking for Python 3.8. The scripts I write work well with P11. And the newer ones will run with P12 too.




FVerbaas ( ) posted Tue, 19 January 2021 at 11:49 AM
Forum Coordinator

HartyBart posted at 11:36AM Tue, 19 January 2021 - #4410680

But perhaps I'm actually describing the PoserLogger? I can find no trace of anything under that name. Is it internal in Poser and undocumented, or one of your own creations?

'PoserLogger' was indeed the name I dreamed up for the system. LOL! Again the idea is to keep track of the 'ingredients' used, to support fading memories, for crediting when publishing or later building 'something similar'. A script to regenerate the scene was not the idea.


adp001 ( ) posted Tue, 19 January 2021 at 12:26 PM

FVerbaas posted at 12:22PM Tue, 19 January 2021 - #4410728

'PoserLogger' was indeed the name I dreamed up for the system. LOL! Again the idea is to keep track of the 'ingredients' used, to support fading memories, for crediting when publishing or later building 'something similar'. A script to regenerate the scene was not the idea.

With a script written as an add-on you are able to get some information:


class SceneObserver:
    def objectsAdded(self, objects):
        pass
    def objectsDeleted(self, objects):
        pass    
    def objectsRenamed(self, objectsOldNames):
        pass    
    def objectsInternalRenamed(self, objectsOldInternalNames):
        pass
    def objectSelected(self, selection):
        pass
    def sceneDeleting(self, scene):
        pass
    def sceneCreated(self, scene):
        pass
    def frameChanged(self):
        pass
    def materialsChanged(self, materials):
        pass
    def cameraChanged(self): 
        pass
    def lightsChanged(self):
        pass

After one of those events occure you have to dig for further information.




FVerbaas ( ) posted Tue, 19 January 2021 at 2:11 PM
Forum Coordinator

adp001 posted at 1:57PM Tue, 19 January 2021 - #4410732

With a script written as an add-on you are able to get some information:

That would be the mechanism, yes. Problem is Python can only see the inside, after the load. We have come some way since any figure would be named 'figure', but still it is fragile beause content providers are, how shall I put it 'creative' in naming.
I would want to record which file was loaded, because that is what I will need if I want to make 'something similar' or answer a question about how I made it.


HartyBart ( ) posted Sun, 31 January 2021 at 5:57 AM

Thank for all your help on this. The three finished scripts are now on Freestuff as "Find It", as Renderosity either found a Poser 11 tester or let them on anyway. These three scripts don't seem to have blown up anyone's PC yet, and several people have said elsewhere that they're useful.

Yes, for my bodging together future scripts it would be nice to have an auto-assistant that flags obvious errors, re: Python 3. I've been looking for such a thing for Notepad++. I don't yet have Poser 12 as a native testing environment.



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


adp001 ( ) posted Sun, 31 January 2021 at 8:11 AM

Notepad++ is a popular tool, I know. However, it's not exactly a Python development tool, it's more like an egg-laying pig in a poke.

You would simplify your life as a Python developer a lot if you used a dedicated editor. Something like PyCharm or VS Code. Whereby Pycharm - subjectively - is the better choice.

You don't even have to learn much new stuff. In the beginning actually nothing at all. Just start it, type in the code and save it. Like Notepad. If you then use my tool (POSER_FAKE), developing scripts for Poser becomes a piece of cake. Especially with PyCharm. PyCharm also alerts you to incompatibilities between Python versions if you have specified multiple Python versions.

As I wrote several times here: pyCharm for Python is available as open source version for free (no restrictions and regular updates): https://www.jetbrains.com/pycharm/




HartyBart ( ) posted Sun, 31 January 2021 at 11:09 AM · edited Sun, 31 January 2021 at 11:13 AM

Thanks. Yes I had spent an hour this morning trying to discover the right tool.

Microsoft Visual Code looked the best in the end, but seemed to have one too many dependencies. Its support for Python 2 autosuggest etc also appears to be on the way out (its Jedi module "is expected to be the last release to support Python 2.7").

Sublime Text also looked interesting and is said to be popular, but... $80(!) and which version to use... 2, 3, or 4? Looks pretty, but not really viable in terms of cost.

So thanks for the PyCharm suggestion. Looks nice. Downloading now (350Mb!). Once installed it appears to have the ability to go get the Python installs needed for debugging, which is useful as it presumably gets the right ones and knows where to install them. The clear support pages for newbies are also encouraging and current...

https://www.jetbrains.com/help/pycharm/configuring-python-interpreter.html

https://www.jetbrains.com/help/pycharm/migrating-from-text-editors.html



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


HartyBart ( ) posted Sun, 31 January 2021 at 12:06 PM

Ah well, so much for the automatic install of Python. I had to go get Python 2.7 and 3.7 manually and then tell PyCharm where they were. And then it would not allow me use Python 2.7, only the latest 3.x. Its other and major problem is the incredibly sluggish interface... sooo sloooowwww, compared to Notepad++. No, sorry... uninstalled. I shall try Microsoft Visual Code instead.



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


HartyBart ( ) posted Sun, 31 January 2021 at 1:13 PM

Ah, this is more like it. I've now installed Microsoft Visual Code + its Python helper module(s). A super-quick loadup and also a silky-smooth UI responsiveness. No problem adding the Python module or either of the Python locations on Windows. Easy switching between them, too. It also auto-prompted for download of a few Python helper modules and dependencies, which happened inside the UI. It also has editor color themes, which can be browsed and downloaded inside the UI. "Nord" and "Darktooth" are pleasing color themes, but I settled on "Choco Dark" which is similar to what I have on Notepad++. All I will have to be careful about is upgrading, re: the likely future inability of a Python autocomplete module to handle Python 2.7.



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


adp001 ( ) posted Sun, 31 January 2021 at 1:30 PM

:)

I have none of the trouble you described. Not one. But I'm using PyCharm with Linux, not Windows. Installing was easy as "apt install pycharm" - with all features included. Runs really fast, even on my somewhat older laptop with an I5 :)

I use VS-Code for C++ and Javascript. Spoiled by PyCharm, VS-Code feels pretty damn rough. Cluttered, messy, untidy. It works for C++, but with Python I find it very cumbersome to work with. But maybe it's just me...

I use Windows software like Poser and DAZ only in a virtual machine running under Linux. So not much Windows experience here.




HartyBart ( ) posted Sun, 31 January 2021 at 2:28 PM · edited Sun, 31 January 2021 at 2:28 PM

Thanks, I've found POSER_FAKE .zip, and also its required code to add to the top of testing scripts...

try:
    import poser
except ImportError:
    import POSER_FAKE as poser

There's no information to be found on where the .zip contents should be copied to on the PC's hard-drive, in order to work with Visual Code Studio. But POSER_FAKE appears to work when both files are copied into...

..|AppData|Local|Programs|PythonPython37|Lib

and also

..|Python27|Lib

The user of Visual Code Studio then gets in-script tooltips suited to PoserPython, when using either Python 2.7 or 3.7, and can also choose to hold down Ctrl to see a bit more. Or for the full list can right-click on a bit of PoserPython code and get the Definition, along with adjacent other definitions.

Is there more that I'm missing, in terms of the POSER_FAKE functionality?



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


HartyBart ( ) posted Sun, 31 January 2021 at 2:35 PM · edited Sun, 31 January 2021 at 2:36 PM

A screenshot of the latest Visual Code Studio, with the Choco Dark color theme, feeling very easy and Notepad++ like for me (that's a good thing). I turned off the default basic Python linting, as it didn't seem to be very useful for PoserPython.

vcs.jpg



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


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.