[Subversion] / PyDicia / README.txt  

Diff of /PyDicia/README.txt

Parent Directory | Revision Log

version 2319, Wed Jul 4 02:58:44 2007 UTC version 2320, Wed Jul 4 16:25:46 2007 UTC
Line 31 
Line 31 
 Developer's Guide  Developer's Guide
 -----------------  -----------------
   
 Basic Use  Basic XML Generation
 =========  ====================
   
   PyDicia simplifies the creation of XML for DAZzle by using objects to specify
   what data needs to go in the XML.  These objects are mostly ``DocInfo``
   instances, or callables that create ``DocInfo`` instances.  However, the
   framework is extensible, so that you can use your own object types with the
   same API.  Your object types can either generate ``DocInfo`` instances, or
   directly manipulate the XML using ElementTree APIs for maximum control.
   
   In the simpler cases, however, you will just use lists or tuples of objects
   provided by (or created with) the PyDicia API to represent packages or labels.
   
   
   Batch Objects
   -------------
   
   XML documents are represented using ``Batch`` objects::
   
     >>> from pydicia import *      >>> from pydicia import *
       >>> b = Batch()
   
   The ``tostring()`` method of a batch returns its XML in string form, optionally
   in a given encoding (defaulting to ASCII if not specified)::
   
       >>> print b.tostring('latin1')
       <?xml version='1.0' encoding='latin1'?>
       <DAZzle />
   
   To add a package to a batch, you use the ``add_package()`` method::
   
       >>> b.add_package(ToName('Phillip Eby'))
       >>> print b.tostring()
       <DAZzle>
           <Package ID="1">
                <ToName>Phillip Eby</ToName>
           </Package>
       </DAZzle>
   
   The ``add_package()`` method accepts zero or more objects that can manipulate
   PyDicia package objects.  It also accepts tuples or lists of such objects,
   nested to arbitrary depth.
   
       >>> b.add_package([COD, (Stealth, ToName('Ty Sarna'))], FlatRateBox)
   
       >>> print b.tostring()
       <DAZzle>
           <Package ID="1">
               <ToName>Phillip Eby</ToName>
           </Package>
           <Package ID="2">
               <Services COD="ON" />
               <Stealth>TRUE</Stealth>
               <ToName>Ty Sarna</ToName>
               <PackageType>FLATRATEBOX</PackageType>
           </Package>
       </DAZzle>
   
   And the ``packages`` attribute of a batch keeps track of the arguments that
   have been passed to ``add_package()``::
   
       >>> b.packages
       [(DocInfo('ToName', 'Phillip Eby', None),),
        ([DocInfo('Services', 'ON', 'COD'), (DocInfo('Stealth', 'TRUE', None),
          DocInfo('ToName', 'Ty Sarna', None))],
         DocInfo('PackageType', 'FLATRATEBOX', None))]
   
   Each "package" in the list is a tuple of the arguments that were supplied for
   each invocation of ``add_package()``.
   
   
   Treating Your Objects as Packages
   ---------------------------------
   
   It also accepts any custom objects of your own design, that are registered with
   the ``pydicia.add_to_package()`` or ``pydicia.iter_docinfo()`` generic
   functions::
   
       >>> class Customer:
       ...     def __init__(self, **kw):
       ...         self.__dict__ = kw
   
       >>> @iter_docinfo.when_type(Customer)
       ... def cust_docinfo(ob):
       ...     yield ToName(ob.name)
       ...     yield ToAddress(ob.address)
       ...     yield ToCity(ob.city)
       ...     yield ToState(ob.state)
       ...     yield ToPostalCode(ob.zip)
   
       >>> b = Batch()
       >>> c = Customer(
       ...     name='PJE', address='123 Nowhere Dr', state='FL', city='Nowhere',
       ...     zip='12345-6789'
       ... )
       >>> b.add_package(c)
       >>> print b.tostring()
       <DAZzle>
           <Package ID="1">
               <ToName>PJE</ToName>
               <ToAddress1>123 Nowhere Dr</ToAddress1>
               <ToCity>Nowhere</ToCity>
               <ToState>FL</ToState>
               <ToPostalCode>12345-6789</ToPostalCode>
           </Package>
       </DAZzle>
   
   This allows you to pass customer, package, product, invoice, or other
   application-specific objects into ``add_package()``.  And the objects yielded
   by your ``iter_docinfo`` implementation can also be application objects, e.g.::
   
       >>> class Invoice:
       ...     def __init__(self, **kw):
       ...         self.__dict__ = kw
   
       >>> @iter_docinfo.when_type(Invoice)
       ... def invoice_docinfo(ob):
       ...     yield ob.shippingtype
       ...     yield ob.products
       ...     yield ob.customer
   
       >>> b = Batch()
       >>> i = Invoice(
       ...     shippingtype=(Tomorrow, MailClass('MEDIAMAIL')),
       ...     products=[WeightOz(27),], customer=c
       ... )
       >>> b.add_package(i)
       >>> print b.tostring()
       <DAZzle>
           <Package ID="1">
               <DateAdvance>1</DateAdvance>
               <MailClass>MEDIAMAIL</MailClass>
               <WeightOz>27</WeightOz>
               <ToName>PJE</ToName>
               <ToAddress1>123 Nowhere Dr</ToAddress1>
               <ToCity>Nowhere</ToCity>
               <ToState>FL</ToState>
               <ToPostalCode>12345-6789</ToPostalCode>
           </Package>
       </DAZzle>
   
   Also note that there is no particular significance to my choice of lists vs.
   tuples in these examples; they're more to demonstrate that you can use
   arbitrary structures, as long as they contain objects that are supported by
   either ``iter_docinfo()`` or ``add_to_package()``.  Normally, you will simply
   use collections of either PyDicia-provided symbols, or application objects for
   which you've defined an ``iter_docinfo()`` method.
   
   You will also usually want to implement your PyDicia support in a module by
   itself, so you can use ``from pydicia import *`` without worrying about symbol
   collisions.
   
   
   Batch-wide Options
   ------------------
   
   When you create a batch, you can pass in any number of objects, to specify
   options that will be applied to every package.  For example, this batch will
   have every package set to be mailed tomorrow as media mail::
   
       >>> b = Batch( Tomorrow, MailClass('MEDIAMAIL') )
       >>> b.add_package(ToName('PJE'))
       >>> print b.tostring()
       <DAZzle>
           <Package ID="1">
               <ToName>PJE</ToName>
               <DateAdvance>1</DateAdvance>
               <MailClass>MEDIAMAIL</MailClass>
           </Package>
       </DAZzle>
   
   
   Multi-Batch Shipments
   =====================
   
   Certain DAZzle options can only be set once per file, such as the choice of
   layout file.  If you are shipping multiple packages with different label
   layouts (such as domestic vs. international mail), you need to separate these
   packages into different batches.  The ``Shipment`` class handles this
   separation for you automatically.
   
   When you create a shipment, it initially has no batches::
   
     >>> s = Shipment()      >>> s = Shipment()
     >>> s.batches      >>> s.batches
     []      []
   
     >>> s.ship(ToName('Phillip Eby'), Test)  
   But as you add packages to it, it will create batches as needed::
   
       >>> s.add_package(ToName('Phillip Eby'), Test)
     >>> len(s.batches)      >>> len(s.batches)
     1      1
     >>> s.batches[0].packages  
     [(DocInfo('ToName', 'Phillip Eby', None), DocInfo('DAZzle', 'YES', 'Test'))]  
   
     >>> print s.batches[0].tostring()      >>> print s.batches[0].tostring()
     <DAZzle Test="YES"><Package ID="1"><ToName>Phillip      <DAZzle Test="YES">
     Eby</ToName></Package></DAZzle>          <Package ID="1">
               <ToName>Phillip Eby</ToName>
           </Package>
       </DAZzle>
   
   As long as you're adding packages with the same or compatible options, the
   same batch will be reused::
   
     >>> s.ship(ToName('Ty Sarna'))      >>> s.add_package(ToName('Ty Sarna'), Test)
     >>> len(s.batches)      >>> len(s.batches)
     1      1
     >>> print s.batches[0].tostring()      >>> print s.batches[0].tostring()
     <DAZzle Test="YES"><Package ID="1"><ToName>Phillip      <DAZzle Test="YES">
     Eby</ToName></Package><Package ID="2"><ToName>Ty          <Package ID="1">
     Sarna</ToName></Package></DAZzle>              <ToName>Phillip Eby</ToName>
           </Package>
           <Package ID="2">
               <ToName>Ty Sarna</ToName>
           </Package>
       </DAZzle>
   
   But as soon as you add a package with any incompatible options, a new batch
   will be created and used::
   
     >>> s.ship(ToName('PJE'), ~Test)      >>> s.add_package(ToName('PJE'), ~Test)
     >>> len(s.batches)      >>> len(s.batches)
     2      2
   
       >>> print s.batches[1].tostring()
       <DAZzle Test="NO">
           <Package ID="1">
               <ToName>PJE</ToName>
           </Package>
       </DAZzle>
   
   And each time you add a package, it's added to the first compatible batch::
   
       >>> s.add_package(ToName('Some Body'), ~Test)
       >>> len(s.batches)
       2
   
     >>> print s.batches[1].tostring()      >>> print s.batches[1].tostring()
     <DAZzle Test="NO"><Package ID="1"><ToName>PJE</ToName></Package></DAZzle>      <DAZzle Test="NO">
           <Package ID="1">
               <ToName>PJE</ToName>
           </Package>
           <Package ID="2">
               <ToName>Some Body</ToName>
           </Package>
       </DAZzle>
   
       >>> s.add_package(ToName('No Body'), Test)
       >>> len(s.batches)
       2
   
       >>> print s.batches[0].tostring()
       <DAZzle Test="YES">
           <Package ID="1">
               <ToName>Phillip Eby</ToName>
           </Package>
           <Package ID="2">
               <ToName>Ty Sarna</ToName>
           </Package>
           <Package ID="3">
               <ToName>No Body</ToName>
           </Package>
       </DAZzle>
   
   By the way, as with batches, you can create a shipment with options that will
   be applied to all packages::
   
       >>> s = Shipment(Tomorrow, COD)
       >>> s.add_package(ToName('Some Body'), Test)
       >>> s.add_package(ToName('No Body'), ~Test)
       >>> len(s.batches)
       2
       >>> print s.batches[0].tostring()
       <DAZzle Test="YES">
           <Package ID="1">
               <ToName>Some Body</ToName>
               <DateAdvance>1</DateAdvance>
               <Services COD="ON" />
           </Package>
       </DAZzle>
   
       >>> print s.batches[1].tostring()
       <DAZzle Test="NO">
           <Package ID="1">
               <ToName>No Body</ToName>
               <DateAdvance>1</DateAdvance>
               <Services COD="ON" />
           </Package>
       </DAZzle>
   
   
   
   Invoking DAZzle
   ===============
   
   
 Application Integration  Application Integration
 =======================  =======================
   
 DocInfo yielding, Status handling, Address updating, ...  Status handling, Address updating, ...
   
   
 Advanced Customization  Advanced Customization
 ======================  ======================
   
 Using DocInfo elements  Using DocInfo elements, add_to_package()
   
   
 -----------------  -----------------
