473,320 Members | 2,029 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Call for suggestions: Declaring data entry forms using Pythonclasses

Hello all,

I'm posting this to the list with the intention to form a group of
people interested in this type of solution. I'm not going to spam the
list with it, unless for occasional and relevant announcements. If
you're interested, drop me a note. But if for some reason you think
that this discussion is fine here at the c.l.py, please let me know.

** LONG POST AHEAD **

I'm doing good progress on my form declarative language library. The
idea (for those who haven't read about it) is to be able to specify a
form declaration in the following format:

class ComplexForm(Form):
class Header(Form):
nickname = TextBox(length=15, default="")
password = TextBox(length=10, default="", password=True)
name = TextBox(length=40, default="")
class Comment(Form):
comments = TextBox(length=200, default="", multiline=True)

This is an experimental approach, with the intention to allow one to
write the form description in pure Python code, with the least
syntactic clutter possible. The main alternative is to use a data
driven approach -- feeding dicts or XML based representation to a
constructor -- but as I said, that's not the goal of this experiment.

I'm already able to properly build the example mentioned above. The
result is a conventional class filled with all attributes, and an
extra <_fields> member which is a ordered list of field object
instances. The metaclass constructor checks for some issues:

1) For the purposes of GUI description, field attributes are
order-dependant. But the dict passed to the metaclass constructor
isn't ordered. My first solution used stack information (using the
inspect module) to solve this problem. Thomas Heller and Andrew Dalke
proposed a simpler solution using a global counter that I've included
in the current incarnation (I'm wondering why did I try that hack
before, this solution is *much* better).

2) The inner classes (Header and Comment, in the example above) are
converted to *instances* of the same name during the construction of
the outer class (ComplexForm, in the example). The goal was to achieve
consistency; if some field members are classes and other instances,
then you have to check types while iterating the _fields structure to
render the GUI -- that's not what I had in mind.

Building GUIs

I'm just starting to work on this part. A renderer object will take
the form as a parameter, and will build the GUI accordingly with the
structure contained there.

To build the GUI, the renderer has to iterate over its fields. It's a
recursive process, because a form can contain other forms, either
declared directly as classes as in the example above, or through
normal attributes. I''m working on a generic iterator interface for
the form, which would allow to proceed without recursion on the
renderer side, but I'm not sure if this is the best approach. I'm
still thinkering with this part of the code. Suggestions are welcome.

#=======================
Enough talk, that's the code. Use it as you want, but please, give it
proper attribution if you're going to use it elsewhere.
#=======================

from inspect import isclass

# auxiliar functions

def getmyposition():
"""
Returns the position of the caller, relative to the sequence of
statements that were executed during class creation.

Three possible methods were evaluated: using a global counter; using
a timestamp; or using the line number retrieved from the call stack.
For all purposes here, a simple counter is enough. It doesn't need
to be thread aware, because all that matters is the relative
ordering of statements that, by definition, will be executed within
the same thread during the class initialization.
"""
counter = 0
while True:
counter += 1
yield counter

# decorates getmyposition to hide the internal static var
getmyposition = getmyposition().next

def getfields(dct):
"""
takes a dictionary of class attributes and returns a decorated list
containing all valid field instances and their relative position.
"""
for fname, fobj in dct.items():
if isinstance(fobj,Component):
print "found box: ", fname, fobj._mypos
yield (fobj._mypos, (fname, fobj))
elif isclass(fobj) and issubclass(fobj,Component):
print "found container: ", fname, fobj._mypos
# substitutes the contained class for its instance
yield (fobj._mypos, (fname, fobj()))
else:
print "unknown: ", fname, fobj, type(fobj)
# returns the original object with tag order = 0
yield (0, (fname, fobj))

def makefieldsdict(dct):
# build the field list and sort it
fields = list(getfields(dct))
fields.sort()
# undecorate the list and return it converted to dict; the _field
# attribute is added automatically to refer to the sorted list
sorted_field_list = [field[1] for field in fields]
field_dict = dict(sorted_field_list)
field_dict['_fields'] = [field for field in sorted_field_list
if isinstance(field[1],Component)]
return field_dict

# metaclasses

class Container(type):
def __new__(cls, name, bases, dct):
# creates the class using only the processed field list
newclass = type.__new__(cls, name, bases, makefieldsdict(dct))
newclass._mypos = getmyposition()
return newclass

# Component is the ancestor of all elements in a
# form, including containers and boxes

class Component(object):
pass

# BoxElement is the ancestor of all elements that are
# instantiated as objects inside the container classes

class Box(Component):
def __init__(self):
self._mypos = getmyposition()

# a form is a container of other components

class Form(Component):
__metaclass__ = Container
# I'm trying several versions of the iterator interface, I really don't
# know which one is going to be useful in real cases -- I'll have to write
# more code an try some alternatives first

def iterfields1(self):
# this iterator returns field objects without recursion
for fname, fobj in self._fields:
yield (fname, fobj)

