Re: Dynamic Class Creation

2010-04-02 Thread Aahz
In article <8d79f0cb-9c5b-4243-8891-a15fb311f...@z18g2000prh.googlegroups.com>,
Josh English   wrote:
>
>
>Analog Science Fiction and Fact
>Analog
>Science Fiction
>First Contact
>Hard Science Fiction
>
>Stanley Schmidt, Editor
>267 Broadway, 4th Floor
>New York, NY 10007-2352
>
>http://www.analogsf.com
>
>
>A child element with text and an attribute or two, for example, pose a
>problem. I can call Market.title but should I try Market.title.field
>or Market.title_field.
>
>Multiple elements, such as keywords, are allowed in xml but harder to
>map to the object. I don't know if I want to go create a list and
>methods for accessing those keywords as a list, or redefine the rules
>of my XML to not allow multiple child elements with the same tag. I
>can't decide.

You should always think "LIST!" any time you have the potential for
multiple elements with the same semantic tag.  Whether you do it as a
list for all elements or as a combo dict/list is something you need to
decide; the latter is faster in many ways but is more cumbersome:

Market.title.keyword[1]

(Instance attributes and dict keys are almost trivially convertible.)

You would probably get some mileage out of looking at the ElementTree
implementation.
-- 
Aahz (a...@pythoncraft.com)   <*> http://www.pythoncraft.com/

Why is this newsgroup different from all other newsgroups?  
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Dynamic Class Creation

2010-03-17 Thread Gerard Flanagan

Josh English wrote:

Chris,

Thanks. This worked for the attributes, but I think the tactic is
still misleading. There are child elements I can't quite determine how
to deal with:


Analog Science Fiction and Fact
Analog
Science Fiction
First Contact
Hard Science Fiction

Stanley Schmidt, Editor
267 Broadway, 4th Floor
New York, NY 10007-2352

http://www.analogsf.com


A child element with text and an attribute or two, for example, pose a
problem. I can call Market.title but should I try Market.title.field
or Market.title_field.

Multiple elements, such as keywords, are allowed in xml but harder to
map to the object. I don't know if I want to go create a list and
methods for accessing those keywords as a list, or redefine the rules
of my XML to not allow multiple child elements with the same tag. I
can't decide.

Then the address is a bit of a bear.

In short, I have to figure out the whole object interface to the XML
and how I want that to work.




Have you heard of or considered PyXB (http://pyxb.sourceforge.net/)? Not 
that I've much experience with it, but you can use it to generate python 
code from XML Schema files, and, I think, WSDL definitions. It's a bit 
of a rabbit hole, but then isn't that half the fun!


The following might give you the idea. You start with a Schema 
schema.xsd, generate a python module from it, then read in some XML with 
the generated classes to get your custom objects.



 schema.xsd --

http://www.josh.com/schema/0.1";
xmlns:xs="http://www.w3.org/2001/XMLSchema";
xmlns:josh="http://www.josh.com/schema/0.1";>








maxOccurs="unbounded"/>

































minOccurs="0"/>
minOccurs="0"/>

















 genbindings.sh ---

#!/bin/sh

pyxbgen -u schema.xsd -m market_binding -r

 demo.py ---

s = """
http://www.josh.com/schema/0.1";
code="anlg"
tier="ProMarket"
mail="True">

Analog Science Fiction and Fact
Analog
Science Fiction
First Contact
Hard Science Fiction

Stanley Schmidt, Editor
267 Broadway, 4th Floor
New York

http://www.analogsf.com

"""

import xml.dom.minidom
import market_binding

market = 
market_binding.CreateFromDOM(xml.dom.minidom.parseString(s).documentElement)


print market.tier
print market.code
print market.keyword
assert len(market.keyword) == 3
print market.address.name
print market.toxml()



--
http://mail.python.org/mailman/listinfo/python-list


Re: Dynamic Class Creation

2010-03-16 Thread Josh English
Chris,

Thanks. This worked for the attributes, but I think the tactic is
still misleading. There are child elements I can't quite determine how
to deal with:


Analog Science Fiction and Fact
Analog
Science Fiction
First Contact
Hard Science Fiction

Stanley Schmidt, Editor
267 Broadway, 4th Floor
New York, NY 10007-2352

http://www.analogsf.com


A child element with text and an attribute or two, for example, pose a
problem. I can call Market.title but should I try Market.title.field
or Market.title_field.

Multiple elements, such as keywords, are allowed in xml but harder to
map to the object. I don't know if I want to go create a list and
methods for accessing those keywords as a list, or redefine the rules
of my XML to not allow multiple child elements with the same tag. I
can't decide.

Then the address is a bit of a bear.

In short, I have to figure out the whole object interface to the XML
and how I want that to work.

Thanks for the suggestion. It is undeniably clever.

Josh
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Dynamic Class Creation

2010-03-16 Thread Chris Rebert
On Tue, Mar 16, 2010 at 9:49 AM, Jack Diederich  wrote:
> On Tue, Mar 16, 2010 at 2:18 AM, Chris Rebert  wrote:
>> On Mon, Mar 15, 2010 at 11:01 PM, Josh English
>>  wrote:

>>> What's the best way to create these helper methods?
>
> You can either define a catch-all __getattr__ method to look them up
> dynamically, or as Chris kinda-suggested write descriptors for the
> individual elements.
>
> class Market():
>  def __init__(self, elem):
>    self._elem = elem
>  def __getattr__(self, name):
>    try:
>      # I'm assuming this raises a KeyError when not found
>      return self._elem.get(name)
>    except KeyError:
>      return self._elem.find(name)
>  def __setitem__(self, name, value):

did you mean __setattr__ here?


> The getattr/setattr method is easier to understand and will handle
> arbitrary elements;  for the descriptors version you'll have to define
> one for each tag that might be used on the class.

Cheers,
Chris
--
http://blog.rebertia.com
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Dynamic Class Creation

2010-03-16 Thread Jack Diederich
On Tue, Mar 16, 2010 at 2:18 AM, Chris Rebert  wrote:
> On Mon, Mar 15, 2010 at 11:01 PM, Josh English
>  wrote:
>> I have a large program with lots of data stored in XML. I'm upgrading
>> my GUI to use ObjectListView, but with my data in XML, I don't have
>> regular objects to interact with the OLV. I do have an XML validator
>> that defines the structure of the XML elements, and I'm trying to
>> dynamically create a class to wrap the XML element.
>>
>> So, an element like:
>>
>> 
>> Writers of the Future
>> 
>>
>> I want to create a class like:
>>
>> class Market(object):
>>    def __init__(self, elem):
>>        self._elem = elem
>>
>>    def get_code(self):
>>        return self._elem.get('code')
>>
>>    def set_code(self, value):
>>        self._elem.set('code', value)
>>
>>    def get_title(self):
>>        return self._elem.find('title').text
>>
>>    def set_title(self, value):
>>        node = self._elem.find('title')
>>        node.text = value
>>
>> Naturally, I don't want to hand code this for every interface but
>> would like to create them dynamically. (The laziness of programming, I
>> guess.)
>>
>> What's the best way to create these helper methods?

You can either define a catch-all __getattr__ method to look them up
dynamically, or as Chris kinda-suggested write descriptors for the
individual elements.

class Market():
  def __init__(self, elem):
self._elem = elem
  def __getattr__(self, name):
try:
  # I'm assuming this raises a KeyError when not found
  return self._elem.get(name)
except KeyError:
  return self._elem.find(name)
  def __setitem__(self, name, value):
 # like __getitem__ but for setting

Chris' property maker function is almost like a descriptor class (how
properties are implemented under the hood), here's a refactoring
[untested]