Line 86 
Line 348 
   
 MailClass(text), NoPostage  MailClass(text), NoPostage
   
 DateAdvance, Today, Tomorrow  DateAdvance(), Today, Tomorrow
 WeightOz(), Width(), Length(), Depth()  WeightOz(), Width(), Length(), Depth()
 Value  Value()
 Description  Description()
   
 Addresses  Addresses
 =========  =========
Line 211 
Line 473 
     >>> p = Package(b)      >>> p = Package(b)
   
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle><Package ID="1" /></DAZzle>      <DAZzle>
           <Package ID="1" />
       </DAZzle>
   
     >>> Box = DocInfo('FlatRate', 'BOX')      >>> Box = DocInfo('FlatRate', 'BOX')
     >>> add_to_package(Box, p, False)      >>> add_to_package(Box, p, False)
   
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle><Package ID="1"><FlatRate>BOX</FlatRate></Package></DAZzle>      <DAZzle>
           <Package ID="1">
               <FlatRate>BOX</FlatRate>
           </Package>
       </DAZzle>
   
     >>> Envelope = DocInfo('FlatRate', 'TRUE')      >>> Envelope = DocInfo('FlatRate', 'TRUE')
     >>> add_to_package(Envelope, p, False)      >>> add_to_package(Envelope, p, False)