def iterfields2(self, _level=0):
# this iterator recursively returns tuples of
# (parent, level, iscontainer, name, component)
for fname, fobj in self._fields:
if hasattr(fobj, '_fields'):
yield (self, _level, True, fname, fobj)
for parent, level, iscont, name, field in
fobj.iterfields2(_level=_level+1):
yield (parent, level, iscont, name, field)
else:
yield (self, _level, False, fname, fobj)

def iterfields3(self):
# this iterator returns a nested list representation that is
# built recursively
for fname, fobj in self._fields:
if hasattr(fobj,'_fields'):
yield (self, fname, list(fobj.iterfields3()))
else:
yield (self, fname, fobj)

# data entry controls

class TextBox(Box):
def __init__(self, length=40, default="", password=False, multiline=False):
Box.__init__(self)
self._length = length
self._default = default
self._password = password
self._multiline = multiline

# forms

class UserForm(Form):
nickname = TextBox(length=15, default="")
password = TextBox(length=10, default="", password=True)
name = TextBox(length=40, default="")

class ComplexForm(Form):
class Header(Form):
nickname = TextBox(length=15, default="")
password = TextBox(length=10, default="", password=True)
name = TextBox(length=40, default="")
class Comment(Form):
comments = TextBox(length=200, default="", multiline=True)
summary = TextBox(length=200, default="", multiline=True)

# simple test for the iterators
x = ComplexForm()
print
print "ComplexForm.iterfields1"
print "\n".join([str(item) for item in x.iterfields1()])
print
print "ComplexForm.iterfields2"
print "\n".join([str(item) for item in x.iterfields2()])
print
print "ComplexForm.iterfields3"
print "\n".join([str(item) for item in x.iterfields3()])
print
--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #1
5 2365
On Thu, 23 Sep 2004 13:36:19 -0300, Carlos Ribeiro <ca********@gmail.com> wrote:
Hello all,

I'm posting this to the list with the intention to form a group of
people interested in this type of solution. I'm not going to spam the
list with it, unless for occasional and relevant announcements. If
you're interested, drop me a note. But if for some reason you think
that this discussion is fine here at the c.l.py, please let me know.

No comment for now other than suggesting replacing pass with def __repr__ in

class Component(object):
def __repr__(self): return '<Comp %r>' % type(self).__name__

for a more userfriendly printout. Interesting stuff. I wonder about
one-dimensional position vs composing with various top/left/right/bottom/fill
aggregation indicator info etc.

Also wonder if just plain defining your own python-inspired but not python-constrained
language for expressing what you want to express might not be a viable alternative,
given the nice tools for language processing that are part of the open python kit.

IOW, you are using python in a certain way in order to be able to "spell" your
form-descriptions in a certain way. How would you spell them if you were not
constrained by python syntax?

Regards,
Bengt Richter
Jul 18 '05 #2
On 23 Sep 2004 19:53:37 GMT, Bengt Richter <bo**@oz.net> wrote:
On Thu, 23 Sep 2004 13:36:19 -0300, Carlos Ribeiro <ca********@gmail.com> wrote:
Hello all,

I'm posting this to the list with the intention to form a group of
people interested in this type of solution. I'm not going to spam the
list with it, unless for occasional and relevant announcements. If
you're interested, drop me a note. But if for some reason you think
that this discussion is fine here at the c.l.py, please let me know.
No comment for now other than suggesting replacing pass with def __repr__ in

class Component(object):
def __repr__(self): return '<Comp %r>' % type(self).__name__

for a more userfriendly printout. Interesting stuff. I wonder about
one-dimensional position vs composing with various top/left/right/bottom/fill
aggregation indicator info etc.


I'm doing stuff like this right now. My debug display was awful, it's
nicer after some __repr__() customization. I've also changed some
class names and moved the basic metaclass stuff in a module of their
own, called "metacontainer". It will make easier to reuse the basic
engine while I'm testing it.
IOW, you are using python in a certain way in order to be able to "spell" your
form-descriptions in a certain way. How would you spell them if you were not
constrained by python syntax?


I regard this as an experiment. I don't know if it will be successful
or not, but I have to try it first ;-). I have a hunch that it will be
more usable in the long run, even with all constraints imposed by
Python syntax, than to define yet another language.

BTW, one can think about the constraints as problems, but they have a
definitive advantage: they limit the scope of the problem to a much
more manageable size. I've seen plenty of projects for description
languages go nowhere, partly because people would spend a lot of time
arguing on how should things be structured :-)

Finally, I ask you to think about it for a while. It's still not
usable, but it may be really soon. I'm confident that, once one starts
using it, it will feel more natural than to have to work with yet
another language (as Tanebaum once said, there's a nice thing about
standards -- there are so many to choose from).

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #3
Carlos Ribeiro wrote:
# decorates getmyposition to hide the internal static var
getmyposition = getmyposition().next


Codewise this is probably cleaner

