Extending ATContentTypes

 RichDocument extends ATDocument from ATContentTypes. Doing so is relatively easy. Before we look at the code that achieves this, though, let's consider the package layout of RichDocument::
 
 __init__.py
 config.py
 
 interfaces/
 interfaces/richdocument.py
 
 content/
 content/__init__.py
 content/attachments.py
 content/richdocument.py

 widget/
 widget/__init__.py
 widget/attachments.py
 widget/images.py

 Extensions/Install.py
 Extensions/utils.py
 
 skins/
 skins/RichDocument/*
 skins/attachment_widgets/*

 tests/
 tests/framework.py
 tests/runalltests.py
 tests/testSetup.py
 tests/testSkeleton.py

This layout follows the ATContentTypes conventions for content types. In particular, note the preference for singular module names ('widget', 'content'), and module names in all lowercase. This makes it easier to distinguish between modules and classes being imported from them, for example.

Considering the major pieces in turn:

__init__.py -- This file is run when Zope loads the RichDocument product. It contains the code to initialise the product so that Zope understands it. It also registers the FileSystemDirectoryViews for the 'skins' folder, which means that after RichDocument is installed, 'portal_skins/RichDocument' will mirror the contents of the 'skins/RichDocument' folder, for example.

config.py -- Contains configuration constants, including the name of the product and the add-contents permission to use

The interfaces/ folder -- Contains the interfaces defined in this product. The 'IRichDocument' interface extends the 'IDocument' interface from ATContentTypes to indicate that content types which declare they provide this interface are also implicitly declaring they support everything 'IDocument' is providing. Defining interfaces are not strictly necessary for the content type to work, but is good practice, as they provide documentation and the ability to assert certain things about your classes.

The content/ folder -- Contains the actual content types. 'richdocument.py' contains the RichDocument type, whilst 'attachments.py' contains the ImageAttachment and FileAttachment types used to hold uploaded images and file attachments. The '__init__.py' file loads these, so that to import RichDocument, all you need to write is 'from Products.RichDocument.content import RichDocument'.

The widget/ folder -- Contains the custom widgets RichDocument uses in a module that's initialised by '__init__.py' in a similar way to 'content/__init__.py'. RichDocument defines two fairly complex widgets which use form controller actions in order to support in-form upload and management of images and attachments.

The Extensions/ folder -- Contains the installation External Methods. The file 'Install.py' is read by the QuickInstaller in Plone and its 'install()' and 'uninstall()' methods are executed when the product is installed or uninstalled. The 'utils.py' file contains some additional setup methods called from the main 'install()' method.

The skins/ folder -- The standard installation machinery makes sure that the 'skins/RichDocument' and 'skins/attachment_widget' folders are registered with 'portal_skins'. This makes the page templates and python scripts used by RichDocument and its images/attachments upload widgets available in the portal after it has been installed.

The tests/ folder -- This folder contains the unit tests and test framework. PloneTestCase and its dependencies are needed to run the tests. The 'framework.py' and 'runalltests.py' files are boilerplate needed in all tests' directories. 'testSkeleton.py' is a skeleton file that can be used as a template for new tests, whilst 'testSetup.py' contains the only unit tests currently written for RichDocument.