Line 226 
Line 494 
     DocInfoConflict: Can't set 'FlatRate=TRUE' when 'FlatRate=BOX' already set      DocInfoConflict: Can't set 'FlatRate=TRUE' when 'FlatRate=BOX' already set
   
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle><Package ID="1"><FlatRate>BOX</FlatRate></Package></DAZzle>      <DAZzle>
           <Package ID="1">
               <FlatRate>BOX</FlatRate>
           </Package>
       </DAZzle>
   
     >>> add_to_package(Box, p, False)      >>> add_to_package(Box, p, False)
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle><Package ID="1"><FlatRate>BOX</FlatRate></Package></DAZzle>      <DAZzle>
           <Package ID="1">
               <FlatRate>BOX</FlatRate>
           </Package>
       </DAZzle>
   
     >>> add_to_package(Envelope, p, True)      >>> add_to_package(Envelope, p, True)
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle><Package ID="1"><FlatRate>BOX</FlatRate></Package></DAZzle>      <DAZzle>
           <Package ID="1">
     >>> del p.element[-1]              <FlatRate>BOX</FlatRate>
     >>> print b.tostring()          </Package>
     <DAZzle><Package ID="1" /></DAZzle>      </DAZzle>
   
       >>> del p.element[-1]; p.element.text=''
       >>> print b.tostring()
       <DAZzle>
           <Package ID="1" />
       </DAZzle>
   
     >>> verify_zip = DocInfo('DAZzle', 'DAZ', 'Start')      >>> verify_zip = DocInfo('DAZzle', 'DAZ', 'Start')
   
     >>> add_to_package(verify_zip, p, False)      >>> add_to_package(verify_zip, p, False)
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle Start="DAZ"><Package ID="1" /></DAZzle>      <DAZzle Start="DAZ">
           <Package ID="1" />
       </DAZzle>
   
     >>> add_to_package(DocInfo('DAZzle', 'PRINTING', 'Start'), p, False)      >>> add_to_package(DocInfo('DAZzle', 'PRINTING', 'Start'), p, False)
     Traceback (most recent call last):      Traceback (most recent call last):
       ...        ...
     DocInfoConflict: Can't set 'DAZzle.Start=PRINTING' when 'DAZzle.Start=DAZ' already set      DocInfoConflict: Can't set 'DAZzle.Start=PRINTING' when 'DAZzle.Start=DAZ' already set
   
     >>> root = ET.Element('DAZzle')  
     >>> pkg = ET.SubElement(root, 'Package', ID='1')  
     >>> print ET.tostring(root)  
     <DAZzle><Package ID="1" /></DAZzle>  
   
     >>> b = Batch()      >>> b = Batch()
     >>> p = Package(b)      >>> p = Package(b)
     >>> add_to_package([verify_zip, Envelope], p, False)      >>> add_to_package([verify_zip, Envelope], p, False)
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle Start="DAZ"><Package ID="1"><FlatRate>TRUE</FlatRate></Package></DAZzle>      <DAZzle Start="DAZ">
           <Package ID="1">
               <FlatRate>TRUE</FlatRate>
           </Package>
       </DAZzle>
   
     >>> p.should_queue(COD)      >>> p.should_queue(COD)
     True      True
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle Start="DAZ"><Package ID="1"><FlatRate>TRUE</FlatRate></Package></DAZzle>      <DAZzle Start="DAZ">
           <Package ID="1">
               <FlatRate>TRUE</FlatRate>
           </Package>
       </DAZzle>
   
     >>> p.finish()      >>> p.finish()
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle Start="DAZ"><Package ID="1"><FlatRate>TRUE</FlatRate><Services      <DAZzle Start="DAZ">
             COD="ON" /></Package></DAZzle>          <Package ID="1">
               <FlatRate>TRUE</FlatRate>
               <Services COD="ON" />
           </Package>
       </DAZzle>
   
     >>> p.should_queue(COD)      >>> p.should_queue(COD)
     False      False
   
