python-ogre 0.90's new iterators

deficite

14-03-2007 22:02:25

I've been tinkering with the little clue of the new iterators given in the highlights of the 0.90 release but I can't figure them out. I can iterate over the sections just fine, but I can't figure out how to get what the section's name is. If somebody can give me an example of loading a resources.cfg file with the new iterators it'd be greatly appreciated.

andy

14-03-2007 23:27:34

You've picked an example where you really need to use the C++ styles access as you don't really want to "iterate" through the values, instead you want access to the "keys" and "values".

My test program looks like:
config = Ogre.ConfigFile()
config.load('resources.cfg' ) #, '', False )
### Note we have to use the C++ access to the iterator as we need access to the 'KEY' value
### if we use the python iterator style (for x in iter:) we only get the value
iter = config.getSectionIterator()
while iter.hasMoreElements():
SectionName = iter.peekNextKey()
Section = iter.getNext()
for item in Section:
print SectionName, item.key, item.value

Where as my iterator tests are like:
for reg in s.getRegionIterator(): ##
for lod in reg.getLODIterator():
for mat in lod.getMaterialIterator():
for geom in mat.getGeometryIterator():
print "Iterators:", reg, lod, mat, geom

Part of this is due to the fact that Ogre Iterators are implemented as helper functions, and are not necessarly complete C++ iterators

Cheers
Andy

Game_Ender

15-03-2007 00:54:15

Then maybe our wrapping should be a bit more robust? Its standard python style to do:

d = {1 : 'b', 2 : 'c', 3 : 'd' }
for key, value in d.iteritems():
print key,' : ',value


Maybe we should change the names to more like the standard python dict API. Something like this:
  1. Iterate over Region Values: iterRegions() (or iterRegionValues())[/*:m]
  2. Iterate over Region Names: iterRegionNames() (or iterRegionKeys() [/*:m]
  3. Iterate over a tuple of both: iterRegionPairs() (or iterRegionItems())[/*:m][/list:u]The ones in parenthesis are more like the Dict object method names, but the first one will be more in keeping with the Ogre API.

deficite

15-03-2007 06:43:18

Andy, have you read the 0.90 release highlights? It says you can use (somewhat) Pythonic iteration (as in "for item in blah.getBlahIterator()) as of 0.90. I already know how to do it in the C++ fashion in python and in C++ (I started using Ogre with C++ and I still do)

Game_Ender: I know what standard python style is. This is what's confusing me. Whenever I do something like this:
for i in rc.getSectionIterator():
blah
blah
blah

"i" contains a SettingsMultiMap which has keys and values for a section in the resources.cfg file. So I can get all the values I need, but I don't know the name of the section needed for the third parameter of the addResourceLocation function. In the C++ way you get this from peekNextKey(). I just need a simple way to find what "i"'s section name is, such as "Bootstrap"

andy

15-03-2007 07:41:09

Andy, have you read the 0.90 release highlights? It says you can use (somewhat) Pythonic iteration (as in "for item in blah.getBlahIterator()) as of 0.90.
Dare I admit that I wrote the release highlights and helped with the iterator implemention (for better or worse) so let me answer your question as best I can (and once we get a 1.0 release out I promise to spend more time on docs :? )

These notes are from my memory and are quite possibly wrong :oops: so any comments are welcome...

The iterators in Ogre are implemented in C++ either as Maps (key/value) or Vectors (value list). They don't support random access, only forward iteration,which makes Ogre Map iterator different to iterating over a Python "dictionary"

Implementating Vector iterators was easy - they simply return a list of objects so
for x in i:
....

Map iterators don't work like this - and to make the "ConfigFile" example work I would have to return a tuple with key,value which would mean any python code that iterators over a Map would read
for x,y in i:
...

hence the python code becomes different based upon the underlying C++ structures (ugly) and apart from the ConfigFile I didn't see any other examples in the C++ demos/samples where this was done. There are plenty of iterations over Map objects, but only the value is being used, not the key.

So - I decided to keep things "simple and consistant", and implemented iterators in a fashion that only returns the value, regardless of the underlying iterator type.. Knowing that if you really want the key then the C++ access method is fairly simple ..

I did consider always returning a tuple, with the first items being the value, so vector iterators return a tuple with a single value, map iterators have 2 values (value, key) - however this makes the python code ugly (IMHO)

Fundementally I didn't want different Python code depending upon the specific Ogre Iterator implementation - subject to change if need be :D

Cheers
Andy

deficite

15-03-2007 21:17:52

I hope I didn't come off as offensive in my writing (as well as the fact that I didn't realize you wrote those highlights, lol)

I still don't understand what the hell is going on with those highlights, but I'm going to ignore it and just use the C++ fashion for now. I loved how PyOgre handled this:
for section, key, path in configFile.values:
ogre.ResourceGroupManager.getSingleton().addResourceLocation( path, key, section )

andy

16-03-2007 00:14:49

Ah... I think I understand better now -- and will make an effort to clarify the docs......

The question isn't really about iterator support but about the helper function that was in PyOgre to help with the ConfigFile..

The PyOgre team created their own "load" function which processed the resources file to a tuple (called values).. With Python-Ogre we are trying to expose the underlying C++ functions as best we can without any 'special' wrappers - this helps us with code maintainence and makes it easy to stay with the latest and greatest version of Ogre.

However there is nothing stopping you adding helper code to make conversion from PyOgre to Python-Ogre easier.

You could add the following code to your source and you'll get the same operation as PyOgre (or add it to the ogre __init__.py) -- although I personally think using the C++ interface (in this case) is cleaner.

This is the code from the original PyOgre module (and hence unsupported by the Python-Ogre team :) )..

class ConfigFile(_ogre_.ConfigFile ):
def load_special(self, filename):
""" this is code from the original PyOgre which some people might find useful
HOWEVER:: It bypasses Ogre's internal routines that are used to parse the resource
file, which means that if Ogre changes the resource.cfg format (unlikely I know)
then this code will need to be changed as well
"""
import re
section_re = re.compile(r"\[([a-zA-Z][a-zA-Z0-9_]*)\]")
self.values=[]

fp = file(filename, "r")
lines = fp.readlines()
fp.close()

section = ""
for line in lines:
line = line[:line.find("#")]

match = section_re.search(line)
if match is not None:
section = match.group(1)

else:
line = line.split("=")
if len(line) == 2:
self.values.append((section, line[0].strip(), line[1].strip()))

Cheers

Andy

deficite

16-03-2007 18:12:51

That wasn't really my question, but thanks for your time nonetheless. I'll just use the C++ fashion (I don't think I am articulating myself very well, I'm sorry for that)