Re: Keeping python code and database in sync

2014-08-30 Thread dieter
Frank Millman fr...@chagford.com writes:
 ...
 It is a simple matter to write a program that updates the database 
 automatically. The question is, what should trigger such an update? My first 
 thought is to use a version number - store a version number in the working 
 directory, and have a matching number in the code. If someone downloads the 
 latest version, the numbers will no longer match, and I can run the upgrade 
 program.

 The problem with that is that version numbers are usually reserved for 
 tagged releases, but this could happen as the result of any commit in the 
 current development cycle.

I use data model version numbers for this. They identify the
data model version and are idenpendent of any program version number.
Such a version number is changed whenever the data model changes
(and there is the need for a model upgrade).

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


Re: Keeping python code and database in sync

2014-08-29 Thread Rustom Mody
On Friday, August 29, 2014 6:12:06 PM UTC+5:30, Frank Millman wrote:
 Hi all

 Now that I have bitten the bullet and published my repository, I am forced 
 to change my working practices (which is a good thing!).

 The project is inherently database-driven. The python code expects to find 
 certain tables and columns in the database. As I develop new features, I 
 sometimes need to modify the database structure. In the bad old days (like 
 yesterday) I would just make the modifications and carry on. Now I have to 
 be aware that others may have downloaded the project, so I have to consider 
 how to ensure that their database is kept up to date.


There are tools like this
http://alembic.readthedocs.org/en/latest/

It may help to read that to avoid reinvention



 It is a simple matter to write a program that updates the database 
 automatically. The question is, what should trigger such an update? My first 
 thought is to use a version number - store a version number in the working 
 directory, and have a matching number in the code. If someone downloads the 
 latest version, the numbers will no longer match, and I can run the upgrade 
 program.

 The problem with that is that version numbers are usually reserved for 
 tagged releases, but this could happen as the result of any commit in the 
 current development cycle.


I dont think alembic can solve that.
Still it may help to study it
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Chris Angelico
On Fri, Aug 29, 2014 at 10:42 PM, Frank Millman fr...@chagford.com wrote:
 It is a simple matter to write a program that updates the database
 automatically. The question is, what should trigger such an update? My first
 thought is to use a version number - store a version number in the working
 directory, and have a matching number in the code. If someone downloads the
 latest version, the numbers will no longer match, and I can run the upgrade
 program.

This is a well-known problem, and there's no really perfect solution.
The first thing to consider is: What happens if someone back-levels
the program? If you can afford to say never back-level past a schema
change, then you can simply version the schema, independently of the
code. A simple incrementing integer will do - you don't need a
multipart version number. Then you just have code like this:

# Get the current schema version, or 0 if there's nothing yet
version = db.query(select schema_version from config)
if version  1:
# Brand new database
db.query(create table blah blah)
db.query(create table spam)
# etc
if version  2:
db.query(alter table spam add whatever)

# Add new patch levels here
db.query(update config set schema_version = 2)
else:
throw_really_noisy_error(YOU BACKLEVELLED!)

To add a new patch level, you add a new condition with the next
number, add its code, and change the update statement at the end. So
it'd look like this:

 if version  2:
 db.query(alter table spam add whatever)
+if version  3:
+db.query(create table brand_new_table)

 # Add new patch levels here
-db.query(update config set schema_version = 2)
+db.query(update config set schema_version = 3)
else:
 throw_really_noisy_error(YOU BACKLEVELLED!)

It's fairly straight-forward and readable. You'll sometimes need to go
back and defang old patch code (if you simplify or break stuff), and
you might prefer to keep your patch 0 handling up-to-date (so it
doesn't then have to do all the rest of the patches - have that one
immediately set version and bail out), but that's a basic structure
that's been proven in real-world usage. (Note that the exact code
above might be buggy. I'm recreating from memory and porting to Python
at the same time. But the design intent is there.)

Ideally, you want to minimize churn. Don't do heaps of schema changes
in a short period of time. But this can handle plenty of changes
fairly easily, and it'll handle either incremental changes or big
blocks of them just the same way (if you upgrade from patch level 10
to patch level 35 all at once, it'll just grind through all those
changes one after another).

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Frank Millman