class ElemGetProperty():
def __init__(self, name):
  self.name = name
def __get__(self, ob, cls):
  return ob._elem.get(self.name)
def __set__(self, ob, val):
   ob._elem.set(self.name, val)

You could write one property class for each kind of element (get/find)
and then put them in your class like this

class Market():
code = ElemGetProperty('code')
title = ElemFindProeprty('title')

The getattr/setattr method is easier to understand and will handle
arbitrary elements;  for the descriptors version you'll have to define
one for each tag that might be used on the class.

-Jack
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Dynamic Class Creation

2010-03-15 Thread Chris Rebert
On Mon, Mar 15, 2010 at 11:01 PM, Josh English
 wrote:
> I have a large program with lots of data stored in XML. I'm upgrading
> my GUI to use ObjectListView, but with my data in XML, I don't have
> regular objects to interact with the OLV. I do have an XML validator
> that defines the structure of the XML elements, and I'm trying to
> dynamically create a class to wrap the XML element.
>
> So, an element like:
>
> 
> Writers of the Future
> 
>
> I want to create a class like:
>
> class Market(object):
>    def __init__(self, elem):
>        self._elem = elem
>
>    def get_code(self):
>        return self._elem.get('code')
>
>    def set_code(self, value):
>        self._elem.set('code', value)
>
>    def get_title(self):
>        return self._elem.find('title').text
>
>    def set_title(self, value):
>        node = self._elem.find('title')
>        node.text = value
>
> Naturally, I don't want to hand code this for every interface but
> would like to create them dynamically. (The laziness of programming, I
> guess.)
>
> I have tried several solutions that I found on various forums, but
> they are all several years old.
>
> Questions:
>
> What's the best way to create these helper methods?

Nested functions:

def make_attr_getset(name):
def get(self):
return self._elem.get(name)

def set(self, value):
self._elem.set(name, value)
return get, set

get_code, set_code = make_attr_getset('code')

def make_subelement_getset(name):
def get(self):
return self._elem.find(name).text

def set(self, value):
node = self._elem.find(name)
node.text = value
return get, set

get_title, set_title = make_subelement_getset('title')

> How can I attach them to the class and have it run?

Use properties and setattr():

class Market(object):
def __init__(... #same as before

setattr(Market, 'code', property(get_code, set_code))
setattr(Market, 'title', property(get_title, set_title))

m = Market(the_XML)
print m.title #=> Writers of the Future
m.title = "Writers of the Past"
print m.code #=> WotF
m.code = "WofP"

Cheers,
Chris
--
http://blog.rebertia.com
-- 
http://mail.python.org/mailman/listinfo/python-list