From waterbug at step.nasa.gov  Tue May  1 01:43:35 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May  1 01:43:37 2007
Subject: [pangalactic-commits] Begin work on full part 21 parsing.
Message-ID: <200705010543.l415hZBk020962@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/io/part21.py 1.9 1.10
PanGalactic/sandbox/parsers/part21_pyparsing.py 1.1 None
PanGalactic/sandbox/parsers/part21_simpleparse.py 1.1 None

Log message:
Begin work on full part 21 parsing.


Index: PanGalactic/pangalactic/utils/io/part21.py
diff -u PanGalactic/pangalactic/utils/io/part21.py:1.9 PanGalactic/pangalactic/utils/io/part21.py:1.10
--- PanGalactic/pangalactic/utils/io/part21.py:1.9	Sun Apr 29 02:14:58 2007
+++ PanGalactic/pangalactic/utils/io/part21.py	Tue May  1 01:43:33 2007
@@ -1,556 +1,116 @@
 #!/usr/bin/env python
-# $Id: part21.py,v 1.9 2007/04/29 06:14:58 waterbug Exp $
+# $Id: part21.py,v 1.10 2007/05/01 05:43:33 waterbug Exp $
 """
 A generic (no dependencies on the rest of PanGalactic) reader/writer for
 "Part 21 files" (ISO 10303-21, STEP "Clear Text Encoding", a serialization
-format).  This module reads a STEP Part 21 data file into a set of
-Python dictionaries.
+format).
 
-@version: $Revision: 1.9 $
+@version: $Revision: 1.10 $
 """
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
-import re, sys, string, time
+import sys, string
 from optparse import OptionParser
 from pprint import pprint