Rustom Mody rustompm...@gmail.com wrote in message 
news:1cdf6e52-e09b-40f1-8db1-db6cbbee9...@googlegroups.com...
 On Friday, August 29, 2014 6:12:06 PM UTC+5:30, Frank Millman wrote:
 Hi all

 Now that I have bitten the bullet and published my repository, I am 
 forced
 to change my working practices (which is a good thing!).

 The project is inherently database-driven. The python code expects to 
 find
 certain tables and columns in the database. As I develop new features, I
 sometimes need to modify the database structure. In the bad old days 
 (like
 yesterday) I would just make the modifications and carry on. Now I have 
 to
 be aware that others may have downloaded the project, so I have to 
 consider
 how to ensure that their database is kept up to date.


 There are tools like this
 http://alembic.readthedocs.org/en/latest/

 It may help to read that to avoid reinvention


Thanks for the link, Rustom.

I glanced at it, and it looks very powerful, but I will have to find the 
time to study it at leisure.

In the meantime, Chris' suggestion is simple to implement and adequate for 
my present needs, so I will run with that for now.

Frank



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


Re: Keeping python code and database in sync

2014-08-29 Thread Frank Millman

Chris Angelico ros...@gmail.com wrote in message 
news:CAPTjJmrJBciRuterUKWP=qtqxd8xyqum4nx+ofd-twm5oos...@mail.gmail.com...
 On Fri, Aug 29, 2014 at 10:42 PM, Frank Millman fr...@chagford.com 
 wrote:
 It is a simple matter to write a program that updates the database
 automatically. The question is, what should trigger such an update? My 
 first
 thought is to use a version number - store a version number in the 
 working
 directory, and have a matching number in the code. If someone downloads 
 the
 latest version, the numbers will no longer match, and I can run the 
 upgrade
 program.

 This is a well-known problem, and there's no really perfect solution.
 The first thing to consider is: What happens if someone back-levels
 the program? If you can afford to say never back-level past a schema
 change, then you can simply version the schema, independently of the
 code. A simple incrementing integer will do - you don't need a
 multipart version number.

Thanks, Chris, this sounds ideal for my current requirements.

You mentioned keeping schema changes to a minimum, which I agree with, but 
that is not actually my main problem.

Right now I am writing a tool to allow users to view and modify menu 
definitions. The tool is effectively a form definition, which in my system 
is expressed in xml and stored in the database in the 'sys_form_defns' 
table. The raw xml will be uploaded as part of the commit, and will be 
downloaded when someone pulls the latest version, but it still has to be 
inserted into the database before it is accessible.

It is not a problem - I can use the same mechanism that you described - but 
it will be happening quite a lot until the system settles down.

Frank



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


Re: Keeping python code and database in sync

2014-08-29 Thread Chris Angelico
On Fri, Aug 29, 2014 at 11:31 PM, Frank Millman fr...@chagford.com wrote:
 Right now I am writing a tool to allow users to view and modify menu
 definitions. The tool is effectively a form definition, which in my system
 is expressed in xml and stored in the database in the 'sys_form_defns'
 table. The raw xml will be uploaded as part of the commit, and will be
 downloaded when someone pulls the latest version, but it still has to be
 inserted into the database before it is accessible.

 It is not a problem - I can use the same mechanism that you described - but
 it will be happening quite a lot until the system settles down.

The system I described is intended for cases where each edit builds on
the previous ones - for instance, if patch 4 creates a table and patch
7 adds a column to it, you have to have done them in that order. But
for that XML data, it sounds as if each update completely overwrites
all previous ones - is this right? In that case, I'd simplify it:
after doing all the other patches (anything more complicated than
update this one column can still go through a patching scheme like I
described), you just hard code an overwrite that sets the appropriate
field to the current XML. You don't need to update it through all the
previous states just to get to this one.

Basically, take the simplest approach that will do what you want :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Frank Millman