Line 280 
Line 573 
     >>> print b.tostring()      >>> print b.tostring()
     <DAZzle />      <DAZzle />
   
     >>> b.ship(FlatRateEnvelope, FlatRateBox)      >>> b.add_package(FlatRateEnvelope, FlatRateBox)
     Traceback (most recent call last):      Traceback (most recent call last):
       ...        ...
     DocInfoConflict: Can't set 'PackageType=FLATRATEBOX' when      DocInfoConflict: Can't set 'PackageType=FLATRATEBOX' when
Line 293 
Line 586 
 Misc shipment::  Misc shipment::
   
     >>> s = Shipment(verify_zip)      >>> s = Shipment(verify_zip)
     >>> s.ship(Box)      >>> s.add_package(Box)
     >>> s.ship(Envelope)      >>> s.add_package(Envelope)
     >>> root, = s.batches      >>> root, = s.batches
     >>> print root.tostring()      >>> print root.tostring()
     <DAZzle Start="DAZ"><Package      <DAZzle Start="DAZ">
     ID="1"><FlatRate>BOX</FlatRate></Package><Package          <Package ID="1">
     ID="2"><FlatRate>TRUE</FlatRate></Package></DAZzle>              <FlatRate>BOX</FlatRate>
           </Package>
           <Package ID="2">
               <FlatRate>TRUE</FlatRate>
           </Package>
       </DAZzle>
   
   
 DocInfo inversion::  DocInfo inversion::
Line 320 
Line 618 
     DocInfo('DAZzle', 'YES', 'Prompt')      DocInfo('DAZzle', 'YES', 'Prompt')
   
   
   
   
 The ``iter_docinfo()`` generic function yields "docinfo" objects for an  The ``iter_docinfo()`` generic function yields "docinfo" objects for an
 application object.  The default implementation is to raise an error::  application object.  The default implementation is to raise an error::
   


Generate output suitable for use with a patch program
Legend:
Removed from v.2319  
changed lines
  Added in v.2320

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help