-from simpleparse.common import numbers, strings, comments
-from simpleparse.parser import Parser
-from simpleparse import dispatchprocessor as dp
-
-
-# Part 21 File EBNF syntax specification (informal)
-
-# Productions whose names are all caps are formally named and specified in ISO
-# 10303-21:2002(E).  Productions with lower-case names are either "convenience"
-# productions invented for this parser, or are specified in ISO 10303-21:2002(E)
-# somewhere other than the formal file syntax specification (e.g., the
-# attributes of the HEADER entities such as the 'name' attribute of the
-# FILE_DESCRIPTION, etc.).
-
-# us_entity_instance -> "unparsed simple entity instance"
-# uc_entity_instance -> "unparsed complex entity instance"
-# u_entity_instance  -> "unparsed entity instance"
-
-p21_syntax_all = r'''
-STRING                := "'", [][ \ta-zA-Z0-9\.+,-:_!"*$%&#,()?/:;<=>@{|}^`~_]*,
-                         "'"
-LIST_OF_STRING        := '(', STRING?, (comma, STRING)*, ')'
-STANDARD_KEYWORD      := [A-Z_], [A-Z0-9_]*
-USER_DEFINED_KEYWORD  := '!', STANDARD_KEYWORD
-KEYWORD               := USER_DEFINED_KEYWORD/STANDARD_KEYWORD
-ENUMERATION           := '.', [A-Z], [A-Z0-9]*, '.'
-INTEGER               := [+-]?, [0-9]+
-BINARY                := [0-3], [0-9a-fA-F]+
-ENTITY_INSTANCE_NAME  := '#', [0-9]+
-<eol>                 := '\r'?, '\n'
-<simple_terminator>   := ';', eol
-<complex_terminator>  := ');', eol
-simple_content        := -simple_terminator*, simple_terminator
-complex_content       := -complex_terminator*, complex_terminator
-us_entity_instance    := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, KEYWORD,
-                         simple_content
-uc_entity_instance    := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, '(', KEYWORD,
-                         complex_content
-u_entity_instance     := us_entity_instance/uc_entity_instance
-<ts>                  := [ \t]*
-<comma>               := ',', ts, eol?, ts
-<nullline>            := ts, eol
-record                := u_entity_instance/(ts, c_comment)/nullline
-DATA_SECTION          := 'DATA;', record*, ts, 'ENDSEC;', eol
-description           := LIST_OF_STRING
-implementation_level  := STRING
-FILE_DESCRIPTION      := ts, 'FILE_DESCRIPTION(', description, comma,
-                         implementation_level, ');'
-name                  := STRING
-timestamp             := STRING
-authors               := LIST_OF_STRING
-organization          := LIST_OF_STRING
-preprocessor_version  := STRING
-originating_system    := STRING
-authorization         := STRING
-FILE_NAME             := ts, 'FILE_NAME(', name, comma, timestamp, comma,
-                         authors, comma, organization, comma,
-                         preprocessor_version, comma, originating_system, comma,
-                         authorization, ');', eol
-schema_identifier     := STRING
-object_identifier     := STRING
-schema_name           := schema_identifier, ts, object_identifier?
-schema_identifiers    := '(', schema_name, (comma, schema_name)*, ')'
-FILE_SCHEMA           := ts, 'FILE_SCHEMA(', schema_identifiers, ');', eol
-<header_tag>          := 'HEADER;', eol?
-<ignorable_stuff>     := (ts, c_comment)/nullline
-HEADER_SECTION        := header_tag, FILE_DESCRIPTION, eol?, FILE_NAME, eol?,
-                         FILE_SCHEMA, ignorable_stuff*, 'ENDSEC;', eol
-<exch_file_tag>       := 'ISO-10303-21;', eol?
-EXCHANGE_FILE         := exch_file_tag, ignorable_stuff*, HEADER_SECTION,
-                         ignorable_stuff*, DATA_SECTION, (ignorable_stuff*,
-                         DATA_SECTION)*, ignorable_stuff*, 'END-ISO-10303-21;',
-                         nullline*
-'''
-
-p21_syntax = r'''
-ENTITY_INSTANCE_NAME  := '#', [0-9]+
-STANDARD_KEYWORD      := [A-Z_], [A-Z0-9_]*
-USER_DEFINED_KEYWORD  := '!', STANDARD_KEYWORD
-KEYWORD               := USER_DEFINED_KEYWORD/STANDARD_KEYWORD
-<eol>                 := '\r'?, '\n'
-<simple_terminator>   := ';', eol
-<complex_terminator>  := ');', eol
-simple_content        := -simple_terminator*, simple_terminator
-complex_content       := -complex_terminator*, complex_terminator
-us_entity_instance    := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, KEYWORD,
-                         simple_content
-uc_entity_instance    := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, '(', KEYWORD,
-                         complex_content
-u_entity_instance     := us_entity_instance/uc_entity_instance
-<ts>                  := [ \t]*
-<comma>               := ',', ts, eol?, ts
-<nullline>            := ts, eol
-record                := u_entity_instance/(ts, c_comment)/nullline
-DATA_SECTION          := 'DATA;', record*, ts, 'ENDSEC;', eol
-header_tag            := 'HEADER;', eol?
-end_tag               := 'ENDSEC;', eol
-<ignorable_stuff>     := (ts, c_comment)/nullline
-HEADER_SECTION        := header_tag, -end_tag*, end_tag
-<exch_file_tag>       := 'ISO-10303-21;', eol?
-EXCHANGE_FILE         := exch_file_tag, ignorable_stuff*, HEADER_SECTION,
-                         ignorable_stuff*, DATA_SECTION, (ignorable_stuff*,
-                         DATA_SECTION)*, ignorable_stuff*, 'END-ISO-10303-21;',
-                         nullline*
-'''
-
-
-class Part21Parser(Parser):
-    """
-    Parser for Part 21 files.
-    """
-
-    def __init__(self, *arg):
-        Parser.__init__(self, *arg)
-        self.res = {}
-
-    def buildProcessor(self):
-        return Part21Processor(self.res)
-
-
-class Part21Processor(dp.DispatchProcessor):
-    """
-    Processing object for postprocessing the Part 21 grammar definitions into a
-    new generator.
-    """
-
-    def __init__(self, res):
-        self.res = res
-
-    def STRING(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{STRING} production.
-        """
-        return (tag, start, stop, subtags)
-
-    def LIST_OF_STRING(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{LIST_OF_STRING} production.
-        """
-        value = []
-        if subtags:
-            value = [dp.getString(s) for s in subtags]
-        return value
-
-    def KEYWORD(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{KEYWORD} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def STANDARD_KEYWORD(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{STANDARD_KEYWORD} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def USER_DEFINED_KEYWORD(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{USER_DEFINED_KEYWORD} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def ENUMERATION(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{ENUMERATION} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def INTEGER(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{INTEGER} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def BINARY(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{BINARY} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def ENTITY_INSTANCE_NAME(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{ENTITY_INSTANCE_NAME} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def simple_content(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{simple_content} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def complex_content(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{complex_content} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def us_entity_instance(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{us_entity_instance} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def uc_entity_instance(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{uc_entity_instance} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def u_entity_instance(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{u_entity_instance} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def record(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{record} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def DATA_SECTION(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{DATA_SECTION} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def description(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{description} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def implementation_level(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{implementation_level} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def FILE_DESCRIPTION(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{FILE_DESCRIPTION} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def name(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{name} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def timestamp(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{timestamp} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def authors(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{authors} production.
-        """
-        self.res['authors'] = []
-        if subtags:
-            self.res['authors'] = self.LIST_OF_STRING(subtags[0])
-
-    def organization(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{organization} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def preprocessor_version(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{preprocessor_version} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def originating_system(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{originating_system} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def authorization(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{authorization} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def FILE_NAME(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{FILE_NAME} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def schema_identifier(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{schema_identifier} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def object_identifier(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{object_identifier} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def schema_name(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{schema_name} production.
-        """
-        self.res['schema_name'] = dp.getString((tag, start, stop, subtags),
-                                               buffer)
-
-    def schema_identifiers(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{schema_identifiers} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-    def FILE_SCHEMA(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{FILE_SCHEMA} production.
-        """
-        self.res['FILE_SCHEMA'] = dp.getString((tag, start, stop, subtags),
-                                               buffer)
-
-    def HEADER_SECTION(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{HEADER_SECTION} production.
-        """
-        return (tag, start, stop, subtags)
-
-    def EXCHANGE_FILE(self, (tag, start, stop, subtags), buffer):
-        """
-        Process C{EXCHANGE_FILE} production.
-        """
-        return dp.getString((tag, start, stop, subtags), buffer)
-
-
-def read(f=None, perf=False, verbose=False, test=False):
-    # NOTE:  test is always True for now ...
-    """
-    (These docs are fiction at the moment ... ;)
-
-    Read a STEP Part 21 file/stream and return a set of Python dictionaries.
-
-    @param f:  path to a file containing STEP Part 21 data
-    @type  f:  C{str}
-
-    @param null:  a value to use for nulls in the data, which are
-        represented by '$' in Part 21.  Attributes with null values will not
-        be included in the instance dictionaries unless a value is supplied
-        for null, in which case they will be included with that value
-    @type  null:  C{str}
-
-    @return:  a dictionary of instance dictionaries, mapped by their
-        C{id} attributes.
-
-             {id-1 : {attr:value, ...},
-              id-2 : {attr:value, ...},
-              ...}
-
-        ... where each C{id-n} attribute is of the form '#'+str(int) and
-        must be unique within the dataset.
-
-    @rtype:   C{dict}
-    """
-    p = Parser(p21_syntax)
-    if f:
-        data = open(f).read()
-        if perf:
-            start = time.clock()
-        success, res, nextchar = p.parse(data, production='EXCHANGE_FILE')
-        if perf:
-            end = time.clock()
-            print "\nTotal parse time: %6.2f sec" % (end - start)
-            print len(data.split("\n"))," lines\n"
-        if test:
-            print '---------------'
-            print 'Sample of Data:'
-            print '---------------'
-            sample = data[:100]
-            print sample
-            print '\n------------'
-            print 'Result Tree:'
-            print '------------'
-            # print res
-            pprint(res)
-        else:
-            print '\n------------'
-            print 'Result Tree:'
-            print '------------'
-            # print res
-            pprint(res)
-            rd = makeResDict(res, data)
-            print '\n------------'
-            print 'Result Dict:'
-            print '------------\n'
-            pprint(rd)
-    elif test:
-        # run all tests on p21_syntax
-        from pangalactic.test import test_part21
-        for production, test_data in test_part21.tests.items():
-            if verbose:
-                print '* production:', production
-            for data in test_data:
-                success, children, nextcharacter = p.parse(data,
-                                                production=production)
-                assert success and nextcharacter==len(data), ''.join([
-                    "Wasn't able to parse %s as a %s " % (
-                        repr(data), production),
-                    "(%s chars parsed of %s), returned value was %s" % (
-                        nextcharacter, len(data),
-                        (success, children, nextcharacter))
-                        ])
-                if verbose:
-                    print '  * data:', data
-                    print '  * output:'
-                    pprint(p.parse(data, production=production))
-                    print
-                elif success:
-                    print '  * passed: ', production
-    else:
-        pass
-
-def makeResDict(res, data):
-    """
-    Create a dictionary from a result tree.
-    """
-    next = res
-    rd = {}
-    while next:
-        this_level = next
-        next = []
-        for e in this_level:
-            if e[3]:
-                rd[e[0]] = e[3] or data[e[1]:e[2]]
-            next += e[3]
-    return rd
-
-###  THIS APPROACH IS ON HOLD FOR NOW  ###################
-#
-# def processChildren(children, data):
-#     """
-#     Process the children; if there are any primitives among the children, return
-#     their values.
-#     """
-# 
-#     if len(children) == 1 and 
-#     for child in children:
-#         f = primitives.get(child[0])
-#         if f:
-#             
-# 
-# primitives = ['STRING' : 
-#               'LIST_OF_STRING', [dp.getString(s) for s in subtags]
-#               'INTEGER',
-#               'ENUMERATION',
-#               'BINARY',
-#               'ENTITY_INSTANCE_NAME',
-#               'STANDARD_KEYWORD',
-#               'simple_content',
-#               'complex_content']
-# 
-# def list_of_string(x):
-#     return [dp.getString(s) for s in subtags]
-
-def write(dataset, schema='pgef', fname='out.p21', description='',
-          null='$', wrap='element'):
-    """
-    Write a dataset out to a Part 21 file/stream.
-
-    @param dataset:  a dictionary of dictionaries of the form:
-
-             {id-1 : {attr:value, ...},
-              id-2 : {attr:value, ...},
-              ...}
-
-        ... where each C{id-n} attribute is of the form '#'+str(int) and
-        must be unique within the dataset.
-
-    @type  dataset:  C{dict}
-
-    @param schema:  name of the schema governing the data
-    @type  schema:  C{str}
-
-    @param fname:  the name of the file to write to
-    @type  fname:  C{str}
-
-    @param description:  some text describing the data
-    @type  description:  C{str}
-
-    @param null:  a value to use for nulls in the data, which are
-        represented by '$' in Part 21.  Attributes with null values will not be
-        included in the instance dictionaries unless a value is supplied for
-        null, in which case they will be included with that value
-    @type  null:  C{str}
-
-    @param wrap:  type of wrapping to use for output:
-
-        'element' :  wrap elements
-        'pprint'  :  wrap elements and attributes
-        otherwise :  no wrap (any other value of 'wrap')
-
-    @type  wrap:  C{str}
-    """
-    f = file(fname, 'w')
-    f.write('Part 21 File\n')
-    f.close()
+from pyparsing import Word, Optional, Forward, ZeroOrMore
+from pyparsing import delimitedList
+
+# added by Paul McGuire (thanks, Paul!)
+from pyparsing import Combine,sglQuotedString,Group,Suppress,removeQuotes
+from pyparsing import Dict,OneOrMore,cppStyleComment
+
+from pangalactic.utils.io.part21_preparse
+
+import time
+time.clock()
+
+def groupInParens(expr):
+    return Group(Suppress("(") + expr + Suppress(")"))
+    
+pre = '0123'
+HEX = string.hexdigits
+BINARY = Word(pre, HEX)
+
+DIGIT = string.digits
+LOWER = string.lowercase
+UPPER = string.uppercase + '_'
+SPECIAL = '!"*$%&.#+,-()?/:;<=>@[]{|}^`~'
+REVERSE_SOLIDUS = '\\'
+APOSTROPHE = "'"
+SIGN = Word('+-', max=1)
+CHARACTER = Word((' ' + DIGIT + LOWER + UPPER + SPECIAL + REVERSE_SOLIDUS +
+                  APOSTROPHE), max=1)
+NON_Q_CHAR = Word((' ' + DIGIT + LOWER + UPPER + SPECIAL), max=1)
+STRING = sglQuotedString.setParseAction(removeQuotes)
+ENUMERATION = Combine('.' + Word(UPPER, UPPER + DIGIT) + '.')
+ENTITY_INSTANCE_NAME = Word('#',DIGIT)
+
+REAL = Combine(Optional(SIGN) + Word(DIGIT) + "." + Optional(Word(DIGIT)) + 
+        Optional('E' + Optional(SIGN) + Word(DIGIT)))
+INTEGER = Word('+-'+DIGIT,DIGIT)
+STANDARD_KEYWORD = Word(UPPER, UPPER + DIGIT)
+USER_DEFINED_KEYWORD = Combine('!' + STANDARD_KEYWORD)
+KEYWORD = USER_DEFINED_KEYWORD | STANDARD_KEYWORD
+
+OMITTED_PARAMETER = '*'
+LIST = Forward()
+UNTYPED_PARAMETER = Forward()
+PARAMETER = Forward()
+TYPED_PARAMETER = Forward()
+PARAMETER_LIST = Forward()
+LIST << groupInParens( Optional(PARAMETER_LIST) )
+
+# replacing '^' with '|' in the next two expressions accounted for most of the performance speedup
+UNTYPED_PARAMETER << ("$" | REAL | INTEGER | STRING | ENTITY_INSTANCE_NAME
+                      | ENUMERATION | BINARY | LIST)
+PARAMETER << (TYPED_PARAMETER | UNTYPED_PARAMETER | OMITTED_PARAMETER)
+TYPED_PARAMETER << (KEYWORD + groupInParens( PARAMETER ))
+PARAMETER_LIST << Group(delimitedList(PARAMETER, delim=','))
+unparsed_record = KEYWORD + groupInParens('.*')
+SIMPLE_RECORD = KEYWORD + groupInParens( Optional(PARAMETER_LIST) )
+SIMPLE_RECORD_LIST = SIMPLE_RECORD + ZeroOrMore(SIMPLE_RECORD)
+SUBSUPER_RECORD = groupInParens( SIMPLE_RECORD_LIST )
+#~ COMPLEX_ENTITY_INSTANCE = ENTITY_INSTANCE_NAME + '=' + SUBSUPER_RECORD + ';'
+#~ ENTITY_INSTANCE = (SIMPLE_ENTITY_INSTANCE ^ COMPLEX_ENTITY_INSTANCE)
+ENTITY_INSTANCE = Group(ENTITY_INSTANCE_NAME + '=' + ( SIMPLE_RECORD | SUBSUPER_RECORD ) + ';')
+ENTITY_INSTANCE_LIST = ZeroOrMore(ENTITY_INSTANCE)
+
+DATA_SECTION = ('DATA' + Optional( groupInParens( PARAMETER_LIST ).setResultsName("PARAMETERS")) + ';' + Dict(ENTITY_INSTANCE_LIST) + 'ENDSEC;')
+
+HEADER_ENTITY = KEYWORD + groupInParens( Optional(PARAMETER_LIST) ) + ";"
+HEADER_ENTITY_LIST = HEADER_ENTITY + ZeroOrMore(HEADER_ENTITY)
+HEADER_SECTION = ("HEADER;" + HEADER_ENTITY + HEADER_ENTITY + HEADER_ENTITY +
+                  Optional(HEADER_ENTITY_LIST) + "ENDSEC;")
+EXCHANGE_FILE = ("ISO-10303-21;" + HEADER_SECTION.setResultsName("HEADER") + 
+                 OneOrMore(DATA_SECTION).setResultsName("DATA") + "END-ISO-10303-21;")
+EXCHANGE_FILE.ignore(cppStyleComment)
 
 
 if __name__ == '__main__':
     usage = 'usage:  %prog [options] file.p21'
     optparser = OptionParser(usage)
-    optparser.add_option("-p", "--perf", action='store_true',
-                         dest="performance", default=False,
-                         help="run the parser's unit tests")
-    optparser.add_option("-t", "--test", action='store_true',
-                         dest="test", default=False,
-                         help="run the parser's unit tests")
-    optparser.add_option("-v", "--verbose", action='store_true',
-                         dest="verbose", default=False,
-                         help="verbose output from test (no effect on normal function)")
-    (options, args) = optparser.parse_args(args=sys.argv)
-    # debugging:
-    # print "options:  %s" % str(options)
-    # print "args:     %s" % str(args)
-    if len(args) > 1:
-        read(f=args[1],
-             perf=options.performance,
-             verbose=options.verbose,
-             test=options.test)
-    elif options.test:
-        read(test=True,
-             perf=options.performance,
-             verbose=options.verbose)
-    else:
-        optparser.print_help()
+    optparser.add_option("-t", "--time", action='store_true',
+                         dest="show_time", default=False,
+                         help="show the time consumed")
+    (options, args) = optparser.parse_args(args=sys.argv[1:] or ['-h'])
+    if args[0] != '-h':
+        data = open(args[0]).read()
+        if options.show_time:
+            startTime = time.clock()
+        res = EXCHANGE_FILE.parseString(data)
+        if options.show_time:
+            endTime = time.clock()
+            totalTime = endTime - startTime
+            print "\nTotal parse time: %6.2f sec" % totalTime
+            print len(data.split("\n"))," lines\n"
+        # pprint( res.asList() )
+        print res.HEADER
+        keylist = list(res.DATA.keys())
+        # print '\nitem IDs are:', keylist
+        print '\nfirst 10 items are:'
+        for k in range(10):
+            print keylist[k], res.DATA[keylist[k]][1], res.DATA[keylist[k]][2]
+        print '\nlast 10 items are:'
+        for k in range(11)[1:]:
+            print keylist[(-1)*k], res.DATA[keylist[(-1)*k]][1], res.DATA[keylist[(-1)*k]][2]
 

From waterbug at step.nasa.gov  Thu May  3 12:27:18 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May  3 12:27:20 2007
Subject: [pangalactic-commits] Mainly refinements to part 21 file parsing ...
Message-ID: <200705031627.l43GRIWY024575@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.183 1.184
PanGalactic/pangalactic/test/test_part21_preparse.py 1.2 1.3
PanGalactic/pangalactic/utils/io/import_assembly.py None 1.1
PanGalactic/pangalactic/utils/io/part21.py 1.10 1.11
PanGalactic/pangalactic/utils/io/part21_preparse.py 1.3 1.4

Log message:
Mainly refinements to part 21 file parsing ...
also, a "demo" application (get assemblies from a file).


Index: PanGalactic/pangalactic/test/test_part21_preparse.py
diff -u PanGalactic/pangalactic/test/test_part21_preparse.py:1.2 PanGalactic/pangalactic/test/test_part21_preparse.py:1.3
--- PanGalactic/pangalactic/test/test_part21_preparse.py:1.2	Mon Apr 30 15:43:55 2007
+++ PanGalactic/pangalactic/test/test_part21_preparse.py	Thu May  3 12:27:15 2007
@@ -1,10 +1,10 @@
-# $Id: test_part21_preparse.py,v 1.2 2007/04/30 19:43:55 waterbug Exp $
+# $Id: test_part21_preparse.py,v 1.3 2007/05/03 16:27:15 waterbug Exp $
 """
 Tests for STEP Part 21 file parsing
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 
 tests = {
@@ -52,15 +52,13 @@
         """#57=DATE_TIME_ROLE('classification_date');
 """,
         """#58=APPROVAL_DATE_TIME(#50,#21);
+""",
+        """#167=APPLICATION_CONTEXT
+('CONFIGURATION CONTROLLED 3D DESIGNS OF MECHANICAL PARTS AND ASSEMBLIES');
 """
         ],
 
     'complex_instance' : [
-        """#90=(GEOMETRIC_REPRESENTATION_CONTEXT(3) 
-                GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#91)) 
-                GLOBAL_UNIT_ASSIGNED_CONTEXT((#92,#93,#94)) 
-                REPRESENTATION_CONTEXT('',''));
-""",
         """#92=(LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.));
 """,
         """#93=(NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.));

Index: PanGalactic/pangalactic/utils/io/part21_preparse.py
diff -u PanGalactic/pangalactic/utils/io/part21_preparse.py:1.3 PanGalactic/pangalactic/utils/io/part21_preparse.py:1.4
--- PanGalactic/pangalactic/utils/io/part21_preparse.py:1.3	Mon Apr 30 15:43:56 2007
+++ PanGalactic/pangalactic/utils/io/part21_preparse.py	Thu May  3 12:27:16 2007
@@ -1,14 +1,14 @@
 #!/usr/bin/env python
-# $Id: part21_preparse.py,v 1.3 2007/04/30 19:43:56 waterbug Exp $
+# $Id: part21_preparse.py,v 1.4 2007/05/03 16:27:16 waterbug Exp $
 """
 A generic (no dependencies on the rest of PanGalactic) reader/writer for
 "Part 21 files" (ISO 10303-21, STEP "Clear Text Encoding", a serialization
 format).  This module reads a STEP Part 21 data file into a set of
 Python dictionaries.
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 import re, sys, string, time
 from optparse import OptionParser
@@ -37,14 +37,14 @@
 ENTITY_INSTANCE_NAME  := '#', [0-9]+
 KEYWORD               := [A-Z_], [A-Z0-9_]*
 <eol>                 := '\r'?, '\n'
-<simple_terminator>   := ';', eol
-<complex_terminator>  := ');', eol
-simple_content        := -simple_terminator*, simple_terminator
-complex_content       := -complex_terminator*, complex_terminator
+<record_terminator>   := ')', ts, ';', eol
+parameter_list        := -record_terminator, -record_terminator*
 simple_instance       := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, KEYWORD,
-                         simple_content
-complex_instance      := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, '(', KEYWORD,
-                         complex_content
+                         ts, eol?, '(', parameter_list, record_terminator
+instance_list         := KEYWORD, ts, eol?, '(', parameter_list, ')', ts, eol?,
+                         (KEYWORD, '(', parameter_list, ')', ts, eol?)*
+complex_instance      := ts, ENTITY_INSTANCE_NAME, ts, '=', ts, '(',
+                         parameter_list, record_terminator
 <ts>                  := [ \t]*
 <comma>               := ',', ts, eol?, ts
 <nullline>            := ts, eol
@@ -65,9 +65,9 @@
 '''
 
 
-class Part21Parser(Parser):
+class Part21Preparser(Parser):
     """
-    Parser for Part 21 files.
+    Preparser for Part 21 files.
     """
 
     def __init__(self, *arg):
@@ -104,17 +104,22 @@
         """
         return dp.getString((tag, start, stop, subtags), buffer)
 
-    def simple_content(self, (tag, start, stop, subtags), buffer):
+    def parameter_list(self, (tag, start, stop, subtags), buffer):
         """
         Process C{simple_content} production.
         """
         return dp.getString((tag, start, stop, subtags), buffer)
 
-    def complex_content(self, (tag, start, stop, subtags), buffer):
+    def instance_list(self, (tag, start, stop, subtags), buffer):
         """
         Process C{complex_content} production.
+
+        @return:  a 2-tuple of (keywords, parameter lists), where keywords is
+            the list of KEYWORD occurrences and parameter lists is a list of
+            strings (each of which is an unparsed parameter list).
         """
-        return dp.getString((tag, start, stop, subtags), buffer)
+        inst = dp.multiMap((tag, start, stop, subtags), buffer)
+        return inst.get('KEYWORD'), inst.get('parameter_list')
 
     def simple_instance(self, (tag, start, stop, subtags), buffer):
         """
@@ -122,7 +127,7 @@
         """
         inst = dp.singleMap(subtags, self, buffer)
         self.res['contents'][
-            inst.get('ENTITY_INSTANCE_NAME')] = inst.get('simple_content')
+            inst.get('ENTITY_INSTANCE_NAME')] = inst.get('parameter_list')
         self.res['insttype'][
             inst.get('ENTITY_INSTANCE_NAME')] = inst.get('KEYWORD')
 
@@ -132,9 +137,9 @@
         """
         inst = dp.singleMap(subtags, self, buffer)
         self.res['contents'][
-            inst.get('ENTITY_INSTANCE_NAME')] = inst.get('complex_content')
+            inst.get('ENTITY_INSTANCE_NAME')] = inst.get('parameter_list')
         self.res['insttype'][
-            inst.get('ENTITY_INSTANCE_NAME')] = inst.get('KEYWORD')
+            inst.get('ENTITY_INSTANCE_NAME')] = 'complex_type'
 
     def HEADER_SECTION(self, (tag, start, stop, subtags), buffer):
         """
@@ -143,7 +148,7 @@
         self.res['header'] = dp.getString((tag, start, stop, subtags), buffer)
 
 
-def read(f=None, perf=False, verbose=False, test=False):
+def readStepFile(f=None, perf=False, verbose=False, test=False):
     # NOTE:  test is always True for now ...
     """
     (These docs are fiction at the moment ... ;)
@@ -159,19 +164,14 @@
         for null, in which case they will be included with that value
     @type  null:  C{str}
 
-    @return:  a dictionary of instance dictionaries, mapped by their
-        C{id} attributes.
-
-             {id-1 : {attr:value, ...},
-              id-2 : {attr:value, ...},
-              ...}
-
-        ... where each C{id-n} attribute is of the form '#'+str(int) and
-        must be unique within the dataset.
-
+    @return:  a result C{dict} that contains 3 items:  (1) 'header', the
+        unparsed header section of the part 21 file; (2) 'contents', a C{dict}
+        that maps entity instance numbers (production: 'ENTITY_INSTANCE_NAME')
+        to their unparsed content; and (3) 'insttype', a C{dict} that maps
+        entity instance numbers to their declared types (production: 'KEYWORD').
     @rtype:   C{dict}
     """
-    p = Part21Parser(p21_syntax)
+    p = Part21Preparser(p21_syntax)
     if f:
         data = open(f).read()
         if perf:
@@ -187,10 +187,11 @@
             print '---------------'
             sample = data[:100]
             print sample
-        print '\n------------'
-        print 'Result Tree:'
-        print '------------'
-        pprint(p.res)
+        # print '\n------------'
+        # print 'Result Tree:'
+        # print '------------'
+        # pprint(p.res)
+        return p.res
     elif test:
         # run all tests on p21_syntax
         from pangalactic.test import test_part21_preparse as tpp
@@ -278,14 +279,14 @@
     # print "options:  %s" % str(options)
     # print "args:     %s" % str(args)
     if len(args) > 1:
-        read(f=args[1],
-             perf=options.performance,
-             verbose=options.verbose,
-             test=options.test)
+        readStepFile(f=args[1],
+                     perf=options.performance,
+                     verbose=options.verbose,
+                     test=options.test)
     elif options.test:
-        read(test=True,
-             perf=options.performance,
-             verbose=options.verbose)
+        readStepFile(test=True,
+                     perf=options.performance,
+                     verbose=options.verbose)
     else:
         optparser.print_help()
 

Index: PanGalactic/pangalactic/utils/io/part21.py
diff -u PanGalactic/pangalactic/utils/io/part21.py:1.10 PanGalactic/pangalactic/utils/io/part21.py:1.11
--- PanGalactic/pangalactic/utils/io/part21.py:1.10	Tue May  1 01:43:33 2007
+++ PanGalactic/pangalactic/utils/io/part21.py	Thu May  3 12:27:16 2007
@@ -1,13 +1,13 @@
 #!/usr/bin/env python
-# $Id: part21.py,v 1.10 2007/05/01 05:43:33 waterbug Exp $
+# $Id: part21.py,v 1.11 2007/05/03 16:27:16 waterbug Exp $
 """
 A generic (no dependencies on the rest of PanGalactic) reader/writer for
 "Part 21 files" (ISO 10303-21, STEP "Clear Text Encoding", a serialization
 format).
 
-@version: $Revision: 1.10 $
+@version: $Revision: 1.11 $
 """
-__version__ = "$Revision: 1.10 $"[11:-2]
+__version__ = "$Revision: 1.11 $"[11:-2]
 
 import sys, string
 from optparse import OptionParser
@@ -19,7 +19,7 @@
 from pyparsing import Combine,sglQuotedString,Group,Suppress,removeQuotes
 from pyparsing import Dict,OneOrMore,cppStyleComment
 
-from pangalactic.utils.io.part21_preparse
+from pangalactic.utils.io.part21_preparse import Part21Preparser
 
 import time
 time.clock()

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.183 PanGalactic/pangalactic/node/pangalaxian.py:1.184
--- PanGalactic/pangalactic/node/pangalaxian.py:1.183	Wed Apr 25 13:47:47 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Thu May  3 12:27:15 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.183 2007/04/25 17:47:47 waterbug Exp $
+# $Id: pangalaxian.py,v 1.184 2007/05/03 16:27:15 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.183 $
+@version: $Revision: 1.184 $
 """
-__version__ = "$Revision: 1.183 $"[11:-2]
+__version__ = "$Revision: 1.184 $"[11:-2]
 
 # Python
 import logging
@@ -111,6 +111,10 @@
             id=wx.ID_ANY,
             text="Log&out",
             help="Logout from repository ...")
+        self.file_import = self.file_menu.Append(
+            id=wx.ID_ANY,
+            text="&Import...",
+            help="Import data from file ...")
         # self.file_export = self.file_menu.Append(
         #     id=wx.ID_ANY,
         #     text="&Export",
@@ -473,6 +477,7 @@
         self.Bind(wx.EVT_MENU, self.onNewObject, self.file_object)
         self.Bind(wx.EVT_MENU, self.openFullLoginDialog, self.file_login)
         self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
+        self.Bind(wx.EVT_MENU, self.onImport, self.file_import)
         # self.Bind(wx.EVT_MENU, self.onExport, self.file_export)
         self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
         #
@@ -579,6 +584,14 @@
             self.log.info('   Wizard was cancelled')
         wizard.Destroy()
 
+    def onImport(self, event):
+        """
+        Import data from a file.
+        """
+        # TODO:  create a Wizard for the import process
+        self.log.info(' - PanGalaxian.onImport')
+        
+
     def updateProjects(self):
         """
         Update the C{projects} instance variable, if necessary.

From waterbug at step.nasa.gov  Thu May  3 16:29:11 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May  3 16:29:12 2007
Subject: [pangalactic-commits] Point commit for demo.
Message-ID: <200705032029.l43KTBPb030891@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/io/import_assembly.py 1.1 1.2
PanGalactic/pangalactic/utils/io/part21_preparse.py 1.4 1.5

Log message:
Point commit for demo.


Index: PanGalactic/pangalactic/utils/io/part21_preparse.py
diff -u PanGalactic/pangalactic/utils/io/part21_preparse.py:1.4 PanGalactic/pangalactic/utils/io/part21_preparse.py:1.5
--- PanGalactic/pangalactic/utils/io/part21_preparse.py:1.4	Thu May  3 12:27:16 2007
+++ PanGalactic/pangalactic/utils/io/part21_preparse.py	Thu May  3 16:29:09 2007
@@ -1,14 +1,14 @@
 #!/usr/bin/env python
-# $Id: part21_preparse.py,v 1.4 2007/05/03 16:27:16 waterbug Exp $
+# $Id: part21_preparse.py,v 1.5 2007/05/03 20:29:09 waterbug Exp $
 """
 A generic (no dependencies on the rest of PanGalactic) reader/writer for
 "Part 21 files" (ISO 10303-21, STEP "Clear Text Encoding", a serialization
 format).  This module reads a STEP Part 21 data file into a set of
 Python dictionaries.
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import re, sys, string, time
 from optparse import OptionParser
@@ -87,10 +87,12 @@
     def __init__(self, res):
         self.res = res
         # TODO:  set this up as a sqlite database
-        # contents:  maps ent inst nbr (n) to unparsed content
-        # insttype:  maps ent inst nbr (n) to KEYWORD (i.e. type)
+        # contents:  maps entity inst nbr (n) to unparsed content
+        # insttype:  maps entity inst nbr (n) to KEYWORD (i.e. type)
+        # insttype:  maps KEYWORD (i.e. type) (n) to entity inst nbr
         self.res['contents'] = {}
         self.res['insttype'] = {}
+        self.res['typeinst'] = {}
 
     def ENTITY_INSTANCE_NAME(self, (tag, start, stop, subtags), buffer):
         """
@@ -130,6 +132,12 @@
             inst.get('ENTITY_INSTANCE_NAME')] = inst.get('parameter_list')
         self.res['insttype'][
             inst.get('ENTITY_INSTANCE_NAME')] = inst.get('KEYWORD')
+        try:
+            self.res['typeinst'][
+                inst.get('KEYWORD')].append(inst.get('ENTITY_INSTANCE_NAME'))
+        except:
+            self.res['typeinst'][
+                inst.get('KEYWORD')] = [inst.get('ENTITY_INSTANCE_NAME')]
 
     def complex_instance(self, (tag, start, stop, subtags), buffer):
         """
@@ -140,6 +148,12 @@
             inst.get('ENTITY_INSTANCE_NAME')] = inst.get('parameter_list')
         self.res['insttype'][
             inst.get('ENTITY_INSTANCE_NAME')] = 'complex_type'
+        try:
+            self.res['typeinst'][
+                inst.get('KEYWORD')].append(inst.get('ENTITY_INSTANCE_NAME'))
+        except:
+            self.res['typeinst'][
+                inst.get('KEYWORD')] = [inst.get('ENTITY_INSTANCE_NAME')]
 
     def HEADER_SECTION(self, (tag, start, stop, subtags), buffer):
         """
@@ -180,17 +194,17 @@
         if perf:
             end = time.clock()
             print "\nTotal parse time: %6.2f sec" % (end - start)
-            print len(data.split("\n"))," lines\n"
+            print len(list(p.res.get('contents', [])))," instances\n"
         if test:
             print '---------------'
             print 'Sample of Data:'
             print '---------------'
             sample = data[:100]
             print sample
-        # print '\n------------'
-        # print 'Result Tree:'
-        # print '------------'
-        # pprint(p.res)
+            print '\n------------'
+            print 'Result Tree:'
+            print '------------'
+            pprint(p.res)
         return p.res
     elif test:
         # run all tests on p21_syntax

Index: PanGalactic/pangalactic/utils/io/import_assembly.py
diff -u PanGalactic/pangalactic/utils/io/import_assembly.py:1.1 PanGalactic/pangalactic/utils/io/import_assembly.py:1.2
--- PanGalactic/pangalactic/utils/io/import_assembly.py:1.1	Thu May  3 12:27:16 2007
+++ PanGalactic/pangalactic/utils/io/import_assembly.py	Thu May  3 16:29:09 2007
@@ -1,3 +1,4 @@
+from pprint import pprint
 from pangalactic.utils.io.part21 import PARAMETER_LIST
 from pangalactic.utils.io.part21_preparse import readStepFile
 
@@ -34,7 +35,17 @@
 
 def getAssemblies(f):
     data = readStepFile(f)
-    nauo_ids = [i for i in list(data['insttype'])
-                if data['insttype'][i] == 'NEXT_ASSEMBLY_USAGE_OCCURRENCE']
-    return nauo_ids    
+    nauo = {}
+    for n in data['typeinst']['NEXT_ASSEMBLY_USAGE_OCCURRENCE']:
+        parent, child = [x.strip(' \n\r#')
+                         for x in data['contents'][n].split(',')[3:5]]
+        nauo[n] = {'oid'    : ''.join(['#', n]),
+                   'id'     : ' '.join(['nauo', n]),
+                   # relating_product_definition (4th attr)
+                   'parent' : parent,
+                   # related_product_definition (5th attr)
+                   'child'  : child,
+                   'reference_designator' : '' # test data doesn't have
+                   }
+    pprint(nauo)
 

From waterbug at step.nasa.gov  Thu May  3 19:05:09 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May  3 19:05:11 2007
Subject: [pangalactic-commits] STEP importAssemblies demo works!  Yay!  :)
Message-ID: <200705032305.l43N59Sq000659@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.184 1.185
PanGalactic/pangalactic/utils/io/import_assembly.py 1.2 1.3

Log message:
STEP importAssemblies demo works!  Yay!  :)


Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.184 PanGalactic/pangalactic/node/pangalaxian.py:1.185
--- PanGalactic/pangalactic/node/pangalaxian.py:1.184	Thu May  3 12:27:15 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Thu May  3 19:05:06 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.184 2007/05/03 16:27:15 waterbug Exp $
+# $Id: pangalaxian.py,v 1.185 2007/05/03 23:05:06 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.184 $
+@version: $Revision: 1.185 $
 """
-__version__ = "$Revision: 1.184 $"[11:-2]
+__version__ = "$Revision: 1.185 $"[11:-2]
 
 # Python
 import logging
@@ -53,6 +53,7 @@
 from pangalactic.node.uberorb                      import orb
 from pangalactic.utils.identity                    import generateOid
 from pangalactic.utils.identity                    import setOidBase
+from pangalactic.utils.io.import_assembly          import getAssemblies
 from pangalactic.utils.datetimes                   import dtstamp
 
 
@@ -113,8 +114,8 @@
             help="Logout from repository ...")
         self.file_import = self.file_menu.Append(
             id=wx.ID_ANY,
-            text="&Import...",
-            help="Import data from file ...")
+            text="&Import STEP data...",
+            help="Import STEP data from a file ...")
         # self.file_export = self.file_menu.Append(
         #     id=wx.ID_ANY,
         #     text="&Export",
@@ -590,7 +591,15 @@
         """
         # TODO:  create a Wizard for the import process
         self.log.info(' - PanGalaxian.onImport')
-        
+        dlg = wx.FileDialog(
+            self, message="Choose a file", defaultDir=os.getcwd(), 
+            defaultFile="", style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)
+        if dlg.ShowModal() == wx.ID_OK:
+            paths = dlg.GetPaths()
+            project, acus, models = getAssemblies(paths[0])
+            orb.save(project)
+            orb.save(models)
+            orb.save(acus)
 
     def updateProjects(self):
         """

Index: PanGalactic/pangalactic/utils/io/import_assembly.py
diff -u PanGalactic/pangalactic/utils/io/import_assembly.py:1.2 PanGalactic/pangalactic/utils/io/import_assembly.py:1.3
--- PanGalactic/pangalactic/utils/io/import_assembly.py:1.2	Thu May  3 16:29:09 2007
+++ PanGalactic/pangalactic/utils/io/import_assembly.py	Thu May  3 19:05:07 2007
@@ -1,4 +1,7 @@
+import os
 from pprint import pprint
+from pangalactic.meta.pgefobject import PgefObject
+from pangalactic.node.uberorb import orb
 from pangalactic.utils.io.part21 import PARAMETER_LIST
 from pangalactic.utils.io.part21_preparse import readStepFile
 
@@ -35,17 +38,54 @@
 
 def getAssemblies(f):
     data = readStepFile(f)
+    projid = os.path.basename(f).split('.')[0].upper()
+    projoid = ''.join(['DEMO_', projid])
+    project = PgefObject(_schema=orb.interfaces['Project'], oid=projoid,
+                         id=projid)
     nauo = {}
     for n in data['typeinst']['NEXT_ASSEMBLY_USAGE_OCCURRENCE']:
-        parent, child = [x.strip(' \n\r#')
+        parent, child = [x.strip(" \n\r#'")
                          for x in data['contents'][n].split(',')[3:5]]
-        nauo[n] = {'oid'    : ''.join(['#', n]),
-                   'id'     : ' '.join(['nauo', n]),
+        nauo[n] = {'oid'    : n,
+                   'id'     : ''.join(['nauo #', n]),
                    # relating_product_definition (4th attr)
                    'parent' : parent,
                    # related_product_definition (5th attr)
                    'child'  : child,
                    'reference_designator' : '' # test data doesn't have
                    }
-    pprint(nauo)
+    # product_definitions
+    pdset = (set([na['parent'] for na in nauo.values()]) |
+             set([na['child'] for na in nauo.values()]))
+    pd = {}
+    for pdref in pdset:
+        pdfref = data['contents'][pdref].split(',')[2].strip(" \n\r#'")
+        version = data['contents'][pdfref].split(',')[0].strip(" \n\r#'")
+        mpref = data['contents'][pdfref].split(',')[2].strip(" \n\r#'")
+        # product name (or id if no name)
+        product_name = (data['contents'][mpref].split(',')[1].strip(" \n\r#'")
+                       or data['contents'][mpref].split(',')[0].strip(" \n\r#'"))
+        pd[pdref] = {'oid' : pdref,
+                     'id'  : ''.join(['product definition #', pdref,
+                                      'v.', version]),
+                     'base_id'  : ''.join(['product definition #', pdref])
+                     'cm_authority' : projoid,
+                     # version from pdf
+                     'version' : version,
+                     # modeled product
+                     'name' : product_name
+                     }
+    # print 'assemblies:'
+    # pprint(nauo)
+    # print '-----------------------------------'
+    # print 'product_definitions:'
+    # print pdset
+    # print '-----------------------------------'
+    # print 'models:'
+    # pprint(pd)
+    acus = [PgefObject(_schema=orb.interfaces['Acu'], **nauo[n])
+            for n in nauo]
+    models = [PgefObject(_schema=orb.interfaces['Model'], **pd[p])
+              for p in pd]
+    return project, acus, models
 

From waterbug at step.nasa.gov  Thu May  3 20:03:49 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May  3 20:03:50 2007
Subject: [pangalactic-commits] A few tweaks to the demo ...
Message-ID: <200705040003.l4403nwm001122@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/io/import_assembly.py 1.3 1.4

Log message:
A few tweaks to the demo ...


Index: PanGalactic/pangalactic/utils/io/import_assembly.py
diff -u PanGalactic/pangalactic/utils/io/import_assembly.py:1.3 PanGalactic/pangalactic/utils/io/import_assembly.py:1.4
--- PanGalactic/pangalactic/utils/io/import_assembly.py:1.3	Thu May  3 19:05:07 2007
+++ PanGalactic/pangalactic/utils/io/import_assembly.py	Thu May  3 20:03:47 2007
@@ -63,12 +63,17 @@
         version = data['contents'][pdfref].split(',')[0].strip(" \n\r#'")
         mpref = data['contents'][pdfref].split(',')[2].strip(" \n\r#'")
         # product name (or id if no name)
-        product_name = (data['contents'][mpref].split(',')[1].strip(" \n\r#'")
-                       or data['contents'][mpref].split(',')[0].strip(" \n\r#'"))
+        pre_id = (data['contents'][mpref].split(',')[1].strip(" \n\r#'")
+                  or data['contents'][mpref].split(',')[0].strip(" \n\r#'"))
+        base_id = ''.join([pre_id, ' (#', pdref, ')'])
+        vinfo = ''
+        if version:
+            vinfo = ''.join([' v. ', version])
+        product_id = ''.join([pre_id, '_', pdref, '_', version])
+        product_name = ''.join([pre_id, vinfo, ' (#', pdref, ')'])
         pd[pdref] = {'oid' : pdref,
-                     'id'  : ''.join(['product definition #', pdref,
-                                      'v.', version]),
-                     'base_id'  : ''.join(['product definition #', pdref])
+                     'id'  : product_id,
+                     'base_id'  : base_id,
                      'cm_authority' : projoid,
                      # version from pdf
                      'version' : version,

From waterbug at step.nasa.gov  Fri May  4 20:51:17 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May  4 20:51:19 2007
Subject: [pangalactic-commits] Minor refinements to assembly import.
Message-ID: <200705050051.l450pHhk011998@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.185 1.186
PanGalactic/pangalactic/utils/io/import_assembly.py 1.4 1.5
PanGalactic/pangalactic/utils/io/part21_preparse.py 1.5 1.6

Log message:
Minor refinements to assembly import.


Index: PanGalactic/pangalactic/utils/io/part21_preparse.py
diff -u PanGalactic/pangalactic/utils/io/part21_preparse.py:1.5 PanGalactic/pangalactic/utils/io/part21_preparse.py:1.6
--- PanGalactic/pangalactic/utils/io/part21_preparse.py:1.5	Thu May  3 16:29:09 2007
+++ PanGalactic/pangalactic/utils/io/part21_preparse.py	Fri May  4 20:51:16 2007
@@ -1,14 +1,14 @@
 #!/usr/bin/env python
-# $Id: part21_preparse.py,v 1.5 2007/05/03 20:29:09 waterbug Exp $
+# $Id: part21_preparse.py,v 1.6 2007/05/05 00:51:16 waterbug Exp $
 """
 A generic (no dependencies on the rest of PanGalactic) reader/writer for
 "Part 21 files" (ISO 10303-21, STEP "Clear Text Encoding", a serialization
 format).  This module reads a STEP Part 21 data file into a set of
 Python dictionaries.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 import re, sys, string, time
 from optparse import OptionParser
@@ -18,7 +18,7 @@
 from simpleparse import dispatchprocessor as dp
 
 
-# Part 21 File EBNF syntax specification (informal)
+# Part 21 File syntax specification (informal)
 
 # Productions whose names are all caps are formally named and specified in ISO
 # 10303-21:2002(E).  Productions with lower-case names are either "convenience"

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.185 PanGalactic/pangalactic/node/pangalaxian.py:1.186
--- PanGalactic/pangalactic/node/pangalaxian.py:1.185	Thu May  3 19:05:06 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Fri May  4 20:51:15 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.185 2007/05/03 23:05:06 waterbug Exp $
+# $Id: pangalaxian.py,v 1.186 2007/05/05 00:51:15 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.185 $
+@version: $Revision: 1.186 $
 """
-__version__ = "$Revision: 1.185 $"[11:-2]
+__version__ = "$Revision: 1.186 $"[11:-2]
 
 # Python
 import logging
@@ -1020,7 +1020,6 @@
             dlg = wx.MessageDialog(self,
                        "No projects have been created or retrieved yet.",
                        "Yes, we have no projects", wx.OK)
-            prefs['projects'] = []
             dlg.ShowModal()
             dlg.Destroy()
 

Index: PanGalactic/pangalactic/utils/io/import_assembly.py
diff -u PanGalactic/pangalactic/utils/io/import_assembly.py:1.4 PanGalactic/pangalactic/utils/io/import_assembly.py:1.5
--- PanGalactic/pangalactic/utils/io/import_assembly.py:1.4	Thu May  3 20:03:47 2007
+++ PanGalactic/pangalactic/utils/io/import_assembly.py	Fri May  4 20:51:16 2007
@@ -1,8 +1,8 @@
-import os
+import os, sys, time
+from optparse import OptionParser
 from pprint import pprint
 from pangalactic.meta.pgefobject import PgefObject
 from pangalactic.node.uberorb import orb
-from pangalactic.utils.io.part21 import PARAMETER_LIST
 from pangalactic.utils.io.part21_preparse import readStepFile
 
 # nauo attrs:
@@ -39,7 +39,13 @@
 def getAssemblies(f):
     data = readStepFile(f)
     projid = os.path.basename(f).split('.')[0].upper()
-    projoid = ''.join(['DEMO_', projid])
+    projoid = projid
+    # TODO:
+    #   - this function really needs a wizard
+    #     + pick a namespace (default to user's preferred ns)
+    #     + ask if user wants to create a context related to this data
+    #     + pick a project (default to current project if user has permission;
+    #       otherwise, default to user's preferred project, if any)
     project = PgefObject(_schema=orb.interfaces['Project'], oid=projoid,
                          id=projid)
     nauo = {}
@@ -66,31 +72,44 @@
         pre_id = (data['contents'][mpref].split(',')[1].strip(" \n\r#'")
                   or data['contents'][mpref].split(',')[0].strip(" \n\r#'"))
         base_id = ''.join([pre_id, ' (#', pdref, ')'])
-        vinfo = ''
+        vinfo = 'v.0'
         if version:
-            vinfo = ''.join([' v. ', version])
-        product_id = ''.join([pre_id, '_', pdref, '_', version])
-        product_name = ''.join([pre_id, vinfo, ' (#', pdref, ')'])
-        pd[pdref] = {'oid' : pdref,
-                     'id'  : product_id,
-                     'base_id'  : base_id,
+            vinfo = ''.join(['v.', version])
+        product_id = '-'.join([pre_id, pdref, vinfo])
+        product_name = ' '.join([pre_id, vinfo, '( STEP file instance:', pdref, ')'])
+        pd[pdref] = {'oid'          : pdref,
+                     'id'           : product_id,
+                     'base_id'      : base_id,
                      'cm_authority' : projoid,
                      # version from pdf
-                     'version' : version,
+                     'version'      : version,
                      # modeled product
-                     'name' : product_name
+                     'name'         : product_name
                      }
-    # print 'assemblies:'
-    # pprint(nauo)
-    # print '-----------------------------------'
-    # print 'product_definitions:'
-    # print pdset
-    # print '-----------------------------------'
-    # print 'models:'
-    # pprint(pd)
     acus = [PgefObject(_schema=orb.interfaces['Acu'], **nauo[n])
             for n in nauo]
     models = [PgefObject(_schema=orb.interfaces['Model'], **pd[p])
               for p in pd]
     return project, acus, models
 
+if __name__ == '__main__':
+    usage = 'usage:  %prog [options] file.p21'
+    opt = OptionParser(usage)
+    opt.add_option("-p", "--perf", action='store_true',
+                   dest="performance", default=False,
+                   help="run the parser's unit tests")
+    (options, args) = opt.parse_args(args=sys.argv)
+    # debugging:
+    # print "options:  %s" % str(options)
+    # print "args:     %s" % str(args)
+    if len(args) > 1:
+        if options.performance:
+            start = time.clock()
+        project, nauo, pdset = getAssemblies(f=args[1])
+        if options.performance:
+            end = time.clock()
+            print "\nTotal time: %6.2f sec" % (end - start)
+        print len(list(nauo))," assemblies\n"
+    else:
+        opt.print_help()
+

From waterbug at step.nasa.gov  Sat May  5 20:13:08 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sat May  5 20:13:10 2007
Subject: [pangalactic-commits] Work on namespace management, and some notes.
Message-ID: <200705060013.l460D8WT014078@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/NOTES 1.13 1.14
PanGalactic/pangalactic/node/uberorb.py 1.142 1.143
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.116 1.117

Log message:
Work on namespace management, and some notes.


Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.142 PanGalactic/pangalactic/node/uberorb.py:1.143
--- PanGalactic/pangalactic/node/uberorb.py:1.142	Thu Apr 26 09:41:59 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Sat May  5 20:13:05 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.142 2007/04/26 13:41:59 waterbug Exp $
+# $Id: uberorb.py,v 1.143 2007/05/06 00:13:05 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.142 $
+@version: $Revision: 1.143 $
 """
-__version__ = "$Revision: 1.142 $"[11:-2]
+__version__ = "$Revision: 1.143 $"[11:-2]
 
 import logging
 import mimetypes
@@ -838,7 +838,7 @@
             self.log.debug('   + logged in -- going to the server ...')
             base_ids = self.xmlrpc.getBaseIds(ns) or []
         else:
-            self.log.info("   + in local mode -- can't give a good answer.")
+            self.log.info("   + in local mode -- info may be incomplete ...")
             base_ids = []
         return base_ids
 

Index: PanGalactic/NOTES
diff -u PanGalactic/NOTES:1.13 PanGalactic/NOTES:1.14
--- PanGalactic/NOTES:1.13	Tue Apr 17 01:11:55 2007
+++ PanGalactic/NOTES	Sat May  5 20:13:05 2007
@@ -51,24 +51,38 @@
     - general interfaces:  PanGalaticFu [Identifiable, Manageable, etc.]
     - these will be managed in 'p.meta.metaobjects' as code (but still in the
       form of extracts, maybe)
-    - Everything else is really "domain" and can go into a "pgef domain ontology"
-      that is not required.  Can be maintained as OWL, etc. and cached at startup;
-      can be versioned separately from "core pgef", but as a close companion for
-      which some application niceties have been developed.
+    - maintain all pgef ontology objects as extracts;
+    - need to be able to generate OWL for them so they can be used by
+      application developers who want to use Protege or some type of OWL-based
+      technology for defining their application domain objects.
 
 Semi-random notes:
 
 * PmofDatatype
-    - new datatypes can be created and managed.
-    - needs to reference a serialization method
-    - some way to specify presentation/editing (smth. MIME-like?)
-    - also mapped from imported schemas' datatypes
+  - new datatypes can be created and managed.
+  - needs to reference a serialization method
+  - some way to specify presentation/editing (smth. MIME-like?)
+  - also mapped from imported schemas' datatypes
 
 * PgefProperty
   - implements IProperty and IPgefObject
   - attrs defined in __slots__, which is constructed from the attrs of
     PmofProperty
 
+* Namespaces (PgefNamespace and PmofNamespace)
+  - runtime namespaces (PgefNamespace instances) for metaobject (M1 and above)
+    names (i.e., 'pgef' and any application namespaces -- e.g. 'space_mission',
+    etc.) must be distinguishable from those for runtime object (M0) names.
+  - metaobject namespaces and the names they contain should only be displayed
+    when in a 'meta' context -- which should be selectable, and should not be
+    the "default default" (although one could set it as a preference).
+  - try using a 'meta_level' property, with values 'Mn'.  Namespaces for
+    normal application objects would have a meta_level of 'M0', and only those
+    namespaces would be displayed unless a 'meta' context other than M0 is set
+    (in which case the 'M0' namespaces would be excluded).
+  - it should be possible to set the meta context to any one or any combination
+    of two or more meta levels (M0, M1, M2, etc.).
+
 * Pmof MetaObjects
   - created by registry from extracts (createPmofObjectFromExtract)
   - need methodology for versioning
@@ -81,6 +95,8 @@
       iteration = 0, etc.)
     + for namespace types (PmofClass, PmofOntology, PmofTaxonomy, etc.), 'names'
       should probably be a Python property (e.g., for PmofClass, all registered
+      PmofProperties with domain of that PmofClass would populate its 'names'
+      property).
       
 
 *** ITEM 2 ***
@@ -94,13 +110,14 @@
     Should it be a datatype object instead?
 
     + pro:
-        * doable
-          - PmofProperty.range would still be strings (name of class or
-            datatype)
-        * PgefProperty.range could be used for casting, if nec.
+      * doable
+        - PmofProperty.range would still be strings (name of class or
+          datatype)
+      * PgefProperty.range could be used for casting, if nec.
+      * might make generic functions easier to implement where useful
 
     + con:
-        * will need unit tests (not a huge deal, really)
+      * will need unit tests (not a huge deal, really)
 
   - Should there be a module-level dictionary of datatypes in pgefdatatype?
     (I think so -- it is needed especially if PgefProperty.range remains a

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.116 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.117
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.116	Wed Mar  7 00:21:56 2007
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Sat May  5 20:13:06 2007
@@ -1,17 +1,18 @@
-# $Id: xmlrpcinterface.py,v 1.116 2007/03/07 05:21:56 waterbug Exp $
+# $Id: xmlrpcinterface.py,v 1.117 2007/05/06 00:13:06 waterbug Exp $
 
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.116 $
+@version: $Revision: 1.117 $
 """
-__version__ = "$Revision: 1.116 $"[11:-2]
+__version__ = "$Revision: 1.117 $"[11:-2]
 
 import base64
 import xmlrpclib
 import string
 import httplib
 from pprint import pprint
+from pangalactic.node.uberorb import orb
 
 
 class BasicAuthTransport(xmlrpclib.Transport):
@@ -120,9 +121,9 @@
         else:
             conns = 'http://'
         conns = conns + hostandport
-        print 'XmlrpcInterface:  connection string is', conns
-        print '                  userid is:          ', userid
-        print '                  passwd is:          ', passwd
+        orb.log.debug('XmlrpcInterface:  connection string is "%s"' % conns)
+        orb.log.debug('                  userid is:           "%s"' % userid)
+        orb.log.debug('                  passwd is:           "%s"' % passwd)
         if userid and passwd:
             self.userid = userid
             if secure:
@@ -185,14 +186,14 @@
             (now with new state info in their repository-related
             attributes)
         """
-        print "XmlrpcInterface.addobjects"
+        orb.log.debug("XmlrpcInterface.addobjects")
         if not objs:
-            print "  * empty object list"
+            orb.log.debug("  * empty object list")
             newexts = []
         else:
-            print "  * oids and schemas of objects to be added:"
+            orb.log.debug("  * oids and schemas of objects to be added:")
             for o in objs:
-                print '   + %s (%s)' % (o.oid, o._schema.__name__)
+                orb.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.addObjects(extracts)
         return newexts
@@ -209,14 +210,14 @@
             (now with new state info in their repository-related
             attributes)
         """
-        print "XmlrpcInterface.updateObjects"
+        orb.log.debug("XmlrpcInterface.updateObjects")
         if not objs:
-            print "  * empty object list"
+            orb.log.debug("  * empty object list")
             newexts = []
         else:
-            print "  * oids and schemas of objects to be updated:"
+            orb.log.debug("  * oids and schemas of objects to be updated:")
             for o in objs:
-                print '   + %s (%s)' % (o.oid, o._schema.__name__)
+                orb.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.updateObjects(extracts)
         return newexts
@@ -232,14 +233,14 @@
             updated with an iteration, version, id, etc.
         @rtype:   C{list} of extracts (C{dict}s)
         """
-        print "XmlrpcInterface.commitVersions()"
+        orb.log.debug("XmlrpcInterface.commitVersions()")
         if not objs:
-            print "  * empty object list"
+            orb.log.debug("  * empty object list")
             newexts = []
         else:
-            print "  * ids and schemas of versions to be committed:"
+            orb.log.debug("  * ids and schemas of versions to be committed:")
             for o in objs:
-                print '   + %s (%s)' % (o.id, o._schema.__name__)
+                orb.log.debug('   + %s (%s)' % (o.id, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.commitVersions(extracts)
         return newexts
@@ -267,9 +268,10 @@
         @param params:  attr-value criteria for desired objects
         @type  params:  C{dict}
         """
-        # print "xmlrpc.getobjects"
-        print ' - xmlrpc.getObjects command is:'
-        print '   getObjects(%s, %s, %s, %s)' % (schema_name, refs, subtypes, params)
+        orb.log.debug("XmlrpcInterface.getobjects")
+        orb.log.debug(' - xmlrpc.getObjects command is:')
+        orb.log.debug('   getObjects(%s, %s, %s, %s)' % (
+                                    schema_name, refs, subtypes, params))
         return self._RPC.getObjects(schema_name, refs, subtypes, params)
 
     def getObjectsByOids(self, oids):
@@ -279,7 +281,7 @@
         @type  oids:  C{list}
         @param oids:  oids of the desired objects
         """
-        # print "xmlrpcinterface.getObjectsByOids"
+        orb.log.debug("XmlrpcInterface.getObjectsByOids")
         return self._RPC.getObjectsByOids(oids)
 
     def getNames(self, ns):
@@ -289,7 +291,7 @@
         @param ns:  the URL (oid) of a namespace
         @type  ns:  C{str}
         """
-        # print "xmlrpcinterface.getNames()"
+        orb.log.debug("XmlrpcInterface.getNames()")
         return self._RPC.getNames(ns)
 
     def getBaseIds(self, ns):
@@ -299,7 +301,7 @@
         @param ns:  the URL (oid) of a namespace
         @type  ns:  C{str}
         """
-        # print "xmlrpcinterface.getNames()"
+        orb.log.debug("xmlrpcinterface.getBaseIds()")
         return self._RPC.getBaseIds(ns)
 
     def search(self, schema_name, refs, subtypes, params, spec):
@@ -337,16 +339,16 @@
 
         @return:  a C{list} of extracts of the objects that were found
         """
-        print "- Xmlrpcinterface.search:"
-        print "  search(%s, %s, %s, %s, %s)" % (
-                        schema_name, refs, subtypes, params, spec)
+        orb.log.debug("- XmlrpcInterface.search:")
+        orb.log.debug("  search(%s, %s, %s, %s, %s)" % (
+                                schema_name, refs, subtypes, params, spec))
         if not spec:
             spec = []
         data = self._RPC.search(schema_name, refs, subtypes, params, spec)
         if data:
-            print "  - data returned:", len(data), 'items'
+            orb.log.debug("  - data returned:  %s items." % len(data))
         else:
-            print "  - no %s instances found" % schema_name
+            orb.log.debug("  - no %s instances found" % schema_name)
         return data
 
     def getCount(self, schema_name, refs, subtypes, params):
@@ -380,14 +382,14 @@
 
         @return:  a C{list} of extracts of the objects that were found
         """
-        print " - Xmlrpcinterface.getCount()"
-        print "   search(schema_name, refs, subtypes, params)"
-        print "   search(%s, %s, %s, %s)" % (
-                        schema_name, refs, subtypes, params)
+        orb.log.debug(" - XmlrpcInterface.getCount()")
+        orb.log.debug("   search(schema_name, refs, subtypes, params)")
+        orb.log.debug("   search(%s, %s, %s, %s)" % (
+                        schema_name, refs, subtypes, params))
         count = self._RPC.getCount(schema_name, refs, subtypes, params)
-        # if count:
-            # print "  - count returned:", count
-        # else:
-            # print "  - no %s instances matched" % schema_name
+        if count:
+            orb.log.debug("  - count returned:  %s" % count)
+        else:
+            orb.log.debug("  - no %s instances matched" % schema_name)
         return count
 

From waterbug at step.nasa.gov  Sun May  6 02:24:42 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May  6 02:24:42 2007
Subject: [pangalactic-commits] Improvements to PanGalaxian's logging.
Message-ID: <200705060624.l466Ogvq014474@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/meta/registry.py 1.173 1.174
PanGalactic/pangalactic/node/cache.py 1.32 1.33
PanGalactic/pangalactic/node/uberorb.py 1.143 1.144
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.117 1.118

Log message:
Improvements to PanGalaxian's logging.


Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.143 PanGalactic/pangalactic/node/uberorb.py:1.144
--- PanGalactic/pangalactic/node/uberorb.py:1.143	Sat May  5 20:13:05 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Sun May  6 02:24:39 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.143 2007/05/06 00:13:05 waterbug Exp $
+# $Id: uberorb.py,v 1.144 2007/05/06 06:24:39 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.143 $
+@version: $Revision: 1.144 $
 """
-__version__ = "$Revision: 1.143 $"[11:-2]
+__version__ = "$Revision: 1.144 $"[11:-2]
 
 import logging
 import mimetypes
@@ -113,7 +113,7 @@
             # self.__cache = ObjectCache(self.interfaces.values(), home=home)
             ifaces = [self.interfaces[i] for i in self.persistables]
             self.log.debug('   interfaces:  %s' % str(self.persistables))
-            self.__cache = ObjectCache(ifaces, home=home)
+            self.__cache = ObjectCache(ifaces, home=home, log=self.log)
             # self.createDefaultNamespace()
         else:
             raise ValueError, 'the orb already has a cache.'
@@ -175,7 +175,7 @@
         @type  secure:  C{bool}
         """
         # TODO: implement HTTP proxy handling
-        # self.log.debug(' - orb._initXmlrpcInterface creating XmlrpcInterface') 
+        self.log.debug(' - orb._initXmlrpcInterface creating XmlrpcInterface') 
         if secure:
             conns = 'https://' + hostandport
         else:
@@ -183,7 +183,8 @@
         return XmlrpcInterface(hostandport=hostandport,
                                userid=userid,
                                passwd=passwd,
-                               secure=secure)
+                               secure=secure,
+                               log=self.log)
 
     def login(self, hostandport, userid, passwd, secure=True):
         """
@@ -202,7 +203,7 @@
             in this case)
         @type  secure:  C{bool}
         """
-        # self.log.debug(' - orb.login')
+        self.log.debug(' - orb.login')
         self.xmlrpc = self._initXmlrpcInterface(hostandport, userid, passwd,
                                                 secure=secure)
         try:
@@ -865,11 +866,11 @@
         Retrieves all Acu objects associated with a specified assembly (parent)
         oid.
         """
-        # self.log.debug(' - getAcusByAssemblyOid')
-        # self.log.debug('   + parent oid:  %s' % oid)
+        self.log.debug(' - getAcusByAssemblyOid')
+        self.log.debug('   + parent oid:  %s' % oid)
         acus = []
         if oid in self.assy_maps:
-            # self.log.debug('   + oid found in self.assy_maps')
+            self.log.debug('   + oid found in self.assy_maps')
             acus = self.assy_maps[oid]
         else:
             for obj in self.getDict('Acu').values():
@@ -877,10 +878,10 @@
                     acus.append(obj)
                 elif getattr(obj.parent, 'oid', '') == oid:
                     acus.append(obj)
-            # self.log.debug('     local acus with parent oid == %s:  %s' % (oid,
-            #                                 str([o.oid for o in acus])))
-        # self.log.debug('   + returning %s acus' % len(acus))
-        # self.log.debug('   + end getAcusByAssemblyOid')
+            self.log.debug('     local acus with parent oid == %s:  %s' % (oid,
+                                                    str([o.oid for o in acus])))
+        self.log.debug('   + returning %s acus' % len(acus))
+        self.log.debug('   + end getAcusByAssemblyOid')
         return acus
 
     def removeLocalObjFromCache(self, o):
@@ -890,6 +891,7 @@
         @param objoroid:  a C{PgefObject} instance
         @type  objoroid:  C{PgefObject}
         """
+        self.log.debug(' - removeLocalObjFromCache')
         if getattr(self, 'cache'):
             self.cache.delete(o)
 

Index: PanGalactic/pangalactic/meta/registry.py
diff -u PanGalactic/pangalactic/meta/registry.py:1.173 PanGalactic/pangalactic/meta/registry.py:1.174
--- PanGalactic/pangalactic/meta/registry.py:1.173	Sun Mar 18 02:28:28 2007
+++ PanGalactic/pangalactic/meta/registry.py	Sun May  6 02:24:38 2007
@@ -1,11 +1,11 @@
-# $Id: registry.py,v 1.173 2007/03/18 06:28:28 waterbug Exp $
+# $Id: registry.py,v 1.174 2007/05/06 06:24:38 waterbug Exp $
 
 """
 The Pan Galactic Meta Object Registry
 
-@version: $Revision: 1.173 $
+@version: $Revision: 1.174 $
 """
-__version__ = "$Revision: 1.173 $"[11:-2]
+__version__ = "$Revision: 1.174 $"[11:-2]
 
 # Python
 import glob
@@ -112,10 +112,11 @@
             # start in-memory logging until we get a file to write to ...
             class logger: pass
             self.log = logger()
-            self.log.temp = []
-            self.log.info = lambda x: self.log.temp.append(x)
-            self.log.debug = lambda x: self.log.temp.append(x)
-        self.log.info('initializing registry logging.')
+            self.log.info_temp = []
+            self.log.debug_temp = []
+            self.log.info = lambda x: self.log.info_temp.append(x)
+            self.log.debug = lambda x: self.log.debug_temp.append(x)
+        self.log.info(' - initializing registry logging.')
         self.sources = {}
         self.interfaces = {}
         self.properties = {}
@@ -137,15 +138,22 @@
         """
         Begin registry logging.
         """
-        self.templog = None
-        if hasattr(self, 'log') and hasattr(self.log, 'temp'):
-            self.templog = self.log.temp
+        self.tempinfolog = None
+        self.tempdebuglog = None
+        if hasattr(self, 'log'):
+            if hasattr(self.log, 'info_temp'):
+                self.tempinfolog = self.log.info_temp
+            if hasattr(self.log, 'debug_temp'):
+                self.tempdebuglog = self.log.debug_temp
         import logging
         if hasattr(logging, 'filename'):
             self.log = logging.getLogger('registry')
-            if self.templog:
-                for line in self.templog:
+            if self.tempinfolog:
+                for line in self.tempinfolog:
                     self.log.info(line)
+            if self.tempdebuglog:
+                for line in self.tempdebuglog:
+                    self.log.debug(line)
 
     def createCoreMetaObjects(self, module='pangalactic.meta.names'):
         """
@@ -447,8 +455,8 @@
         self.log.info('   + to_python = %s' % str(to_python))
         cnames = source.getClassNames(nsprefix)
         self.log.debug('   + cnames:  %s' % cnames)
-        # self.log.debug('     ... finding build order of <%s> cnames ...' % (
-        #                                                             nsprefix))
+        self.log.debug('     ... finding build order of <%s> cnames ...' % (
+                                                                     nsprefix))
         # First construct a dictionary mapping names to lists of base names
         # (to avoid calling source.getBaseNames too much).  Since the purpose
         # here is to find the proper build order (so all dependendencies of an
@@ -489,7 +497,7 @@
             extr['_schema_name'] = 'PmofProperty'
             extracts[pname] = extr
         for cname in build_order:
-            # self.log.debug(' - constructing interface for %s' % cname)
+            self.log.debug('   + constructing interface for %s' % cname)
             if nsprefix == 'pgef':
                 # for 'pgef' interfaces, just include 'pgef' base classes (scope
                 # is just 'pgef') ...
@@ -501,18 +509,19 @@
                 # class hierarchy all the way up (scope is 'pgef' and nsprefix)
                 base_names = source.getBaseNames(nsprefix, cname,
                                                  scope=['pgef', nsprefix])
-            # self.log.debug('   base_names: %s' % base_names)
+            # self.log.debug('     base_names: %s' % base_names)
             # in case this is an app interface, some of its bases may need to be
             # looked up in self.interfaces ...
             interface_bases = [ifdict.get(bn, self.interfaces[bn])
                                for bn in base_names]
-            # self.log.debug('  bases ... %s' % str(interface_bases))
+            # self.log.debug('     bases ... %s' % str(interface_bases))
             interface_props = [p for p in propdict.values()
                                if p.domain == cname]
-            # self.log.debug('  properties:')
+            # self.log.debug('     properties:')
             # for p in interface_props:
-                # self.log.debug('  - %s (%s), range: %s' % (p.id, type(p.id),
-                #                                            p.range))
+                # self.log.debug('     - %s (%s), range: %s' % (p.id,
+                #                                               type(p.id),
+                #                                               p.range))
                 # for a in p._schema:
                     # self.log.debug('    + %s ... %s (%s)' % (a, getattr(p, a),
                     #                                     type(getattr(p, a))))
@@ -530,7 +539,7 @@
                                bases=interface_bases,
                                attrs=interface_attrs
                                )
-            self.log.debug('  interface created:  %s' % str(i))
+            self.log.debug('     + interface created:  %s' % str(i))
             ifdict[cname] = i
             # only add interfaces to the registered (runtime) interfaces if not
             # generating python ...
@@ -595,7 +604,7 @@
                 pprint(extracts[i], f)
                 f.write('\n')
             f.close()
-            self.log.debug('  %s of %s interfaces written to classes.py' % (
+            self.log.debug('   + %s of %s interfaces written to classes.py' % (
                                                          str(len(build_order)),
                                                          str(len(ifdict))))
             f = open(os.path.join(to_python, 'properties.py'), 'w')
@@ -606,7 +615,7 @@
                 pprint(extracts[p], f)
                 f.write('\n')
             f.close()
-            self.log.debug('  %s properties written to properties.py' % (
+            self.log.debug('   + %s properties written to properties.py' % (
                                                           str(len(propdict))))
             # save the namespace for nsprefix as an extract of a PmofNamespace
             # object
@@ -617,7 +626,7 @@
             pprint(extracts[nsprefix], f)
             f.write('\n')
             f.close()
-            self.log.debug('  %s namespace written to nspaces.py' % (
+            self.log.debug('   + %s namespace written to nspaces.py' % (
                                                               str(nsprefix)))
         # update registry [meta object] extracts from the imported ontology --
         # its Classes and Properties are assumed authoritative (modulo
@@ -856,7 +865,7 @@
                 break
         for name in build_order:
             e = interface_extracts[name]
-            # self.log.debug('- constructing interface for %s' % name)
+            self.log.debug('- constructing interface for %s' % name)
             interface_bases = [interfaces[n] for n in e['bases']]
             # self.log.debug('  bases ... %s' % str(interface_bases))
             interface_props = props[name]

Index: PanGalactic/pangalactic/node/cache.py
diff -u PanGalactic/pangalactic/node/cache.py:1.32 PanGalactic/pangalactic/node/cache.py:1.33
--- PanGalactic/pangalactic/node/cache.py:1.32	Mon Apr 23 15:48:55 2007
+++ PanGalactic/pangalactic/node/cache.py	Sun May  6 02:24:39 2007
@@ -1,12 +1,12 @@
 """
 Local object cache manager (a layer over ZODB)
 
-@version: $Revision: 1.32 $
+@version: $Revision: 1.33 $
 """
-__version__ = "$Revision: 1.32 $"[11:-2]
+__version__ = "$Revision: 1.33 $"[11:-2]
 
 # Python
-import os
+import os, sys
 
 # ZODB
 from persistent.mapping import PersistentMapping
@@ -25,18 +25,22 @@
     Light-weight local object persistence for a PanGalactic node.
     """
 
-    def __init__(self, interfaces, home=''):
+    def __init__(self, interfaces, home='', log=None):
         """
         Initialize an C{ObjectCache} instance.
 
         @param interfaces:  
         """
+        self.log = log
+        if not log:
+            self.log.debug = sys.stdout.write
+            self.log.info = sys.stdout.write
         # If modifying this stuff, be careful:  order is important
-        print 'ObjectCache (ZODB) starting up ...'
-        print ' - initializing LocalStorage'
+        self.log.debug('ObjectCache (ZODB) starting up ...')
+        self.log.debug(' - initializing LocalStorage')
         datadir = os.path.join(home, "data")
         if not os.path.exists(datadir):
-            print ' - no data dir found; creating one'
+            self.log.debug(' - no data dir found; creating one')
             os.makedirs(datadir)
         self.filename = os.path.join(datadir, "pgef.fs")
         self.storage = FileStorage.FileStorage(self.filename)
@@ -91,7 +95,8 @@
         @param iface:  an C{Interface} to be supported by the cache
         @type  iface:  L{zope.interface.interface.InterfaceClass} instance
         """
-        # print ' - ObjectCache.addInterface:  adding', iface.__name__
+        self.log.debug(' - ObjectCache.addInterface:  adding %s'
+                                                            % iface.__name__)
         if iface.__name__ not in self.dbroot.keys():
             self.dbroot[iface.__name__] = PersistentMapping()
         self.commit()
@@ -110,7 +115,7 @@
         @type  objs:  list (usually of instances of
             L{pangalactic.meta.pgefobject.PgefObject}
         """
-        # print " - ObjectCache.saveObjects"
+        self.log.debug(" - ObjectCache.saveObjects")
         # TODO:  'merge' -- i.e., in case of oid collision, compare
         # last-modified dates.  If the repo copy has been modified and the
         # cache copy has not, replace the cache copy; if both have been
@@ -153,8 +158,8 @@
         @return:  a list of objects
         @rtype:   C{list}
         """
-        print " - ObjectCache.searchLocalObjects"
-        print "   + kw =", kw
+        self.log.debug(" - ObjectCache.searchLocalObjects")
+        self.log.debug("   + kw = %s" % str(kw))
         if kw:
             objs = [x for x in self.objs.values() if self._getFilter(x, **kw)]
         else:
@@ -172,7 +177,7 @@
         @param objs:  C{PgefObject}s to be added
         @type  objs:  C{list}
         """
-        # print " - ObjectCache.add"
+        self.log.debug(" - ObjectCache.add")
         self.saveObjects(objs)
         self.commit()
 
@@ -197,7 +202,7 @@
     # strange special cases for Workflow stuff
 
     def GetWorkflows(self, attrlist = None):
-        # print " - ObjectCache.getworkflows"
+        self.log.debug(" - ObjectCache.getworkflows")
         wf_dict = self.getDict(self.WFPROCESSINSTANCE)
         objdict = {}
         for wfid, wfobj in wf_dict.items():
@@ -210,7 +215,7 @@
         itemdict = dict(objdict)
         for wfid, wfobj in itemdict.items():
             if wfobj._schema.__name__ == "WfProcessInstance":
-                #print "   + wfobj.name", wfobj.name
+                self.log.debug("   + wfobj.name '%s'" % str(wfobj.name))
                 if objdict.has_key(wfid):
                     if wfobj.state != 'DELETE':
                         tmpobj = self.objs[wfobj.oid]
@@ -221,11 +226,11 @@
                     if wfobj.state != 'DELETE':
                         tmpobj = self.objs[wfobj.oid]
                         objdict[wfid] = tmpobj
-        #print "   + objdict", objdict
+        self.log.debug("   + objdict:  %s" % str(objdict))
         return objdict
 
     def saveWfProcessInstance(self, wflist, recurse=False):
-        #print " - ObjectCache.SaveWfProcessInstance"
+        self.log.debug(" - ObjectCache.SaveWfProcessInstance")
         self.saveObjects(wflist)
         for wfobj in wflist:
             for entry in wfobj.history:
@@ -236,7 +241,7 @@
         self.commit()
 
     def addWfProcessInstance(self, wflist, recurse=False):
-        #print " - ObjectCache.addWfProcessInstance"
+        #self.log.debug(" - ObjectCache.addWfProcessInstance")
         self.saveObjects(wflist)
         for wfobj in wflist:
             for entry in wfobj.history:

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.117 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.118
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.117	Sat May  5 20:13:06 2007
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Sun May  6 02:24:40 2007
@@ -1,18 +1,17 @@
-# $Id: xmlrpcinterface.py,v 1.117 2007/05/06 00:13:06 waterbug Exp $
+# $Id: xmlrpcinterface.py,v 1.118 2007/05/06 06:24:40 waterbug Exp $
 
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.117 $
+@version: $Revision: 1.118 $
 """
-__version__ = "$Revision: 1.117 $"[11:-2]
+__version__ = "$Revision: 1.118 $"[11:-2]
 
 import base64
 import xmlrpclib
 import string
 import httplib
 from pprint import pprint
-from pangalactic.node.uberorb import orb
 
 
 class BasicAuthTransport(xmlrpclib.Transport):
@@ -97,7 +96,8 @@
     """
     XML-RPC API to PGER
     """
-    def __init__(self, hostandport, userid='', passwd='', secure=True):
+    def __init__(self, hostandport, userid='', passwd='', secure=True,
+                 log=None):
         """
         Initialize an XML-RPC server proxy for the specified host, port, userid,
         and password.
@@ -114,16 +114,23 @@
         @param secure:  flag to indicate whether connection should use SSL
             (True, the default) or not.
         @type  secure:  C{bool}
+
+        @param log:  a writable log object (normally, the orb's log)
+        @type  log:  C{logging.Logger}
         """
+        self.log = log
+        if not log:
+            self.log.debug = sys.stdout.write
+            self.log.info = sys.stdout.write
         # (worry about proxies later, if necessary)
         if secure:
             conns = 'https://'
         else:
             conns = 'http://'
         conns = conns + hostandport
-        orb.log.debug('XmlrpcInterface:  connection string is "%s"' % conns)
-        orb.log.debug('                  userid is:           "%s"' % userid)
-        orb.log.debug('                  passwd is:           "%s"' % passwd)
+        self.log.debug('XmlrpcInterface:  connection string is "%s"' % conns)
+        self.log.debug('                  userid is:           "%s"' % userid)
+        self.log.debug('                  passwd is:           "%s"' % passwd)
         if userid and passwd:
             self.userid = userid
             if secure:
@@ -186,14 +193,14 @@
             (now with new state info in their repository-related
             attributes)
         """
-        orb.log.debug("XmlrpcInterface.addobjects")
+        self.log.debug("XmlrpcInterface.addobjects")
         if not objs:
-            orb.log.debug("  * empty object list")
+            self.log.debug("  * empty object list")
             newexts = []
         else:
-            orb.log.debug("  * oids and schemas of objects to be added:")
+            self.log.debug("  * oids and schemas of objects to be added:")
             for o in objs:
-                orb.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
+                self.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.addObjects(extracts)
         return newexts
@@ -210,14 +217,14 @@
             (now with new state info in their repository-related
             attributes)
         """
-        orb.log.debug("XmlrpcInterface.updateObjects")
+        self.log.debug("XmlrpcInterface.updateObjects")
         if not objs:
-            orb.log.debug("  * empty object list")
+            self.log.debug("  * empty object list")
             newexts = []
         else:
-            orb.log.debug("  * oids and schemas of objects to be updated:")
+            self.log.debug("  * oids and schemas of objects to be updated:")
             for o in objs:
-                orb.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
+                self.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.updateObjects(extracts)
         return newexts
@@ -233,14 +240,14 @@
             updated with an iteration, version, id, etc.
         @rtype:   C{list} of extracts (C{dict}s)
         """
-        orb.log.debug("XmlrpcInterface.commitVersions()")
+        self.log.debug("XmlrpcInterface.commitVersions()")
         if not objs:
-            orb.log.debug("  * empty object list")
+            self.log.debug("  * empty object list")
             newexts = []
         else:
-            orb.log.debug("  * ids and schemas of versions to be committed:")
+            self.log.debug("  * ids and schemas of versions to be committed:")
             for o in objs:
-                orb.log.debug('   + %s (%s)' % (o.id, o._schema.__name__))
+                self.log.debug('   + %s (%s)' % (o.id, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.commitVersions(extracts)
         return newexts
@@ -268,9 +275,9 @@
         @param params:  attr-value criteria for desired objects
         @type  params:  C{dict}
         """
-        orb.log.debug("XmlrpcInterface.getobjects")
-        orb.log.debug(' - xmlrpc.getObjects command is:')
-        orb.log.debug('   getObjects(%s, %s, %s, %s)' % (
+        self.log.debug("XmlrpcInterface.getobjects")
+        self.log.debug(' - xmlrpc.getObjects command is:')
+        self.log.debug('   getObjects(%s, %s, %s, %s)' % (
                                     schema_name, refs, subtypes, params))
         return self._RPC.getObjects(schema_name, refs, subtypes, params)
 
@@ -281,7 +288,7 @@
         @type  oids:  C{list}
         @param oids:  oids of the desired objects
         """
-        orb.log.debug("XmlrpcInterface.getObjectsByOids")
+        self.log.debug("XmlrpcInterface.getObjectsByOids")
         return self._RPC.getObjectsByOids(oids)
 
     def getNames(self, ns):
@@ -291,7 +298,7 @@
         @param ns:  the URL (oid) of a namespace
         @type  ns:  C{str}
         """
-        orb.log.debug("XmlrpcInterface.getNames()")
+        self.log.debug("XmlrpcInterface.getNames()")
         return self._RPC.getNames(ns)
 
     def getBaseIds(self, ns):
@@ -301,7 +308,7 @@
         @param ns:  the URL (oid) of a namespace
         @type  ns:  C{str}
         """
-        orb.log.debug("xmlrpcinterface.getBaseIds()")
+        self.log.debug("xmlrpcinterface.getBaseIds()")
         return self._RPC.getBaseIds(ns)
 
     def search(self, schema_name, refs, subtypes, params, spec):
@@ -339,16 +346,16 @@
 
         @return:  a C{list} of extracts of the objects that were found
         """
-        orb.log.debug("- XmlrpcInterface.search:")
-        orb.log.debug("  search(%s, %s, %s, %s, %s)" % (
+        self.log.debug("- XmlrpcInterface.search:")
+        self.log.debug("  search(%s, %s, %s, %s, %s)" % (
                                 schema_name, refs, subtypes, params, spec))
         if not spec:
             spec = []
         data = self._RPC.search(schema_name, refs, subtypes, params, spec)
         if data:
-            orb.log.debug("  - data returned:  %s items." % len(data))
+            self.log.debug("  - data returned:  %s items." % len(data))
         else:
-            orb.log.debug("  - no %s instances found" % schema_name)
+            self.log.debug("  - no %s instances found" % schema_name)
         return data
 
     def getCount(self, schema_name, refs, subtypes, params):
@@ -382,14 +389,14 @@
 
         @return:  a C{list} of extracts of the objects that were found
         """
-        orb.log.debug(" - XmlrpcInterface.getCount()")
-        orb.log.debug("   search(schema_name, refs, subtypes, params)")
-        orb.log.debug("   search(%s, %s, %s, %s)" % (
+        self.log.debug(" - XmlrpcInterface.getCount()")
+        self.log.debug("   search(schema_name, refs, subtypes, params)")
+        self.log.debug("   search(%s, %s, %s, %s)" % (
                         schema_name, refs, subtypes, params))
         count = self._RPC.getCount(schema_name, refs, subtypes, params)
         if count:
-            orb.log.debug("  - count returned:  %s" % count)
+            self.log.debug("  - count returned:  %s" % count)
         else:
-            orb.log.debug("  - no %s instances matched" % schema_name)
+            self.log.debug("  - no %s instances matched" % schema_name)
         return count
 

From waterbug at step.nasa.gov  Sun May  6 02:30:18 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May  6 02:30:19 2007
Subject: [pangalactic-commits] Start work on getting namespaces from repo.
Message-ID: <200705060630.l466UIJB014538@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/repo/pger.py 1.144 1.145

Log message:
Start work on getting namespaces from repo.


Index: PanGalactic/pangalactic/repo/pger.py
diff -u PanGalactic/pangalactic/repo/pger.py:1.144 PanGalactic/pangalactic/repo/pger.py:1.145
--- PanGalactic/pangalactic/repo/pger.py:1.144	Sun Mar 18 02:28:31 2007
+++ PanGalactic/pangalactic/repo/pger.py	Sun May  6 02:30:17 2007
@@ -1,10 +1,10 @@
-# $Id: pger.py,v 1.144 2007/03/18 06:28:31 waterbug Exp $
+# $Id: pger.py,v 1.145 2007/05/06 06:30:17 waterbug Exp $
 """
 The Pan Galactic Entropy Reverser
 
-@version: $Revision: 1.144 $
+@version: $Revision: 1.145 $
 """
-__version__ = "$Revision: 1.144 $"[11:-2]
+__version__ = "$Revision: 1.145 $"[11:-2]
 
 import base64
 import sys
@@ -764,6 +764,16 @@
                 system='PGER')
         log.err(error)
 
+    def getNamespaces(self, requestor, ns):
+        """
+        Get all names (C{id} Property values) currently registered for the
+        specified namespace.
+        """
+        res = self.search(requestor, 'Identifiable', refs=0, subtypes=1,
+                          spec=['id'], args=[('id_ns', '=', ns)])
+        res.addCallback(lambda x: [r[0] for r in x])
+        return res
+
     def getNames(self, requestor, ns):
         """
         Get all names (C{id} Property values) currently registered for the

From waterbug at step.nasa.gov  Tue May  8 23:50:13 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May  8 23:50:15 2007
Subject: [pangalactic-commits] Minor bug fix and some notes.
Message-ID: <200705090350.l493oDPk001906@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/NOTES 1.14 1.15
PanGalactic/pangalactic/meta/names.py 1.41 1.42
PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py 1.7 1.8

Log message:
Minor bug fix and some notes.


Index: PanGalactic/NOTES
diff -u PanGalactic/NOTES:1.14 PanGalactic/NOTES:1.15
--- PanGalactic/NOTES:1.14	Sat May  5 20:13:05 2007
+++ PanGalactic/NOTES	Tue May  8 23:50:10 2007
@@ -8,7 +8,39 @@
 Other stuff is just notes that haven't found their way into regular docs yet.
 -----------------------------------------------------------------------------
 
-*** ITEM 1 ***
+-----------------------------------------------------------------------
+Enhancements to "Project", contexts, namespaces, ids, oids, names, etc.
+-----------------------------------------------------------------------
+
+New names (created by user) must have a namespace
+
+* default namespace is "local" (prefix only; not a valid URL)
+* before committing local objs to a repo, user must pick or define a namespace
+  - can be any namespace to which user has permission to add names
+  - can be a Project created by the user
+  - the Project will be checked by the repository for uniqueness of its id
+    within either its parent namespace (e.g., an organizational namespace) or
+    within the repository's knowledge of the "world" namespace
+* the current namespace serves as default ns for all local user-created objects
+
+
+So ... coding:
+
+* Rules:
+  - oid = id_ns + id
+  - id must not have spaces (so oid is a valid URL)
+    + default id = name, with spaces (if any) replaced by underscores
+    + as currently, id must include version reference for uniqueness
+
+* Display should use prefixes for all "non-local" id's (id's that are not within
+  the current context's namespace)
+  - this is important for the Project select widget
+  - also may be important for id's in grids
+  - think about whether it is needed for PgxnObject ...
+    + maybe not:  already have id_ns (which is prefix)
+    + but maybe so:  when PgxnObj becomes customizable, user might not want to
+      have id_ns in the interface -- then prefix should be used with id.
+
 ---------------------------------------------
 Pgef/Pmof MetaObject creation and maintenance
 ---------------------------------------------
@@ -206,31 +238,3 @@
     - namespaces
 
 
------------------------------------------------------
-Enhancements to "Project", contexts, namespaces, etc.
------------------------------------------------------
-
-* Need to have a context -- a "space" (really, a namespace)
-  - space will be the area in which the user can create objects, etc.
-  - space will typically be the user's organization's space, but could be an
-    arbitrary namespace
-  - space will determine the local namespace (id's with no prefixes)
-  - PanGalaxian needs to append a prefix to "non-local" names when "space" is
-    specified as a context, and to *all* names when space is "Any"
-
-* User can create a Project in their space (which, again, may be an arbitrary
-  namespace they specify, or their organization's space, etc.)
-  - their new Project will then be the default context for any new objects they
-    create (the New Object dialog will allow them to specify another namespace
-    for which they are authorized).
-
-So ... coding:
-
-* Use prefixes for all "non-local" id's
-  - this is especially important for the Project select widget
-  - also do it for all id's in grids
-  - think about whether it is needed for PgxnObject ...
-    + maybe not:  already have id_ns (which is prefix)
-    + but maybe so:  when PgxnObj becomes customizable, user might not want to
-      have id_ns in the interface -- then prefix should be used with id.
-

Index: PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.7 PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.8
--- PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.7	Wed Apr 25 13:47:47 2007
+++ PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py	Tue May  8 23:50:11 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnchecklist.py,v 1.7 2007/04/25 17:47:47 waterbug Exp $
+# $Id: pgxnchecklist.py,v 1.8 2007/05/09 03:50:11 waterbug Exp $
 """
 A dialog that has a checkable list of items.
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 from pprint import pprint
 import sys
@@ -31,7 +31,7 @@
     @type  content:  C{dict}
 
     @param colnames:  a list of column names
-    @type  colnames:  C{dict}
+    @type  colnames:  C{list}
 
     @param checked:  a list of the keys of rows that are initially checked --
         note that this parameter becomes an instance variable, and is the best
@@ -45,7 +45,7 @@
         CheckListCtrlMixin.__init__(self)
         self.itemdict = content or {}
         self.colnames = colnames or []
-        self.checked = checked
+        self.checked = checked or []
         self.setColumns(colnames)
         self.setCheckListItems(content)
         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)

Index: PanGalactic/pangalactic/meta/names.py
diff -u PanGalactic/pangalactic/meta/names.py:1.41 PanGalactic/pangalactic/meta/names.py:1.42
--- PanGalactic/pangalactic/meta/names.py:1.41	Wed Apr 25 17:48:15 2007
+++ PanGalactic/pangalactic/meta/names.py	Tue May  8 23:50:10 2007
@@ -1,11 +1,11 @@
-# $Id: names.py,v 1.41 2007/04/25 21:48:15 waterbug Exp $
+# $Id: names.py,v 1.42 2007/05/09 03:50:10 waterbug Exp $
 """
 Objects and services for handling identifiers, addresses, and namespaces.
 
-@version: $Revision: 1.41 $
+@version: $Revision: 1.42 $
 """
 
-__version__ = "$Revision: 1.41 $"[11:-2]
+__version__ = "$Revision: 1.42 $"[11:-2]
 
 
 try:
@@ -33,12 +33,18 @@
 
     @ivar names:  the namespace's names
     @type names:  C{set}
+
+    @ivar meta:  the meta-level of the namespace -- an integer corresponding to
+        the n in the "Mn" meta-levels specified for the OMG's Meta Object
+        Facility.  A meta-level of 10 is used to indicate that a namespace can
+        apply at any meta-level > 0.
+    @type meta:  C{int}
     """
     # TODO:  decide whether an exception should be raised for attempts to
     # add a name that a Namespace already has
 
     def __init__(self, id, uri, names=None, complete=False, iteration=0,
-                 version='baseline'):
+                 version='baseline', meta=0):
         """
         Initialize a PgefNamespace.
 
@@ -54,6 +60,9 @@
         @param complete:  flag indicating whether the included member set
             is complete
         @type  complete:  C{bool}
+
+        @param meta:  (see definition in ivars, above.)
+        @type  meta:  C{int}
         """
         if not id and not uri:
             raise NameError, 'At least one of id and uri must be non-empty.'
@@ -65,6 +74,7 @@
         else:
             self.names  = set([])
         self.complete = complete
+        self.meta = meta
         self.iteration = iteration
         self.version = version
 
@@ -143,6 +153,7 @@
 # XML Schema namespace (not available anywhere in RDF that I could find).
 registerNamespace(PgefNamespace(id=u'xsd',
                         uri=u'http://www.w3.org/2001/XMLSchema',
+                        meta=10,
                         names=[
                         u'string', u'normalizedString', u'boolean',
                         u'decimal', u'float', u'double',
@@ -158,14 +169,18 @@
 
 # RDF namespace
 registerNamespace(PgefNamespace(id='rdf',
+                            meta=10,
                             uri='http://www.w3.org/1999/02/22-rdf-syntax-ns#'))
 
 # RDFS namespace
 registerNamespace(PgefNamespace(id='rdfs',
+                                meta=10,
                                 uri='http://www.w3.org/2000/01/rdf-schema#'))
 
 # OWL namespace
-registerNamespace(PgefNamespace(id='owl', uri='http://www.w3.org/2002/07/owl#'))
+registerNamespace(PgefNamespace(id='owl',
+                                meta=10,
+                                uri='http://www.w3.org/2002/07/owl#'))
 
 # 'pgeftest' namespace
 # PGEF permanent test object namespace.  This namespace is intended to include
@@ -174,6 +189,7 @@
 # PanGalactic/src/sql/populate_pgerdb.sh.  NOTE:  insertion of other names into
 # this namespace may cause some unit tests to fail.
 registerNamespace(PgefNamespace(id='pgeftest',
+                                meta=0,
                                 uri='http://pangalactic.us/test/lib/'))
 
 # 'pgeftesttmp' namespace
@@ -181,11 +197,13 @@
 # NOTE:  insertion of other names into this namespace may cause some unit tests
 # to fail.
 registerNamespace(PgefNamespace(id='pgeftesttmp',
+                                meta=0,
                                 uri='http://pangalactic.us/test/tmp/'))
 
 # 'pgefobjects' namespace
 # Namespace for PGEF reference objects (e.g., the 'admin' Person object).
 registerNamespace(PgefNamespace(id='pgefobjects',
+                                meta=0,
                                 uri='http://pangalactic.us/objects/'))
 
 # 'world' namespace
@@ -193,11 +211,13 @@
 # appropriate -- should be used with the awareness that it may get "crowded"
 # eventually ... ;)
 registerNamespace(PgefNamespace(id='world',
+                                meta=0,
                                 uri='http://earth.milkyway.universe/'))
 
 # 'mime' namespace
 # MIME media-types
 registerNamespace(PgefNamespace(id='mime',
+                            meta=0,
                             uri='http://www.iana.org/assignments/media-types/'))
 
 def u2q(uri):

From waterbug at step.nasa.gov  Wed May  9 14:47:33 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  9 14:47:36 2007
Subject: [pangalactic-commits] Attempt to fix bug in proj selection
	checklist on mswin.
Message-ID: <200705091847.l49IlXQN014805@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.186 1.187

Log message:
Attempt to fix bug in proj selection checklist on mswin.


Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.186 PanGalactic/pangalactic/node/pangalaxian.py:1.187
--- PanGalactic/pangalactic/node/pangalaxian.py:1.186	Fri May  4 20:51:15 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Wed May  9 14:47:30 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.186 2007/05/05 00:51:15 waterbug Exp $
+# $Id: pangalaxian.py,v 1.187 2007/05/09 18:47:30 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.186 $
+@version: $Revision: 1.187 $
 """
-__version__ = "$Revision: 1.186 $"[11:-2]
+__version__ = "$Revision: 1.187 $"[11:-2]
 
 # Python
 import logging
@@ -999,14 +999,17 @@
         self.log.info(' - onSelectProjects()')
         if orb.projects:
             nonseloids = set(list(orb.projects)) - set(prefs['projects'])
-            self.log.debug('   orb.projects [oids]:  %s'
+            self.log.debug('   + orb.projects [oids]:  %s'
                            % str(list(orb.projects)))
-            self.log.debug('   prefs[projects]:  %s' % str(prefs['projects']))
+            self.log.debug('   + current prefs[projects]:  %s'
+                           % str(prefs['projects']))
             projoids = prefs['projects'] + list(nonseloids)
             projdict = dict([(i, [orb.projects[projoids[i]].id,
                                   str(orb.projects[projoids[i]].name)])
                             for i in range(len(projoids))])
-            self.selected_projects = list(range(len(prefs['projects'])))
+            self.selected_projects = range(len(prefs['projects']))
+            self.log.debug('   + selected_projects:  %s'
+                           % str(self.selected_projects))
             dlg = PgxnCheckListDialog(self,
                                       title='Select Projects',
                                       content=projdict,
@@ -1014,7 +1017,11 @@
                                       checked=self.selected_projects)
             dlg.ShowModal()
             dlg.Destroy()
-            prefs['projects'] = [projoids[i] for i in self.selected_projects]
+            # str() is here because of possible unicode issue on mswin
+            prefs['projects'] = [str(projoids[i])
+                                 for i in self.selected_projects]
+            self.log.debug('   + new prefs[projects]:  %s'
+                           % str(prefs['projects']))
             self.updateProjects()
         else:
             dlg = wx.MessageDialog(self,

From waterbug at step.nasa.gov  Wed May  9 14:57:19 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  9 14:57:19 2007
Subject: [pangalactic-commits] *Actually* fix the proj selection bug.  ;)
Message-ID: <200705091857.l49IvJvU015192@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py 1.8 1.9

Log message:
*Actually* fix the proj selection bug.  ;)


Index: PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.8 PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.9
--- PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.8	Tue May  8 23:50:11 2007
+++ PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py	Wed May  9 14:57:17 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnchecklist.py,v 1.8 2007/05/09 03:50:11 waterbug Exp $
+# $Id: pgxnchecklist.py,v 1.9 2007/05/09 18:57:17 waterbug Exp $
 """
 A dialog that has a checkable list of items.
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 from pprint import pprint
 import sys
@@ -61,7 +61,7 @@
         if flag:
             what = "checked"
             if index not in self.checked:
-                (self.checked.append(index)).sort()
+                self.checked.append(index)
         else:
             what = "unchecked"
             if index in self.checked:

From waterbug at step.nasa.gov  Wed May  9 15:18:46 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  9 15:18:50 2007
Subject: [pangalactic-commits] OK, so I lied ... another attempt ...
Message-ID: <200705091918.l49JIkOQ016093@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.187 1.188

Log message:
OK, so I lied ... another attempt ...


Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.187 PanGalactic/pangalactic/node/pangalaxian.py:1.188
--- PanGalactic/pangalactic/node/pangalaxian.py:1.187	Wed May  9 14:47:30 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Wed May  9 15:18:42 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.187 2007/05/09 18:47:30 waterbug Exp $
+# $Id: pangalaxian.py,v 1.188 2007/05/09 19:18:42 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.187 $
+@version: $Revision: 1.188 $
 """
-__version__ = "$Revision: 1.187 $"[11:-2]
+__version__ = "$Revision: 1.188 $"[11:-2]
 
 # Python
 import logging
@@ -1004,9 +1004,13 @@
             self.log.debug('   + current prefs[projects]:  %s'
                            % str(prefs['projects']))
             projoids = prefs['projects'] + list(nonseloids)
+            self.log.debug('   + projoids:  %s'
+                           % str(projoids))
             projdict = dict([(i, [orb.projects[projoids[i]].id,
                                   str(orb.projects[projoids[i]].name)])
                             for i in range(len(projoids))])
+            self.log.debug('   + projdict:  %s'
+                           % str(projdict))
             self.selected_projects = range(len(prefs['projects']))
             self.log.debug('   + selected_projects:  %s'
                            % str(self.selected_projects))

From waterbug at step.nasa.gov  Wed May  9 15:31:00 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  9 15:31:04 2007
Subject: [pangalactic-commits] Okay, let's see what this does.
Message-ID: <200705091931.l49JV0Tc016609@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.188 1.189

Log message:
Okay, let's see what this does.


Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.188 PanGalactic/pangalactic/node/pangalaxian.py:1.189
--- PanGalactic/pangalactic/node/pangalaxian.py:1.188	Wed May  9 15:18:42 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Wed May  9 15:30:57 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.188 2007/05/09 19:18:42 waterbug Exp $
+# $Id: pangalaxian.py,v 1.189 2007/05/09 19:30:57 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.188 $
+@version: $Revision: 1.189 $
 """
-__version__ = "$Revision: 1.188 $"[11:-2]
+__version__ = "$Revision: 1.189 $"[11:-2]
 
 # Python
 import logging
@@ -1007,7 +1007,8 @@
             self.log.debug('   + projoids:  %s'
                            % str(projoids))
             projdict = dict([(i, [orb.projects[projoids[i]].id,
-                                  str(orb.projects[projoids[i]].name)])
+                                  orb.projects[projoids[i]].name or
+                                  orb.projects[projoids[i]].id])
                             for i in range(len(projoids))])
             self.log.debug('   + projdict:  %s'
                            % str(projdict))

From waterbug at step.nasa.gov  Wed May  9 16:14:59 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  9 16:15:01 2007
Subject: [pangalactic-commits] Try some more things ...
Message-ID: <200705092014.l49KExBV017423@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py 1.9 1.10

Log message:
Try some more things ...


Index: PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.9 PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.10
--- PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.9	Wed May  9 14:57:17 2007
+++ PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py	Wed May  9 16:14:57 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnchecklist.py,v 1.9 2007/05/09 18:57:17 waterbug Exp $
+# $Id: pgxnchecklist.py,v 1.10 2007/05/09 20:14:57 waterbug Exp $
 """
 A dialog that has a checkable list of items.
 
-@version: $Revision: 1.9 $
+@version: $Revision: 1.10 $
 """
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 from pprint import pprint
 import sys
@@ -40,14 +40,15 @@
     """
 
     def __init__(self, parent, content, colnames, checked):
-        orb.log.debug('PgxnCheckList')
+        orb.log.debug('  + PgxnCheckList')
         wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
         CheckListCtrlMixin.__init__(self)
         self.itemdict = content or {}
+        orb.log.debug('    self.itemdict:  %s' % (pprint(self.itemdict)))
         self.colnames = colnames or []
         self.checked = checked or []
         self.setColumns(colnames)
-        self.setCheckListItems(content)
+        self.setCheckListItems(self.itemdict)
         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
         self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self)
         self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self)
@@ -76,8 +77,9 @@
             # self.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT)
 
     def setCheckListItems(self, content):
-        orb.log.debug('  content:  %s' % (pprint(content)))
-        content = content or []
+        orb.log.debug('  + PgxnCheckList.setCheckListItems')
+        orb.log.debug('    content:  %s' % (pprint(content)))
+        content = content or {}
         for key, data in content.iteritems():
             index = self.InsertStringItem(sys.maxint, data[0])
             if len(data) > 1:
@@ -102,7 +104,7 @@
     """
     # TODO:  define "checkeditems" property, based on state of checklist
 
-    def __init__(self, parent, title, content, colnames, checked=None,
+    def __init__(self, parent, title, content, colnames, checked,
                  size=wx.DefaultSize,
                  pos=wx.DefaultPosition, 
                  style=wx.DEFAULT_DIALOG_STYLE):
@@ -113,9 +115,13 @@
                       style=wx.NORMAL,
                       weight=wx.BOLD))
         sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
-        self.checklist = PgxnCheckList(self, content, colnames, checked)
-        self.checked = self.checklist.checked
+        self.checked = checked
         self.content = content
+        self.colnames = colnames
+        self.checklist = PgxnCheckList(self,
+                                       self.content,
+                                       self.colnames,
+                                       self.checked)
         minsize = self.checklist.GetSize()
         sizer.Add(self.checklist, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
         sizer.SetMinSize(minsize)

From waterbug at step.nasa.gov  Thu May 10 00:30:58 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 10 00:31:00 2007
Subject: [pangalactic-commits] Okay, no defaults here, dammit!  Fixed ...
Message-ID: <200705100430.l4A4UwW3022191@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py 1.10 1.11

Log message:
Okay, no defaults here, dammit!  Fixed ...


Index: PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.10 PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.11
--- PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py:1.10	Wed May  9 16:14:57 2007
+++ PanGalactic/pangalactic/node/gui/dialogs/pgxnchecklist.py	Thu May 10 00:30:56 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnchecklist.py,v 1.10 2007/05/09 20:14:57 waterbug Exp $
+# $Id: pgxnchecklist.py,v 1.11 2007/05/10 04:30:56 waterbug Exp $
 """
 A dialog that has a checkable list of items.
 
-@version: $Revision: 1.10 $
+@version: $Revision: 1.11 $
 """
-__version__ = "$Revision: 1.10 $"[11:-2]
+__version__ = "$Revision: 1.11 $"[11:-2]
 
 from pprint import pprint
 import sys
@@ -45,8 +45,8 @@
         CheckListCtrlMixin.__init__(self)
         self.itemdict = content or {}
         orb.log.debug('    self.itemdict:  %s' % (pprint(self.itemdict)))
-        self.colnames = colnames or []
-        self.checked = checked or []
+        self.colnames = colnames
+        self.checked = checked
         self.setColumns(colnames)
         self.setCheckListItems(self.itemdict)
         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)

From waterbug at step.nasa.gov  Thu May 10 11:13:51 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 10 11:13:53 2007
Subject: [pangalactic-commits] Fixed state/prefs writing bug.
Message-ID: <200705101513.l4AFDp2S028710@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.189 1.190
PanGalactic/pangalactic/node/gui/widgets/pgxncontextpanel.py 1.5 1.6

Log message:
Fixed state/prefs writing bug.


Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.189 PanGalactic/pangalactic/node/pangalaxian.py:1.190
--- PanGalactic/pangalactic/node/pangalaxian.py:1.189	Wed May  9 15:30:57 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Thu May 10 11:13:49 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.189 2007/05/09 19:30:57 waterbug Exp $
+# $Id: pangalaxian.py,v 1.190 2007/05/10 15:13:49 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.189 $
+@version: $Revision: 1.190 $
 """
-__version__ = "$Revision: 1.189 $"[11:-2]
+__version__ = "$Revision: 1.190 $"[11:-2]
 
 # Python
 import logging
@@ -420,7 +420,7 @@
         # self.GodMenu = None
         # self.GodMode = None
         # self.prefs_loginconfirm.Check(prefs.get('show_login_confirmed', True))
-        prefs['projects'] = prefs.get('projects', list(orb.projects))
+        prefs['projects'] = prefs.get('projects', [])
         self.contexts = state.get('contexts') or []
         self.__set_properties()
         self.__do_layout()
@@ -603,7 +603,7 @@
 
     def updateProjects(self):
         """
-        Update the C{projects} instance variable, if necessary.
+        Update the project selection widget.
         """
         # TODO:  pass in a namespace or some form of context to restrict the
         # list
@@ -771,12 +771,12 @@
         for s in state:
             if s != 'imaps' and s != 'pmaps':
                 self.log.info("   * %s = %s" % (s, state[s]))
-        self.log.info('   + writing state to %s ...' % os.path.join(
-                                                          os.getcwd(), 'state'))
-        writeState('state')
-        self.log.info('   + writing prefs to %s ...' % os.path.join(
-                                                          os.getcwd(), 'prefs'))
-        writePrefs('prefs')
+        self.log.info('   + writing state to %s ...'
+                                    % os.path.join(prefs['home'], 'state'))
+        writeState(os.path.join(prefs['home'], 'state'))
+        self.log.info('   + writing prefs to %s ...'
+                                    % os.path.join(prefs['home'], 'prefs'))
+        writePrefs(os.path.join(prefs['home'], 'prefs'))
         self.log.info(' - state and prefs files written.')
         self.log.info(" - g'night!")
         self.Destroy()

Index: PanGalactic/pangalactic/node/gui/widgets/pgxncontextpanel.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxncontextpanel.py:1.5 PanGalactic/pangalactic/node/gui/widgets/pgxncontextpanel.py:1.6
--- PanGalactic/pangalactic/node/gui/widgets/pgxncontextpanel.py:1.5	Sun Apr 22 22:07:52 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxncontextpanel.py	Thu May 10 11:13:50 2007
@@ -1,9 +1,9 @@
 """
 PanGalaxian's panel containing context widgets (combos)
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 import wx
 from pangalactic.node                       import prefs, state
@@ -54,7 +54,6 @@
         self.contextwidget = contextwgt
 
     def onStateChange(self):
-        # TODO:  change orb.projects to pref['projects'], when available
         self.projectwidget.items = [(orb.projects[oid].id, oid)
                                     for oid in prefs['projects']]
         self.projectwidget.selected = state.get('project')

From waterbug at step.nasa.gov  Fri May 11 17:40:22 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 11 17:40:24 2007
Subject: [pangalactic-commits] Beginnings of a trash can for cache objs.
Message-ID: <200705112140.l4BLeMcB022463@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/cache.py 1.33 1.34
PanGalactic/pangalactic/node/uberorb.py 1.144 1.145

Log message:
Beginnings of a trash can for cache objs.


Index: PanGalactic/pangalactic/node/cache.py
diff -u PanGalactic/pangalactic/node/cache.py:1.33 PanGalactic/pangalactic/node/cache.py:1.34
--- PanGalactic/pangalactic/node/cache.py:1.33	Sun May  6 02:24:39 2007
+++ PanGalactic/pangalactic/node/cache.py	Fri May 11 17:40:20 2007
@@ -1,9 +1,9 @@
 """
 Local object cache manager (a layer over ZODB)
 
-@version: $Revision: 1.33 $
+@version: $Revision: 1.34 $
 """
-__version__ = "$Revision: 1.33 $"[11:-2]
+__version__ = "$Revision: 1.34 $"[11:-2]
 
 # Python
 import os, sys
@@ -52,6 +52,14 @@
         self.interfaces = {}
         for i in interfaces:
             self.addInterface(i)
+        # create a cache trashcan
+        self.trashfilename = os.path.join(datadir, "trash.fs")
+        self.trashstorage = FileStorage.FileStorage(self.trashfilename)
+        self.trashdb = DB(self.trashstorage)
+        self.trashdbconnection = self.trashdb.open()
+        self.trashdbroot = self.trashdbconnection.root()
+        if not self.trashdbroot.get('OidLookup'):
+            self.trashdbroot['OidLookup'] = PersistentMapping()
 
     # property:  objs
 
@@ -61,13 +69,23 @@
         """
         return self.dbroot['OidLookup']
 
-    def setObjs(self, value):
-        raise TypeError, 'objs attribute cannot be set.'
+    objs = property(getObjs, 'objs')
 
-    def delObjs(self):
-        raise TypeError, 'objs attribute cannot be deleted.'
+    # property:  trash
 
-    objs = property(getObjs, setObjs, delObjs, 'objs')
+    def getTrash(self):
+        """
+        Get a dictionary of the objects in the cache's trashcan by oid.
+        """
+        return self.trashdbroot['OidLookup']
+
+    def setTrash(self, value):
+        raise TypeError, 'trash attribute cannot be set.'
+
+    def delTrash(self):
+        raise TypeError, 'trash attribute cannot be deleted.'
+
+    trash = property(getTrash, 'trash')
 
     def pack(self):
         """
@@ -77,11 +95,12 @@
         self.commit()
 
     def clear(self):
+        import shutil
+        shutil.copy("data/pgef.fs", "data/pgef.fs.deleted")
         for entry in self.dbroot['OidLookup'].keys():
             del self.dbroot['OidLookup'][entry]
+        self.commit()
         del self.dbroot['OidLookup']
-        import shutil
-        shutil.copy("data/pgef.fs", "data/pgef.fs.deleted")
 
     def commit(self):
         transaction.get().commit()
@@ -104,7 +123,37 @@
 
     def saveObjects(self, objs):
         """
-        Save some objects in the cache.  Map the object's oid to the object
+        Save some objects to the cache.  Map the object's oid to the object
+        in the dictionary C{self.objs} (which includes *all* objects in the
+        cache).  By default, also add the object to the dictionary
+        C{self.dbroot[schema]}, where C{schema} is the object's
+        _schema.__name__, and to any dictionaries whose schemas are parents
+        of the object's _schema.
+
+        @param objs:  objects to be saved
+        @type  objs:  list (usually of instances of
+            L{pangalactic.meta.pgefobject.PgefObject}
+        """
+        self.log.debug(" - ObjectCache.saveObjects")
+        # TODO:  'merge' -- i.e., in case of oid collision, compare
+        # last-modified dates.  If the object to be saved has been modified more
+        # recently than the cache copy, replace the cache copy; if both have
+        # been modified, notify user of the conflict.
+        if type(objs) is not list:
+            objs = [objs]
+        for obj in objs:
+            self.objs[obj.oid] = obj
+            if hasattr(obj, '_schema'):
+                self.dbroot[obj._schema.__name__][obj.oid] = obj
+                # dictionaries of parents of the object's _schema
+                for name in [x.__name__ for x in self.interfaces.values()
+                             if x in allYourBase(obj._schema)]:
+                    self.dbroot[name][obj.oid] = obj
+        self.commit()
+
+    def deleteObjects(self, objs):
+        """
+        Save some objects to the cache.  Map the object's oid to the object
         in the dictionary C{self.objs} (which includes *all* objects in the
         cache).  By default, also add the object to the dictionary
         C{self.dbroot[schema]}, where C{schema} is the object's
@@ -117,12 +166,11 @@
         """
         self.log.debug(" - ObjectCache.saveObjects")
         # TODO:  'merge' -- i.e., in case of oid collision, compare
-        # last-modified dates.  If the repo copy has been modified and the
-        # cache copy has not, replace the cache copy; if both have been
-        # modified, notify user of the conflict.
+        # last-modified dates.  If the object to be saved has been modified more
+        # recently than the cache copy, replace the cache copy; if both have
+        # been modified, notify user of the conflict.
         if type(objs) is not list:
             objs = [objs]
-        iface_names = list(self.interfaces)
         for obj in objs:
             self.objs[obj.oid] = obj
             if hasattr(obj, '_schema'):
@@ -133,6 +181,21 @@
                     self.dbroot[name][obj.oid] = obj
         self.commit()
 
+    def delete(self, o):
+        """
+        Delete an object from the local cache, either by direct reference
+        or by oid.
+
+        @param obj:  a C{PgefObject} instance or the oid of an instance
+        @type  obj:  C{PgefObject} or C{str}
+        """
+        if isAString(o):
+            if self.objs[o]:
+                del self.objs[o]
+        elif o.oid in self.objs:
+            del self.objs[o.oid]
+        self.commit()
+
     def _getFilter(self, obj, **kw):
         """
         Return True for an object that matches all attr/values, False
@@ -170,32 +233,6 @@
         # applications may only have some of the dicts that the cache has
         return self.dbroot.get(name)
 
-    def add(self, objs):
-        """
-        Add new locally created objects to the cache.
-
-        @param objs:  C{PgefObject}s to be added
-        @type  objs:  C{list}
-        """
-        self.log.debug(" - ObjectCache.add")
-        self.saveObjects(objs)
-        self.commit()
-
-    def delete(self, o):
-        """
-        Delete an object from the local cache, either by direct reference
-        or by oid.
-
-        @param obj:  a C{PgefObject} instance or the oid of an instance
-        @type  obj:  C{PgefObject} or C{str}
-        """
-        if isAString(o):
-            if self.objs[o]:
-                del self.objs[o]
-        elif o.oid in self.objs:
-            del self.objs[o.oid]
-        self.commit()
-
     # FIXME:  Domain-specific stuff (everything from here on) should be in one
     # or more separate modules
 

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.144 PanGalactic/pangalactic/node/uberorb.py:1.145
--- PanGalactic/pangalactic/node/uberorb.py:1.144	Sun May  6 02:24:39 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Fri May 11 17:40:20 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.144 2007/05/06 06:24:39 waterbug Exp $
+# $Id: uberorb.py,v 1.145 2007/05/11 21:40:20 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.144 $
+@version: $Revision: 1.145 $
 """
-__version__ = "$Revision: 1.144 $"[11:-2]
+__version__ = "$Revision: 1.145 $"[11:-2]
 
 import logging
 import mimetypes
@@ -400,12 +400,6 @@
             self.log.info('    * no updates found.')
         return objs
 
-    def add(self, addlist):
-        if self.cache:
-            self.cache.add(addlist)
-        else:
-            pass
-
     def save(self, objs):
         if self.cache:
             self.cache.saveObjects(objs)

From waterbug at step.nasa.gov  Fri May 11 22:54:54 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 11 22:54:55 2007
Subject: [pangalactic-commits] Cache interface improvements (more coming
	...).
Message-ID: <200705120254.l4C2ssf6023428@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/cache.py 1.34 1.35
PanGalactic/pangalactic/node/uberorb.py 1.145 1.146

Log message:
Cache interface improvements (more coming ...).


Index: PanGalactic/pangalactic/node/cache.py
diff -u PanGalactic/pangalactic/node/cache.py:1.34 PanGalactic/pangalactic/node/cache.py:1.35
--- PanGalactic/pangalactic/node/cache.py:1.34	Fri May 11 17:40:20 2007
+++ PanGalactic/pangalactic/node/cache.py	Fri May 11 22:54:53 2007
@@ -1,9 +1,9 @@
 """
 Local object cache manager (a layer over ZODB)
 
-@version: $Revision: 1.34 $
+@version: $Revision: 1.35 $
 """
-__version__ = "$Revision: 1.34 $"[11:-2]
+__version__ = "$Revision: 1.35 $"[11:-2]
 
 # Python
 import os, sys
@@ -49,9 +49,7 @@
         self.dbroot = self.dbconnection.root()
         if not self.dbroot.get('OidLookup'):
             self.dbroot['OidLookup'] = PersistentMapping()
-        self.interfaces = {}
-        for i in interfaces:
-            self.addInterface(i)
+        self.addInterfaces(interfaces)
         # create a cache trashcan
         self.trashfilename = os.path.join(datadir, "trash.fs")
         self.trashstorage = FileStorage.FileStorage(self.trashfilename)
@@ -79,12 +77,6 @@
         """
         return self.trashdbroot['OidLookup']
 
-    def setTrash(self, value):
-        raise TypeError, 'trash attribute cannot be set.'
-
-    def delTrash(self):
-        raise TypeError, 'trash attribute cannot be deleted.'
-
     trash = property(getTrash, 'trash')
 
     def pack(self):
@@ -105,21 +97,24 @@
     def commit(self):
         transaction.get().commit()
 
-    def addInterface(self, iface):
+    def addInterfaces(self, ifaces):
         """
         For an C{Interface}, set up a root dictionary in the cache that
         will contain C{PgefObject} instances whose _schema is that
         C{Interface}.
 
-        @param iface:  an C{Interface} to be supported by the cache
-        @type  iface:  L{zope.interface.interface.InterfaceClass} instance
-        """
-        self.log.debug(' - ObjectCache.addInterface:  adding %s'
-                                                            % iface.__name__)
-        if iface.__name__ not in self.dbroot.keys():
-            self.dbroot[iface.__name__] = PersistentMapping()
+        @param ifaces:  a list of C{Interface} instances that will be supported
+            by the cache
+        @type  ifaces:  C{list} of L{zope.interface.interface.InterfaceClass}
+        """
+        self.log.debug(' - ObjectCache.addInterfaces')
+        self.interfaces = getattr(self, 'interfaces', {})
+        for i in ifaces:
+            self.log.debug('   + %s' % i.__name__)
+            if i.__name__ not in self.dbroot.keys():
+                self.dbroot[i.__name__] = PersistentMapping()
+            self.interfaces[i.__name__] = i
         self.commit()
-        self.interfaces[iface.__name__] = iface
 
     def saveObjects(self, objs):
         """
@@ -153,12 +148,7 @@
 
     def deleteObjects(self, objs):
         """
-        Save some objects to the cache.  Map the object's oid to the object
-        in the dictionary C{self.objs} (which includes *all* objects in the
-        cache).  By default, also add the object to the dictionary
-        C{self.dbroot[schema]}, where C{schema} is the object's
-        _schema.__name__, and to any dictionaries whose schemas are parents
-        of the object's _schema.
+        Delete objects from the cache and save them into trash.
 
         @param objs:  objects to be saved
         @type  objs:  list (usually of instances of
@@ -172,28 +162,14 @@
         if type(objs) is not list:
             objs = [objs]
         for obj in objs:
-            self.objs[obj.oid] = obj
             if hasattr(obj, '_schema'):
-                self.dbroot[obj._schema.__name__][obj.oid] = obj
-                # dictionaries of parents of the object's _schema
+                del self.dbroot[obj._schema.__name__][obj.oid]
+                # delete from dictionaries of parents of the object's _schema
                 for name in [x.__name__ for x in self.interfaces.values()
-                             if x in allYourBase(obj._schema)]:
-                    self.dbroot[name][obj.oid] = obj
-        self.commit()
-
-    def delete(self, o):
-        """
-        Delete an object from the local cache, either by direct reference
-        or by oid.
-
-        @param obj:  a C{PgefObject} instance or the oid of an instance
-        @type  obj:  C{PgefObject} or C{str}
-        """
-        if isAString(o):
-            if self.objs[o]:
-                del self.objs[o]
-        elif o.oid in self.objs:
-            del self.objs[o.oid]
+                             if (x in allYourBase(obj._schema)
+                                 and self.dbroot[name].get(obj.oid))]:
+                    del self.dbroot[name][obj.oid]
+            del self.objs[obj.oid]
         self.commit()
 
     def _getFilter(self, obj, **kw):

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.145 PanGalactic/pangalactic/node/uberorb.py:1.146
--- PanGalactic/pangalactic/node/uberorb.py:1.145	Fri May 11 17:40:20 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Fri May 11 22:54:53 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.145 2007/05/11 21:40:20 waterbug Exp $
+# $Id: uberorb.py,v 1.146 2007/05/12 02:54:53 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.145 $
+@version: $Revision: 1.146 $
 """
-__version__ = "$Revision: 1.145 $"[11:-2]
+__version__ = "$Revision: 1.146 $"[11:-2]
 
 import logging
 import mimetypes
@@ -878,17 +878,6 @@
         self.log.debug('   + end getAcusByAssemblyOid')
         return acus
 
-    def removeLocalObjFromCache(self, o):
-        """
-        Remove a local object from the cache (ZODB).
-
-        @param objoroid:  a C{PgefObject} instance
-        @type  objoroid:  C{PgefObject}
-        """
-        self.log.debug(' - removeLocalObjFromCache')
-        if getattr(self, 'cache'):
-            self.cache.delete(o)
-
 
 """
 A singleton UberORB instance:  orb

From waterbug at step.nasa.gov  Sat May 12 16:00:48 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sat May 12 16:00:51 2007
Subject: [pangalactic-commits] Enhanced:  logging, events, state change ...
Message-ID: <200705122000.l4CK0mPI025413@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/cache.py 1.35 1.36
PanGalactic/pangalactic/node/pangalaxian.py 1.190 1.191
PanGalactic/pangalactic/node/uberorb.py 1.146 1.147
PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py 1.146 1.147
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.34 1.35
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.118 1.119

Log message:
Enhanced:  logging, events, state change ...
* widget-specific loggers, cache and xmlrpcinterface loggers
* more sensible login/logout state changes
* UI now less jumpy on those events, e.g. (phew! :)


Index: PanGalactic/pangalactic/node/cache.py
diff -u PanGalactic/pangalactic/node/cache.py:1.35 PanGalactic/pangalactic/node/cache.py:1.36
--- PanGalactic/pangalactic/node/cache.py:1.35	Fri May 11 22:54:53 2007
+++ PanGalactic/pangalactic/node/cache.py	Sat May 12 16:00:44 2007
@@ -1,12 +1,12 @@
 """
 Local object cache manager (a layer over ZODB)
 
-@version: $Revision: 1.35 $
+@version: $Revision: 1.36 $
 """
-__version__ = "$Revision: 1.35 $"[11:-2]
+__version__ = "$Revision: 1.36 $"[11:-2]
 
 # Python
-import os, sys
+import logging, os, sys
 
 # ZODB
 from persistent.mapping import PersistentMapping
@@ -25,16 +25,13 @@
     Light-weight local object persistence for a PanGalactic node.
     """
 
-    def __init__(self, interfaces, home='', log=None):
+    def __init__(self, interfaces, home=''):
         """
         Initialize an C{ObjectCache} instance.
 
         @param interfaces:  
         """
-        self.log = log
-        if not log:
-            self.log.debug = sys.stdout.write
-            self.log.info = sys.stdout.write
+        self.log = logging.getLogger('cache')
         # If modifying this stuff, be careful:  order is important
         self.log.debug('ObjectCache (ZODB) starting up ...')
         self.log.debug(' - initializing LocalStorage')
@@ -50,7 +47,7 @@
         if not self.dbroot.get('OidLookup'):
             self.dbroot['OidLookup'] = PersistentMapping()
         self.addInterfaces(interfaces)
-        # create a cache trashcan
+        # create a cache trash
         self.trashfilename = os.path.join(datadir, "trash.fs")
         self.trashstorage = FileStorage.FileStorage(self.trashfilename)
         self.trashdb = DB(self.trashstorage)
@@ -84,6 +81,7 @@
         Remove old entries from and optimize the cache.
         """
         self.db.pack()
+        self.dbtrash.pack()
         self.commit()
 
     def clear(self):

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.118 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.119
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.118	Sun May  6 02:24:40 2007
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Sat May 12 16:00:46 2007
@@ -1,16 +1,17 @@
-# $Id: xmlrpcinterface.py,v 1.118 2007/05/06 06:24:40 waterbug Exp $
+# $Id: xmlrpcinterface.py,v 1.119 2007/05/12 20:00:46 waterbug Exp $
 
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.118 $
+@version: $Revision: 1.119 $
 """
-__version__ = "$Revision: 1.118 $"[11:-2]
+__version__ = "$Revision: 1.119 $"[11:-2]
 
 import base64
-import xmlrpclib
-import string
 import httplib
+import logging
+import string
+import xmlrpclib
 from pprint import pprint
 
 
@@ -96,8 +97,7 @@
     """
     XML-RPC API to PGER
     """
-    def __init__(self, hostandport, userid='', passwd='', secure=True,
-                 log=None):
+    def __init__(self, hostandport, userid='', passwd='', secure=True):
         """
         Initialize an XML-RPC server proxy for the specified host, port, userid,
         and password.
@@ -114,23 +114,17 @@
         @param secure:  flag to indicate whether connection should use SSL
             (True, the default) or not.
         @type  secure:  C{bool}
-
-        @param log:  a writable log object (normally, the orb's log)
-        @type  log:  C{logging.Logger}
         """
-        self.log = log
-        if not log:
-            self.log.debug = sys.stdout.write
-            self.log.info = sys.stdout.write
+        self.log = logging.getLogger('xmlrpciface')
         # (worry about proxies later, if necessary)
         if secure:
             conns = 'https://'
         else:
             conns = 'http://'
         conns = conns + hostandport
-        self.log.debug('XmlrpcInterface:  connection string is "%s"' % conns)
-        self.log.debug('                  userid is:           "%s"' % userid)
-        self.log.debug('                  passwd is:           "%s"' % passwd)
+        self.log.debug(' - connect:  "%s"' % conns)
+        self.log.debug(' - userid:   "%s"' % userid)
+        self.log.debug(' - passwd:   "%s"' % passwd)
         if userid and passwd:
             self.userid = userid
             if secure:
@@ -193,14 +187,14 @@
             (now with new state info in their repository-related
             attributes)
         """
-        self.log.debug("XmlrpcInterface.addobjects")
+        self.log.debug(" - addObjects")
         if not objs:
-            self.log.debug("  * empty object list")
+            self.log.debug("   + empty object list")
             newexts = []
         else:
-            self.log.debug("  * oids and schemas of objects to be added:")
+            self.log.debug("   + oids and schemas of objects to be added:")
             for o in objs:
-                self.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
+                self.log.debug('     * %s (%s)' % (o.oid, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.addObjects(extracts)
         return newexts
@@ -217,14 +211,14 @@
             (now with new state info in their repository-related
             attributes)
         """
-        self.log.debug("XmlrpcInterface.updateObjects")
+        self.log.debug(" - updateObjects")
         if not objs:
-            self.log.debug("  * empty object list")
+            self.log.debug("   + empty object list")
             newexts = []
         else:
-            self.log.debug("  * oids and schemas of objects to be updated:")
+            self.log.debug("   + oids and schemas of objects to be updated:")
             for o in objs:
-                self.log.debug('   + %s (%s)' % (o.oid, o._schema.__name__))
+                self.log.debug('     * %s (%s)' % (o.oid, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.updateObjects(extracts)
         return newexts
@@ -240,14 +234,14 @@
             updated with an iteration, version, id, etc.
         @rtype:   C{list} of extracts (C{dict}s)
         """
-        self.log.debug("XmlrpcInterface.commitVersions()")
+        self.log.debug(" - commitVersions()")
         if not objs:
-            self.log.debug("  * empty object list")
+            self.log.debug("   + empty object list")
             newexts = []
         else:
-            self.log.debug("  * ids and schemas of versions to be committed:")
+            self.log.debug("   + ids and schemas of versions to be committed:")
             for o in objs:
-                self.log.debug('   + %s (%s)' % (o.id, o._schema.__name__))
+                self.log.debug('     * %s (%s)' % (o.id, o._schema.__name__))
             extracts = [o.extract() for o in objs]
             newexts = self._RPC.commitVersions(extracts)
         return newexts
@@ -275,9 +269,7 @@
         @param params:  attr-value criteria for desired objects
         @type  params:  C{dict}
         """
-        self.log.debug("XmlrpcInterface.getobjects")
-        self.log.debug(' - xmlrpc.getObjects command is:')
-        self.log.debug('   getObjects(%s, %s, %s, %s)' % (
+        self.log.debug(' - getObjects(%s, %s, %s, %s)' % (
                                     schema_name, refs, subtypes, params))
         return self._RPC.getObjects(schema_name, refs, subtypes, params)
 
@@ -288,7 +280,7 @@
         @type  oids:  C{list}
         @param oids:  oids of the desired objects
         """
-        self.log.debug("XmlrpcInterface.getObjectsByOids")
+        self.log.debug(" - getObjectsByOids(%s)" % (str(oids)))
         return self._RPC.getObjectsByOids(oids)
 
     def getNames(self, ns):
@@ -298,7 +290,7 @@
         @param ns:  the URL (oid) of a namespace
         @type  ns:  C{str}
         """
-        self.log.debug("XmlrpcInterface.getNames()")
+        self.log.debug(" - getNames(%s)" % ns)
         return self._RPC.getNames(ns)
 
     def getBaseIds(self, ns):
@@ -308,7 +300,7 @@
         @param ns:  the URL (oid) of a namespace
         @type  ns:  C{str}
         """
-        self.log.debug("xmlrpcinterface.getBaseIds()")
+        self.log.debug(" - getBaseIds(%s)" % ns)
         return self._RPC.getBaseIds(ns)
 
     def search(self, schema_name, refs, subtypes, params, spec):
@@ -346,16 +338,15 @@
 
         @return:  a C{list} of extracts of the objects that were found
         """
-        self.log.debug("- XmlrpcInterface.search:")
-        self.log.debug("  search(%s, %s, %s, %s, %s)" % (
+        self.log.debug(" - search(%s, %s, %s, %s, %s)" % (
                                 schema_name, refs, subtypes, params, spec))
         if not spec:
             spec = []
         data = self._RPC.search(schema_name, refs, subtypes, params, spec)
         if data:
-            self.log.debug("  - data returned:  %s items." % len(data))
+            self.log.debug("   + data returned:  %s items." % len(data))
         else:
-            self.log.debug("  - no %s instances found" % schema_name)
+            self.log.debug("   + no %s instances found" % schema_name)
         return data
 
     def getCount(self, schema_name, refs, subtypes, params):
@@ -389,14 +380,13 @@
 
         @return:  a C{list} of extracts of the objects that were found
         """
-        self.log.debug(" - XmlrpcInterface.getCount()")
-        self.log.debug("   search(schema_name, refs, subtypes, params)")
-        self.log.debug("   search(%s, %s, %s, %s)" % (
+        self.log.debug(" - getCount(schema_name, refs, subtypes, params)")
+        self.log.debug("   + getCount(%s, %s, %s, %s)" % (
                         schema_name, refs, subtypes, params))
         count = self._RPC.getCount(schema_name, refs, subtypes, params)
         if count:
-            self.log.debug("  - count returned:  %s" % count)
+            self.log.debug("   + count returned:  %s" % count)
         else:
-            self.log.debug("  - no %s instances matched" % schema_name)
+            self.log.debug("   + no %s instances matched" % schema_name)
         return count
 

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.146 PanGalactic/pangalactic/node/uberorb.py:1.147
--- PanGalactic/pangalactic/node/uberorb.py:1.146	Fri May 11 22:54:53 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Sat May 12 16:00:45 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.146 2007/05/12 02:54:53 waterbug Exp $
+# $Id: uberorb.py,v 1.147 2007/05/12 20:00:45 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.146 $
+@version: $Revision: 1.147 $
 """
-__version__ = "$Revision: 1.146 $"[11:-2]
+__version__ = "$Revision: 1.147 $"[11:-2]
 
 import logging
 import mimetypes
@@ -73,7 +73,6 @@
     def register(self, receiver, signal, **kw):
         dispatcher.connect(receiver, signal, **kw)
 
-
     def startLogging(self, console=False, server=False, level=logging.INFO):
         """
         Create a logger and begin writing to the log.  This function assumes
@@ -113,7 +112,7 @@
             # self.__cache = ObjectCache(self.interfaces.values(), home=home)
             ifaces = [self.interfaces[i] for i in self.persistables]
             self.log.debug('   interfaces:  %s' % str(self.persistables))
-            self.__cache = ObjectCache(ifaces, home=home, log=self.log)
+            self.__cache = ObjectCache(ifaces, home=home)
             # self.createDefaultNamespace()
         else:
             raise ValueError, 'the orb already has a cache.'
@@ -183,8 +182,7 @@
         return XmlrpcInterface(hostandport=hostandport,
                                userid=userid,
                                passwd=passwd,
-                               secure=secure,
-                               log=self.log)
+                               secure=secure)
 
     def login(self, hostandport, userid, passwd, secure=True):
         """

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.146 PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.147
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.146	Mon Mar 26 02:12:39 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py	Sat May 12 16:00:45 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobject.py,v 1.146 2007/03/26 06:12:39 waterbug Exp $
+# $Id: pgxnobject.py,v 1.147 2007/05/12 20:00:45 waterbug Exp $
 """
 PanGalaxianObject (a C{PgefObject} viewer/editor)
 
-@version: $Revision: 1.146 $
+@version: $Revision: 1.147 $
 """
-__version__ = "$Revision: 1.146 $"[11:-2]
+__version__ = "$Revision: 1.147 $"[11:-2]
 
 import logging
 from copy import deepcopy
@@ -81,7 +81,7 @@
             zero-length string.
         @type  editing:  C{str}
         """
-        self.log = logging.getLogger('PanGalaxianObject')
+        self.log = logging.getLogger('pgxnobject')
         self.log.debug(' - PanGalaxianObject initializing for %s ...' % (
                                                 obj._schema.__name__,))
         wx.Frame.__init__(self, parent, -1,

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.34 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.35
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.34	Sat Feb 17 16:11:45 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Sat May 12 16:00:45 2007
@@ -1,11 +1,11 @@
-# $Id: pgxnstatusbar.py,v 1.34 2007/02/17 21:11:45 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.35 2007/05/12 20:00:45 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.34 $
+@version: $Revision: 1.35 $
 """
-__version__ = "$Revision: 1.34 $"[11:-2]
+__version__ = "$Revision: 1.35 $"[11:-2]
 
 # Python core modules
 import logging
@@ -33,7 +33,7 @@
         self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_IDLE, self.OnIdle)
         self.SetFieldsCount(6)
-        self.log = logging.getLogger('pgxnstatusbar')
+        self.log = logging.getLogger('statusbar')
         # fields:
         # 0 - help on current menu item (maybe)
         # 1 - offline or repo status
@@ -92,24 +92,24 @@
             self.reposition()
 
     def onClick(self, evt):
-        self.log.info("onClick() [status bar 'connect' icon]")
+        self.log.debug(" - onClick() ['connect' icon]")
         if state.get('repo'):
             # self.parent.onLogout(wx.EVT_MENU)
-            self.log.info(" - dispatching 'logout' message")
+            self.log.debug("   + dispatching 'logout' message")
             dispatcher.send(signal='logout', event=None)
         else:
             # self.parent.onLogin(wx.EVT_MENU)
-            self.log.info(" - dispatching 'login' message")
+            self.log.debug("   + dispatching 'login' message")
             dispatcher.send(signal='login', event=None)
 
     def onStateChange(self):
         """
         Check state and set things accordingly.
         """
-        self.log.info("onStateChange() -- checking state")
+        self.log.debug(" - onStateChange() -- checking state")
         if state.get('repo'):
-            self.log.debug(" - state['repo'] = '%s'" % state['repo'])
-            self.log.debug(" - logged in")
+            self.log.debug("   + state['repo'] = '%s'" % state['repo'])
+            self.log.debug("   + logged in")
             self.SetStatusText('repo: ' + state['repo'], 1)
             # self.SetBackgroundColour((100, 255, 0))
             self.onbutton.Hide()
@@ -121,9 +121,9 @@
                 self.unlockbitmap.Hide()
                 self.lockbitmap.Show()
         else:
-            self.log.debug(" - state.get('repo') = '%s'" % str(
+            self.log.debug("   + state.get('repo') = '%s'" % str(
                                                             state.get('repo')))
-            self.log.debug(" - logged out")
+            self.log.debug("   + logged out")
             self.SetStatusText('offline', 1)
             # self.SetBackgroundColour((255, 255, 255))
             self.onbutton.Show()

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.190 PanGalactic/pangalactic/node/pangalaxian.py:1.191
--- PanGalactic/pangalactic/node/pangalaxian.py:1.190	Thu May 10 11:13:49 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Sat May 12 16:00:45 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.190 2007/05/10 15:13:49 waterbug Exp $
+# $Id: pangalaxian.py,v 1.191 2007/05/12 20:00:45 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.190 $
+@version: $Revision: 1.191 $
 """
-__version__ = "$Revision: 1.190 $"[11:-2]
+__version__ = "$Revision: 1.191 $"[11:-2]
 
 # Python
 import logging
@@ -353,14 +353,15 @@
         self.log.info(" - build: %s.  version:  %s" % (BUILD_DATE, VERSION))
         self.log.info(" - wxPython version:  %s" % wx.__version__)
         self.log.info(" - home directory (and current working dir) = %s" % prefs['home'])
-        self.log.info(" - prefs:")
-        for p in prefs:
-            if p != 'imaps' and p != 'pmaps':
-                self.log.info("   * %s = %s" % (p, prefs[p]))
-        self.log.info(" - state:")
-        for s in state:
-            if s != 'imaps' and s != 'pmaps':
-                self.log.info("   * %s = %s" % (s, state[s]))
+        if self.debugmode:
+            self.log.debug(" - prefs:")
+            for p in prefs:
+                if p != 'imaps' and p != 'pmaps':
+                    self.log.debug("   * %s = %s" % (p, prefs[p]))
+            self.log.debug(" - state:")
+            for s in state:
+                if s != 'imaps' and s != 'pmaps':
+                    self.log.debug("   * %s = %s" % (s, state[s]))
         # start orb logging
         orb.startLogging()
         # the "interfaces updated" event needs to be registered before
@@ -448,7 +449,8 @@
         self.projectwidget = self.contextpanel.projectwidget
         self.systemwidget  = self.contextpanel.systemwidget
         self.contextwidget = self.contextpanel.contextwidget
-        # eine kleine nachttesting!
+        # TODO:  "contexts" (incl. projects) are being refactored/enhanced
+        self.updateProjectWidget()
         # self.projectwidget.items = [(i,i) for i in ['foo', 'bar']]
         self.systemwidget.items  = [(i,i) for i in ['spam', 'eggs']]
         self.contextwidget.items = [(i,i) for i in ['garg', 'barg']]
@@ -529,7 +531,7 @@
         # getObject, getObjectsFromServer, commit, getNamespaces, and
         # getAcusByAssemblyOid.
         orb.register(self.refreshView, 'updates received')
-        orb.register(self.updateProjects, 'update projects')
+        orb.register(self.updateProjectWidget, 'update projects')
 
     def onInterfaceUpdate(self):
         """
@@ -601,7 +603,7 @@
             orb.save(models)
             orb.save(acus)
 
-    def updateProjects(self):
+    def updateProjectWidget(self):
         """
         Update the project selection widget.
         """
@@ -761,16 +763,17 @@
         PanGalaxian exit process.
         """
         self.log.info(' - onExit()')
-        self.log.info("  + setting state['repo'] = ''")
+        self.log.debug("  + setting state['repo'] = ''")
         state['repo'] = ''
-        self.log.info(" - prefs:")
-        for p in prefs:
-            if p != 'imaps' and p != 'pmaps':
-                self.log.info("   * %s = %s" % (p, prefs[p]))
-        self.log.info(" - state:")
-        for s in state:
-            if s != 'imaps' and s != 'pmaps':
-                self.log.info("   * %s = %s" % (s, state[s]))
+        if self.debugmode:
+            self.log.debug(" - prefs:")
+            for p in prefs:
+                if p != 'imaps' and p != 'pmaps':
+                    self.log.debug("   * %s = %s" % (p, prefs[p]))
+            self.log.debug(" - state:")
+            for s in state:
+                if s != 'imaps' and s != 'pmaps':
+                    self.log.debug("   * %s = %s" % (s, state[s]))
         self.log.info('   + writing state to %s ...'
                                     % os.path.join(prefs['home'], 'state'))
         writeState(os.path.join(prefs['home'], 'state'))
@@ -910,14 +913,15 @@
         from one.
         """
         self.log.info(" - onStateChange")
-        self.log.info(" - prefs:")
-        for p in prefs:
-            if p != 'imaps' and p != 'pmaps':
-                self.log.info("   * %s = %s" % (p, prefs[p]))
-        self.log.info(" - state:")
-        for s in state:
-            if s != 'imaps' and s != 'pmaps':
-                self.log.info("   * %s = %s" % (s, state[s]))
+        if self.debugmode:
+            self.log.debug(" - prefs:")
+            for p in prefs:
+                if p != 'imaps' and p != 'pmaps':
+                    self.log.debug("   * %s = %s" % (p, prefs[p]))
+            self.log.debug(" - state:")
+            for s in state:
+                if s != 'imaps' and s != 'pmaps':
+                    self.log.debug("   * %s = %s" % (s, state[s]))
         if state.get('repo'):
             self.log.info("*** logged in to repository (non-local mode) ***")
             orb.getProjectsFromServer()
@@ -949,16 +953,14 @@
             self.tools_getmystuff.Enable(0)
             self.tools_passwd.Enable(0)
             self.log.info("*** not logged in (local mode) ***")
-        self.onSetProject(None)
         self.statusbar.onStateChange()
-        self.contextpanel.onStateChange()
-        self.treebook.onStateChange()
         # signal to any interested objects that state has changed ...
+        # NOTE:  currently there are no receivers for this signal
         # NOTE:  this does not force the state to change, it just notifies any
         # receiver to check state['repo'] -- if it is an empty string, we're in
         # "local mode" (not talking to a repo); if a non-empty string, we're
         # "connected to" (authenticated and directing messages to) a repo.
-        # Note:  PanGalaxian has no "session" concept.
+        # NOTE:  PanGalaxian has no "session" concept.
         dispatcher.send(signal='state changed')
         self.log.info(' - signal "state changed" dispatched ...')
 
@@ -1027,7 +1029,7 @@
                                  for i in self.selected_projects]
             self.log.debug('   + new prefs[projects]:  %s'
                            % str(prefs['projects']))
-            self.updateProjects()
+            self.updateProjectWidget()
         else:
             dlg = wx.MessageDialog(self,
                        "No projects have been created or retrieved yet.",

From waterbug at step.nasa.gov  Sun May 13 20:41:32 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 13 20:41:34 2007
Subject: [pangalactic-commits] ObjectCache.deleteObjects seems to work.
Message-ID: <200705140041.l4E0fWrH012568@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.121 1.122
PanGalactic/pangalactic/node/cache.py 1.36 1.37
PanGalactic/pangalactic/node/pangalaxian.py 1.191 1.192
PanGalactic/pangalactic/node/uberorb.py 1.147 1.148
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.46 1.47
PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py 1.66 1.67
PanGalactic/pangalactic/node/gui/widgets/pgxntree.py 1.12 1.13
PanGalactic/pangalactic/test/test_uberorb.py 1.5 1.6

Log message:
ObjectCache.deleteObjects seems to work.
- also deprecated orb.getLocalObject in favor of getObject, since
  getObject does the same thing unless logged in ...
- so getLocalObject should only be used if it is important
  *not* to get the object from the repo even if logged in.



Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.121 PanGalactic/TODO:1.122
--- PanGalactic/TODO:1.121	Thu Apr 26 09:41:58 2007
+++ PanGalactic/TODO	Sun May 13 20:41:28 2007
@@ -10,6 +10,7 @@
 TOP PRIORITIES
 --------------
 [*] BUG:  fix namespace collision-checking in PanGalaxianObject
+    (are we sure it's broken?)
 [*] ENHANCEMENTS:  give PanGalaxianObject some reasonable defaults:
     [-] creator, owner, modifier = current user
     [-] cm auth = current project
@@ -597,5 +598,5 @@
     [+] one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.121 2007/04/26 13:41:58 waterbug Exp $
+# $Id: TODO,v 1.122 2007/05/14 00:41:28 waterbug Exp $
 

Index: PanGalactic/pangalactic/test/test_uberorb.py
diff -u PanGalactic/pangalactic/test/test_uberorb.py:1.5 PanGalactic/pangalactic/test/test_uberorb.py:1.6
--- PanGalactic/pangalactic/test/test_uberorb.py:1.5	Sat Jan  6 23:39:16 2007
+++ PanGalactic/pangalactic/test/test_uberorb.py	Sun May 13 20:41:30 2007
@@ -1,4 +1,4 @@
-# $Id: test_uberorb.py,v 1.5 2007/01/07 04:39:16 waterbug Exp $
+# $Id: test_uberorb.py,v 1.6 2007/05/14 00:41:30 waterbug Exp $
 
 """
 Unit tests for pangalactic.node.uberorb
@@ -61,18 +61,6 @@
         pass
     test_save.todo = 'not done.'
 
-    def test_clearCache(self):
-        pass
-    test_clearCache.todo = 'not done.'
-
-    def test_packLocalDB(self):
-        pass
-    test_packLocalDB.todo = 'not done.'
-
-    def test_getLocalObjects(self, oid):
-        pass
-    test_getLocalObjects.todo = 'not done.'
-
     def test_getObject(self, dict, oid):
         pass
     test_getObject.todo = 'not done.'

Index: PanGalactic/pangalactic/node/cache.py
diff -u PanGalactic/pangalactic/node/cache.py:1.36 PanGalactic/pangalactic/node/cache.py:1.37
--- PanGalactic/pangalactic/node/cache.py:1.36	Sat May 12 16:00:44 2007
+++ PanGalactic/pangalactic/node/cache.py	Sun May 13 20:41:28 2007
@@ -1,9 +1,9 @@
 """
 Local object cache manager (a layer over ZODB)
 
-@version: $Revision: 1.36 $
+@version: $Revision: 1.37 $
 """
-__version__ = "$Revision: 1.36 $"[11:-2]
+__version__ = "$Revision: 1.37 $"[11:-2]
 
 # Python
 import logging, os, sys
@@ -46,7 +46,6 @@
         self.dbroot = self.dbconnection.root()
         if not self.dbroot.get('OidLookup'):
             self.dbroot['OidLookup'] = PersistentMapping()
-        self.addInterfaces(interfaces)
         # create a cache trash
         self.trashfilename = os.path.join(datadir, "trash.fs")
         self.trashstorage = FileStorage.FileStorage(self.trashfilename)
@@ -55,6 +54,7 @@
         self.trashdbroot = self.trashdbconnection.root()
         if not self.trashdbroot.get('OidLookup'):
             self.trashdbroot['OidLookup'] = PersistentMapping()
+        self.addInterfaces(interfaces)
 
     # property:  objs
 
@@ -76,22 +76,6 @@
 
     trash = property(getTrash, 'trash')
 
-    def pack(self):
-        """
-        Remove old entries from and optimize the cache.
-        """
-        self.db.pack()
-        self.dbtrash.pack()
-        self.commit()
-
-    def clear(self):
-        import shutil
-        shutil.copy("data/pgef.fs", "data/pgef.fs.deleted")
-        for entry in self.dbroot['OidLookup'].keys():
-            del self.dbroot['OidLookup'][entry]
-        self.commit()
-        del self.dbroot['OidLookup']
-
     def commit(self):
         transaction.get().commit()
 
@@ -111,6 +95,8 @@
             self.log.debug('   + %s' % i.__name__)
             if i.__name__ not in self.dbroot.keys():
                 self.dbroot[i.__name__] = PersistentMapping()
+            if i.__name__ not in self.trashdbroot.keys():
+                self.trashdbroot[i.__name__] = PersistentMapping()
             self.interfaces[i.__name__] = i
         self.commit()
 
@@ -127,7 +113,7 @@
         @type  objs:  list (usually of instances of
             L{pangalactic.meta.pgefobject.PgefObject}
         """
-        self.log.debug(" - ObjectCache.saveObjects")
+        self.log.debug(" - saveObjects()")
         # TODO:  'merge' -- i.e., in case of oid collision, compare
         # last-modified dates.  If the object to be saved has been modified more
         # recently than the cache copy, replace the cache copy; if both have
@@ -152,7 +138,7 @@
         @type  objs:  list (usually of instances of
             L{pangalactic.meta.pgefobject.PgefObject}
         """
-        self.log.debug(" - ObjectCache.saveObjects")
+        self.log.debug(" - deleteObjects()")
         # TODO:  'merge' -- i.e., in case of oid collision, compare
         # last-modified dates.  If the object to be saved has been modified more
         # recently than the cache copy, replace the cache copy; if both have
@@ -160,16 +146,51 @@
         if type(objs) is not list:
             objs = [objs]
         for obj in objs:
+            self.log.debug('   + oid:  %s' % obj.oid)
             if hasattr(obj, '_schema'):
-                del self.dbroot[obj._schema.__name__][obj.oid]
+                self.log.debug("     * _schema: %s" % obj._schema.__name__)
+                if self.dbroot[obj._schema.__name__].get(obj.oid):
+                    self.log.debug("     * deleting from dbroot['%s']"
+                                   % obj._schema.__name__)
+                    del self.dbroot[obj._schema.__name__][obj.oid]
+                else:
+                    self.log.debug("     * not found in dbroot['%s']"
+                                   % obj._schema.__name__)
                 # delete from dictionaries of parents of the object's _schema
                 for name in [x.__name__ for x in self.interfaces.values()
-                             if (x in allYourBase(obj._schema)
-                                 and self.dbroot[name].get(obj.oid))]:
-                    del self.dbroot[name][obj.oid]
-            del self.objs[obj.oid]
+                             if x in allYourBase(obj._schema)]:
+                    if self.dbroot[name].get(obj.oid):
+                        del self.dbroot[name][obj.oid]
+                        self.log.debug("     * deleting from dbroot['%s']" % name)
+                    else:
+                        self.log.debug("     * not found in dbroot['%s']" % name)
+            if self.dbroot['OidLookup'].get(obj.oid):
+                self.log.debug("     * deleting from dbroot['OidLookup']")
+                del self.dbroot['OidLookup'][obj.oid]
+            else:
+                self.log.debug("     * not found in dbroot['OidLookup']")
+            if self.objs.get(obj.oid):
+                self.log.debug("     * deleting from cache.objs")
+                del self.objs[obj.oid]
+            else:
+                self.log.debug("     * not found in cache.objs")
+        # put objects into trash
+        for obj in objs:
+            self.trash[obj.oid] = obj
+            if hasattr(obj, '_schema'):
+                self.trashdbroot[obj._schema.__name__][obj.oid] = obj
+                # dictionaries of parents of the object's _schema
+                for name in [x.__name__ for x in self.interfaces.values()
+                             if x in allYourBase(obj._schema)]:
+                    self.trashdbroot[name][obj.oid] = obj
         self.commit()
 
+    def clear(self):
+        """
+        Delete all objects in the cache.
+        """
+        self.deleteObjects(self.objs.values())
+
     def _getFilter(self, obj, **kw):
         """
         Return True for an object that matches all attr/values, False
@@ -207,6 +228,17 @@
         # applications may only have some of the dicts that the cache has
         return self.dbroot.get(name)
 
+    # May revisit pack() later, but probably don't need it for now, and it is a
+    # very expensive operation.
+    #
+    # def pack(self):
+    #     """
+    #     Remove old entries from and optimize the cache.
+    #     """
+    #     self.db.pack()
+    #     self.dbtrash.pack()
+    #     self.commit()
+
     # FIXME:  Domain-specific stuff (everything from here on) should be in one
     # or more separate modules
 

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.191 PanGalactic/pangalactic/node/pangalaxian.py:1.192
--- PanGalactic/pangalactic/node/pangalaxian.py:1.191	Sat May 12 16:00:45 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Sun May 13 20:41:28 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.191 2007/05/12 20:00:45 waterbug Exp $
+# $Id: pangalaxian.py,v 1.192 2007/05/14 00:41:28 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.191 $
+@version: $Revision: 1.192 $
 """
-__version__ = "$Revision: 1.191 $"[11:-2]
+__version__ = "$Revision: 1.192 $"[11:-2]
 
 # Python
 import logging
@@ -308,8 +308,10 @@
             readState(os.path.join(home, 'state'))
             # in case 'home' was omitted from the prefs file
             prefs['home'] = home
-            prefs['userid'] =  prefs.get('userid', '')
-        useroid = prefs.get('userid', 'local')
+        prefs['userid'] =  prefs.get('userid', 'localuser')
+        # TODO:  create a temporary user Person object here that can be updated
+        # later if necessary when logging in to services
+        useroid = prefs['userid']
         # cd to the user-selected home directory
         os.chdir(prefs['home'])
         # make sure we have a directory for user ontologies (there also needs to
@@ -390,7 +392,6 @@
         # onto it until it exits
         self.hold_passwd = True
         setOidBase(useroid)
-        prefs['userid'] = prefs.get('userid', '')
         state['userid'] = prefs['userid']
         passwds = prefs.get('passwds', {})
         state['passwd'] = passwds.get('userid', '')
@@ -567,14 +568,23 @@
                 props['id'] = ' '.join([wizard.new_id, '(working version)'])
                 props['version'] = 'working'
                 props['iteration'] = 0
+                # TODO:  this should be prompted for by the wizard
+                if state['project'] != 'Any':
+                    props['cm_authority'] = orb.cache.objs[state['project']]
             else:
                 props['id'] = wizard.new_id
             props['id_ns'] = wizard.ns
-            props['oid'] = generateOid(prefs['userid'])  # FIXME
-            props['owner'] = prefs['userid']
-            props['creator'] = prefs['userid']
-            props['modifier'] = prefs['userid']
             dt = dtstamp()
+            # find user's Person object, or create a placeholder
+            user = orb.getObject(state['userid'])
+            if not user:
+                user = PgefObject(orb.interfaces['Person'],
+                                  oid=state['userid'])
+                orb.save(user)
+            props['oid'] = generateOid(state['userid'])  # FIXME
+            props['owner'] = user
+            props['creator'] = user
+            props['modifier'] = user
             props['create_datetime'] = dt
             props['mod_datetime'] = dt
             new_obj = PgefObject(wizard.iface, **props)
@@ -657,8 +667,9 @@
                                                             prefs['repo'])
                     state['repo'] = prefs['repo']
                     # order is very important here:  state['repo'] *must* be set
-                    # before onStateChange() is called -- state['repo'] is the
-                    # loggedin/loggedout state indicator!
+                    # before getting the user object and before onStateChange()
+                    # is called -- state['repo'] is the loggedin/loggedout state
+                    # indicator!
                     self.onStateChange()
                 else:
                     self.log.info('   + login failed (no answer).')

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.147 PanGalactic/pangalactic/node/uberorb.py:1.148
--- PanGalactic/pangalactic/node/uberorb.py:1.147	Sat May 12 16:00:45 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Sun May 13 20:41:28 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.147 2007/05/12 20:00:45 waterbug Exp $
+# $Id: uberorb.py,v 1.148 2007/05/14 00:41:28 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.147 $
+@version: $Revision: 1.148 $
 """
-__version__ = "$Revision: 1.147 $"[11:-2]
+__version__ = "$Revision: 1.148 $"[11:-2]
 
 import logging
 import mimetypes
@@ -117,6 +117,41 @@
         else:
             raise ValueError, 'the orb already has a cache.'
 
+    # property:  cache
+
+    def getCache(self):
+        return self.__cache
+
+    cache = property(fget=getCache, doc='cache')
+
+    # cache operations
+
+    def getDict(self, name):
+        """
+        Get the {oid : obj} dictionary for the named Interface from the cache
+        (this is a wrapper for cache.getDict).
+        """
+        d = {}
+        if getattr(self, 'cache'):
+            d = self.cache.getDict(name)
+        else:
+            self.log.debug('   + no cache -- call orb.initCache() first')
+        return d
+
+    def save(self, objs):
+        self.log.debug(' - save()')
+        if getattr(self, 'cache'):
+            self.log.debug('   + saving %s objs to cache' % str(len(objs)))
+            self.cache.saveObjects(objs)
+        else:
+            self.log.debug('   + no cache -- call orb.initCache() first')
+
+    def clearCache(self):
+        if self.cache:
+            self.cache.clear()
+        else:
+            pass
+
     def getAppOntologies(self, home=''):
         """
         Add application ontologies from models/owl to the core ontology.
@@ -149,13 +184,6 @@
         else:
             raise ValueError, 'the cache has not been initialized yet.'
 
-    # property:  cache
-
-    def getCache(self):
-        return self.__cache
-
-    cache = property(fget=getCache, doc='cache')
-
     def _initXmlrpcInterface(self, hostandport, userid, passwd, secure=True):
         """
         Initialize a server proxy for a host and port.
@@ -249,16 +277,6 @@
             response = "Not logged in; can't change password"
         return response
 
-    def getDict(self, name):
-        """
-        Get the {oid : obj} dictionary for the named Interface from the cache
-        (this is a wrapper for cache.getDict).
-        """
-        d = {}
-        if self.cache:
-            d = self.cache.getDict(name)
-        return d
-
     def getUser(self, userid):
         return self.getObject(userid)
 
@@ -398,19 +416,6 @@
             self.log.info('    * no updates found.')
         return objs
 
-    def save(self, objs):
-        if self.cache:
-            self.cache.saveObjects(objs)
-        else:
-            pass
-
-    def clearCache(self):
-        if self.cache:
-            self.cache.clear()
-            self.cache.pack()
-        else:
-            pass
-
     def remember(self, e):
         """
         Marshall (re-member heh ;) a C{PgefObject} from an extract.  If no local
@@ -484,19 +489,21 @@
 
     def getObject(self, oid):
         """
-        Get an object from the server by oid and save it to the cache.
+        Get an object, trying the cache first, and if it's not there and we are
+        logged in to a repository, getting it by oid from the server and saving
+        it to the cache.
 
         @param oid:  unique identifier attribute of the object sought
         @type  oid:  C{str}
         """
-        self.log.debug(' - getObject')
+        self.log.debug(' - getObject(%s)' % oid)
         obj = None
         if not oid:
-            pass
+            self.log.debug('   + no oid -- ignoring request')
         if self.cache:
             obj = self.cache.objs.get(oid)
             if not obj and state.get('repo'):
-                self.log.debug('   + logged in, checking server')
+                self.log.debug('   + not in cache; logged in, checking repo')
                 res = self.xmlrpc.getObjectsByOids([oid])
                 if res:
                     obj = self.remember(res[0])
@@ -504,9 +511,13 @@
                         obj.repo = state['repo']
                         self.save(obj)
                         self.log.debug(
-                          '   + object from server is: %s' % repr(obj))
+                          '   + object from repo is: %s' % repr(obj))
                         self.log.debug('dispatching signal "updates received"')
                         dispatcher.send(signal='updates received')
+            elif not obj:
+                self.log.debug('   + not in cache and no repo, giving up')
+        else:
+            self.log.debug('   + initialize cache first!')
         return obj
 
     def getLocalObject(self, oid):
@@ -818,7 +829,7 @@
             names = self.xmlrpc.getNames(ns) or []
         else:
             self.log.info("   + in local mode -- can't give a good answer.")
-            names = []
+            names = set([o.id for o in self.searchLocalObjects(id_ns=ns)])
         return names
 
     def getBaseIds(self, ns):
@@ -832,7 +843,8 @@
             base_ids = self.xmlrpc.getBaseIds(ns) or []
         else:
             self.log.info("   + in local mode -- info may be incomplete ...")
-            base_ids = []
+            base_ids = set([getattr(o, 'base_id', o.id)
+                            for o in self.searchLocalObjects(id_ns=ns)])
         return base_ids
 
     def getVersionsForBaseId(self, base_id):

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.46 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.47
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.46	Sun Mar 18 17:20:35 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Sun May 13 20:41:29 2007
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.46 $
+@version: $Revision: 1.47 $
 """
-__version__ = "$Revision: 1.46 $"[11:-2]
+__version__ = "$Revision: 1.47 $"[11:-2]
 
 
 import wx
@@ -162,7 +162,7 @@
                 self.trees[oid] = PanGalaxianTree(self, dragndrop=False)
                 self.trees[oid].SetBackgroundColour('WHITE')
                 self.AddPage(self.trees[oid], id)
-                self.trees[oid].loadTreeForObject(orb.getLocalObject(oid))
+                self.trees[oid].loadTreeForObject(orb.getObject(oid))
                 self.pages[oid] = oid
             else:
                 # TODO:  figure out some rational policy for picking
@@ -173,7 +173,7 @@
                     self.trees[oid] = PanGalaxianTree(self, dragndrop=False)
                     self.trees[oid].SetBackgroundColour('WHITE')
                     self.AddPage(self.trees[oid], id)
-                    self.trees[oid].loadTreeForObject(orb.getLocalObject(oid))
+                    self.trees[oid].loadTreeForObject(orb.getObject(oid))
                     self.pages[oid] = oid
         self.SetSelection(0)
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.66 PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.67
--- PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.66	Sun Mar 18 17:20:35 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py	Sun May 13 20:41:29 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnproperty.py,v 1.66 2007/03/18 21:20:35 waterbug Exp $
+# $Id: pgxnproperty.py,v 1.67 2007/05/14 00:41:29 waterbug Exp $
 """
 PanGalaxianProperty (the Mother of all PanGalaxian Property widgets)
 
-@version: $Revision: 1.66 $
+@version: $Revision: 1.67 $
 """
-__version__ = "$Revision: 1.66 $"[11:-2]
+__version__ = "$Revision: 1.67 $"[11:-2]
 
 import logging
 from pprint import pprint
@@ -130,7 +130,7 @@
             label = '[None]'
         elif isAString(v):  # (an oid)
             # objects may not have been fetched yet ... give it a try
-            v = orb.getLocalObject(v) or v
+            v = orb.getObject(v) or v
             if isAString(v):
                 # I got nothin'
                 label = '[' + self.prop.range + ' -- not available]'
@@ -160,7 +160,7 @@
             helpwin = wx.TipWindow(self, helptext, 250)
         else:
             if isAString(self.value):
-                obj = orb.getLocalObject(self.value)
+                obj = orb.getObject(self.value)
             else:
                 obj = self.value
             if obj:
@@ -794,7 +794,7 @@
             # objects have not been fetched yet ... give it a try
             # print '    - has not been fetched ... trying now ...'
             for val in v:
-                v[v.index(val)] = orb.getLocalObject(val) or val
+                v[v.index(val)] = orb.getObject(val) or val
             if isAString(v[0]):
                 # I got nothin'
                 # print '      nothing found.'
@@ -835,7 +835,7 @@
         self.menu = wx.Menu()
         for v in self.value:
             if isAString(v): # (oid)
-                obj = orb.getLocalObject(v)
+                obj = orb.getObject(v)
             else:
                 obj = v
             if obj:

Index: PanGalactic/pangalactic/node/gui/widgets/pgxntree.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxntree.py:1.12 PanGalactic/pangalactic/node/gui/widgets/pgxntree.py:1.13
--- PanGalactic/pangalactic/node/gui/widgets/pgxntree.py:1.12	Mon Apr 23 10:18:46 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxntree.py	Sun May 13 20:41:29 2007
@@ -1,10 +1,10 @@
-# $Id: pgxntree.py,v 1.12 2007/04/23 14:18:46 waterbug Exp $
+# $Id: pgxntree.py,v 1.13 2007/05/14 00:41:29 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.12 $
+@version: $Revision: 1.13 $
 """
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 import wx
 
@@ -91,9 +91,9 @@
             acu_oids.append(acu_obj.oid)
         # print '  - acu_oids: ', acu_oids
         for acu_oid in acu_oids:
-            acu_obj = orb.getLocalObject(acu_oid)
+            acu_obj = orb.getObject(acu_oid)
             if acu_obj:
-                child = orb.getLocalObject(acu_obj.child)
+                child = orb.getObject(acu_obj.child)
                 if child:
                     treeid = self.AppendItem(rootnode, child.id)
                     self.SetPyData(treeid, [acu_obj.oid, child.oid])
@@ -121,7 +121,7 @@
             # print "  - looking for children"
             treetuple = self.GetPyData(node)
             # print '  - treetuple:', treetuple
-            obj = orb.getLocalObject(treetuple[1])
+            obj = orb.getObject(treetuple[1])
             # print ' - obj:', obj
             linkedobjs = []
             linkedobjs = orb.getAcusByAssemblyOid(obj.oid)

From waterbug at step.nasa.gov  Mon May 14 02:05:39 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 14 02:05:41 2007
Subject: [pangalactic-commits] Record bug fix.
Message-ID: <200705140605.l4E65dlA013420@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.122 1.123

Log message:
Record bug fix.


Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.122 PanGalactic/TODO:1.123
--- PanGalactic/TODO:1.122	Sun May 13 20:41:28 2007
+++ PanGalactic/TODO	Mon May 14 02:05:37 2007
@@ -9,10 +9,11 @@
 --------------
 TOP PRIORITIES
 --------------
-[*] BUG:  fix namespace collision-checking in PanGalaxianObject
-    (are we sure it's broken?)
 [*] ENHANCEMENTS:  give PanGalaxianObject some reasonable defaults:
     [-] creator, owner, modifier = current user
+        note:  need to get or create a Person object for current user; if
+        created locally, it will need to be updated when connected to a
+        repository or identity service (esp. the latter)
     [-] cm auth = current project
     [-] others?
 [*] ENHANCEMENT:  add 'delete from cache' function, accessible from any object
@@ -448,6 +449,7 @@
 ----
 DONE
 ----
+[+] *** BUG FIXED:  namespace collision-checking in PanGalaxianObject
 [+] ENHANCEMENT:  Fix Project handling -- use 'id' property (using oid as
     handle right now)
     [+] Finish work on pgxndictcombo.py (will select project oid but show
@@ -598,5 +600,5 @@
     [+] one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.122 2007/05/14 00:41:28 waterbug Exp $
+# $Id: TODO,v 1.123 2007/05/14 06:05:37 waterbug Exp $
 

From waterbug at step.nasa.gov  Wed May 16 22:16:26 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 16 22:16:30 2007
Subject: [pangalactic-commits] Improvements to logging.
Message-ID: <200705170216.l4H2GQeV027311@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.47 1.48
PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py 1.67 1.68

Log message:
Improvements to logging.


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.47 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.48
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.47	Sun May 13 20:41:29 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Wed May 16 22:16:24 2007
@@ -1,14 +1,14 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.47 $
+@version: $Revision: 1.48 $
 """
-__version__ = "$Revision: 1.47 $"[11:-2]
+__version__ = "$Revision: 1.48 $"[11:-2]
 
 
+import logging
 import wx
 from twisted.python.reflect import allYourBase
-from pprint import pprint
 from pangalactic.node.gui.widgets.pgxntree       import PanGalaxianTree
 from pangalactic.node.gui.widgets.pgxnobjectgrid import PanGalaxianObjectGrid
 from pangalactic.node.uberorb                    import orb
@@ -26,6 +26,7 @@
         wx.Panel.__init__(self, parent, -1)
         minor = wx.SashLayoutWindow(self, -1, wx.DefaultPosition,
                                     (200,30), wx.NO_BORDER|wx.SW_3D)
+        self.log = logging.getLogger('PgxnPanes')
         minor.SetDefaultSize((220, 600))
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)
@@ -88,6 +89,7 @@
         wx.Choicebook.__init__(self, parent, -1,
                                pos=wx.DefaultPosition,
                                size=wx.Size(250,600))
+        self.log = logging.getLogger('PgxnTreeBook')
         self.master = master
         self.trees = {}
         self.pages = {}
@@ -117,35 +119,31 @@
         """
         Handler for the event of state['view'] being set.
         """
-        # print 'PgxnTreeBook.onSetView'
+        self.log.debug(' - PgxnTreeBook.onSetView')
         if self.pages:
             for page in self.pages:
                 id = self.GetSelection()
                 if id < 0:
                     break
-                # print ' - deleting page:', id
+                self.log.debug('   + deleting page:  %s' % id)
                 self.DeletePage(id)
             self.pages = {}
         if not assemblies:
-            # print ' - no assemblies passed to me -- checking for myself ...'
+            self.log.debug(
+                '   + no assemblies passed to me -- checking for myself ...')
             # no assemblies were passed in, taking matters into my own hands
             if getattr(self.master, 'objs', None):
-                # print '  - the notebook has refs to objects:'
-                # for o in self.master.objs:
-                    # print 'oid:  %s (%s)' % (o.oid, o._schema.__name__)
                 models = [x for x in self.master.objs
                           if ((x._schema.__name__ == 'Model')
                                or (orb.interfaces['Model']
                                    in allYourBase(x._schema)))]
                 if models:
-                    print ' - Models found'
-                    # for o in models:
-                    #     print 'oid:  %s (%s)' % (o.oid, o._schema.__name__)
-                    print ' - now looking for Acus ...'
+                    self.log.debug('   + %s Models found' % len(models))
+                    self.log.debug('     now looking for assemblies ...')
                     assemblies = [x for x in models
                                   if orb.getAcusByAssemblyOid(x.oid)]
         if not assemblies:
-            print ' - no assemblies found.'
+            self.log.debug('     * no assemblies found.')
             self.pages = {}
             win = wx.Panel(self)
             win.SetBackgroundColour('WHITE')
@@ -157,7 +155,7 @@
             self.pages['default'] = win
         else:
             if len(assemblies) == 1:
-                print ' - 1 assembly found:  oid =', assemblies[0].oid
+                self.log.debug('     * 1 assembly found.')
                 oid, id = assemblies[0].oid, assemblies[0].id
                 self.trees[oid] = PanGalaxianTree(self, dragndrop=False)
                 self.trees[oid].SetBackgroundColour('WHITE')
@@ -167,8 +165,7 @@
             else:
                 # TODO:  figure out some rational policy for picking
                 # default page (for now, page 0 is default)
-                print ' - multiple assemblies found'
-                # print '   %s' % str([a.oid for a in assemblies])
+                self.log.debug('     * %s assemblies found.' % len(assemblies))
                 for oid, id in [(o.oid, o.id) for o in assemblies]:
                     self.trees[oid] = PanGalaxianTree(self, dragndrop=False)
                     self.trees[oid].SetBackgroundColour('WHITE')
@@ -201,6 +198,7 @@
         wx.Notebook.__init__(self, parent, -1, pos=wx.DefaultPosition,
                              size=size)
         self.parent = parent
+        self.log = logging.getLogger('PgxnNotebook')
         self.pages = {}
         if not objs:
             self.objs = []
@@ -241,13 +239,13 @@
         @type  val:  C{list} or C{Set}
         """
         # TODO:  set a default tab order and make it customizable
-        # print 'PgxnNotebook.setObjs'
+        self.log.debug('PgxnNotebook.setObjs')
         self.__objs = val
         self.parent.objs = val
         if self.pages:
             for page in self.pages:
                 id = self.GetSelection()
-                # print ' - deleting page:', id
+                self.log.debug(' - deleting page:', id)
                 self.DeletePage(id)
             self.pages = {}
         if val:

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.67 PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.68
--- PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.67	Sun May 13 20:41:29 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py	Wed May 16 22:16:24 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnproperty.py,v 1.67 2007/05/14 00:41:29 waterbug Exp $
+# $Id: pgxnproperty.py,v 1.68 2007/05/17 02:16:24 waterbug Exp $
 """
 PanGalaxianProperty (the Mother of all PanGalaxian Property widgets)
 
-@version: $Revision: 1.67 $
+@version: $Revision: 1.68 $
 """
-__version__ = "$Revision: 1.67 $"[11:-2]
+__version__ = "$Revision: 1.68 $"[11:-2]
 
 import logging
 from pprint import pprint
@@ -61,7 +61,7 @@
         @type  obj:
             L{pangalactic.node.gui.widgets.pgxnobject.PanGalaxianObject}
         """
-        self.log = logging.getLogger('PanGalaxianProperty')
+        self.log = logging.getLogger('pgxnproperty')
         self.prop = prop
         self.obj = obj
         self.link = hl.HyperLinkCtrl(
@@ -298,7 +298,7 @@
     in length.
     """
     def __init__(self, parent, prop, obj):
-        self.log = logging.getLogger('PgxnStringFnEdit')
+        self.log = logging.getLogger('PgxnStrFnEd')
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         # initialize widget
         # TODO:  make 'height' (instead of simply 'narrative') a parameter
@@ -338,7 +338,7 @@
     and is a "narrative" type of property, typically several lines of text.
     """
     def __init__(self, parent, prop, obj):
-        self.log = logging.getLogger('PgxnStringFnEditNarrative')
+        self.log = logging.getLogger('PgxnStrFnEdNar')
         self.parent = parent
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         self.__value = getattr(self.obj, prop.id) or '' # in case None

From waterbug at step.nasa.gov  Thu May 17 01:37:49 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 17 01:37:50 2007
Subject: [pangalactic-commits] Add a grid "object menu" ...
Message-ID: <200705170537.l4H5bneZ027885@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/NOTES 1.15 1.16
PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py 1.35 1.36

Log message:
Add a grid "object menu" ...
which will first be used for deleting objects.


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.35 PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.36
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.35	Wed Jan  3 11:18:31 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py	Thu May 17 01:37:47 2007
@@ -1,12 +1,13 @@
-# $Id: pgxnobjectgrid.py,v 1.35 2007/01/03 16:18:31 waterbug Exp $
+# $Id: pgxnobjectgrid.py,v 1.36 2007/05/17 05:37:47 waterbug Exp $
 """
 A table-based, late-bound, configurable object grid
 
-@version: $Revision: 1.35 $
+@version: $Revision: 1.36 $
 """
-__version__ = "$Revision: 1.35 $"[11:-2]
+__version__ = "$Revision: 1.36 $"[11:-2]
 
 from pprint import pprint
+import logging
 
 import wx
 import wx.grid           as gridlib
@@ -206,6 +207,7 @@
         @type  objs:  C{list or Set}
         """
         gridlib.Grid.__init__(self, parent, -1, **kw)
+        self.log = logging.getLogger('PgxnObjectGrid')
         # put an icon in the (-1,-1) label position, to be clicked on to
         # change column configuration
         cornerwin = self.GetGridCornerLabelWindow()
@@ -235,6 +237,7 @@
         self.Bind(gridlib.EVT_GRID_LABEL_LEFT_DCLICK, self.sortOnColumn)
         self.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.noSelect)
         self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.viewObject, self)
+        self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.popupObjectMenu, self)
 
     # properties (for convenience)
 
@@ -319,7 +322,7 @@
             # print "No objects -- can't operate on an empty grid."
             return
         else:
-            self.gridPopup(evt)
+            self.gridPopupMenu(evt)
 
     def onColMove(self,evt):
         """
@@ -330,11 +333,11 @@
         self._table.MoveColumn(frm,to)
         self.reset()
 
-    def gridPopup(self, evt):
+    def gridPopupMenu(self, evt):
         """
         Display the grid popup menu for adding/removing columns.
         """
-        # print '- in PanGalaxianObjectGrid.gridPopup'
+        self.log.debug(' - gridPopupMenu')
         self.grid_menu = wx.Menu()
         self.visible_cols_menu = wx.Menu()
         self.grid_menu.AppendMenu(-1, 'Visible Columns',
@@ -466,6 +469,23 @@
         obj = self.getObject(evt.GetRow())
         PanGalaxianObject(None, obj).Show()
 
+    def popupObjectMenu(self, evt):
+        """
+        View (and edit, if permissions allow) an Object from the grid.
+        """
+        self.log.debug(' - popupObjectMenu')
+        row = evt.GetRow()
+        self.object_menu = wx.Menu()
+        self.delete_object = self.object_menu.Append(
+            id=wx.ID_ANY,
+            text="Delete Object",
+            help="Delete this Object")
+        epos = evt.GetPosition()
+        pos = (epos[0] - 80, epos[1] - 30)
+        self.PopupMenu(self.object_menu, pos)
+        self.reset()
+        self.object_menu.Destroy()
+
 
 ###############
 # Testing stuff

Index: PanGalactic/NOTES
diff -u PanGalactic/NOTES:1.15 PanGalactic/NOTES:1.16
--- PanGalactic/NOTES:1.15	Tue May  8 23:50:10 2007
+++ PanGalactic/NOTES	Thu May 17 01:37:47 2007
@@ -14,15 +14,16 @@
 
 New names (created by user) must have a namespace
 
-* default namespace is "local" (prefix only; not a valid URL)
-* before committing local objs to a repo, user must pick or define a namespace
-  - can be any namespace to which user has permission to add names
-  - can be a Project created by the user
-  - the Project will be checked by the repository for uniqueness of its id
-    within either its parent namespace (e.g., an organizational namespace) or
-    within the repository's knowledge of the "world" namespace
-* the current namespace serves as default ns for all local user-created objects
-
+* namespaces
+  - default local prefix for all user-created objects is "sandbox:"
+  - when committed to a repo, would go into repo's sandbox under user's id on
+    the repo unless specifically committed to some other namespace to which the
+    user has permission to commit.
+  - to create a top-level Project on a repo requires permission from the repo
+    admin(s)
+    + a Project will be checked by the repository for uniqueness of its id
+      within the repo's projects or within another namespace (e.g., an
+      organizational namespace) used on that repo, etc.
 
 So ... coding:
 

From waterbug at step.nasa.gov  Fri May 18 01:11:20 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 18 01:11:22 2007
Subject: [pangalactic-commits] orb.deleteFromCache() works -- yarrr!  :)
Message-ID: <200705180511.l4I5BKTZ011819@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/cache.py 1.37 1.38
PanGalactic/pangalactic/node/pangalaxian.py 1.192 1.193
PanGalactic/pangalactic/node/uberorb.py 1.148 1.149
PanGalactic/pangalactic/node/gui/dialogs/useradmin.py 1.26 1.27
PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py 1.147 1.148
PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py 1.36 1.37
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.48 1.49
PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py 1.68 1.69
PanGalactic/pangalactic/utils/io/import_assembly.py 1.5 1.6

Log message:
orb.deleteFromCache() works -- yarrr!  :)
- deletes any Relationships in which the deleted objects are parents
  or children
- right-click on object grid pops up a menu, in which 'delete' is
  currently the only choice ;)
- deletion triggers PanGalaxian's refreshView(), which updates the
  grid and tree
- also did some more improvements to logging ...


Index: PanGalactic/pangalactic/node/gui/dialogs/useradmin.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/useradmin.py:1.26 PanGalactic/pangalactic/node/gui/dialogs/useradmin.py:1.27
--- PanGalactic/pangalactic/node/gui/dialogs/useradmin.py:1.26	Wed Apr 18 02:19:03 2007
+++ PanGalactic/pangalactic/node/gui/dialogs/useradmin.py	Fri May 18 01:11:16 2007
@@ -2,9 +2,9 @@
 A dialog to enable the admin user to add, modify, or delete users for a
 PGER Node.
 
-@version: $Revision: 1.26 $
+@version: $Revision: 1.27 $
 """
-__version__ = "$Revision: 1.26 $"[11:-2]
+__version__ = "$Revision: 1.27 $"[11:-2]
 
 import wx
 
@@ -168,7 +168,7 @@
                 # with such things as record_create_datetime, etc., filled in
                 project_persons = orb.xmlrpc.addObjects([project_person])
                 # save the new ProjectPerson to the cache
-                orb.save([project_persons[0]])
+                orb.saveToCache([project_persons[0]])
                 self.person_projects.items += [project]
             else:
                 dlg = wx.MessageDialog(self, 'No Project selected!',

Index: PanGalactic/pangalactic/node/cache.py
diff -u PanGalactic/pangalactic/node/cache.py:1.37 PanGalactic/pangalactic/node/cache.py:1.38
--- PanGalactic/pangalactic/node/cache.py:1.37	Sun May 13 20:41:28 2007
+++ PanGalactic/pangalactic/node/cache.py	Fri May 18 01:11:15 2007
@@ -1,9 +1,9 @@
 """
 Local object cache manager (a layer over ZODB)
 
-@version: $Revision: 1.37 $
+@version: $Revision: 1.38 $
 """
-__version__ = "$Revision: 1.37 $"[11:-2]
+__version__ = "$Revision: 1.38 $"[11:-2]
 
 # Python
 import logging, os, sys
@@ -120,6 +120,7 @@
         # been modified, notify user of the conflict.
         if type(objs) is not list:
             objs = [objs]
+        self.log.debug("   + oids:  %s" % str([o.oid for o in objs]))
         for obj in objs:
             self.objs[obj.oid] = obj
             if hasattr(obj, '_schema'):
@@ -145,6 +146,7 @@
         # been modified, notify user of the conflict.
         if type(objs) is not list:
             objs = [objs]
+        self.log.debug("   + oids:  %s" % str([o.oid for o in objs]))
         for obj in objs:
             self.log.debug('   + oid:  %s' % obj.oid)
             if hasattr(obj, '_schema'):
@@ -225,6 +227,10 @@
         return objs
 
     def getDict(self, name):
+        """
+        Get the cache's dictionary of objects that implement the interface with
+        the specified name.
+        """
         # applications may only have some of the dicts that the cache has
         return self.dbroot.get(name)
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.36 PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.37
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.36	Thu May 17 01:37:47 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py	Fri May 18 01:11:17 2007
@@ -1,11 +1,12 @@
-# $Id: pgxnobjectgrid.py,v 1.36 2007/05/17 05:37:47 waterbug Exp $
+# $Id: pgxnobjectgrid.py,v 1.37 2007/05/18 05:11:17 waterbug Exp $
 """
 A table-based, late-bound, configurable object grid
 
-@version: $Revision: 1.36 $
+@version: $Revision: 1.37 $
 """
-__version__ = "$Revision: 1.36 $"[11:-2]
+__version__ = "$Revision: 1.37 $"[11:-2]
 
+from louie  import dispatcher
 from pprint import pprint
 import logging
 
@@ -322,7 +323,7 @@
             # print "No objects -- can't operate on an empty grid."
             return
         else:
-            self.gridPopupMenu(evt)
+            self.popupGridMenu(evt)
 
     def onColMove(self,evt):
         """
@@ -333,11 +334,11 @@
         self._table.MoveColumn(frm,to)
         self.reset()
 
-    def gridPopupMenu(self, evt):
+    def popupGridMenu(self, evt):
         """
         Display the grid popup menu for adding/removing columns.
         """
-        self.log.debug(' - gridPopupMenu')
+        self.log.debug(' - popupGridMenu')
         self.grid_menu = wx.Menu()
         self.visible_cols_menu = wx.Menu()
         self.grid_menu.AppendMenu(-1, 'Visible Columns',
@@ -475,17 +476,33 @@
         """
         self.log.debug(' - popupObjectMenu')
         row = evt.GetRow()
+        self.SelectRow(row)
         self.object_menu = wx.Menu()
         self.delete_object = self.object_menu.Append(
-            id=wx.ID_ANY,
-            text="Delete Object",
-            help="Delete this Object")
+                                                id=wx.ID_ANY,
+                                                text="Delete Object",
+                                                help="Delete this Object")
+        self.Bind(wx.EVT_MENU, self.onDeleteObject, self.delete_object)
         epos = evt.GetPosition()
         pos = (epos[0] - 80, epos[1] - 30)
         self.PopupMenu(self.object_menu, pos)
         self.reset()
         self.object_menu.Destroy()
 
+    def onDeleteObject(self, evt):
+        """
+        Delete the object for which this event was triggered.
+        """
+        self.log.debug(' - onDeleteObject')
+        obj = self.getObject(self.GetSelectedRows()[0])
+        self.log.debug('   + deleting obj with oid %s' % obj.oid)
+        orb.deleteFromCache([obj])
+        # remove that row from the grid
+        objsnow = list(self.objs)
+        objsnow.remove(obj)
+        self.objs = objsnow
+        dispatcher.send(signal='refresh views')
+
 
 ###############
 # Testing stuff

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.148 PanGalactic/pangalactic/node/uberorb.py:1.149
--- PanGalactic/pangalactic/node/uberorb.py:1.148	Sun May 13 20:41:28 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Fri May 18 01:11:16 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.148 2007/05/14 00:41:28 waterbug Exp $
+# $Id: uberorb.py,v 1.149 2007/05/18 05:11:16 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.148 $
+@version: $Revision: 1.149 $
 """
-__version__ = "$Revision: 1.148 $"[11:-2]
+__version__ = "$Revision: 1.149 $"[11:-2]
 
 import logging
 import mimetypes
@@ -138,14 +138,36 @@
             self.log.debug('   + no cache -- call orb.initCache() first')
         return d
 
-    def save(self, objs):
-        self.log.debug(' - save()')
+    def saveToCache(self, objs):
+        """
+        Save the specified objects to the cache.
+        """
+        self.log.debug(' - saveToCache()')
         if getattr(self, 'cache'):
-            self.log.debug('   + saving %s objs to cache' % str(len(objs)))
             self.cache.saveObjects(objs)
         else:
             self.log.debug('   + no cache -- call orb.initCache() first')
 
+    def deleteFromCache(self, objs):
+        """
+        Delete the specified objects from the cache.
+
+        @param objs:  C{PgefObject} instance(s) in the cache
+        @type  objs:  C{list} or C{PgefObject}
+        """
+        self.log.debug(' - deleteFromCache()')
+        if type(objs) is not list:
+            objs = [objs]
+        if getattr(self, 'cache'):
+            # make sure *all* Relationships in which these objects are the
+            # parent or child are also deleted
+            rels = self.cache.getDict('Relationship').values()
+            objs += [r for r in rels if [o for o in objs if (
+                     r.parent == o.oid or r.child == o.oid)]]
+            self.cache.deleteObjects(objs)
+        else:
+            self.log.debug('   + no cache -- call orb.initCache() first')
+
     def clearCache(self):
         if self.cache:
             self.cache.clear()
@@ -180,7 +202,7 @@
                     if not self.searchLocalObjects(base_id=e['id'],
                                                    id_ns=e['id_ns']):
                         mos.append(self.createPmofObjectFromExtract(e))
-            self.save(mos)
+            self.saveToCache(mos)
         else:
             raise ValueError, 'the cache has not been initialized yet.'
 
@@ -509,7 +531,7 @@
                     obj = self.remember(res[0])
                     if obj:
                         obj.repo = state['repo']
-                        self.save(obj)
+                        self.saveToCache(obj)
                         self.log.debug(
                           '   + object from repo is: %s' % repr(obj))
                         self.log.debug('dispatching signal "updates received"')
@@ -557,7 +579,7 @@
                                          params=params)
             if res:
                 objs = [self.remember(e) for e in res]
-                self.save(objs)
+                self.saveToCache(objs)
             if objs:
                 self.log.info('   + %s objects retrieved from server' % str(
                                                                     len(objs)))
@@ -640,7 +662,7 @@
         else:
             objs = [self.remember(e) for e in data]
             ret = objs
-            self.save(objs)
+            self.saveToCache(objs)
         return ret
         # except:
         #     self.log.info('   + exception: xmlrpc error')
@@ -773,7 +795,7 @@
                 self.log.info("""   + not logged in; can't commit.""")
         else:
             self.log.info('   + no objects specified.')
-        self.save(objs)
+        self.saveToCache(objs)
  
     def getProjectsFromServer(self):
         """
@@ -809,7 +831,7 @@
 #                                             params=params)
 #             namespaces = [self.remember(e) for e in nsexts]
 #             if namespaces:
-#                 self.save(namespaces)
+#                 self.saveToCache(namespaces)
 #                 self.log.info('dispatching signal "updates received"')
 #                 dispatcher.send(signal='updates received')
 #         else:

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.48 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.49
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.48	Wed May 16 22:16:24 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Fri May 18 01:11:17 2007
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.48 $
+@version: $Revision: 1.49 $
 """
-__version__ = "$Revision: 1.48 $"[11:-2]
+__version__ = "$Revision: 1.49 $"[11:-2]
 
 
 import logging
@@ -125,7 +125,7 @@
                 id = self.GetSelection()
                 if id < 0:
                     break
-                self.log.debug('   + deleting page:  %s' % id)
+                self.log.debug('   + deleting page')
                 self.DeletePage(id)
             self.pages = {}
         if not assemblies:
@@ -245,7 +245,7 @@
         if self.pages:
             for page in self.pages:
                 id = self.GetSelection()
-                self.log.debug(' - deleting page:', id)
+                self.log.debug(' - deleting page')
                 self.DeletePage(id)
             self.pages = {}
         if val:

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.68 PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.69
--- PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.68	Wed May 16 22:16:24 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py	Fri May 18 01:11:17 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnproperty.py,v 1.68 2007/05/17 02:16:24 waterbug Exp $
+# $Id: pgxnproperty.py,v 1.69 2007/05/18 05:11:17 waterbug Exp $
 """
 PanGalaxianProperty (the Mother of all PanGalaxian Property widgets)
 
-@version: $Revision: 1.68 $
+@version: $Revision: 1.69 $
 """
-__version__ = "$Revision: 1.68 $"[11:-2]
+__version__ = "$Revision: 1.69 $"[11:-2]
 
 import logging
 from pprint import pprint
@@ -383,7 +383,7 @@
         editor.Show(True)
         if self.value:
             self.widget.SetLabel(self.genLabel(self.value))
-        self.log.debug(' - editor done; value is:  %s' % str(self.value))
+        self.log.debug(' - value:  %s' % str(self.value))
 
 
 class PgxnDatetimeFnView(PanGalaxianProperty):

Index: PanGalactic/pangalactic/utils/io/import_assembly.py
diff -u PanGalactic/pangalactic/utils/io/import_assembly.py:1.5 PanGalactic/pangalactic/utils/io/import_assembly.py:1.6
--- PanGalactic/pangalactic/utils/io/import_assembly.py:1.5	Fri May  4 20:51:16 2007
+++ PanGalactic/pangalactic/utils/io/import_assembly.py	Fri May 18 01:11:18 2007
@@ -37,6 +37,12 @@
 
 
 def getAssemblies(f):
+    """
+    Extract assembly structures from a STEP file.
+
+    @param f:  name of a STEP file
+    @type  f:  C{str}
+    """
     data = readStepFile(f)
     projid = os.path.basename(f).split('.')[0].upper()
     projoid = projid

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.192 PanGalactic/pangalactic/node/pangalaxian.py:1.193
--- PanGalactic/pangalactic/node/pangalaxian.py:1.192	Sun May 13 20:41:28 2007
+++ PanGalactic/pangalactic/node/pangalaxian.py	Fri May 18 01:11:16 2007
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian.py,v 1.192 2007/05/14 00:41:28 waterbug Exp $
+# $Id: pangalaxian.py,v 1.193 2007/05/18 05:11:16 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF GUI client.
 
 WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.192 $
+@version: $Revision: 1.193 $
 """
-__version__ = "$Revision: 1.192 $"[11:-2]
+__version__ = "$Revision: 1.193 $"[11:-2]
 
 # Python
 import logging
@@ -524,13 +524,16 @@
         orb.register(self.onLogout, 'logout')
         # to avoid creating loops:
         #   * 'objects saved' should be used *only* for local saves
-        #   * 'updates received' should be used *only* for remote interactions
         orb.register(self.refreshView, 'objects saved')
-        # in addition to triggering self.refreshView,
-        # 'updates received' triggers all PanGalaxianObjects to resync()
-        # -- it's dispatched by the following UberORB methods:
-        # getObject, getObjectsFromServer, commit, getNamespaces, and
-        # getAcusByAssemblyOid.
+        #   * 'refresh views' is used (so far) only by orb.deleteObjectsFromCache
+        #     + it *only* triggers self.refreshView
+        orb.register(self.refreshView, 'refresh views')
+        #   * 'updates received' should be used *only* for remote interactions
+        #     + in addition to triggering self.refreshView,
+        #       it triggers all PanGalaxianObjects to resync()
+        #     + it's dispatched by the following UberORB methods:
+        #       getObject, getObjectsFromServer, commit, getNamespaces, and
+        #       getAcusByAssemblyOid.
         orb.register(self.refreshView, 'updates received')
         orb.register(self.updateProjectWidget, 'update projects')
 
@@ -580,7 +583,7 @@
             if not user:
                 user = PgefObject(orb.interfaces['Person'],
                                   oid=state['userid'])
-                orb.save(user)
+                orb.saveToCache(user)
             props['oid'] = generateOid(state['userid'])  # FIXME
             props['owner'] = user
             props['creator'] = user
@@ -608,10 +611,11 @@
             defaultFile="", style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)
         if dlg.ShowModal() == wx.ID_OK:
             paths = dlg.GetPaths()
+            self.log.debug('   + paths:  %s' % str(paths))
             project, acus, models = getAssemblies(paths[0])
-            orb.save(project)
-            orb.save(models)
-            orb.save(acus)
+            orb.saveToCache(project)
+            orb.saveToCache(models)
+            orb.saveToCache(acus)
 
     def updateProjectWidget(self):
         """

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.147 PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.148
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.147	Sat May 12 16:00:45 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py	Fri May 18 01:11:17 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobject.py,v 1.147 2007/05/12 20:00:45 waterbug Exp $
+# $Id: pgxnobject.py,v 1.148 2007/05/18 05:11:17 waterbug Exp $
 """
 PanGalaxianObject (a C{PgefObject} viewer/editor)
 
-@version: $Revision: 1.147 $
+@version: $Revision: 1.148 $
 """
-__version__ = "$Revision: 1.147 $"[11:-2]
+__version__ = "$Revision: 1.148 $"[11:-2]
 
 import logging
 from copy import deepcopy
@@ -520,7 +520,7 @@
         self.log.debug(' - PGO.onEdit')
         self.obj.editor = prefs.get('userid')
         self.editing = True
-        orb.save([self.obj])
+        orb.saveToCache([self.obj])
         self.setPropertybookState()
         self.setToolbarState()
 
@@ -559,7 +559,7 @@
         """
         self.log.debug(' - PGO.onSaveToCache:  saving to cache ...')
         self.obj.update(**self.view)
-        orb.save(self.obj)
+        orb.saveToCache(self.obj)
         self.notebook.resync()
         self.resyncVersionPanel()
         self.setPropertybookState()

From waterbug at step.nasa.gov  Fri May 18 10:43:17 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 18 10:43:19 2007
Subject: [pangalactic-commits] Removed overriding grid events from
	cachebrowser ...
Message-ID: <200705181443.l4IEhHbW016448@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.32 1.33
PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py 1.37 1.38

Log message:
Removed overriding grid events from cachebrowser ...
now right-click menu (with delete) works in cachebrowser -- ha! :)


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.37 PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.38
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.37	Fri May 18 01:11:17 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py	Fri May 18 10:43:15 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobjectgrid.py,v 1.37 2007/05/18 05:11:17 waterbug Exp $
+# $Id: pgxnobjectgrid.py,v 1.38 2007/05/18 14:43:15 waterbug Exp $
 """
 A table-based, late-bound, configurable object grid
 
-@version: $Revision: 1.37 $
+@version: $Revision: 1.38 $
 """
-__version__ = "$Revision: 1.37 $"[11:-2]
+__version__ = "$Revision: 1.38 $"[11:-2]
 
 from louie  import dispatcher
 from pprint import pprint
@@ -474,6 +474,9 @@
         """
         View (and edit, if permissions allow) an Object from the grid.
         """
+        # see also code below, "def OnRightDown", removed from cachebrowser,
+        # which generated a right-click menu.  Some good ideas/techniques in
+        # there.
         self.log.debug(' - popupObjectMenu')
         row = evt.GetRow()
         self.SelectRow(row)
@@ -503,6 +506,38 @@
         self.objs = objsnow
         dispatcher.send(signal='refresh views')
 
+    # Code removed from the cachebrowser module -- some of it might be useful
+    # (it was interfering with popupObjectMenu, above)
+    # def OnRightDown(self, event):
+    #     """
+    #     Generate and show the menu for a mouse right-click
+    #     """
+    #     # print "dbb.onrightdown"
+    #     if self.objs:
+    #         if len(self.objs) == 0:
+    #             return
+    #     else:
+    #         return
+    #     if event.GetId() == self.objectgrid.GetId():
+    #         menu = wx.Menu()
+    #         x,y = event.GetPosition()
+    #         y1 = y - self.objectgrid.GetColLabelSize()
+    #         curr_row = self.objectgrid.YToRow(y1)
+    #         if curr_row >= 0:
+    #             self.objectgrid.SelectRow(curr_row)
+    #         else:
+    #             return
+    #         obj = self.objs[curr_row]
+    #         options = self.BaseRightClickMenuOptions
+    #         options.extend(self.RightClickMenuOptions)
+    #         for menuid, menulabel in options:
+    #             if menuid == OBJECT_VIEWER:
+    #                 if isinstance(obj, PgefObject):
+    #                     menu.Append(menuid, menulabel)
+    #             else:
+    #                 menu.Append(menuid, menulabel)
+    #         gridx, gridy = self.objectgrid.GetPositionTuple()
+    #         self.PopupMenuXY(menu, x+gridx, y+gridy)
 
 ###############
 # Testing stuff

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.32 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.33
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.32	Mon Apr 23 10:18:46 2007
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Fri May 18 10:43:15 2007
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.32 2007/04/23 14:18:46 waterbug Exp $
+# $Id: cachebrowser.py,v 1.33 2007/05/18 14:43:15 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.32 $
+@version: $Revision: 1.33 $
 """
-__version__ = "$Revision: 1.32 $"[11:-2]
+__version__ = "$Revision: 1.33 $"[11:-2]
 
 # wxPython
 import wx
@@ -33,10 +33,6 @@
     PanGalaxian cache browser (works with PgefObjects in a local ZODB).
     """
 
-    BaseRightClickMenuOptions = [(OBJECT_VIEWER, "Object Viewer..."),
-                                 (ID_POPUP_CLEAR_SELECTION, "Clear Selection")]
-    RightClickMenuOptions = []
-
     def __init__(self, parent, pos=wx.DefaultPosition, size=wx.DefaultSize):
         wx.Panel.__init__(self, parent, -1, pos=pos, size=size,
                           style=wx.THICK_FRAME)
@@ -78,19 +74,9 @@
         self.Bind(wx.EVT_LISTBOX, self.FillGrid, self.rootitems)
         self.Bind(wx.EVT_CLOSE, self.OnClose)
         self.objs = None
-        grid.EVT_GRID_CELL_RIGHT_CLICK(self.objectgrid, self.OnRightDown)
-        grid.EVT_GRID_CELL_LEFT_CLICK(self.objectgrid, self.onLeftClick)
         self.FillChoice()
         orb.register(self.FillGrid, 'objects saved')
 
-    def onLeftClick(self, event):
-        # print "cachebrowser.leftclick"
-        if event.GetId() == self.objectgrid.GetId():
-            temprow = event.GetRow()
-            self.objectgrid.SelectRow(temprow)
-        else:
-            event.Skip()
-
     def FillChoice(self):
         choice = self.rootitems
         choice.Clear()
@@ -119,36 +105,6 @@
             if self.objdict is not None:
                 self.objectgrid.objs = self.objdict.values()
 
-    def OnRightDown(self, event):
-        """
-        Generate and show the menu for a mouse right-click
-        """
-        # print "dbb.onrightdown"
-        if self.objs:
-            if len(self.objs) == 0:
-                return
-        else:
-            return
-        if event.GetId() == self.objectgrid.GetId():
-            menu = wx.Menu()
-            x,y = event.GetPosition()
-            y1 = y - self.objectgrid.GetColLabelSize()
-            curr_row = self.objectgrid.YToRow(y1)
-            if curr_row >= 0:
-                self.objectgrid.SelectRow(curr_row)
-            else:
-                return
-            obj = self.objs[curr_row]
-            options = self.BaseRightClickMenuOptions
-            options.extend(self.RightClickMenuOptions)
-            for menuid, menulabel in options:
-                if menuid == OBJECT_VIEWER:
-                    if isinstance(obj, PgefObject):
-                        menu.Append(menuid, menulabel)
-                else:
-                    menu.Append(menuid, menulabel)
-            gridx, gridy = self.objectgrid.GetPositionTuple()
-            self.PopupMenuXY(menu, x+gridx, y+gridy)
 
 class TestFrame(wx.Frame):
     def __init__(self, parent):

From waterbug at step.nasa.gov  Mon May 21 00:24:50 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 21 00:24:52 2007
Subject: [pangalactic-commits] Revise docs and roadmap; capture some notes.
Message-ID: <200705210424.l4L4Oo9k010278@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/NOTES 1.16 1.17
PanGalactic/TODO 1.123 1.124
PanGalactic/doc/PgefManual.txt 1.47 1.48
PanGalactic/doc/PgefRoadmap.txt 1.16 1.17

Log message:
Revise docs and roadmap; capture some notes.


Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.123 PanGalactic/TODO:1.124
--- PanGalactic/TODO:1.123	Mon May 14 02:05:37 2007
+++ PanGalactic/TODO	Mon May 21 00:24:47 2007
@@ -10,14 +10,19 @@
 TOP PRIORITIES
 --------------
 [*] ENHANCEMENTS:  give PanGalaxianObject some reasonable defaults:
+    [-] new oids:  each object will have a local oid in the following default
+        canonical format:
+        'pgef-local:[project id]:[id]'
+        ... in which the default project-id is "sandbox"
     [-] creator, owner, modifier = current user
         note:  need to get or create a Person object for current user; if
         created locally, it will need to be updated when connected to a
         repository or identity service (esp. the latter)
+    [-] each user will have an Person object.  The user's Person object will
+        have an associated Role (with credentials, e.g. userid/passwd) for each
+        service (e.g. repository) known to PanGalaxian.
     [-] cm auth = current project
     [-] others?
-[*] ENHANCEMENT:  add 'delete from cache' function, accessible from any object
-    grid, by right-click menu
 [*] ENHANCEMENT:  show by background color-coding which objects are local-only
     (i.e., not saved to any repository)
 [*] ENHANCEMENT:  re-factor registry to use Pmof objects as the canonical
@@ -371,13 +376,6 @@
 [-] ENHANCEMENT:  PanGalaxian Editor (text fields)
     [-] append a file's contents to the field
     [-] journal/undo/redo
-[-] *** ENHANCEMENT:  New userid paradigms ...
-    [-] each user will have an oid in the form of a URI.  The default format of
-        the URI will be: 'http://pangalactic.us/pgef/Person/[userid]', where
-        userid is unique within the pgef/Person namespace.  This URI will serve
-        as the oid of their Person object, and the userid string will be their
-        PanGalactic userid.  LDAP connection is TBD -- for NASA, probably by way
-        of the canonical email address/identifier.
     [-] easiest method to implement userid/passwd assignment:  admin assigns a
         userid/passwd and notifies the user of them (possibly requiring an
         immediate change of passwd upon login).
@@ -449,6 +447,8 @@
 ----
 DONE
 ----
+[+] ENHANCEMENT:  add 'delete from cache' function, accessible from any object
+    grid, by right-click menu
 [+] *** BUG FIXED:  namespace collision-checking in PanGalaxianObject
 [+] ENHANCEMENT:  Fix Project handling -- use 'id' property (using oid as
     handle right now)
@@ -600,5 +600,5 @@
     [+] one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.123 2007/05/14 06:05:37 waterbug Exp $
+# $Id: TODO,v 1.124 2007/05/21 04:24:47 waterbug Exp $
 

Index: PanGalactic/doc/PgefManual.txt
diff -u PanGalactic/doc/PgefManual.txt:1.47 PanGalactic/doc/PgefManual.txt:1.48
--- PanGalactic/doc/PgefManual.txt:1.47	Mon Dec 18 04:10:20 2006
+++ PanGalactic/doc/PgefManual.txt	Mon May 21 00:24:48 2007
@@ -7,8 +7,8 @@
 
 :Author: Stephen Waterbury <stephen dot c dot waterbury at nasa dot gov>
 :Author: Ginny Keech
-:Version: $Revision: 1.47 $
-:Date: $Date: 2006/12/18 09:10:20 $
+:Version: $Revision: 1.48 $
+:Date: $Date: 2007/05/21 04:24:48 $
 
 
 .. contents:: Table of Contents
@@ -416,14 +416,16 @@
 
     Each **PanGalactic** application object is assigned a unique identifier, the
     ``oid``.  The preferred form for the oid is a URI, if one is available or
-    can be constructed canonically.  Otherwise, an arbitrary (but unique)
-    one will be generated as follows:
+    can be constructed canonically.  The default canonical form is:
 
         ::
 
-            [object creator's oid] + [creation time-date stamp]
+            'http://[local IP]/pgef/oids/[datetime stamp].[sequence number]'
 
-    where the creation time-date stamp is in Universal Time.
+    where the creation datetime stamp is in Universal Time and is created
+    by PanGalaxian when it starts up.  That datetime stamp is used for all
+    objects created during a PanGalaxian session, the sequence number being
+    incremented for each new oid, thus ensuring uniqueness.
 
 .. _`Security and Access Control`:
 
@@ -1895,4 +1897,4 @@
 .. _Interfaces:  http://www.zope.org/Wikis/Interfaces/FrontPage
 .. _Interface:  Interfaces_
 
-$Id: PgefManual.txt,v 1.47 2006/12/18 09:10:20 waterbug Exp $
+$Id: PgefManual.txt,v 1.48 2007/05/21 04:24:48 waterbug Exp $

Index: PanGalactic/doc/PgefRoadmap.txt
diff -u PanGalactic/doc/PgefRoadmap.txt:1.16 PanGalactic/doc/PgefRoadmap.txt:1.17
--- PanGalactic/doc/PgefRoadmap.txt:1.16	Thu Nov 16 15:57:55 2006
+++ PanGalactic/doc/PgefRoadmap.txt	Mon May 21 00:24:48 2007
@@ -11,10 +11,10 @@
 --------------------
 
 [*] meta-modeling thread:
-    [-] create MOF ontologies using PanGalaxian (PmofClass, PmofProperty, etc.)
+    [*] create MOF ontologies using PanGalaxian (PmofClass, PmofProperty, etc.)
     [-] use MOF ontology to create schema-driven XMI parser(s)
     [-] use MOF-schema-driven XMI parser to create MEXICO model parser
-    [-] use MEXICO model parser to parse EXPRESS-XMI STEP AP's
+    [*] use MEXICO model parser to parse EXPRESS-XMI STEP AP's
     [-] use resulting STEP AP models to drive Part 21 parser
     [-] use MOF-schema-driven XMI parser to create UML and SysML
         parsers/writers
@@ -117,5 +117,5 @@
 [+] implement build process for Mac platform
 
 -----------------------------------------------------------------
-# $Id: PgefRoadmap.txt,v 1.16 2006/11/16 20:57:55 waterbug Exp $
+# $Id: PgefRoadmap.txt,v 1.17 2007/05/21 04:24:48 waterbug Exp $
 

Index: PanGalactic/NOTES
diff -u PanGalactic/NOTES:1.16 PanGalactic/NOTES:1.17
--- PanGalactic/NOTES:1.16	Thu May 17 01:37:47 2007
+++ PanGalactic/NOTES	Mon May 21 00:24:47 2007
@@ -15,12 +15,29 @@
 New names (created by user) must have a namespace
 
 * namespaces
-  - default local prefix for all user-created objects is "sandbox:"
-  - when committed to a repo, would go into repo's sandbox under user's id on
-    the repo unless specifically committed to some other namespace to which the
-    user has permission to commit.
+
+  - default local prefix for all user-created object ids is:
+    "pgef-local:[project id]:"
+
+  - "pgef-local" prefix will be used by PanGalaxian to identify local objects
+
+  - when a ns-prefix is selected in the New Object Wizard, they will be shown as
+    either "local" or "remote" prefixes (remote ones will show the origin
+    prefix -- whether a repo or other service).
+
+  - when committed to a repo, objects will go into repo's sandbox under user's
+    id on the repo:
+
+    "http://[repo addr]/vger/sandbox/[userid]/[project id]/objs"
+
+    (a fully-qualified URL) unless specifically committed to some other
+    namespace (e.g., a Project) to which the user has permission to commit.
+    (The default VGER config will give users permission to have a sandbox; this
+    will be configurable by the site admin -- i.e. may be disallowed.)
+
   - to create a top-level Project on a repo requires permission from the repo
     admin(s)
+
     + a Project will be checked by the repository for uniqueness of its id
       within the repo's projects or within another namespace (e.g., an
       organizational namespace) used on that repo, etc.
@@ -91,18 +108,44 @@
 
 Semi-random notes:
 
+* Wizards (in general)
+
+  - PanGalaxian's Object creation wizard should dynamically invoke
+    the appropriate "sub-wizard" if one exists for the selected
+    Class
+
+  - By prefs and/or app config, add type-specific wizards to the menus
+    (e.g. Document Wizard, Project Wizard, etc.)
+
+  - For metaobjects, wizards should give the user access to
+    everything PGER/VGER knows about existing metaobjects
+    and contexts -- in particular, Classes, Properties,
+    Ontologies, Taxonomies, Vocabularies, Concept Maps,
+    etc. should never be created in a vacuum
+
+    + provide access to relevant metaobjects
+    + also industry standard metadata
+    + provide capability to create formal mappings
+      (Express-X / OMG OCL equivalent mappings)
+    + Taxonomies should be constrained by Ontologies
+      (classification by Properties is more powerful
+      than arbitrary instance classification)
+
 * PmofDatatype
+
   - new datatypes can be created and managed.
   - needs to reference a serialization method
   - some way to specify presentation/editing (smth. MIME-like?)
   - also mapped from imported schemas' datatypes
 
 * PgefProperty
+
   - implements IProperty and IPgefObject
   - attrs defined in __slots__, which is constructed from the attrs of
     PmofProperty
 
 * Namespaces (PgefNamespace and PmofNamespace)
+
   - runtime namespaces (PgefNamespace instances) for metaobject (M1 and above)
     names (i.e., 'pgef' and any application namespaces -- e.g. 'space_mission',
     etc.) must be distinguishable from those for runtime object (M0) names.
@@ -117,6 +160,7 @@
     of two or more meta levels (M0, M1, M2, etc.).
 
 * Pmof MetaObjects
+
   - created by registry from extracts (createPmofObjectFromExtract)
   - need methodology for versioning
     + core objects, PmofClass (Interface) and PmofProperty (PgefProperty)
@@ -130,7 +174,10 @@
       should probably be a Python property (e.g., for PmofClass, all registered
       PmofProperties with domain of that PmofClass would populate its 'names'
       property).
-      
+      * specifically:  PmofClass should populate its 'names' property with all
+        PmofProperties that have it or a superclass as their domain (the
+        corresponding Interface instance does this anyway), etc.
+
 
 *** ITEM 2 ***
 --------------------
@@ -238,4 +285,147 @@
     - groups of schemas (domain models -- aka schemas)
     - namespaces
 
+----------------------
+PGEF Components (eggs)
+----------------------
+
+* probably have to wait for Twisted eggs to do some, but can start now on
+  architecture
+* rename 'pangalactic' package to 'pgef'
+* prepare pgef to be a namespace
+* release as namespace packages:
+  - owl2zi (creates zope.interfaces from owl)
+  - pger (obj repo and cm service, no gui)
+  - PanGalaxian (gui client w/cache)
+  - uberorb (twisted services hub)
+  - pmof (MOF-like, manages models and maps, etc.)
+    + ontolgies, uml, vocabs, taxonomies, ...
+* define APIs between these components
+  - uberorb hub of everything
+  - pmof can use pger (ZODB is default -- other backend?)
+  - etc.
+
+* Some proposed components (eggs)
+  - registry/orb
+  - vger (multi-protocol services hub)
+    + requires: registry
+  - pangalaxian (vger client, non-gui, minimal: admin fns)
+    + requires: registry, vger
+  - pangalaxian.gui
+    + requires: registry, vger, pangalaxian
+  - vger.web (future:  web interfaces to vger services)
+    + requires: registry, vger
+  - pger (repository + versioning system)
+    + requires: registry, vger
+  - maybe import/export functions (?)
+    + requires: registry
+  - workflow (future)
+    + requires: registry, other?
+
+* [future] "simple components" (orthogonalize?)
+  - workflow
+  - schema/ontology design and mapping, data integration
+    + various file format imports/exports (STEP, etc.)
+  - rule service (rule engine + event dispatch)
+  - notification (email, im, amp [general])
+  - real-time collaboration (Foolscap)
+
+---------
+PGEF Apps
+---------
+
+* include a multi-service (a VGER configuration) and a client
+  (a PanGalaxian configuration)
+
+* this type of configuration should be able to use
+  "standard pgef components", enabling interoperability:
+  - ontologies
+  - ontology maps (conversions between data of 2 or more ontologies)
+  - behaviors (interfaces, API's)
+  - display maps (typically go with ontologies)
+
+* PGEF App configuration includes:
+  - metadata
+    + ontology
+    + behaviors (defined by z.i Interfaces)
+    + display maps (presentation -- similar to Zope "Schema")
+  - VGER configuration, if any (which services + protocols)
+  - PanGalaxian configuration (app context and subcontext definitions)
+    + contexts = definitions of the "views" used by the app
+    + used by PanGalaxian to define
+      * up to 4 PanGalaxian app (sub-)context choices (choice widgets)
+      * menu choices (canned searches, dialogs, etc.)
+      * tree types (semantics of the tree - what are nodes, etc.)
+      * tree context choices (may correspond to global context)
+      * main window
+        - grids (tab meanings)
+        - canvases
+        - notification widgets
+    + contexts can constrain:
+      * the set of visible domain Classes and Properties
+      * display maps (e.g., naming and grouping of Properties)
+
+* PGEF App Architecture
+  - simplest component apps are 1 service and 1 view/context
+  - component apps should be as orthogonal as possible
+  - distributable as python eggs
+
+* Some proposed PGEF Apps
+  - issue tracker ("marvin")
+  - CM/PDM ("PGPDM")
+  - knowledge management service ("hermione")
+  - systems engineer's assistant
+  - parts engineer's assistant
+  - project manager's assistant
+  - structured document editor/assembler
+    + [extension] collaborative document editor/assembler
+  - collaborative system modeler
+    (various kinds/disciplines ... eng/sci/sw/etc.)
+
+* More notes on apps (see also:  ~/sandbox/pangalacticsb/
+
+  - structured document editor/assembler:
+
+    Create a late-bound wizard that can initialize a document of a
+    given type, with user name (etc.: prefs), appropriate document
+    template(s) (MS Word, Powerpoint, etc.), and initial content
+    (could include boilerplate text, logos, etc.)
+
+    This could also be useful for IMDC / systems engineers, etc.
+
+    Essentially, creating an instance of PGEF Document, with an
+    MS Word Representation (and possibly others -- e.g., RST,
+    html, pdf, etc.)
+
+    Also can incorporate data and references from data sources
+    (databases, web sites, etc.) via wizard links.
+
+    + templates for various document types
+        * technology evals / whitepapers
+        * project plans
+        * other project docs
+    + easy doc creation
+        * use template
+        * fill in only content
+        * user should not have to do formatting
+    + version management
+    + "publishing"
+        * automated web pub of latest version
+        * pub/sub notifications on modifications
+    + system for collab
+        * comment / markup of doc drafts
+        * pub/sub for comments / markups
+    + MS Office templates
+    + python "harness" (COM interface to docs)
+        * inject rst content into MS Office template
+        * doc creation wizard
+            - creates an instance of a doc type
+            - guides addition of content
+    + doc repo with
+        * webdav interface
+        * pub/sub notification service
+        * workflow service
+
+-------------------------------------------------------------
+
 

From waterbug at step.nasa.gov  Wed May 23 01:45:53 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 23 01:45:54 2007
Subject: [pangalactic-commits] More notes.
Message-ID: <200705230545.l4N5jrNA006964@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/NOTES 1.17 1.18

Log message:
More notes.


Index: PanGalactic/NOTES
diff -u PanGalactic/NOTES:1.17 PanGalactic/NOTES:1.18
--- PanGalactic/NOTES:1.17	Mon May 21 00:24:47 2007
+++ PanGalactic/NOTES	Wed May 23 01:45:51 2007
@@ -25,15 +25,17 @@
     either "local" or "remote" prefixes (remote ones will show the origin
     prefix -- whether a repo or other service).
 
-  - when committed to a repo, objects will go into repo's sandbox under user's
-    id on the repo:
+  - when committed to a repo, objects will be assigned to the repo's sandbox
+    under user's id, which will be the following id namespace:
 
     "http://[repo addr]/vger/sandbox/[userid]/[project id]/objs"
 
-    (a fully-qualified URL) unless specifically committed to some other
-    namespace (e.g., a Project) to which the user has permission to commit.
-    (The default VGER config will give users permission to have a sandbox; this
-    will be configurable by the site admin -- i.e. may be disallowed.)
+    (which when combined with their id will give them an oid that is a
+    fully-qualified URL) unless they are specifically committed to some other
+    namespace (e.g., a Project) to which the user has permission to commit (in
+    which case their oid will be *that* ns + their id).  (The default VGER
+    config will give users permission to have a sandbox; this will be
+    configurable by the site admin -- i.e. may be disallowed.)
 
   - to create a top-level Project on a repo requires permission from the repo
     admin(s)

From waterbug at step.nasa.gov  Fri May 25 01:55:04 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 25 01:55:06 2007
Subject: [pangalactic-commits] Usability enhancements for PgxnObject ...
Message-ID: <200705250555.l4P5t4Vp009554@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/dialogs/pgxneditor.py 1.10 1.11
PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py 1.148 1.149
PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py 1.69 1.70

Log message:
Usability enhancements for PgxnObject ...
* tab order works now (tabs from button to button in a single notebook page;
  this should be modified later to cross notebook pages and cycle)
* all values are shown in buttons, which display more when pushed
* all text fields are edited by way of the pop-up editor
  - editor's text box receives focus when editor is invoked
  - ESC key kills editor (without saving, currently, but this will change)
  - focus returns to parent button when editor is closed, so tabbing can
    continue
  - editor can also be invoked by pressing <ENTER> on a button that has focus



Index: PanGalactic/pangalactic/node/gui/dialogs/pgxneditor.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/pgxneditor.py:1.10 PanGalactic/pangalactic/node/gui/dialogs/pgxneditor.py:1.11
--- PanGalactic/pangalactic/node/gui/dialogs/pgxneditor.py:1.10	Sat Dec  2 15:45:07 2006
+++ PanGalactic/pangalactic/node/gui/dialogs/pgxneditor.py	Fri May 25 01:55:01 2007
@@ -3,8 +3,9 @@
 PanGalaxian Editor:  an editor for PanGalaxian 'narrative' style text fields.
 """
 
-import  sys
-import  wx
+import logging
+import sys
+import wx
 from pangalactic.node import state
 
 
@@ -22,6 +23,7 @@
         @param pgxnprop:  the property widget that called us.
         @type  pgxnprop:  L{PanGalaxianProperty}
         """
+        self.log = logging.getLogger('pgxneditor')
         self.pgxnprop = pgxnprop
         # prop is the PgefProperty instance that the pgxnprop widget holds
         if pgxnprop:
@@ -48,6 +50,7 @@
 
     def bindEventHandlers(self):
         self.Bind(wx.EVT_CLOSE, self.onCloseWindow)
+        self.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
 
     def makeToolbar(self, win):
         sizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -104,8 +107,18 @@
         self.editwin.SetValue("")
 
     def onCloseWindow(self, event):
+        self.log.debug(' - onCloseWindow')
+        self.pgxnprop.widget.SetFocus()
         self.Destroy()
 
+    def onKeyDown(self, event):
+        self.log.debug(' - onKeyDown')
+        if event.GetKeyCode() == wx.WXK_ESCAPE:
+            self.pgxnprop.widget.SetFocus()
+            self.Destroy()
+        else:
+            event.Skip()
+
     def onClear(self, event):
         if self.editwin.GetValue():
             if not self.okCancelDialog("Clear:  delete all text?", "Clear"):

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.69 PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.70
--- PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.69	Fri May 18 01:11:17 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py	Fri May 25 01:55:02 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnproperty.py,v 1.69 2007/05/18 05:11:17 waterbug Exp $
+# $Id: pgxnproperty.py,v 1.70 2007/05/25 05:55:02 waterbug Exp $
 """
 PanGalaxianProperty (the Mother of all PanGalaxian Property widgets)
 
-@version: $Revision: 1.69 $
+@version: $Revision: 1.70 $
 """
-__version__ = "$Revision: 1.69 $"[11:-2]
+__version__ = "$Revision: 1.70 $"[11:-2]
 
 import logging
 from pprint import pprint
@@ -27,7 +27,7 @@
 from pangalactic.utils.toolbox               import curry, isAString
 
 
-class PanGalaxianProperty(object):
+class PanGalaxianProperty(wx.Window):
     """
     A widget to display or edit a C{PgefProperty}.  C{PanGalaxianProperty}
     is designed to be embedded within an instance of C{PanGalaxianObject}.
@@ -82,7 +82,7 @@
         #                 parent,
         #                 label=state['pmaps']['display_names'][prop.id]+':',
         #                 size=(200, -1),
-        #                 style=wx.NO_BORDER|wx.BU_RIGHT)
+        #                 style=wx.BORDER|wx.BU_RIGHT)
         # self.button.Bind(wx.EVT_BUTTON, self.onHelp, self.button)
 
     def onHelp(self, event):
@@ -102,7 +102,7 @@
     def __init__(self, parent, prop, obj):
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         wx.Button.__init__(self, parent, label='', size=(250, -1),
-                           style=wx.NO_BORDER)
+                           style=wx.BORDER)
         # print ' - PgxnObjectFnView (%s)' % prop.id
         self._available = False
         self.Bind(wx.EVT_BUTTON, self._onPush, self)
@@ -167,7 +167,7 @@
                 dispatcher.send('view object', obj=obj, editing=False)
 
 
-class PgxnStringFnView(PanGalaxianProperty):
+class PgxnStringFnView(PanGalaxianProperty, wx.Button):
     """
     PgxnStringFnView is the PanGalaxianProperty view-only subtype
     for a PgefProperty that has a C{range} of C{'str'} and is Functional
@@ -177,77 +177,45 @@
     def __init__(self, parent, prop, obj):
         # print ' - %s:  PgxnStringFnView' % prop.id
         PanGalaxianProperty.__init__(self, parent, prop, obj)
+        wx.Button.__init__(self, parent, label='', size=(250, -1),
+                           style=wx.BORDER)
         # initialize widgets
-        self.maxi_me = _LargeStringView(parent, prop, obj)
-        self.mini_me = _SmallStringView(parent, prop, obj)
-        self.widgets = [self.maxi_me, self.mini_me]
+        self.obj = obj
+        self.prop = prop
         self.value = getattr(self.obj, prop.id)
+        self.Bind(wx.EVT_BUTTON, self._onPush, self)
+        self.widgets = [self]
 
     ######################################################################
     #  Property:  value
     ######################################################################
 
     def getValue(self):
-        """
-        Get the current value of the Property being viewed or edited.
-        """
-        # print '   - PgxnStringFnView.getValue'
         return self.__value
 
     def setValue(self, v):
-        """
-        Set the value of the Property being viewed or edited.
-
-        @param v:  the value to be set
-        @type  v:  C{str}
-        """
-        if not v or (len(v) < 32 and not '\n' in v):
-            self.maxi_me.Hide()
-            self.mini_me.Show()
-        else:
-            self.mini_me.Hide()
-            self.maxi_me.Show()
-        for widget in self.widgets:
-            widget.value = v
         self.__value = v
+        self.SetLabel(self.genLabel(v))
 
-    value = property(fget=getValue, fset=setValue, doc='value')
-
-
-class _SmallStringView(wx.TextCtrl):
-    def __init__(self, parent, prop, obj):
-        # parent should be a PanGalaxianProperty instance -- so this guy's
-        # actual parent is it's parent's parent:  the PanGalaxianObject
-        self.obj = obj
-        self.prop = prop
-        self.parent = parent
-        # right, the str() is needed here because of the slight evilness that
-        # this widget is used to display other simple types, like integers,
-        # floats, bools, and datetimes ... :P
-        wx.TextCtrl.__init__(self, parent,
-                    value=str(getattr(obj, prop.id)),
-                    size=(250, -1),
-                    style=wx.TE_PROCESS_TAB|wx.TE_READONLY)
-        self.SetFont(wx.ITALIC_FONT)
-
-    ######################################################################
-    #  Property:  value
-    ######################################################################
-
-    def getValue(self):
-        """
-        Get the current value of the Property being viewed or edited.
-        """
-        # print '   - _SmallStringViewWidget.getValue'
-        return self.GetValue()
+    value = property(fget=getValue,
+                     fset=setValue,
+                     doc='value')
 
-    def setValue(self, v):
+    def genLabel(self, v):
         """
-        Set the value of the Property being viewed or edited.
+        Get a string to put on our button.
         """
-        self.SetValue(str(v))
+        label = '[None]'
+        if v:
+            sub = v.splitlines()[0][:32]
+            if len(sub) < len(v):
+                sub = ' '.join(sub.split(' ')[:-1]) + ' ...'
+            label = sub
+        return label
 
-    value = property(fget=getValue, fset=setValue, doc='value')
+    def _onPush(self, event):
+        viewer = wx.TipWindow(self, str(getattr(self.obj, self.prop.id)), 250)
+        viewer.Show(True)
 
 
 class _LargeStringView(wx.Button):
@@ -258,7 +226,7 @@
         self.obj = obj
         self.prop = prop
         wx.Button.__init__(self, parent, label='', size=(250, -1),
-                           style=wx.NO_BORDER)
+                           style=wx.BORDER)
         self.value = str(getattr(obj, prop.id))
         self.Bind(wx.EVT_BUTTON, self._onPush, self)
 
@@ -343,7 +311,7 @@
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         self.__value = getattr(self.obj, prop.id) or '' # in case None
         self.widget = wx.Button(parent, label=self.genLabel(self.__value),
-                                size=(250, -1), style=wx.NO_BORDER)
+                                size=(250, -1), style=wx.BORDER)
         self.widget.Bind(wx.EVT_BUTTON, self._onEdit, self.widget)
         self.widgets = [self.widget]
 
@@ -381,6 +349,7 @@
         x, y = self.widget.GetPositionTuple()
         editor = PgxnEditor(self, pos=(x+200, y+300))
         editor.Show(True)
+        editor.editwin.SetFocus()
         if self.value:
             self.widget.SetLabel(self.genLabel(self.value))
         self.log.debug(' - value:  %s' % str(self.value))
@@ -397,7 +366,7 @@
         # print ' - %s:  PgxnDatetimeFnView' % prop.id
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         # initialize widget
-        self.widget = _SmallStringView(parent, prop, obj)
+        self.widget = _LargeStringView(parent, prop, obj)
         self.widgets = [self.widget]
         self.value = getattr(self.obj, prop.id)
 
@@ -512,7 +481,7 @@
         # print ' - %s:  PgxnBooleanFnView' % prop.id
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         # initialize widget
-        self.widget = _SmallStringView(parent, prop, obj)
+        self.widget = _LargeStringView(parent, prop, obj)
         self.widgets = [self.widget]
         self.value = bool(getattr(self.obj, prop.id))
 
@@ -597,7 +566,7 @@
         # print ' - %s:  PgxnIntegerFnView' % prop.id
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         # initialize widget
-        self.widget = _SmallStringView(parent, prop, obj)
+        self.widget = _LargeStringView(parent, prop, obj)
         self.widgets = [self.widget]
         self.value = getattr(self.obj, prop.id)
 
@@ -682,7 +651,7 @@
         # print ' - %s:  PgxnFloatFnView' % prop.id
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         # initialize widget
-        self.widget = _SmallStringView(parent, prop, obj)
+        self.widget = _LargeStringView(parent, prop, obj)
         self.widgets = [self.widget]
         self.value = getattr(self.obj, prop.id)
 
@@ -772,7 +741,7 @@
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         self._available = False
         self.widget = wx.Button(parent, label='', size=(250, -1),
-                                style=wx.NO_BORDER)
+                                style=wx.BORDER)
         self.widget.Bind(wx.EVT_BUTTON, self._onPush, self.widget)
         self.widgets = [self.widget]
         self.value = getattr(self.obj, prop.id)
@@ -867,7 +836,7 @@
         PanGalaxianProperty.__init__(self, parent, prop, obj)
         # initialize widget
         self.widget = wx.Button(parent, label='', size=(250, -1),
-                                style=wx.NO_BORDER)
+                                style=wx.BORDER)
         # print ' - PgxnStringNonFnView (%s)' % prop.id
         self.widget.Bind(wx.EVT_BUTTON, self._onPush, self.widget)
         self.value = getattr(self.obj, self.prop.id)
@@ -922,7 +891,7 @@
         # TODO:  make the edit_widget an EditableListBox.
         # initialize widget
         self.widget = wx.Button(parent, label='', size=(250, -1),
-                                style=wx.NO_BORDER)
+                                style=wx.BORDER)
         # print ' - PgxnDatetimeNonFnView (%s)' % prop.id
         self.widget.Bind(wx.EVT_BUTTON, self._onPush, self.widget)
         self.value = getattr(self.obj, self.prop.id)
@@ -977,7 +946,7 @@
 # non-functional integer type should be an array -- use Numeric types
 PGXN_WIDGETS = {
     # Functional (single-valued)
-    (True,  'edit', 'str',          '') : PgxnStringFnEdit,
+    (True,  'edit', 'str',          '') : PgxnStringFnEditNarrative,
     (True,  'edit', 'str', 'narrative') : PgxnStringFnEditNarrative,
     (True,  'edit', 'bool',         '') : PgxnBooleanFnEdit,
     (True,  'edit', 'int',          '') : PgxnIntegerFnEdit,

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.148 PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.149
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.148	Fri May 18 01:11:17 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py	Fri May 25 01:55:01 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobject.py,v 1.148 2007/05/18 05:11:17 waterbug Exp $
+# $Id: pgxnobject.py,v 1.149 2007/05/25 05:55:01 waterbug Exp $
 """
 PanGalaxianObject (a C{PgefObject} viewer/editor)
 
-@version: $Revision: 1.148 $
+@version: $Revision: 1.149 $
 """
-__version__ = "$Revision: 1.148 $"[11:-2]
+__version__ = "$Revision: 1.149 $"[11:-2]
 
 import logging
 from copy import deepcopy
@@ -93,7 +93,7 @@
         self.log.debug(' - setting up interface map ...')
         self.interface_map = state['imaps'][self.obj._schema.__name__]
         self.groups = self.interface_map['groups']
-        # self.log.debug('   - interface map:  %s' % str(self.interface_map))
+        self.log.debug('   - interface map:  %s' % str(self.interface_map))
         # self.log.debug('   - groups for %s are:  %s' % (
         #                                             self.obj._schema.__name__,
         #                                             self.groups))
@@ -287,7 +287,7 @@
         """
         Initialize PgxnPropertybook for this PanGalaxianObject.
         """
-        # self.log.debug('   - initPropertybook()')
+        self.log.debug('   - initPropertybook()')
         working_prop_ids = list(self.obj._schema)
         # 'main' group is first notebook page
         main_prop_ids = self.groups['main']
@@ -656,7 +656,7 @@
         @ivar parent:  the wx object that is the parent of this one.
         @type parent:  a subclass of C{wx.Window}
         """
-        self.log = logging.getLogger('PgxnPropertyBook')
+        self.log = logging.getLogger('pgxnpropbook')
         wx.Notebook.__init__(self, parent)
         self.pobj = pobj
         self.obj = self.pobj.obj
@@ -695,7 +695,7 @@
         @param name:  name of the page
         @type  name:  C{str}
         """
-        # self.log.debug('   - PgxnPropertybook.addPropertyPage()')
+        self.log.debug('   - addPropertyPage()')
         win = wx.Window(self, style=wx.CLIP_CHILDREN|wx.FULL_REPAINT_ON_RESIZE)
         win.panels = {}
         # NOTE:  the order in which the panels are instantiated is important
@@ -737,14 +737,14 @@
             must be either 'view' or 'edit'
         @type  mode:  C{str}
         """
-        # self.log.debug('   - PgxnPropertybook.buildPropertyWidgetsForPage()')
+        self.log.debug('   - buildPropertyWidgetsForPage()')
         group = self.pobj.groups[page_name]
         panel = self.panels[(page_name, mode)]
         gridsizer = RowColSizer()
         panel.sizer = gridsizer
         props = [(a, self.obj._schema[a], getattr(self.obj, a)) for a in group]
-        # self.log.debug('     - building new widgets for panel:  %s (%s)') % (
-        #                                                      page_name, mode)
+        self.log.debug('     - building new widgets for panel:  %s (%s)' % (
+                                                             page_name, mode))
         row = 0
         linkflags = wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL
         widgetflags = wx.ALL|wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL
@@ -752,11 +752,12 @@
         widgetorderro = []
         linkorder = []
         for a, prop, p_val in props:
-            # self.log.debug('      * %s' % a)
+            self.log.debug('      * %s' % a)
             if getattr(prop, 'read_only', False):
                 m = 'view'
             else:
                 m = mode
+            self.log.debug('        - m:  %s' % m)
             pw = PGXN_WIDGETS[(prop.functional, m, prop.range,
                      state['pmaps']['display_styles'].get(prop.id, ''))](
                                                      panel, prop, self.pobj.obj)
@@ -779,6 +780,9 @@
                                   flag=widgetflags)
             linkorder.append(pw.link)
             row += 1
+        # self.log.debug('     - linkorder:  %s' % str(linkorder))
+        # self.log.debug('     - widgetorderro:  %s' % str(widgetorderro))
+        # self.log.debug('     - widgetorder:  %s' % str(widgetorder))
         widgetorder = linkorder + widgetorderro + widgetorder
         for i in xrange(len(widgetorder) - 1):
             widgetorder[i+1].MoveAfterInTabOrder(widgetorder[i])

From waterbug at step.nasa.gov  Fri May 25 02:02:37 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 25 02:02:39 2007
Subject: [pangalactic-commits] Revise relevant TODO items.
Message-ID: <200705250602.l4P62bCw009584@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.124 1.125

Log message:
Revise relevant TODO items.


Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.124 PanGalactic/TODO:1.125
--- PanGalactic/TODO:1.124	Mon May 21 00:24:47 2007
+++ PanGalactic/TODO	Fri May 25 02:02:35 2007
@@ -42,6 +42,11 @@
     (preferably identical, modulo objects vs. files) to Bzr/Subversion:  e.g.,
     checkout, update, commit, etc.
 [*] ENHANCEMENTS:  PanGalaxianObject (late-bound viewer/editor)
+    [-] need to do some cleaning up of PgxnProperty now that text field
+        viewing/editing widgets have been rationalized:  eliminate "style"
+        (narrative or not), make PgxnProperty subtypes widgets themselves (as
+        some already are), and rather than having a 'widgets' attribute, the
+        PgxnProperty instance itself will be referenced
     [-] dragndrop or menu selection for setting object-valued properties
     [-] improve datatype support:  create a PmofMetaObject for 'Datatype' so
         that users can define custom types using PMOF.
@@ -50,8 +55,6 @@
     [*] provide field display/order customization (similar to PgefObjectGrid,
         but separate) -- including GUI dialogs to define new notebook tabs,
         which properties go on which notebook page, and the order of the pages
-[-] *** BUG:  PanGalaxianObject's tab order doesn't work properly -- probably
-    because some of the datatype "widgets" are not really wx objects
 [-] ENHANCEMENT:  PanGalaxianObject "New Object" dialog's classes should be in
     alphabetical order
 [-] *** BUG:  PanGalaxianObject's "New Object" dialog can't create instances of
@@ -447,6 +450,7 @@
 ----
 DONE
 ----
+[-] *** BUG FIXED:  PanGalaxianObject's tab order works now
 [+] ENHANCEMENT:  add 'delete from cache' function, accessible from any object
     grid, by right-click menu
 [+] *** BUG FIXED:  namespace collision-checking in PanGalaxianObject
@@ -600,5 +604,5 @@
     [+] one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.124 2007/05/21 04:24:47 waterbug Exp $
+# $Id: TODO,v 1.125 2007/05/25 06:02:35 waterbug Exp $
 

From waterbug at step.nasa.gov  Sat May 26 13:58:24 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sat May 26 13:58:26 2007
Subject: [pangalactic-commits] Lose all those [None]'s ...
Message-ID: <200705261758.l4QHwOB1024500@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/NOTES 1.18 1.19
PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py 1.70 1.71

Log message:
Lose all those [None]'s ...
too cluttered; unlabeled buttons are better.


Index: PanGalactic/NOTES
diff -u PanGalactic/NOTES:1.18 PanGalactic/NOTES:1.19
--- PanGalactic/NOTES:1.18	Wed May 23 01:45:51 2007
+++ PanGalactic/NOTES	Sat May 26 13:58:21 2007
@@ -71,7 +71,7 @@
     etc.)
     ** DONE (for OWL)
 
-c.  create all runtime metaobjects from Pmof (managed) metaobjects.
+b.  create all runtime metaobjects from Pmof (managed) metaobjects.
     Managed Metaobjects and their runtime equivalents:
 
     Managed Metaobject      Runtime Metaobject
@@ -81,13 +81,13 @@
     PmofClass               Interface (zope.interface)
     PmofDatatype            types (Python built-in, Numpy, Scientific, etc.)
 
-d.  the Pmof objects will be cached as extracts but also saved to the
+c.  the Pmof objects will be cached as extracts but also saved to the
     repository.  They should be fetched from the repository at startup, unless
     the repository has been re-initialized, in which case the file cache of
     extracts can be used.  The oids for the Pmof objects should be canonicalized
     as their URI's (which should include version/iteration discriminators).
 
-e.  Long term:
+d.  Long term:
     (1)  every metaobject is uniquely identified by a URI
          -  a PmofClass contains full info about a "node" metaobject
             +  has optional versioning info

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.70 PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.71
--- PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.70	Fri May 25 01:55:02 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py	Sat May 26 13:58:22 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnproperty.py,v 1.70 2007/05/25 05:55:02 waterbug Exp $
+# $Id: pgxnproperty.py,v 1.71 2007/05/26 17:58:22 waterbug Exp $
 """
 PanGalaxianProperty (the Mother of all PanGalaxian Property widgets)
 
-@version: $Revision: 1.70 $
+@version: $Revision: 1.71 $
 """
-__version__ = "$Revision: 1.70 $"[11:-2]
+__version__ = "$Revision: 1.71 $"[11:-2]
 
 import logging
 from pprint import pprint
@@ -127,7 +127,7 @@
         """
         if not v:
             # print '    ... (empty)'
-            label = '[None]'
+            label = ''
         elif isAString(v):  # (an oid)
             # objects may not have been fetched yet ... give it a try
             v = orb.getObject(v) or v
@@ -205,7 +205,7 @@
         """
         Get a string to put on our button.
         """
-        label = '[None]'
+        label = ''
         if v:
             sub = v.splitlines()[0][:32]
             if len(sub) < len(v):
@@ -245,7 +245,7 @@
         """
         Get a string to put on our button.
         """
-        label = '[None]'
+        label = ''
         if v:
             sub = v.splitlines()[0][:32]
             if len(sub) < len(v):
@@ -334,7 +334,7 @@
         """
         Generate a label for our button from a value.
         """
-        label = '[None]'
+        label = ''
         if v:
             sub = v.splitlines()[0][:32]
             if len(sub) < len(v):
@@ -853,13 +853,13 @@
     def setValue(self, v):
         if not v:
             # print '    ... (empty)'
-            label = '[None]'
+            label = '[]'
         else:
             label = ''.join(['[',
                              state['pmaps']['display_names'][self.prop.id],
                              ']'])
         self.widget.SetLabel(label)
-        if label == '[None]':
+        if label == '[]':
             self.widget.SetForegroundColour(wx.RED)
         else:
             self.widget.SetBackgroundColour(wx.WHITE)
@@ -908,13 +908,13 @@
     def setValue(self, v):
         if not v:
             # print '    ... (empty)'
-            label = '[None]'
+            label = '[]'
         else:
             label = ''.join(['[',
                              state['pmaps']['display_names'][self.prop.id],
                              ']'])
         self.widget.SetLabel(label)
-        if label == '[None]':
+        if label == '[]':
             self.widget.SetForegroundColour(wx.RED)
         else:
             self.widget.SetBackgroundColour(wx.WHITE)

From waterbug at step.nasa.gov  Sun May 27 01:27:07 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 27 01:27:08 2007
Subject: [pangalactic-commits] PgxnObject's buttons should not always be
	pushable ...
Message-ID: <200705270527.l4R5R7av025161@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py 1.71 1.72

Log message:
PgxnObject's buttons should not always be pushable ...
-- only pushable if the property value does not fit on the button's label.


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.71 PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.72
--- PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py:1.71	Sat May 26 13:58:22 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnproperty.py	Sun May 27 01:27:05 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnproperty.py,v 1.71 2007/05/26 17:58:22 waterbug Exp $
+# $Id: pgxnproperty.py,v 1.72 2007/05/27 05:27:05 waterbug Exp $
 """
 PanGalaxianProperty (the Mother of all PanGalaxian Property widgets)
 
-@version: $Revision: 1.71 $
+@version: $Revision: 1.72 $
 """
-__version__ = "$Revision: 1.71 $"[11:-2]
+__version__ = "$Revision: 1.72 $"[11:-2]
 
 import logging
 from pprint import pprint
@@ -183,7 +183,11 @@
         self.obj = obj
         self.prop = prop
         self.value = getattr(self.obj, prop.id)
-        self.Bind(wx.EVT_BUTTON, self._onPush, self)
+        label, pushable = self.genLabel(self.value)
+        self.SetLabel(label)
+        if pushable:
+            self.SetForegroundColour(wx.BLUE)
+            self.Bind(wx.EVT_BUTTON, self._onPush, self)
         self.widgets = [self]
 
     ######################################################################
@@ -195,7 +199,6 @@
 
     def setValue(self, v):
         self.__value = v
-        self.SetLabel(self.genLabel(v))
 
     value = property(fget=getValue,
                      fset=setValue,
@@ -203,15 +206,18 @@
 
     def genLabel(self, v):
         """
-        Get a string to put on our button.
+        Get a label for our button and decide whether it will be pushable (only
+        if the label doesn't contain the whole value).
         """
         label = ''
+        pushable = False
         if v:
             sub = v.splitlines()[0][:32]
             if len(sub) < len(v):
-                sub = ' '.join(sub.split(' ')[:-1]) + ' ...'
+                sub = ' '.join(sub.split(' ')[:-1] + ['...'])
+                pushable = True
             label = sub
-        return label
+        return label, pushable
 
     def _onPush(self, event):
         viewer = wx.TipWindow(self, str(getattr(self.obj, self.prop.id)), 250)

From waterbug at step.nasa.gov  Mon May 28 02:50:24 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 28 02:50:26 2007
Subject: [pangalactic-commits] Some changes to grid table; more needed.
Message-ID: <200705280650.l4S6oOJj010639@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.125 1.126
PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py 1.38 1.39
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.49 1.50

Log message:
Some changes to grid table; more needed.


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.49 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.50
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.49	Fri May 18 01:11:17 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Mon May 28 02:50:22 2007
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.49 $
+@version: $Revision: 1.50 $
 """
-__version__ = "$Revision: 1.49 $"[11:-2]
+__version__ = "$Revision: 1.50 $"[11:-2]
 
 
 import logging
@@ -232,7 +232,8 @@
 
     def setObjs(self, val):
         """
-        Add a page for each object type in val
+        Make sure there is a grid page for each object type in val, and that it
+        is populated with all objects of that type in val.
 
         @param val:  a list or set of instances of
             L{pangalactic.meta.pgefobject.PgefObject}
@@ -240,8 +241,6 @@
         """
         # TODO:  set a default tab order and make it customizable
         self.log.debug('PgxnNotebook.setObjs')
-        self.__objs = val
-        self.parent.objs = val
         if self.pages:
             for page in self.pages:
                 id = self.GetSelection()
@@ -259,6 +258,8 @@
                 self._addGridPage(objs)
         else:
             self._addDefaultPage()
+        self.__objs = val
+        self.parent.objs = val
 
     def delObjs(self):
         raise TypeError, 'objs attribute cannot be deleted'

Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.125 PanGalactic/TODO:1.126
--- PanGalactic/TODO:1.125	Fri May 25 02:02:35 2007
+++ PanGalactic/TODO	Mon May 28 02:50:21 2007
@@ -9,6 +9,11 @@
 --------------
 TOP PRIORITIES
 --------------
+[-] *** BUG:  PgxnObjectGrid rebuilds its whole notebook of grids every time its
+    'objs' attr is set -- this is very disruptive and unnecessary!  (It makes
+    the interface jump and changes the selected page.)  Need to add or delete
+    pages only as necessary, and only reset a page if objs have been added or
+    removed from it.
 [*] ENHANCEMENTS:  give PanGalaxianObject some reasonable defaults:
     [-] new oids:  each object will have a local oid in the following default
         canonical format:
@@ -604,5 +609,5 @@
     [+] one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.125 2007/05/25 06:02:35 waterbug Exp $
+# $Id: TODO,v 1.126 2007/05/28 06:50:21 waterbug Exp $
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.38 PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.39
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.38	Fri May 18 10:43:15 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py	Mon May 28 02:50:22 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobjectgrid.py,v 1.38 2007/05/18 14:43:15 waterbug Exp $
+# $Id: pgxnobjectgrid.py,v 1.39 2007/05/28 06:50:22 waterbug Exp $
 """
 A table-based, late-bound, configurable object grid
 
-@version: $Revision: 1.38 $
+@version: $Revision: 1.39 $
 """
-__version__ = "$Revision: 1.38 $"[11:-2]
+__version__ = "$Revision: 1.39 $"[11:-2]
 
 from louie  import dispatcher
 from pprint import pprint
@@ -257,8 +257,13 @@
         return self._table.objs
 
     def set_objs(self, val):
-        self._table.objs = val
-        self.reset()
+        """
+        Set the C{objs} attr of the underlying table to val if the objects in
+        val are different from the current set.
+        """
+        if set([o.oid for o in val]) != set([o.oid for o in self._table.objs]):
+            self.reset()
+            self._table.objs = val
 
     def del_objs(self):
         raise TypeError, 'objs attribute cannot be deleted.'
@@ -293,12 +298,22 @@
 
     def reset(self):
         """
-        Reset the view -- called when the current set of objects and/or the
-        display_map may have changed.
+        Reset the grid table's view.  This method should only be called when
+        rows and/or columns have been added or removed from the table.  If the
+        objects in the table are the same but their values may have changed, use
+        C{update} (less disruptive).
         """
         self._table.setup()
         self._table.ResetView(self)
 
+    def update(self):
+        """
+        Update the grid table's view.  Call this method if the objects in the
+        table are the same but their values may have changed (less disruptive
+        than C{reset}).
+        """
+        self._table.UpdateValues(self)
+
     def noSelect(self, evt):
         """
         Do not select a column.

From waterbug at step.nasa.gov  Mon May 28 23:45:23 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 28 23:45:25 2007
Subject: [pangalactic-commits] Fix bug introduced by change to objectgrid ...
Message-ID: <200705290345.l4T3jNmK014584@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/uberorb.py 1.149 1.150
PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py 1.39 1.40

Log message:
Fix bug introduced by change to objectgrid ...
setting of objs attr and reset() of grid were being done in
wrong order.


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.39 PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.40
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.39	Mon May 28 02:50:22 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py	Mon May 28 23:45:21 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobjectgrid.py,v 1.39 2007/05/28 06:50:22 waterbug Exp $
+# $Id: pgxnobjectgrid.py,v 1.40 2007/05/29 03:45:21 waterbug Exp $
 """
 A table-based, late-bound, configurable object grid
 
-@version: $Revision: 1.39 $
+@version: $Revision: 1.40 $
 """
-__version__ = "$Revision: 1.39 $"[11:-2]
+__version__ = "$Revision: 1.40 $"[11:-2]
 
 from louie  import dispatcher
 from pprint import pprint
@@ -221,7 +221,6 @@
         # table and will destroy it when done.  Otherwise we would need to keep
         # a reference to it and call its Destroy method later.
         self.SetTable(self._table, True)
-        self.objs = self._table.objs
         self.schema = self._table.schema
         self.AutoSizeColumns(True)
         self.AutoSizeRows(True)
@@ -261,9 +260,8 @@
         Set the C{objs} attr of the underlying table to val if the objects in
         val are different from the current set.
         """
-        if set([o.oid for o in val]) != set([o.oid for o in self._table.objs]):
-            self.reset()
-            self._table.objs = val
+        self._table.objs = val
+        self.reset()
 
     def del_objs(self):
         raise TypeError, 'objs attribute cannot be deleted.'

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.149 PanGalactic/pangalactic/node/uberorb.py:1.150
--- PanGalactic/pangalactic/node/uberorb.py:1.149	Fri May 18 01:11:16 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Mon May 28 23:45:20 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.149 2007/05/18 05:11:16 waterbug Exp $
+# $Id: uberorb.py,v 1.150 2007/05/29 03:45:20 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.149 $
+@version: $Revision: 1.150 $
 """
-__version__ = "$Revision: 1.149 $"[11:-2]
+__version__ = "$Revision: 1.150 $"[11:-2]
 
 import logging
 import mimetypes
@@ -66,7 +66,7 @@
             self.log.info = lambda x: self.log.temp.append(x)
             self.log.debug = lambda x: self.log.temp.append(x)
         PanGalacticRegistry.__init__(self, debug=debug)
-        self.__cache = None
+        self.cache = None
         self.xmlrpc = None
         self.assy_maps = {} # cached maps {assy oid : [acu oids]}
 
@@ -104,25 +104,24 @@
         @type  home:  C{str}
         """
         self.log.info(' - initCache (initializing the object cache)')
-        if not self.__cache:
+        if not self.cache:
             # if prefs['home'] is not set, this will raise (as it should)
             # note:  you *can* hand the cache *all* interfaces, but it might be
             # confusing to the end-user to see things there that they can't
             # instantiate.  Here, we just give it 'persistables' ...
-            # self.__cache = ObjectCache(self.interfaces.values(), home=home)
             ifaces = [self.interfaces[i] for i in self.persistables]
             self.log.debug('   interfaces:  %s' % str(self.persistables))
-            self.__cache = ObjectCache(ifaces, home=home)
+            self.cache = ObjectCache(ifaces, home=home)
             # self.createDefaultNamespace()
         else:
-            raise ValueError, 'the orb already has a cache.'
+            raise ValueError, 'the cache has already been initialized.'
 
     # property:  cache
 
-    def getCache(self):
-        return self.__cache
+    # def getCache(self):
+    #     return self.__cache
 
-    cache = property(fget=getCache, doc='cache')
+    # cache = property(fget=getCache, doc='cache')
 
     # cache operations
 

From waterbug at step.nasa.gov  Tue May 29 02:10:50 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 29 02:10:52 2007
Subject: [pangalactic-commits] Beginnings of enforcing local oid uniqueness
	...
Message-ID: <200705290610.l4T6AnMH015053@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/meta/registry.py 1.174 1.175
PanGalactic/pangalactic/node/uberorb.py 1.150 1.151

Log message:
Beginnings of enforcing local oid uniqueness ...
just in registry so far -- next:
* replace PgefObject() invocations in orb, etc. with
  orb.makePgefObject()
* also, for PgxnObjects:  if the oid for a new PgxnObject is the same as the oid
  of an existing PgxnObject, merely transfer focus to the existing one rather
  than creating a new one
* figure out impacts on remember(), etc.
* think about relationship to Cacheable, Referenceable, Copyable, etc.


Index: PanGalactic/pangalactic/meta/registry.py
diff -u PanGalactic/pangalactic/meta/registry.py:1.174 PanGalactic/pangalactic/meta/registry.py:1.175
--- PanGalactic/pangalactic/meta/registry.py:1.174	Sun May  6 02:24:38 2007
+++ PanGalactic/pangalactic/meta/registry.py	Tue May 29 02:10:47 2007
@@ -1,11 +1,11 @@
-# $Id: registry.py,v 1.174 2007/05/06 06:24:38 waterbug Exp $
+# $Id: registry.py,v 1.175 2007/05/29 06:10:47 waterbug Exp $
 
 """
 The Pan Galactic Meta Object Registry
 
-@version: $Revision: 1.174 $
+@version: $Revision: 1.175 $
 """
-__version__ = "$Revision: 1.174 $"[11:-2]
+__version__ = "$Revision: 1.175 $"[11:-2]
 
 # Python
 import glob
@@ -72,14 +72,18 @@
         that no interface occurs in the C{list} before its bases.
     @type interface_base_order:  C{list}
 
-    @ivar properties:  A mapping of the names of C{PgefProperty}s known to the
-        registry to their instances.
-    @type interfaces:  C{dict}
-
     @ivar persistables:  The set of names of C{Interface}s for which there
         are tables in PGER.
     @type persistables:  C{set}
 
+    @ivar pgefobjs:  A C{dict} that maps oids to instances for all objects
+        created by L{makePgefObject}.
+    @type pgefobjs:  C{dict}
+
+    @ivar properties:  A mapping of the names of C{PgefProperty}s known to the
+        registry to their instances.
+    @type interfaces:  C{dict}
+
     @ivar refs:  A mapping of the names of C{Interface}s to the set of names of
         C{Interface}s that occur as the range of a C{PgefProperty} of which they
         are the domain.
@@ -117,6 +121,7 @@
             self.log.info = lambda x: self.log.info_temp.append(x)
             self.log.debug = lambda x: self.log.debug_temp.append(x)
         self.log.info(' - initializing registry logging.')
+        self.pgefobjs = {}
         self.sources = {}
         self.interfaces = {}
         self.properties = {}
@@ -155,6 +160,17 @@
                 for line in self.tempdebuglog:
                     self.log.debug(line)
 
+    def makePgefObject(self, _schema, **kw):
+        """
+        Create a new L{pangalactic.meta.pgefobject.PgefObject} instance or (if
+        the computed oid exists) return a reference to an existing one.
+        """
+        o = PgefObject(_schema, **kw)
+        if o.oid in self.pgefobjs:
+            return self.pgefobjs[o.oid]
+        else:
+            return o
+
     def createCoreMetaObjects(self, module='pangalactic.meta.names'):
         """
         Build a dictionary of C{Interface} instances from the
@@ -556,7 +572,7 @@
         # TODO:  this policy should be user-configurable and/or
         # context-dependent.
         ns = namespaces[nsprefix]
-        pgns = PgefObject(
+        pgns = self.makePgefObject(
                    _schema=self.interfaces['PmofNamespace'],
                    base_id=nsprefix, uri=ns.uri,
                    names=[str(nom) for nom in ns.names],
@@ -947,7 +963,7 @@
         if kw.get('iteration') is None:
             kw['iteration'] = 0
         kw['security_mask'] = kw.get('security_mask', 0)
-        pmofobj = PgefObject(_schema, **kw)
+        pmofobj = self.makePgefObject(_schema, **kw)
         pmofobj.frozen = True
         return pmofobj
 
@@ -1227,10 +1243,11 @@
             e['_schema_name'] = 'PmofClass'
             d[cname] = self.createPmofObjectFromExtract(e)
         ns = namespaces[nsprefix]
-        d[nsprefix] = PgefObject(_schema=self.interfaces['PmofNamespace'],
-                                 base_id=nsprefix, uri=ns.uri,
-                                 names=[str(nom) for nom in ns.names],
-                                 complete=True)
+        d[nsprefix] = self.makePgefObject(
+                                _schema=self.interfaces['PmofNamespace'],
+                                base_id=nsprefix, uri=ns.uri,
+                                names=[str(nom) for nom in ns.names],
+                                complete=True)
         return d
 
 registry = PanGalacticRegistry()

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.150 PanGalactic/pangalactic/node/uberorb.py:1.151
--- PanGalactic/pangalactic/node/uberorb.py:1.150	Mon May 28 23:45:20 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Tue May 29 02:10:48 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.150 2007/05/29 03:45:20 waterbug Exp $
+# $Id: uberorb.py,v 1.151 2007/05/29 06:10:48 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.150 $
+@version: $Revision: 1.151 $
 """
-__version__ = "$Revision: 1.150 $"[11:-2]
+__version__ = "$Revision: 1.151 $"[11:-2]
 
 import logging
 import mimetypes
@@ -116,13 +116,6 @@
         else:
             raise ValueError, 'the cache has already been initialized.'
 
-    # property:  cache
-
-    # def getCache(self):
-    #     return self.__cache
-
-    # cache = property(fget=getCache, doc='cache')
-
     # cache operations
 
     def getDict(self, name):

From waterbug at step.nasa.gov  Wed May 30 01:08:11 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 30 01:08:13 2007
Subject: [pangalactic-commits] New! Only one PanGalaxianObject per
	PgefObject! :D
Message-ID: <200705300508.l4U58BLw031907@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/uberorb.py 1.151 1.152
PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py 1.149 1.150
PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py 1.40 1.41

Log message:
New!  Only one PanGalaxianObject per PgefObject!  :D
At last ... the orb keeps track of all PanGalaxianObjects
(orb.pgxnobjs dict) and all PanGalaxianObject spawning functions
check with the orb to see if there is already a PanGalaxianObject for
the PgefObject in the spawning call ... if there is one, it is raised
to the top of the window hierarchy (z-order) and given focus; if not,
then a new one is spawned.


Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.40 PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.41
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py:1.40	Mon May 28 23:45:21 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobjectgrid.py	Wed May 30 01:08:09 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobjectgrid.py,v 1.40 2007/05/29 03:45:21 waterbug Exp $
+# $Id: pgxnobjectgrid.py,v 1.41 2007/05/30 05:08:09 waterbug Exp $
 """
 A table-based, late-bound, configurable object grid
 
-@version: $Revision: 1.40 $
+@version: $Revision: 1.41 $
 """
-__version__ = "$Revision: 1.40 $"[11:-2]
+__version__ = "$Revision: 1.41 $"[11:-2]
 
 from louie  import dispatcher
 from pprint import pprint
@@ -481,7 +481,11 @@
         """
         # print ' - PanGalaxianObjectGrid.viewObject()'
         obj = self.getObject(evt.GetRow())
-        PanGalaxianObject(None, obj).Show()
+        if obj.oid in orb.pgxnobjs:
+            orb.pgxnobjs[obj.oid].Raise()
+            orb.pgxnobjs[obj.oid].SetFocus()
+        else:
+            PanGalaxianObject(None, obj).Show()
 
     def popupObjectMenu(self, evt):
         """

Index: PanGalactic/pangalactic/node/uberorb.py
diff -u PanGalactic/pangalactic/node/uberorb.py:1.151 PanGalactic/pangalactic/node/uberorb.py:1.152
--- PanGalactic/pangalactic/node/uberorb.py:1.151	Tue May 29 02:10:48 2007
+++ PanGalactic/pangalactic/node/uberorb.py	Wed May 30 01:08:08 2007
@@ -1,11 +1,11 @@
-# $Id: uberorb.py,v 1.151 2007/05/29 06:10:48 waterbug Exp $
+# $Id: uberorb.py,v 1.152 2007/05/30 05:08:08 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_uberorb -*-
 """
 A PanGalaxian node's UberORB
 
-@version: $Revision: 1.151 $
+@version: $Revision: 1.152 $
 """
-__version__ = "$Revision: 1.151 $"[11:-2]
+__version__ = "$Revision: 1.152 $"[11:-2]
 
 import logging
 import mimetypes
@@ -21,7 +21,6 @@
 
 # PanGalactic imports
 from pangalactic.meta.interfaces             import IMofFactory
-from pangalactic.meta.pgefobject             import PgefObject
 from pangalactic.meta.registry               import PanGalacticRegistry
 from pangalactic.node                        import state, prefs
 from pangalactic.node.cache                  import ObjectCache
@@ -32,20 +31,28 @@
 
 class UberORB(PanGalacticRegistry):
     """
-    The UberORB handles all local persistence (i.e., the ObjectCache, a ZODB
-    service) and all communications with the repository.
+    The UberORB provides a local metaobject facility, manages all local
+    persistence (i.e., the ObjectCache, a ZODB service), and mediates all
+    communications with remote repositories (and in the future, other services).
+
+    IMPORTANT:  the UberORB is intended to be a singleton.  The module-level
+    UberORB instance created at the end of this module, 'orb', is what should
+    normally be imported by PanGalactic components and modules (exceptions:
+    testing and debugging -- hence the 'debug' parameter).
 
-    IMPORTANT:  UberORB is intended to be a singleton.  The module-level UberORB
-    instance created at the end of this module, 'orb', is what should normally
-    be imported by PanGalactic components and modules (exceptions:  testing and
-    debugging -- hence the 'debug' parameter).
+    @ivar cache:  the local object cache (ZODB)
+    @type cache:  L{pangalactic.node.cache.ObjectCache}
 
     @ivar interfaces:  a C{dict} of C{Interface} objects (inherited from the
         C{PanGalacticRegistry})
     @type interfaces:  L{pangalactic.node.cache.ObjectCache}
 
-    @ivar cache:  an instance of C{ObjectCache}
-    @type cache:  L{pangalactic.node.cache.ObjectCache}
+    @ivar pgxnobjs:  a C{dict} mapping the oids of all C{PgefObject} instances
+        that have an active C{PanGalaxianObject} instance to that instance
+    @type pgxnobjs:  C{list}
+
+    @ivar xmlrpc:  an XML-RPC client interface
+    @type xmlrpc:  L{pangalactic.utils.xmlrpcinterface.XmlrpcInterface}
     """
 
     implements(IMofFactory)
@@ -69,6 +76,9 @@
         self.cache = None
         self.xmlrpc = None
         self.assy_maps = {} # cached maps {assy oid : [acu oids]}
+        self.pgxnobjs = {}
+        self.register(self.addPgxnObj, signal='pgxnobj spawned')
+        self.register(self.delPgxnObj, signal='pgxnobj killed')
 
     def register(self, receiver, signal, **kw):
         dispatcher.connect(receiver, signal, **kw)
@@ -105,10 +115,12 @@
         """
         self.log.info(' - initCache (initializing the object cache)')
         if not self.cache:
-            # if prefs['home'] is not set, this will raise (as it should)
-            # note:  you *can* hand the cache *all* interfaces, but it might be
-            # confusing to the end-user to see things there that they can't
-            # instantiate.  Here, we just give it 'persistables' ...
+            # Note: you *can* hand the cache all the interfaces known to the
+            # orb, but it might be confusing for the end-user to see interfaces
+            # for which they can't directly create providing instances, so here
+            # we just use the 'instantiable' ones, a.k.a. 'persistables', which
+            # are the ones that have corresponding tables in the repository
+            # (PGER).
             ifaces = [self.interfaces[i] for i in self.persistables]
             self.log.debug('   interfaces:  %s' % str(self.persistables))
             self.cache = ObjectCache(ifaces, home=home)
@@ -120,8 +132,8 @@
 
     def getDict(self, name):
         """
-        Get the {oid : obj} dictionary for the named Interface from the cache
-        (this is a wrapper for cache.getDict).
+        Get the {oid : obj} dictionary of cache objects that provide the named
+        Interface (this is a wrapper for cache.getDict).
         """
         d = {}
         if getattr(self, 'cache'):
@@ -198,6 +210,20 @@
         else:
             raise ValueError, 'the cache has not been initialized yet.'
 
+    def addPgxnObj(self, pgxnobj=None):
+        """
+        When a C{PanGalaxianObject} has been spawned, add its C{PgefObject}'s
+        oid to the 'pgxnobjs' dict.
+        """
+        self.pgxnobjs[pgxnobj.obj.oid] = pgxnobj
+
+    def delPgxnObj(self, pgxnobj=None):
+        """
+        When a C{PanGalaxianObject} has been killed, remove its C{PgefObject}'s
+        oid from the 'pgxnobjs' dict.
+        """
+        del self.pgxnobjs[pgxnobj.obj.oid]
+
     def _initXmlrpcInterface(self, hostandport, userid, passwd, secure=True):
         """
         Initialize a server proxy for a host and port.
@@ -454,7 +480,7 @@
         if not obj:
             self.log.debug('   + no cache obj with oid = %s' % e['oid'])
             self.log.debug('     ... creating a blank obj ...')
-            obj = PgefObject(_schema=self.interfaces[schema_name])
+            obj = self.makePgefObject(_schema=self.interfaces[schema_name])
         updates = dict([(a, schema[a].uncook(e.get(a)))
                            for a in schema])
         self.log.debug('   + updating object')
@@ -481,9 +507,10 @@
             schema_name = self.getSchemaIdForEntityName(entity_name)
             # create objects, using xid's as temp oids (convenient since
             # they already use them to cross-ref each other)
-            objs[xid] = PgefObject(_schema=self.interfaces[schema_name],
-                                          oid=xid,
-                                          **osebdataset['data'][xid])
+            objs[xid] = self.makePgefObject(
+                                        _schema=self.interfaces[schema_name],
+                                        oid=xid,
+                                        **osebdataset['data'][xid])
         return objs
 
     def objects2Oseb(self, objs):

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.149 PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.150
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.149	Fri May 25 01:55:01 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py	Wed May 30 01:08:09 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobject.py,v 1.149 2007/05/25 05:55:01 waterbug Exp $
+# $Id: pgxnobject.py,v 1.150 2007/05/30 05:08:09 waterbug Exp $
 """
 PanGalaxianObject (a C{PgefObject} viewer/editor)
 
-@version: $Revision: 1.149 $
+@version: $Revision: 1.150 $
 """
-__version__ = "$Revision: 1.149 $"[11:-2]
+__version__ = "$Revision: 1.150 $"[11:-2]
 
 import logging
 from copy import deepcopy
@@ -263,6 +263,7 @@
         # register statusbar.onStateChange to receive 'state changed' message
         orb.register(self.statusbar.onStateChange, 'state changed')
         orb.register(self.onStateChange, 'state changed')
+        dispatcher.send(signal='pgxnobj spawned', pgxnobj=self)
         # TODO:  pgxnobject should only be notified if *its* specific object
         # changes ... so redo these 'updates received' events
         # orb.register(self.notebook.resync, 'updates received')
@@ -501,6 +502,8 @@
         if self.closing:
             event.Skip()
         else:
+            # tell the orb to remove this oid from the pgxnobjs set
+            dispatcher.send(signal='pgxnobj killed', pgxnobj=self)
             self.closing = True
             # if self.unsaved:
             #     dlg = wx.MessageDialog(self,
@@ -634,8 +637,12 @@
     """
     Spawn a new instance of PanGalaxianObject.
     """
-    viewer = PanGalaxianObject(None, obj, editing=editing)
-    viewer.Show()
+    if obj.oid in orb.pgxnobjs:
+        orb.pgxnobjs[obj.oid].Raise()
+        orb.pgxnobjs[obj.oid].SetFocus()
+    else:
+        viewer = PanGalaxianObject(None, obj, editing=editing)
+        viewer.Show()
 
 orb.register(spawnPgxnObject, 'view object')
 

From waterbug at step.nasa.gov  Thu May 31 02:17:37 2007
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 31 02:17:39 2007
Subject: [pangalactic-commits] Minor fixes + some notes.
Message-ID: <200705310617.l4V6HbOS015246@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.126 1.127
PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py 1.150 1.151

Log message:
Minor fixes + some notes.


Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.126 PanGalactic/TODO:1.127
--- PanGalactic/TODO:1.126	Mon May 28 02:50:21 2007
+++ PanGalactic/TODO	Thu May 31 02:17:34 2007
@@ -13,7 +13,16 @@
     'objs' attr is set -- this is very disruptive and unnecessary!  (It makes
     the interface jump and changes the selected page.)  Need to add or delete
     pages only as necessary, and only reset a page if objs have been added or
-    removed from it.
+    removed from it.  This needs several separate fixes:
+    [-] only set the 'objs' attr if there is a change of "context" -- e.g., the
+        current project is switched
+    [-] change dispatcher's 'objects saved' message to include an argument
+        (probably 'objs') that passes the saved objects so that the grid (and
+        any other subscribers) can make more fine-grained responses -- e.g., the
+        PgxnObjectGrid can update the specific cells in the pertinent rows (on
+        specific notebook pages), or add rows as necessary
+    [-] change dispatcher's 'updates received' message and listeners in the same
+        way
 [*] ENHANCEMENTS:  give PanGalaxianObject some reasonable defaults:
     [-] new oids:  each object will have a local oid in the following default
         canonical format:
@@ -24,8 +33,8 @@
         created locally, it will need to be updated when connected to a
         repository or identity service (esp. the latter)
     [-] each user will have an Person object.  The user's Person object will
-        have an associated Role (with credentials, e.g. userid/passwd) for each
-        service (e.g. repository) known to PanGalaxian.
+        have an associated Role (Role == 'Avatar' in twisted.cred) with
+        credentials, e.g. userid/passwd, for each.
     [-] cm auth = current project
     [-] others?
 [*] ENHANCEMENT:  show by background color-coding which objects are local-only
@@ -609,5 +618,5 @@
     [+] one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.126 2007/05/28 06:50:21 waterbug Exp $
+# $Id: TODO,v 1.127 2007/05/31 06:17:34 waterbug Exp $
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.150 PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.151
--- PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py:1.150	Wed May 30 01:08:09 2007
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnobject.py	Thu May 31 02:17:35 2007
@@ -1,10 +1,10 @@
-# $Id: pgxnobject.py,v 1.150 2007/05/30 05:08:09 waterbug Exp $
+# $Id: pgxnobject.py,v 1.151 2007/05/31 06:17:35 waterbug Exp $
 """
 PanGalaxianObject (a C{PgefObject} viewer/editor)
 
-@version: $Revision: 1.150 $
+@version: $Revision: 1.151 $
 """
-__version__ = "$Revision: 1.150 $"[11:-2]
+__version__ = "$Revision: 1.151 $"[11:-2]
 
 import logging
 from copy import deepcopy
@@ -33,7 +33,7 @@
     """
     A viewer/editor for instances of C{PgefObject}.  PanGalaxianObject can be in
     any one of 14 possible states, which are documented in The PGEF Manual
-    (PanGalactic/docs/PgefManual.{txt|html}).
+    (PanGalactic/docs/PgefManual.txt).
 
     @ivar groups:  a dictionary that maps the names of groups of the
         object's Properties to lists of Property names
@@ -502,18 +502,10 @@
         if self.closing:
             event.Skip()
         else:
+            self.onSaveToCache(None)
             # tell the orb to remove this oid from the pgxnobjs set
             dispatcher.send(signal='pgxnobj killed', pgxnobj=self)
             self.closing = True
-            # if self.unsaved:
-            #     dlg = wx.MessageDialog(self,
-            #                            'Do you want to save your changes?',
-            #                            'PanGalactic Info',
-            #                            wx.YES_NO | wx.ICON_INFORMATION)
-            #     dlg.CentreOnParent()
-            #     if dlg.ShowModal() == wx.ID_YES:
-            #         self.onSaveToCache(event)
-            #     dlg.Destroy()
             self.Close(True)
 
     def onEdit(self, event):
@@ -523,7 +515,7 @@
         self.log.debug(' - PGO.onEdit')
         self.obj.editor = prefs.get('userid')
         self.editing = True
-        orb.saveToCache([self.obj])
+        # orb.saveToCache([self.obj])
         self.setPropertybookState()
         self.setToolbarState()
 
@@ -534,27 +526,7 @@
         self.log.debug(' - PGO.onView')
         self.editing = False
         self.obj.editor = ''
-        if event:
-            self.onSaveToCache(event)
-        # the "typing in widget" event is disabled (triggered by wx.EVT_TEXT,
-        # etc.) because it is behaving erratically, for whatever reason.  A
-        # simplified approach will be used:  if you go into edit mode, the "Save
-        # to Cache" button will be active, period.
-        # *** This dialog might be reactivated later based on comparing the
-        # "view" object (what's in the property widgets) with the object and if
-        # there are differences, prompting the user. ***
-        # self.log.debug('   + self.unsaved = %s' % self.unsaved)
-        # if self.unsaved:
-        #     dlg = wx.MessageDialog(self,
-        #                            'Do you want to save your changes?',
-        #                            'PanGalactic Info',
-        #                            wx.YES_NO | wx.ICON_INFORMATION)
-        #     dlg.CentreOnParent()
-        #     if dlg.ShowModal() == wx.ID_YES:
-        #         self.onSaveToCache(event)
-        #     dlg.Destroy()
-        # else:
-        #     self.log.debug('   - no changes; nothing to save.')
+        self.onSaveToCache(None)
 
     def onSaveToCache(self, event):
         """