Chris Angelico ros...@gmail.com wrote in message 
news:captjjmp68kh5zcxq50pi0yeaaapnqotxybg1+f58mv__xd9...@mail.gmail.com...
 On Fri, Aug 29, 2014 at 11:31 PM, Frank Millman fr...@chagford.com 
 wrote:
 Right now I am writing a tool to allow users to view and modify menu
 definitions. The tool is effectively a form definition, which in my 
 system
 is expressed in xml and stored in the database in the 'sys_form_defns'
 table. The raw xml will be uploaded as part of the commit, and will be
 downloaded when someone pulls the latest version, but it still has to be
 inserted into the database before it is accessible.

 It is not a problem - I can use the same mechanism that you described - 
 but
 it will be happening quite a lot until the system settles down.

 The system I described is intended for cases where each edit builds on
 the previous ones - for instance, if patch 4 creates a table and patch
 7 adds a column to it, you have to have done them in that order. But
 for that XML data, it sounds as if each update completely overwrites
 all previous ones - is this right? In that case, I'd simplify it:
 after doing all the other patches (anything more complicated than
 update this one column can still go through a patching scheme like I
 described), you just hard code an overwrite that sets the appropriate
 field to the current XML. You don't need to update it through all the
 previous states just to get to this one.

 Basically, take the simplest approach that will do what you want :)


I *think* I understand, but let me restate it in my terms just to be sure.

When I have got this menu definition tool working, I will commit. The files 
involved will probably be one or more 'py' files, and one 'xml' file.

Once downloaded, the 'py' files are automatically 'live', because that is 
how python works. But the xml file will just be sitting in a directory. 
*Something* has to trigger running a program that reads the xml file and 
inserts it into the database.

My idea is to put the 'version number check' in the main program 'start.py'. 
If it detects that an upgrade is required, it will display a warning message 
to the user and then run the upgrade program. The same upgrade program can 
handle both 'schema' changes and (for want of a word) 'meta-data' changes 
such as the menu definition.

Frank



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


Re: Keeping python code and database in sync

2014-08-29 Thread Chris Angelico
On Sat, Aug 30, 2014 at 12:12 AM, Frank Millman fr...@chagford.com wrote:
 Once downloaded, the 'py' files are automatically 'live', because that is
 how python works. But the xml file will just be sitting in a directory.
 *Something* has to trigger running a program that reads the xml file and
 inserts it into the database.

I'm not 100% certain of this distinction, but it depends on how your
code gets invoked.

 My idea is to put the 'version number check' in the main program 'start.py'.
 If it detects that an upgrade is required, it will display a warning message
 to the user and then run the upgrade program. The same upgrade program can
 handle both 'schema' changes and (for want of a word) 'meta-data' changes
 such as the menu definition.

Yes... or start.py can do it directly and automatically, just check
and do whatever changes are needed. That's how I'd do it.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Roy Smith
In article mailman.13604.1409316126.18130.python-l...@python.org,
 Frank Millman fr...@chagford.com wrote:

 The project is inherently database-driven. The python code expects to find 
 certain tables and columns in the database. As I develop new features, I 
 sometimes need to modify the database structure. In the bad old days (like 
 yesterday) I would just make the modifications and carry on. Now I have to 
 be aware that others may have downloaded the project, so I have to consider 
 how to ensure that their database is kept up to date.

Yeah, schema migration is an ugly problem.  There's a number of tools to 
help here, most of which reduce the suckitude, but don't eliminate it 
completely.  Some things you might want to look at:

* SQLAlchemy Migrate
* South (django-specific)
* yoyo-migrations
* alembic

Google for python schema migration tools and you'll probably find 
others.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Jean-Michel Pichavant


- Original Message -
 From: Roy Smith r...@panix.com
 
 Yeah, schema migration is an ugly problem.  There's a number of tools
 to
 help here, most of which reduce the suckitude, but don't eliminate it
 completely.  Some things you might want to look at:
 
 * SQLAlchemy Migrate
 * South (django-specific)
 * yoyo-migrations
 * alembic
 
 Google for python schema migration tools and you'll probably find
 others.

