Python declarative

  • Thread starter Sergio Tortosa Benedito
  • Start date
S

Sergio Tortosa Benedito

Hi I'm developing a sort of language extension for writing GUI programs
called guilang, right now it's written in Lua but I'm considreing Python
instead (because it's more tailored to alone applications). My question
it's if I can achieve this declarative-thing in python. Here's an
example:

Window "myWindow" {
title="Hello world";
Button "myButton" {
label="I'm a button";
onClick=exit
}
}
print(myWindow.myButton.label)

Of course it doesn't need to be 100% equal. Thanks in advance

Sergio
 
F

Francesco Bochicchio

Some time ago I played with Tkinter trying a more declarative way of coding the GUI building part and I come out with this:

top = Tk( 'top' ).add (
Frame( 'frame' ).add (
Pack( side = 'top' ),
Frame ( 'panel1' ).add (
Pack( side='left'),
Label ( 'label', text="Entry 1 : " ),
Entry ( 'entry' )
),
Frame( 'panel2' ).add (
Pack( side='left'),
Label ( 'label', text="Entry 2 : " ),
Entry( 'entry' )
),
Pack( side = 'bottom' ), # packing change
Button( 'button',
text='Click Me' ))
)

top.frame.button["command"] = functools.partial(button_cb, top)
top.realize().mainloop()

which, without changing the underlying plumbing, may also be written this way, which avoid nesting but still looks declarative-ish :

top = Tk( 'top' )
top.add( Frame( 'frame' ) )
top.frame.add (
Pack( side = 'top' ),
Frame ( 'panel1' ),
Frame( 'panel2' ),
Pack( side = 'bottom' ), # packing change
Button( 'button',
text='Click Me',
command = functools.partial(button_cb, top) ) )

top.frame.panel1.add(
Pack( side='left'),
Label ( 'label', text="Entry 1 : " ),
Entry ( 'entry' ) )

top.frame.panel2.add(
Pack( side='left'),
Label ( 'label', text="Entry 1 : " ),
Entry( 'entry' ) )

top.realize().mainloop()


The underlying plumbing for those two examples is just two classes amounting to about fifty lines of code, plus one-liner wrappers for each kind of widgets/geometry

This just to tell you that yes, with python you can write declarative-looking code ... if you don't mind parenthesis :)
 
S

sertorbe

El miércoles, 15 de enero de 2014 18:02:08 UTC+1, Sergio Tortosa Beneditoescribió:
Hi I'm developing a sort of language extension for writing GUI programs

called guilang, right now it's written in Lua but I'm considreing Python

instead (because it's more tailored to alone applications). My question

it's if I can achieve this declarative-thing in python. Here's an

example:



Window "myWindow" {

title="Hello world";

Button "myButton" {

label="I'm a button";

onClick=exit

}

}

print(myWindow.myButton.label)



Of course it doesn't need to be 100% equal. Thanks in advance



Sergio

Wow thank you very much, really. I wasn't expecting that much from everyone.. BTW, sorry for no answering earlier , I'm receiving no e-mails from the list (I'll look later what happens). First, I don't like that all parenthesis, I like to differentiate which type of delimiter is, this is not so bad if using spaces but anyways it's a little more difficult.Second, In regard, to using something like myWindow=Window rather than Window "myWindow", atfirst I didn't liked it that much, but in the end it does tell the user that the attributes can be accesed just like anything else. Finally , the project I'm developing (guilang) it's toolkit-independent so I don't mind having to do some wrappers.

Sergio
 
T

Tim Roberts

First, I don't like that all parenthesis, I like to differentiate
which type of delimiter is, this is not so bad if using spaces but
anyways it's a little more difficult. Second, In regard, to using
something like myWindow=Window rather than Window "myWindow", at
first I didn't liked it that much, but in the end it does tell the
user that the attributes can be accesed just like anything else.

Well, this all depends on whether you want this code to BE Python code, or
just to be READ BY Python code. That's a huge difference. If you want
your layout to BE Python code, then you have little alternative except to
use the suggestions offered. But if you simply want your scripts to be
interpreted by a Python program, then you can do whatever you want.
 
S

sertorbe

El miércoles, 15 de enero de 2014 18:02:08 UTC+1, Sergio Tortosa Beneditoescribió:
Hi I'm developing a sort of language extension for writing GUI programs

called guilang, right now it's written in Lua but I'm considreing Python

instead (because it's more tailored to alone applications). My question

it's if I can achieve this declarative-thing in python. Here's an

example:



Window "myWindow" {

title="Hello world";

Button "myButton" {

label="I'm a button";

onClick=exit

}

}

print(myWindow.myButton.label)



Of course it doesn't need to be 100% equal. Thanks in advance



Sergio

OK, thanks, maybe the to be read by python may be interesting .Anyway, I think I'll have to consider all the options I have right now (Lua,Python,A file readed by Python). Really, thanks, you are awesome.

Sergio.
 
F

Francesco Bochicchio

Looking at my own code after four years, I just realized that most of parentheses can be avoided by redefining the += operators to be a synonym of the add method.

Go figure, I guess that with age it _does_ come a little wisdom ... :)

Ciao
 
S

sertorbe

El miércoles, 15 de enero de 2014 18:02:08 UTC+1, Sergio Tortosa Beneditoescribió:
Hi I'm developing a sort of language extension for writing GUI programs

called guilang, right now it's written in Lua but I'm considreing Python

instead (because it's more tailored to alone applications). My question

it's if I can achieve this declarative-thing in python. Here's an

example:



Window "myWindow" {

title="Hello world";

Button "myButton" {

label="I'm a button";

onClick=exit

}

}

print(myWindow.myButton.label)



Of course it doesn't need to be 100% equal. Thanks in advance



Sergio

Hi again, just wrote to announce that I'm going to rewrite guilang in Python. Again thanks you are all awesome :).
 
A

Asaf Las

Hi I'm developing a sort of language extension for writing GUI programs
called guilang, right now it's written in Lua but I'm considreing Python
instead (because it's more tailored to alone applications). My question
it's if I can achieve this declarative-thing in python. Here's an
example:
Window "myWindow" {
title="Hello world";
Button "myButton" {
label="I'm a button";
onClick=exit
}
}
print(myWindow.myButton.label)
Of course it doesn't need to be 100% equal. Thanks in advance
Sergio

Hi Sergio

i am novice in python, but let me suggest you something:
it would be beneficial to use json text file to specify
your gui so composite data structure can be created using
json and then your program can construct window giving
its content will be based on simple text file?
You can add every parameter to json encoded window system
once your window construction will be using as interpreter
for that. JSON is very structured and quite presentable for
such kind of things.

What Gurus do think about this suggestion?

/Asaf
 
C

Chris Angelico

i am novice in python, but let me suggest you something:
it would be beneficial to use json text file to specify
your gui so composite data structure can be created using
json and then your program can construct window giving
its content will be based on simple text file?
You can add every parameter to json encoded window system
once your window construction will be using as interpreter
for that. JSON is very structured and quite presentable for
such kind of things.

What Gurus do think about this suggestion?

JSON is better than XML for that, but in my opinion, both are
unnecessary. Python code is easy to edit. (See [1] for more on Python
and XML.) When you're writing compiled code, it makes good sense to
drop out of code and use a simple text file when you can; but when
your code *is* a simple text file, why go to the effort of making a
JSON-based window builder? (Unless you already have one. GladeXML may
well be exactly what you want, in which case, go ahead and use it. But
personally, I don't.) JSON is a fantastic format for transmitting
complex objects around the internet; it's compact (unlike XML),
readable in many languages (like XML), easily readable by humans
(UNLIKE XML!), and can represent all the most common data structures
(subtly, XML can't technically do this). It's superb at what it
does... but it doesn't do Python GUIs. For those, use Python itself.

ChrisA

[1] http://dirtsimple.org/2004/12/python-is-not-java.html
 
T

Terry Reedy

JSON is better than XML for that, but in my opinion, both are
unnecessary. Python code is easy to edit. (See [1] for more on Python
and XML.) When you're writing compiled code, it makes good sense to
drop out of code and use a simple text file when you can; but when
your code *is* a simple text file, why go to the effort of making a
JSON-based window builder? (Unless you already have one. GladeXML may
well be exactly what you want, in which case, go ahead and use it. But
personally, I don't.) JSON is a fantastic format for transmitting
complex objects around the internet; it's compact (unlike XML),
readable in many languages (like XML), easily readable by humans
(UNLIKE XML!), and can represent all the most common data structures
(subtly, XML can't technically do this). It's superb at what it
does... but it doesn't do Python GUIs. For those, use Python itself.

I would only use JSON if I wanted a declaration format that was
independent of implementation languages, that could be read and turned
into application objects by as least two languages.
 
F

Frank Millman

Chris Angelico said:
i am novice in python, but let me suggest you something:
it would be beneficial to use json text file to specify
your gui so composite data structure can be created using
json and then your program can construct window giving
its content will be based on simple text file?
You can add every parameter to json encoded window system
once your window construction will be using as interpreter
for that. JSON is very structured and quite presentable for
such kind of things.

What Gurus do think about this suggestion?

JSON is better than XML for that, but in my opinion, both are
unnecessary. Python code is easy to edit. (See [1] for more on Python
and XML.) When you're writing compiled code, it makes good sense to
drop out of code and use a simple text file when you can; but when
your code *is* a simple text file, why go to the effort of making a
JSON-based window builder? (Unless you already have one. GladeXML may
well be exactly what you want, in which case, go ahead and use it. But
personally, I don't.) JSON is a fantastic format for transmitting
complex objects around the internet; it's compact (unlike XML),
readable in many languages (like XML), easily readable by humans
(UNLIKE XML!), and can represent all the most common data structures
(subtly, XML can't technically do this). It's superb at what it
does... but it doesn't do Python GUIs. For those, use Python itself.

I find that I am using JSON and XML more and more in my project, so I
thought I would explain what I am doing to see if others think this is an
acceptable approach or if I have taken a wrong turn.

I have various data structures, some simple, some more complex, of which I
have many instances. I want to serialise and store them in a database. This
has two benefits. Firstly, I just have to write one piece of python code
that interprets and deals with each structure, so it avoids duplicate code.
Secondly, I can design a gui that exposes the structures to non-programmers,
giving them the ability to modify them or create new ones. Simple structures
can be expressed in JSON. I use XML to represent the more complex ones.

I will give two examples, one simple and one complex.

I store database metadata in the database itself. I have a table that
defines each table in the database, and I have a table that defines each
column. Column definitions include information such as data type, allow
null, allow amend, maximum length, etc. Some columns require that the value
is constrained to a subset of allowable values (e.g. 'title' must be one of
'Mr', 'Mrs', etc.). I know that this can be handled by a 'check' constraint,
but I have added some additional features which can't be handled by that. So
I have a column in my column-definition table called 'choices', which
contains a JSON'd list of allowable choices. It is actually more complex
than that, but this will suffice for a simple example.

For my more complex example, I should explain that my project involves
writing a generalised business/accounting system. Anyone who has worked on
these knows that you quickly end up with hundreds of database tables storing
business data, and hundreds of forms allowing users to CRUD the data
(create/read/update/delete). Each form is unique, and yet they all share a
lot of common characteristics. I have abstracted the contents of a form
sufficiently that I can represent at least 90% of it in XML. This is not
just the gui, but all the other elements - the tables required, any input
parameters, any output parameters, creating any variables to be used while
entering the form, any business logic to be applied at each point, etc. Each
form definition is stored as gzip'd XML in a database, and linked to the
menu system. There is just one python program that responds to the selection
of a menu option, retrieves the form from the database, unpacks it and runs
it.

Incidentally, I would take issue with the comment that 'JSON is easily
readable by humans (UNLIKE XML)'. Here is a more complete example of my
'choices' definition.

[true, true, [["admin", "System administrator", [], []], ["ind",
"Individual", [["first_name", true], ["surname", true]], [["first_name", "
"], ["surname", ""]]], ["comp", "Company", [["comp_name", true], ["reg_no",
true], ["vat_no", false]], [["comp_name", ""]]]]]

You can read it, but what does it mean?

This is what it would look like if I stored it in XML -

<choices use_subtypes="true" use_displaynames="true">
<choice code="admin" descr="System administrator">
<subtype_columns/>
<displaynames/>
</choice>
<choice code="ind" descr="Individual">
<subtype_columns>
<subtype_column col_name="first_name" required="true"/>
<subtype_column col_name="surname" required="true"/>
</subtype_columns>
<displaynames>
<displayname col_name="first_name" separator=" "/>
<displayname col_name="surname" separator=""/>
</displaynames>
</choice>
<choice code="comp" descr="Company">
<subtype_columns>
<subtype_column col_name="comp_name" required="true"/>
<subtype_column col_name="reg_no" required="true"/>
<subtype_column col_name="vat_no" required="false"/>
</subtype_columns>
<displaynames>
<displayname col_name="comp_name" separator=""/>
</displaynames>
</choice>
</choices>

More verbose - sure. Less human-readable - I don't think so.

Also, intuitively one would think it would take much longer to process the
XML version compared with the JSON version. I have not done any benchmarks,
but I use lxml, and I am astonished at the speed. Admittedly a typical
form-processor spends most of its time waiting for user input. Even so, for
my purposes, I have never felt the slightest slowdown caused by XML.

Comments welcome.

Frank Millman
 
R

Rustom Mody

Incidentally, I would take issue with the comment that 'JSON is easily
readable by humans (UNLIKE XML)'. Here is a more complete example of my
'choices' definition.
[true, true, [["admin", "System administrator", [], []], ["ind",
"Individual", [["first_name", true], ["surname", true]], [["first_name", "
"], ["surname", ""]]], ["comp", "Company", [["comp_name", true], ["reg_no",
true], ["vat_no", false]], [["comp_name", ""]]]]]
You can read it, but what does it mean?
This is what it would look like if I stored it in XML -

More verbose - sure. Less human-readable - I don't think so.
Also, intuitively one would think it would take much longer to process the
XML version compared with the JSON version. I have not done any benchmarks,
but I use lxml, and I am astonished at the speed. Admittedly a typical
form-processor spends most of its time waiting for user input. Even so, for
my purposes, I have never felt the slightest slowdown caused by XML.
Comments welcome.

Of json/XML/yml I prefer yml because it has the terseness of json and the
structuredness of xml -- well almost

The flipside is that pyyaml needs to be installed unlike json.
But then you are installing lxml anyway
 
C

Chris Angelico

I find that I am using JSON and XML more and more in my project, so I
thought I would explain what I am doing to see if others think this is an
acceptable approach or if I have taken a wrong turn.

Please don't take this the wrong way, but the uses of JSON and XML
that you describe are still completely inappropriate. Python does not
need this sort of thing.
I store database metadata in the database itself. I have a table that
defines each table in the database, and I have a table that defines each
column. Column definitions include information such as data type, allow
null, allow amend, maximum length, etc. Some columns require that the value
is constrained to a subset of allowable values (e.g. 'title' must be one of
'Mr', 'Mrs', etc.). I know that this can be handled by a 'check' constraint,
but I have added some additional features which can't be handled by that. So
I have a column in my column-definition table called 'choices', which
contains a JSON'd list of allowable choices. It is actually more complex
than that, but this will suffice for a simple example.

This is MySQL-style of thinking, that a database is a thing that's
interpreted by an application. The better way to do it is to craft a
check constraint; I don't know what features you're trying to use that
can't be handled by that, but (at least in PostgreSQL) I've never had
anything that can't be expressed that way. With the simple example you
give, incidentally, it might be better to use an enumeration rather
than a CHECK constraint, but whichever way.
For my more complex example, I should explain that my project involves
writing a generalised business/accounting system. Anyone who has worked on
these knows that you quickly end up with hundreds of database tables storing
business data, and hundreds of forms allowing users to CRUD the data
(create/read/update/delete). Each form is unique, and yet they all share a
lot of common characteristics. I have abstracted the contents of a form
sufficiently that I can represent at least 90% of it in XML. This is not
just the gui, but all the other elements - the tables required, any input
parameters, any output parameters, creating any variables to be used while
entering the form, any business logic to be applied at each point, etc. Each
form definition is stored as gzip'd XML in a database, and linked to the
menu system. There is just one python program that responds to the selection
of a menu option, retrieves the form from the database, unpacks it and runs
it.

Write your rendering engine as a few simple helper functions, and then
put all the rest in as code instead of XML. The easiest way to go
about it is to write three forms, from scratch, and then look at the
common parts and figure out which bits can go into helper functions.
You'll find that you can craft a powerful system with just a little
bit of code, if you build it right, and it'll mean _less_ library code
than you currently have as XML. If you currently represent 90% of it
in XML, then you could represent 90% of it with simple calls to helper
functions, which is every bit as readable (probably more so), and much
*much* easier to tweak. Does your XML parsing engine let you embed
arbitrary expressions into your code? Can you put a calculated value
somewhere? With Python, everything's code, so there's no difference
between saying "foo(3)" and saying "foo(1+2)".
Incidentally, I would take issue with the comment that 'JSON is easily
readable by humans (UNLIKE XML)'. Here is a more complete example of my
'choices' definition.

[true, true, [["admin", "System administrator", [], []], ["ind",
"Individual", [["first_name", true], ["surname", true]], [["first_name", "
"], ["surname", ""]]], ["comp", "Company", [["comp_name", true], ["reg_no",
true], ["vat_no", false]], [["comp_name", ""]]]]]

You can read it, but what does it mean?

This is what it would look like if I stored it in XML -

<choices use_subtypes="true" use_displaynames="true">
<choice code="admin" descr="System administrator">
<subtype_columns/>
<displaynames/>
</choice>
<choice code="ind" descr="Individual">
<subtype_columns>
<subtype_column col_name="first_name" required="true"/>
<subtype_column col_name="surname" required="true"/>
</subtype_columns>
<displaynames>
<displayname col_name="first_name" separator=" "/>
<displayname col_name="surname" separator=""/>
</displaynames>
</choice>
<choice code="comp" descr="Company">
<subtype_columns>
<subtype_column col_name="comp_name" required="true"/>
<subtype_column col_name="reg_no" required="true"/>
<subtype_column col_name="vat_no" required="false"/>
</subtype_columns>
<displaynames>
<displayname col_name="comp_name" separator=""/>
</displaynames>
</choice>
</choices>

More verbose - sure. Less human-readable - I don't think so.

Well, that's because you elided all the names in the JSON version. Of
course that's not a fair comparison. :) Here's how I'd render that XML
in JSON. I assume that this is stored in a variable, database field,
or whatever, named "choices", and so I skip that first-level name.

{"use_subtypes":true, "use_displaynames":true, "choice":[
{"code":"admin", "descr":"System administrator",
"subtype_columns":[], "displaynames":[]},
{"code":"ind", "descr":"Individual",
"subtype_columns":[
{"col_name":"first_name", "required":true},
{"col_name":"surname", "required":true}
], "displaynames":[
{"col_name":"first_name", "separator":" "},
{"col_name":"surname", "separator":""}
]
},
{"code":"comp", "descr":"Company",
"subtype_columns":[
{"col_name":"comp_name", "required":true},
{"col_name":"reg_no", "required":true},
{"col_name":"vat_no", "required":false}
], "displaynames":[
{"col_name":"comp_name", "separator":""}
]
}
]}

You can mix and match the two styles to get the readability level you
need. I think the "col_name" and "required" tags are probably better
omitted, which would make the JSON block look like this:

{"use_subtypes":true, "use_displaynames":true, "choice":[
{"code":"admin", "descr":"System administrator",
"subtype_columns":[], "displaynames":[]},
{"code":"ind", "descr":"Individual",
"subtype_columns":[
["first_name", "required"],
["surname", "required"]
], "displaynames":[
["first_name", " "]
["surname", ""]
]
},
{"code":"comp", "descr":"Company",
"subtype_columns":[
["comp_name", "required"]
["reg_no", "required"]
["vat_no", "optional"]
], "displaynames":[
["comp_name", ""]
]
}
]}

Note that instead of "true" or "false", I've simply used "required" or
"optional". Easy readability without excessive verbosity. And you
could probably make "required" the default, so you just have
[["comp_name"], ["reg_no"], ["vat_no", "optional"]] for the last
block.

Now, here's the real killer. You can take this JSON block and turn it
into Python code like this:

choices = ... block of JSON ...

And now it's real code. It's that simple. You can't do that with XML.
And once it's code, you can add functionality to it to improve
readability even more.
Also, intuitively one would think it would take much longer to process the
XML version compared with the JSON version. I have not done any benchmarks,
but I use lxml, and I am astonished at the speed. Admittedly a typical
form-processor spends most of its time waiting for user input. Even so, for
my purposes, I have never felt the slightest slowdown caused by XML.

On this, I absolutely agree. You will almost never see a performance
difference between any of the above. Don't pick based on performance -
pick based on what makes sense and is readable. The pure-code version
might suffer terribly (interpreted Python with several levels of
helper functions, each one having its overhead - though personally, I
expect it'd be comparable to the others), but you would still do
better with it, because the difference will be on the scale of
microseconds.

I've built GUIs in a number of frameworks, including building
frameworks myself. I've built a system for creating CRUD databases.
(It's still in use, incidentally, though only on our legacy OS/2
systems. One of the costs of writing in REXX rather than Python, but I
didn't know Python back in the early 1990s when I wrote Hudson.)
Frameworks that boast that it doesn't take code to use them tend to
suffer from the Inner-Platform Effect [1] [2] if they get sufficiently
powerful, and it quickly becomes necessary to drop to code somewhere.
(Or, if they DON'T get powerful enough to hit the IPE, they overly
restrain what you can do with them. That's fine if all you want is
simple, but what if 99.9% of what you want fits into the framework and
0.1% simply can't be done?)

With Hudson, I handled the "easy bits" with a single program (basic
table view display with some options, database/table selection, etc,
etc), and then dropped to actual GUI code to handle the custom parts
(the main form for displaying one record; optionally the Search
dialog, though a basic one was provided "for free"), with a library of
handy functions available to call on. Okay, I did a terrible job of
the "library" part back in those days - some of them were copied and
pasted into each file :| - but the concept is there.

In Gypsum (a current project, MUD client for Linux/Windows/Mac OS),
all GUI work is done through GTK. But there are a few parts that get
really clunky, like populating a Table layout, so I made a helper
function that creates a table based on a list of lists: effectively, a
2D array of cell values, where a cell could have a string (becomes a
label), a widget (gets placed there), or nothing (the label/widget to
the left spans this cell too). That doesn't cover _every_ possible
use-case (there's no way to span multiple rows), but if I need
something it can't do, I'm writing code already right there, so I can
just use the Table methods directly. There was actually one extremely
common sub-case where even my GTK2Table function got clunky, so I made
a second level of wrapper that takes a simple list of elements and
creates a 2D array of elements, with labels right-justified. Once
again, if I'm doing the same thing three times, it's a prime candidate
for a helper.

The cool thing about doing everything in code is that you can create
helpers at the scope where they're most needed. To build the character
sheet module for Gypsum (one of its uses is Dungeons and Dragons), I
had to build up a more complex and repetitive GUI than most, so I
ended up making a handful of helpers that existed right there in the
charsheet module. (A couple of them have since been promoted to
global; GTK2Table mentioned above started out in charsheet.) Anyone
reading code anywhere _else_ in the project doesn't need to understand
those functions; but they improve readability in that module
enormously. That's something that's fundamentally impossible in an
interpreted/structured system like an XML GUI - at least, impossible
without some horrible form of inner-platform effect.

Python code is more readable than most data structures you could come
up with, because you don't have to predict everything in advance.

ChrisA

[1] http://en.wikipedia.org/wiki/Inner-platform_effect
[2] http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
 
A

Asaf Las

Hi I'm developing a sort of language extension for writing GUI programs
called guilang, right now it's written in Lua but I'm considreing Python
instead (because it's more tailored to alone applications). My question
it's if I can achieve this declarative-thing in python. Here's an
example:
Window "myWindow" {
title="Hello world";
Button "myButton" {
label="I'm a button";
onClick=exit
}
}
print(myWindow.myButton.label)
Of course it doesn't need to be 100% equal. Thanks in advance
Sergio

you can also encode widget event handler
function names into same text file and module names where
functions are written so they will be called by string name.
The only thing will be left - creation of those module(s).py
and writing functions there and of course the subject of your
project interpreter/mapper/creator of encoded text to graphical
primitives.
For convenience text encoding can retain properties of
widget library you will choose. or you can/should
also create derived widgets with some predefined look and feel
and properties to make encoding simpler and typing faster.
 
F

Frank Millman

Chris Angelico said:
Please don't take this the wrong way, but the uses of JSON and XML
that you describe are still completely inappropriate. Python does not
need this sort of thing.

Chris, I really am very grateful for your detailed response. There is much
food for thought there and I will have to read it a few times to glean as
much as possible from it.

Here are some initial thoughts.

1. I don't really understand how your system actually works! You mention
Python code and helper functions, but I cannot picture the overall structure
of the program. I don't know if it is possible to provide a siimple example,
but it would certainly help.

2. I am not sure if you have created this to make it easy for *you* to
create forms, or for others. And if the latter, must they be programmers?
One of my goals is to allow non-programmers to modify forms and even create
them from scratch. I did mention that one benefit of my approach is that I
can design a gui that allows this, but I don't get the sense that your's
does.

3. Thanks for the links to the Inner Platform Effect. I had not heard of it,
but I recognise the symptoms, and I realise that I am skirting close to it
in some areas.

4. You are right that some things cannot be totally abstracted, and can only
be handled by code. My approach is as follows. If at least 80% of the
structure can be handled without resorting to code, I think it is
worthwhile, and I think I have more than achieved that. Of the balance, if
at least 80% of requirements are 'standard', I can write the standard
functions in Python, and create an XML tag that will cause the function to
be invoked at run-time. The 'designer' still does not have to worry about
Python. For the remainder, I have created an XML tag called 'pyfunc' that
provides a path to a custom-written function. For this, a Python programmer
will be required. So far I have only made use of this in my 'form designer',
which is quite complex as it has to take the XML definition and 'explode' it
into a number of in-memory tables so that it can be presented in gui form.
However, the average user is not going to get their hands that dirty.

Thanks again

Frank
 
F

Frank Millman

Rustom Mody said:
On Friday, January 24, 2014 2:51:12 PM UTC+5:30, Frank Millman wrote:
Comments welcome.

Of json/XML/yml I prefer yml because it has the terseness of json and the
structuredness of xml -- well almost

The flipside is that pyyaml needs to be installed unlike json.
But then you are installing lxml anyway

Thanks for that, Rustom. I had a quick look and I like it. Probably too big
a change for me to consider at the moment, but at least I am now aware of
it.

Frank
 
B

Burak Arslan

I store database metadata in the database itself. I have a table that
defines each table in the database, and I have a table that defines each
column. Column definitions include information such as data type, allow
null, allow amend, maximum length, etc. Some columns require that the value
is constrained to a subset of allowable values (e.g. 'title' must be one of
'Mr', 'Mrs', etc.). I know that this can be handled by a 'check' constraint,
but I have added some additional features which can't be handled by that. So
I have a column in my column-definition table called 'choices', which
contains a JSON'd list of allowable choices. It is actually more complex
than that, but this will suffice for a simple example.


I wonder whether your use cases can be fully handled by Xml Schema
standard. It's quite robust and easy to use. You are already doing
validation at the app level so I don't think it'd be much of a problem
for you to adopt it.

e.g.
.... title = Unicode(values=['Mr', 'Mrs', 'Ms'])
....
from lxml import etree
from spyne.util.xml import get_validation_schema
schema = get_validation_schema([C], 'some_ns')
doc1 = etree.fromstring('<C xmlns="some_ns"><title>Mr</title></C>')
print schema.validate(doc1) True
doc2 = etree.fromstring('<C xmlns="some_ns"><title>xyz</title></C>')
print schema.validate(doc2) False
print schema.error_log
<string>:1:0:ERROR:SCHEMASV:SCHEMAV_CVC_ENUMERATION_VALID: Element
'{some_ns}title': [facet 'enumeration'] The value 'xyz' is not an
element of the set {'Mr', 'Mrs', 'Ms'}.
<string>:1:0:ERROR:SCHEMASV:SCHEMAV_CVC_DATATYPE_VALID_1_2_1: Element
'{some_ns}title': 'xyz' is not a valid value of the atomic type
'{some_ns}C_titleType'.

Also, if you need conversion between various serialization formats and
Python object hierarchies, I put together an example for you:
https://gist.github.com/plq/8596519

I hope these help.

Best,
Burak
 
C

Chris Angelico

Chris, I really am very grateful for your detailed response. There is much
food for thought there and I will have to read it a few times to glean as
much as possible from it.

Thanks for taking it the right way :) If I thought you were doing a
terrible job, I'd just archive the thread and move on. The detailed
response means I think you're very close to the mark, but could
improve. :)
Here are some initial thoughts.

1. I don't really understand how your system actually works! You mention
Python code and helper functions, but I cannot picture the overall structure
of the program. I don't know if it is possible to provide a siimple example,
but it would certainly help.

Yeah, it was a bit vague. Unfortunately I haven't actually built any
complex UI in Python, ever, so I'll have to use C, C++, REXX, or Pike,
for the example. In C, it would be using the OS/2 APIs, not very
useful to anyone else. In C++, either Borland's ancient "Object
Windows Library", or the Win32 APIs - either way, not particularly
helpful. REXX you probably don't even know as a language, and you're
unlikely to know any of the GUI libraries I've used - GpfRexx, VREXX,
VX-REXX, VisPro REXX, DrRexx, or a handful of others. So the best bet
is Pike, where I've used GTK, which is also available for Python - but
there are distinct differences. (Oh, I've also used DBExpert, which is
a superb example of how frustrating it can be to try to create a
complex GUI in a "look how easy, it's just drag and drop, no code
needed" system. But that's more arcane stuff from the 1990s that you
most likely don't know, and definitely don't need to know.)

So, here's some code from Gypsum. Firstly, here's a simple window
layout (not strictly what I had in Gypsum):

mainwindow = GTK2.Window(0)->add(GTK2.Vbox(0,0)
->add(GTK2.Label("About Gypsum: big long multi-line string"))
->add(GTK2.HbuttonBox()
->add(GTK2.Button("Close"))
->add(GTK2.Button("Foobar"))
)
);

The window has a simple structure. It contains a vertical box, which
contains a label and a horizontal button box; the latter contains two
buttons. (The real about dialog has only one button, making it a poor
example. I've no idea what clicking Foobar on an about dialog should
do.)

There's a nested structure to it, and it's all code. (It's actually
all one single expression. The add() methods return the parent object,
so they chain nicely.) This gives maximum flexibility, but it gets
repetitive at times, especially when I do up the character sheet.
Here's a screenshot of just the first page:

http://rosuav.com/charsheet.png

(That's how it appears on Windows, since I'm currently testing it for
support there. It also has to work - and look right - on Linux and Mac
OS.)

It's particularly complicated when laying out a table, because the
table is so powerful and flexible.

GTK2.Table(6,2,0)

->attach(GTK2.Label((["label":"Keyword","xalign":1.0])),0,1,0,1,GTK2.Fill,GTK2.Fill,5,0)
->attach_defaults(win->kwd=GTK2.Entry(),1,2,0,1)

->attach(GTK2.Label((["label":"Name","xalign":1.0])),0,1,1,2,GTK2.Fill,GTK2.Fill,5,0)
->attach_defaults(win->name=GTK2.Entry(),1,2,1,2)
->attach(GTK2.Label((["label":"Host
name","xalign":1.0])),0,1,2,3,GTK2.Fill,GTK2.Fill,5,0)
->attach_defaults(win->hostname=GTK2.Entry(),1,2,2,3)

->attach(GTK2.Label((["label":"Port","xalign":1.0])),0,1,3,4,GTK2.Fill,GTK2.Fill,5,0)
->attach_defaults(win->port=GTK2.Entry(),1,2,3,4)

->attach(GTK2.Label((["label":"Auto-log","xalign":1.0])),0,1,4,5,GTK2.Fill,GTK2.Fill,5,0)
->attach_defaults(win->logfile=GTK2.Entry(),1,2,4,5)
->attach(win->use_ka=GTK2.CheckButton("Use
keep-alive"),1,2,5,6,GTK2.Fill,GTK2.Fill,5,0) //No separate label

Horribly repetitive, and requires care to ensure that the
left/right/top/bottom boundaries are correct in all cases. Technically
it's possible for widgets to span rows or columns, and even to
overlap, but that's extremely rare compared to the common case of just
"lay these things out in a grid". (Though spanning columns was easy
enough to implement, so I did it.)

Here's the version with the first helper function:

GTK2Table(({
({"Keyword",win->kwd=GTK2.Entry()}),
({"Name",win->name=GTK2.Entry()}),
({"Host name",win->hostname=GTK2.Entry()}),
({"Port",win->port=GTK2.Entry()}),
({"Auto-log",win->logfile=GTK2.Entry()}),
({"",win->use_ka=GTK2.CheckButton("Use keep-alive")}),
}),(["xalign":1.0]))

I have to create a blank label in there to keep the positioning right
(the previous version simply didn't attach anything in that slot), but
that's a small price to pay. The readability has gone up hugely. And
yet, there's still a little more that can be done, as I realized when
I found myself duplicating the above structure a few times.

two_column(({
"Keyword",win->kwd=GTK2.Entry(),
"Name",win->name=GTK2.Entry(),
"Host name",win->hostname=GTK2.Entry(),
"Port",win->port=GTK2.Entry(),
"Auto-log",win->logfile=GTK2.Entry(),
"",win->use_ka=GTK2.CheckButton("Use keep-alive"),
}))

This is something that I could give to a non-programmer and expect him
to be able to edit, as it's about as clear as the equivalent JSON or
XML would be; there could be a few more tweaks done, perhaps, but it's
pretty readable like that. A non-programmer could, for instance, put
the "Auto-log" line above the "Host name", simply by reordering the
lines of code; it would do exactly what he expects. There's as much
fragility/rigidity in this as there is in any other structured system
(eg if you leave out a comma, this won't work - same with JSON or
XML).

In the specific case of the character sheet, I frequently create entry
fields (GTK2.Entry()) that are bound to specific data attributes. So
in any context where it's legal to write GTK2.Entry(), you can instead
write ef("some_name") and it'll make a properly bound entry field. And
if it's a numeric field, num("some_name") will shrink the default size
and center the text in it as well, which is what people expect of the
numeric fields. Shorthand for the common cases. And then there are
complex cases like the weapon stats block - it needs its keyword,
name, damage roll, enchantment bonus, etc, etc, all laid out nicely;
and there might be three of those weapon blocks. So that's broken out
into a function.

The thing is, if your XML window structure has enough power... well,
that's more part of the next two points:
2. I am not sure if you have created this to make it easy for *you* to
create forms, or for others. And if the latter, must they be programmers?
One of my goals is to allow non-programmers to modify forms and even create
them from scratch. I did mention that one benefit of my approach is that I
can design a gui that allows this, but I don't get the sense that your's
does.

3. Thanks for the links to the Inner Platform Effect. I had not heard of it,
but I recognise the symptoms, and I realise that I am skirting close to it
in some areas.

If your XML window structure has enough power, it'll be nearly
impossible for a non-programmer to make anything but the most trivial
changes to it. (Changing a literal string is usually easy enough. Any
decent system will make _that_ possible, at least.) If a
non-programmer can truly create a form from scratch, that's a sign
that the forms are extremely simple and, if you'll excuse the pun,
formulaic; and if that's the case, it should be possible to make a
really easy-to-use helper function like my two_column() above.
Challenge: Without knowing anything about Pike, or the connect dialog,
add another check box called "Passive mode" called win->passive and
positioned just after the hostname and port. Like the other check box,
it doesn't need a separate label. Can you do it? Could someone who
knows enough to edit XML do it? I suspect probably they could. There's
some boilerplate to copy and paste (same in XML or code), there's some
readable text strings (names, labels, types), and there's punctuation
that makes decent sense.
4. You are right that some things cannot be totally abstracted, and can only
be handled by code. My approach is as follows. If at least 80% of the
structure can be handled without resorting to code, I think it is
worthwhile, and I think I have more than achieved that. Of the balance, if
at least 80% of requirements are 'standard', I can write the standard
functions in Python, and create an XML tag that will cause the function to
be invoked at run-time. The 'designer' still does not have to worry about
Python.

That's nice in theory, but it means you have to plan everything out.
That also means you have to predict your names etc, and then deprecate
old names if you ever find that you made a mistake. When you start
with code, you have the flexibility of looking at actual existing
forms and deciding what should be broken out for simplicity.
For the remainder, I have created an XML tag called 'pyfunc' that
provides a path to a custom-written function. For this, a Python programmer
will be required. So far I have only made use of this in my 'form designer',
which is quite complex as it has to take the XML definition and 'explode' it
into a number of in-memory tables so that it can be presented in gui form.
However, the average user is not going to get their hands that dirty.

That's what I meant when I said a "drop to code" system. Depending on
how smooth the boundary is, that could be either horribly clunky or
reasonably clean; the clean one usually requires a lot of work. On the
flip side, if your GUI creation is *all* code, there's no boundary at
all, and no work.

My system starts by writing an absolute minimum of code and forcing
the form designer to do more work, and then progressively adds code
*that is actually useful* and makes the form design work easier.
Trying to do it all in XML means you have to first predict what will
be needed, and that inevitably means writing a whole lot of code that
isn't, as it turns out, useful. That's an up-front cost before you can
do anything, plus you can't get rid of any of it later without first
making sure no forms are using those tags. Ultimately, a full-featured
GUI is going to require that its form designer understand the
underlying system anyway (in my case that's GTK), because nothing will
change that; and if your forms designers have to understand how GTK
works, they probably have to understand how to write GTK-using code.
At very least, the basics of code (names, structure, etc) will be
critical, and that's true of any GUI builder. DBExpert required that
you think about all that sort of thing, and that's as close as I've
ever seen to a pure "no code needed, build a UI to view a database
table" system. So... instead of fighting that, embrace it! Let it
truly be code.

The structure (your XML interpreter) is code that has a maintenance
cost. The less of that you have, the less it takes to make changes.
And as a rule of thumb, less code means less bugs; and less
development prior to usage means less bugs, too. Let real-world usage
guide your code, and you'll spend less time building stuff you don't
need.

ChrisA
 
M

Matěj Cepl

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Write your rendering engine as a few simple helper functions,
and then put all the rest in as code instead of XML. The
easiest way to go about it is to write three forms, from
scratch, and then look at the common parts and figure out
which bits can go into helper functions.

Perhaps what's missing is full acknowledgment that Python has
dual-inheritance and thus it can have mixin classes (which seems
to me to be the only useful use of dual inheritance). You know
you can have mixins in Python, right?

Also, I wrote my share of XML parsing/writing code, but more and
more I am persuaded that if the answer is “XML†then there is
some wrong with the question. Python is a way more expressive
language than XML, so it is almost always more useful to write
in Python, than to pass any problems to XML.

Matěj

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iD8DBQFS4pS54J/vJdlkhKwRApdcAJ48PRgDz6ccnq1YFD9zx8EDDH3JjgCghU2x
3CV+D0LvquzgYRux2GslZ0E=
=Y3/F
-----END PGP SIGNATURE-----
 
C

Chris Angelico

Perhaps what's missing is full acknowledgment that Python has
dual-inheritance and thus it can have mixin classes (which seems
to me to be the only useful use of dual inheritance). You know
you can have mixins in Python, right?

Hmm, I've never really felt the need to work that way. Usually it's
functions I want, not classes; but if they're classes, then generally
they're just to add a couple of methods, or change the construction
args, so single inheritance is plenty. (I created a
MultiLineEntryField class as a thin wrapper around TextView, adding
get_text() and set_text() with the same signatures as GTK2.Entry()'s
methods of the same names. That wouldn't apply to anything else, so a
mixin wouldn't help much.) But sure. If you want mixins, go for it.

ChrisA
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top