import itertools
getmyposition = itertools.count().next

More than that requires I know how to use metaclasses. :)

If it works like I think it does then it's pretty neat.

Andrew
da***@dalkescientific.com
Jul 18 '05 #4
Carlos Ribeiro wrote:

I'm doing good progress on my form declarative language library. The
idea (for those who haven't read about it) is to be able to specify a
form declaration in the following format:

class ComplexForm(Form):
class Header(Form):
nickname = TextBox(length=15, default="")
password = TextBox(length=10, default="", password=True)
name = TextBox(length=40, default="")
class Comment(Form):
comments = TextBox(length=200, default="", multiline=True)


[snip]

By a strange coincidence, this intermediate representation is eerily
similar to the one used in vb2py when converting Visual Basic forms to
Python ones (implemented in PythonCard).

The process is,

1. Read VB form
2. Write intermediate representation (see below)
3. Convert intermediate to a PythonCard (wxWidgets based) form

The intermediate representation looks like,

class vbobj_frmForm(resource.Form):
Caption = "Form1"
ClientHeight = 3090
ClientLeft = 60
ClientTop = 450
ClientWidth = 4680

class vbobj_btnCheckLike(resource.CommandButton):
Caption = "Like ?"
Height = 375
Left = 1440
TabIndex = 2
Top = 1560
Width = 1815

class vbobj_txtTwo(resource.TextBox):
Height = 405
Left = 240
TabIndex = 1
Text = "Text2"
Top = 840
Width = 4095

class vbobj_txtOne(resource.TextBox):
Height = 375
Left = 240
TabIndex = 0
Text = "Text1"
Top = 240
Width = 4095
I've found that the inner class approach works pretty well although I
must admit that the implementation of the transformation in vb2py is
pretty ugly!

I'm very interested in where you are headed with this - what is your
target UI? Are you planning on releasing this under an OS license?

Regards,

Paul
================================
vb2Py - Visual Basic to Python Conversion
http://vb2py.sourceforge.net
Jul 18 '05 #5
On Fri, 24 Sep 2004 01:30:33 GMT, Paul Paterson
<pa**********@users.sourceforge.net> wrote:
By a strange coincidence, this intermediate representation is eerily
similar to the one used in vb2py when converting Visual Basic forms to
Python ones (implemented in PythonCard).
I don't think it is a coincidence; I think that's because this is the
natural way to represent this structure in Python. If you look at the
way Delphi forms are stored when you choose text format (the default
for newer versions), it's strikingly similar -- just change "class"
for "object". I assume VB internals are structured in the same way.
The intermediate representation looks like,

[...long sample...]


I think that my current code can be easily adapted for your needs. I'm
now working on a generic renderer interface. I'm figuring out how to
make it general enough but still simple to sue. The current
implementation is already able to walk the class attributes in the
order of the original declaration, which is important to preserve some
behavior (specially the implicit tab ordering that is normally used in
GUI design).

As for your last question: yes, it's open source, I just haven't yet
figured out which license to choose from -- either BSD or LGPL, I
think. Part of the problem is that I don't have a nice host to put it
for download yet. I this point BSD would be nice -- it's too little
code to make a fusss about it being used inside some other product --
but if the library gets bigger I tend to go towards LGPL.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Tim ffitch | last post by:
Hi I have created a VB dll file that contains common functions I use across various projects in VB, Access and Excel. Rather than have to code the functions in each I decided to use the dll...
10
by: Clint | last post by:
Hey all - I'm having a really confusing problem concerning a web service. Right now, I have an application that needs to call a web service that does nothing but return "true" (this will...
3
by: Uma sakshi | last post by:
Hi I have one VB.NET application,in that application i have one datagrid control.The datagrid control contains somedata.I want to copy the data in a particular cell and paste it into my C#.NET...
1
by: Steve | last post by:
Hello, Is it possible to call a sub routine from 2 different threads at the same time? Or should I create a class containing this sub and instantiate the class for each thread? The sub pulls...
0
by: Michael | last post by:
Hi Everyone, I'm in the process of designing a app that will load control dynamically from an xml file and need a few questions. 1. Once the form is loaded with the controls needed, how do you...
2
by: filbennett | last post by:
Hi Everyone, I'm generally unfamiliar with Access form design, but have programmed Cold Fusion applications for a couple of years. I'd like to build a data entry form in Access that allows the...
0
by: bpo_ccs | last post by:
We are into BPO and Software development business for past six and half years. We are looking for the following any kind of business from your end. Back Office Process Data Entry, Large Volume...
2
by: x | last post by:
hi i am a pilot by profession. i want to create a database of my logbook using ms access 2002. i am facing a problem regarding the format of time field. when i select "Data/Time" data type for my...
2
by: gmccallum | last post by:
I have a data entry screen using controls bound through a bindingSource, TableAdaptor and a BindingNavigator to move through the records. When I have an data entry error (such as Null for a value)...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.