Note that South is now fully integrated in django 1.7 (It's still ugly but it 
has been polished by the django team).
The OP may want to consider moving to such framework, they tend to provide 
working concepts on critical issues when it comes to webapp/database.

JM


-- IMPORTANT NOTICE: 

The contents of this email and any attachments are confidential and may also be 
privileged. If you are not the intended recipient, please notify the sender 
immediately and do not disclose the contents to any other person, use it for 
any purpose, or store or copy the information in any medium. Thank you.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Skip Montanaro
On Fri, Aug 29, 2014 at 9:54 AM, Roy Smith r...@panix.com wrote:
 Yeah, schema migration is an ugly problem.

It's not really any worse than any other sort of complex data
structure change, is it? If your persistent data lived in a pickle
file, it would likely be as bad or worse.

 ... suckitude ...

Nice word. Let's use it more so my polly app will see it as a common
word and maybe offer it to me in a potential XKCD 936 password. :-)

suckitude suckitude suckitude suckitude suckitude suckitude suckitude

:-)

Skip
-- 
https://mail.python.org/mailman/listinfo/python-list


suckitude classifications [was Re: Keeping python code and database in sync]

2014-08-29 Thread Ethan Furman

On 08/29/2014 10:04 AM, Skip Montanaro wrote:

On Fri, Aug 29, 2014 at 9:54 AM, Roy Smith r...@panix.com wrote:

Yeah, schema migration is an ugly problem.


It's not really any worse than any other sort of complex data
structure change, is it? If your persistent data lived in a pickle
file, it would likely be as bad or worse.


... suckitude ...


Nice word. Let's use it more so my polly app will see it as a common
word and maybe offer it to me in a potential XKCD 936 password. :-)

suckitude suckitude suckitude suckitude suckitude suckitude suckitude


Speaking of suckitude, we could classify technologies that way:

xml: major suckitude

rpc: no suckitude

python: negative suckitude

oh, and suckitude is neither cruft nor corpus !

Polly want a cracker?  ;)

--
~Ethan~
--
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Ben Finney
Roy Smith r...@panix.com writes:

 Yeah, schema migration is an ugly problem. There's a number of tools
 to help here, most of which reduce the suckitude, but don't eliminate
 it completely. Some things you might want to look at:

 * SQLAlchemy Migrate
 * alembic

I can strongly recommend SQLAlchemy. It has several levels of working
with the RDBMS, and they all work well together; you can code primarily
to one API and occasionally use a different part, and it all works
together.

I've never used Alembic, but it is a migration tool built on SQLAlchemy.

 * South (django-specific)

It's worth noting the South is no longer developed as a separate
library:

Please note that South is now end of lifed in favour of the new
migrations framework in Django 1.7, which is based on South but with
significant design improvements. South will not work with Django
1.7; it supports only versions 1.4, 1.5 and 1.6.

URL:http://south.aeracode.org/

-- 
 \ “I think Western civilization is more enlightened precisely |
  `\ because we have learned how to ignore our religious leaders.” |
_o__)—Bill Maher, 2003 |
Ben Finney

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


Re: Keeping python code and database in sync

2014-08-29 Thread Chris Angelico
On Sat, Aug 30, 2014 at 3:04 AM, Skip Montanaro s...@pobox.com wrote:
 On Fri, Aug 29, 2014 at 9:54 AM, Roy Smith r...@panix.com wrote:
 Yeah, schema migration is an ugly problem.

 It's not really any worse than any other sort of complex data
 structure change, is it? If your persistent data lived in a pickle
 file, it would likely be as bad or worse.

Well, correct. The problem isn't because it's in a database; the
problem is a consequence of persistent structured data that can get
out of sync.

It's easy to solve in a simple way that breaks on any sort of
confusion. It takes a bit more complexity (like the scheme I
suggested) to handle a few more cases. It takes a lot more complexity
(like the migration tools Roy listed) to cope with lots of awkward
cases (I suspect at least some of them will handle back-levelling,
which my scheme doesn't). And I doubt any of them is absolutely
perfect.

 ... suckitude ...

 Nice word. Let's use it more so my polly app will see it as a common
 word and maybe offer it to me in a potential XKCD 936 password. :-)

 suckitude suckitude suckitude suckitude suckitude suckitude suckitude


Yeah, it's a great word. As a general rule, suckitude increases with
the square of design complexity and superlinearly with number of bugs.
I'm not sure how suckitude is affected by bugs, exactly; possibly O(N
log N), because each bug has a small probability of affecting another
bug.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: suckitude classifications [was Re: Keeping python code and database in sync]

2014-08-29 Thread Chris Angelico
On Sat, Aug 30, 2014 at 5:02 AM, Ethan Furman et...@stoneleaf.us wrote:
 Speaking of suckitude, we could classify technologies that way:

 xml: major suckitude

 rpc: no suckitude

 python: negative suckitude

I disagree with your last two qualifications. RPC still sucks, just
not as much as some things do. And your last statement implies that
Python actually fixes other problems, which violates one of the
fundamental laws of physics: the Law of Conservation of Suckitude and
Frustration. It's possible to reduce suckitude in one system by
shifting it to another system, and it's possible to overall reduce
suckitude in the universe by engaging in a very frustrating job, but
merely combining two entities cannot actively reduce suckitude. Of
course, sometimes you can wrap the suckitude up in another layer, thus
reducing *apparent* suckitude, and this can make a system safer to
use; but maintenance on the wrapper layer will reveal that nothing has
been destroyed.

Hello, Polly!

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: suckitude classifications [was Re: Keeping python code and database in sync]

2014-08-29 Thread Roy Smith
In article mailman.13623.1409351910.18130.python-l...@python.org,
 Chris Angelico ros...@gmail.com wrote:

 On Sat, Aug 30, 2014 at 5:02 AM, Ethan Furman et...@stoneleaf.us wrote:
  Speaking of suckitude, we could classify technologies that way:
 
  xml: major suckitude
 
  rpc: no suckitude
 
  python: negative suckitude
 
 I disagree with your last two qualifications. RPC still sucks, just
 not as much as some things do.

Are we talking the generic concept of Remote Procedure Calls, or the 
specific implementation of Sun RPC?

I'm surprised at the reaction to the word, as if it were something new.  
I thought the term has been in common parlance for many years.  Contrast 
with winitude.

Anyway, I think it is unfair to describe xml as major suckitude.  True, 
it is somewhat outdated, with more modern alternatives such as JSON, 
YAML, protobuffers, etc.  In its day, however, it was a breakthrough 
technology, even if only an incremental outgrowth of SGML.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: suckitude classifications [was Re: Keeping python code and database in sync]

2014-08-29 Thread Chris Angelico
On Sat, Aug 30, 2014 at 9:19 AM, Roy Smith r...@panix.com wrote:
 In article mailman.13623.1409351910.18130.python-l...@python.org,
  Chris Angelico ros...@gmail.com wrote:

 On Sat, Aug 30, 2014 at 5:02 AM, Ethan Furman et...@stoneleaf.us wrote:
  Speaking of suckitude, we could classify technologies that way:
 
  xml: major suckitude
 
  rpc: no suckitude
 
  python: negative suckitude

 I disagree with your last two qualifications. RPC still sucks, just
 not as much as some things do.

 Are we talking the generic concept of Remote Procedure Calls, or the
 specific implementation of Sun RPC?

I was thinking of XML-RPC, a particular protocol. Although the generic
concept of remotely calling something isn't entirely free of suckitude
- it's all very well in its way, but like everything else, it has its
flaws. In systems that completely hide the details and make it look
identical to local procedure calls, you have the same problem as
creating a Python property that does a lot of work (wait, that call
actually goes out over the network??), and in systems that make it
more clear that this is a network transaction, it's not really a
remote procedure call any more, it's a network action like any other.
But these are small nitpicks. Enough that I'd say minor suckitude or
slight suckitude, but not no suckitude.

 I'm surprised at the reaction to the word, as if it were something new.
 I thought the term has been in common parlance for many years.  Contrast
 with winitude.

It has. It's just that Skip's Polly has never heard the word before,
so we're teaching her.

 Anyway, I think it is unfair to describe xml as major suckitude.  True,
 it is somewhat outdated, with more modern alternatives such as JSON,
 YAML, protobuffers, etc.  In its day, however, it was a breakthrough
 technology, even if only an incremental outgrowth of SGML.

I've never used XML for anything that wasn't mandated by some other
end, and in every single one of those cases, JSON would have been a
much better fit for the data structure. XML is frequently shoehorned
into carrying array data like this:

root
entryheadingfoo/headingsubentrytext/subentrysubentrymore
text/subentrysubentryblah/subentry/entry
entryheadingbar/headingsubentryonly one element/subentry/entry
/root

In JSON, this would be:

{entry:[
{heading:foo,subentry:[text,more text,blah]},
{heading:bar,subentry:[only one element]}
]}

But in XML, there's no way to represent lists/arrays at all, and the
usual way of fitting them in doesn't allow you to distinguish
one-element lists from text strings (compare the heading entry).

So what's the value of XML for information storage? What's it being
compared against that makes it look good? And above all, why do people
still use it when JSON and other formats are available and well known?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Skip Montanaro
On Aug 29, 2014 5:34 PM, Chris Angelico ros...@gmail.com wrote:

 I'm not sure how suckitude is affected by bugs, exactly; possibly O(N
 log N), because each bug has a small probability of affecting another
 bug.

OTOH, bug fixes often have a fairly high probability of adding more bugs to
the system, especially if your test suite isn't up to snuff.

Skip
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Ethan Furman

On 08/29/2014 04:47 PM, Skip Montanaro wrote:

On Aug 29, 2014 5:34 PM, Chris Angelico wrote:


I'm not sure how suckitude is affected by bugs, exactly; possibly O(N
log N), because each bug has a small probability of affecting another
bug.


OTOH, bug fixes often have a fairly high probability of adding more bugs to the 
system, especially if your test suite


Major suckitude !!  must be O(N**2) at least!

[Thus endeth my attempts to train Skip's Polly.  But I am curious -- if 'suckitude' is in immediate contact with 
punctuation such as just now, or at the end of a sentence, does it not count?  That would be suckitude indeed! ;) ]


--
~Ethan~
--
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Skip Montanaro
On Fri, Aug 29, 2014 at 6:54 PM, Ethan Furman et...@stoneleaf.us wrote:
 Thus endeth my attempts to train Skip's Polly.  But I am curious -- if 
 'suckitude' is in immediate contact with punctuation such as just now, or at 
 the end of a sentence, does it not count?  That would be suckitude indeed! ;)

Thank you all, suckitude made it into the corpus, or cruft, or
dustbin, whatever. :-)

? dict /usr/share/dict/words
accessing accounts adapted adding addressed adds adjusted adjusting
advantages advertised aired akumbo algorithms alister allen allowed
...
subscribed suckitude suffered suggested suggestions suggests suited
...

/usr/share/dict/words really isn't a very good dictionary. Note all
the words that are valid but which get flagged, mostly because they
have common suffixes applied to words. I'll fix that shortly.

Yes, words are skipped if they contain anything other than lower
case alphabetic characters. Really simple words = text.split(), then
discard words not meeting the criteria.

Skip
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Keeping python code and database in sync

2014-08-29 Thread Chris Angelico
On Sat, Aug 30, 2014 at 12:14 PM, Skip Montanaro s...@pobox.com wrote:
 Yes, words are skipped if they contain anything other than lower
 case alphabetic characters. Really simple words = text.split(), then
 discard words not meeting the criteria.

Easy way to catch a few more: Just .strip() off a few common items of
punctuation (quotes (all types), full stop, comma, brackets (all
types), etc). If there are any inside the word, discard the word, but
those at one end or other aren't a problem.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list