added integrator package: transparent access to filesystem directories and files
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2441 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									fc6660a457
								
							
						
					
					
						commit
						d505f3629a
					
				
					 10 changed files with 430 additions and 0 deletions
				
			
		
							
								
								
									
										58
									
								
								integrator/README.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								integrator/README.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| ========================================= | ||||
| Integrating objects from external systems | ||||
| ========================================= | ||||
| 
 | ||||
| Integration of external sources. | ||||
| 
 | ||||
|   ($Id$) | ||||
| 
 | ||||
| 
 | ||||
| Getting started | ||||
| =============== | ||||
| 
 | ||||
| Let's do some basic set up | ||||
| 
 | ||||
|   >>> from zope import component, interface | ||||
| 
 | ||||
|   >>> from cybertools.integrator.tests import testDir | ||||
|   >>> from cybertools.integrator.filesystem import ContainerFactory, FileFactory | ||||
|   >>> from cybertools.integrator.interfaces import IContainerFactory | ||||
|   >>> component.provideUtility(ContainerFactory(), name='filesystem') | ||||
|   >>> component.provideUtility(FileFactory(), name='filesystem') | ||||
| 
 | ||||
| 
 | ||||
| Accessing Objects in the Filesystem | ||||
| ======================================= | ||||
| 
 | ||||
|   >>> top = component.getUtility(IContainerFactory, name='filesystem')(testDir) | ||||
|   >>> sorted(top) | ||||
|   ['index.html', 'sub'] | ||||
|   >>> len(top) | ||||
|   2 | ||||
| 
 | ||||
|   >>> sub = top['sub'] | ||||
|   >>> sorted(sub) | ||||
|   ['demo.tgz', 'index.html', 'loops_logo.png'] | ||||
| 
 | ||||
|   >>> file = sub['demo.tgz'] | ||||
|   >>> file.contentType | ||||
|   'application/x-tar' | ||||
|   >>> file.getSize() | ||||
|   432L | ||||
| 
 | ||||
|   >>> logo = sub['loops_logo.png'] | ||||
|   >>> logo.contentType | ||||
|   'image/png' | ||||
|   >>> logo.getImageSize() | ||||
|   (145, 42) | ||||
| 
 | ||||
|   >>> html = top['index.html'] | ||||
|   >>> html.contentType | ||||
|   'text/html' | ||||
|   >>> print html.data | ||||
|   <html>... | ||||
|       <img src="sub/loops_logo.png" /> | ||||
|       <a href="sub">Subdirectory</a> | ||||
|       <a href="sub/demo.tgz">Demo</a>... | ||||
|   </html>... | ||||
| 
 | ||||
							
								
								
									
										3
									
								
								integrator/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								integrator/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| """ | ||||
| $Id$ | ||||
| """ | ||||
							
								
								
									
										134
									
								
								integrator/base.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								integrator/base.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,134 @@ | |||
| # | ||||
| #  Copyright (c) 2008 Helmut Merz helmutm@cy55.de | ||||
| # | ||||
| #  This program is free software; you can redistribute it and/or modify | ||||
| #  it under the terms of the GNU General Public License as published by | ||||
| #  the Free Software Foundation; either version 2 of the License, or | ||||
| #  (at your option) any later version. | ||||
| # | ||||
| #  This program is distributed in the hope that it will be useful, | ||||
| #  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| #  GNU General Public License for more details. | ||||
| # | ||||
| #  You should have received a copy of the GNU General Public License | ||||
| #  along with this program; if not, write to the Free Software | ||||
| #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| 
 | ||||
| """ | ||||
| Base implementation for accessing external content objects. | ||||
| 
 | ||||
| $Id$ | ||||
| """ | ||||
| 
 | ||||
| from zope.app.container.contained import Contained | ||||
| from zope.cachedescriptors.property import Lazy | ||||
| from zope import component | ||||
| from zope.interface import implements | ||||
| 
 | ||||
| from cybertools.integrator.interfaces import IContainerFactory, IFileFactory | ||||
| from cybertools.integrator.interfaces import IReadContainer, IFile, IImage | ||||
| 
 | ||||
| 
 | ||||
| # proxy base (sample) classes | ||||
| 
 | ||||
| class ReadContainer(Contained): | ||||
| 
 | ||||
|     implements(IReadContainer) | ||||
| 
 | ||||
|     factoryName = 'sample' | ||||
| 
 | ||||
|     def __init__(self, address, **kw): | ||||
|         self.address = address | ||||
| 
 | ||||
|     @Lazy | ||||
|     def fileFactory(self): | ||||
|         return component.getUtility(IFileFactory, name=self.factoryName) | ||||
| 
 | ||||
|     @Lazy | ||||
|     def containerFactory(self): | ||||
|         return component.getUtility(IContainerFactory, name=self.factoryName) | ||||
| 
 | ||||
|     def keys(self): | ||||
|         return [k for k, v in self.items()] | ||||
| 
 | ||||
|     def __iter__(self): | ||||
|         return iter(self.keys()) | ||||
| 
 | ||||
|     def __getitem__(self, key): | ||||
|         if key in self: | ||||
|             return self.get(key) | ||||
|         raise KeyError(key) | ||||
| 
 | ||||
|     def get(self, key, default=None): | ||||
|         return default | ||||
| 
 | ||||
|     def values(self): | ||||
|         return [v for k, v in self.items()] | ||||
| 
 | ||||
|     def __len__(self): | ||||
|         return len(self.keys()) | ||||
| 
 | ||||
|     def items(self): | ||||
|         return [] | ||||
| 
 | ||||
|     def __contains__(self, key): | ||||
|         return key in self.keys() | ||||
| 
 | ||||
|     has_key = __contains__ | ||||
| 
 | ||||
| 
 | ||||
| class File(object): | ||||
| 
 | ||||
|     implements(IFile) | ||||
| 
 | ||||
|     contentType = None | ||||
|     data = None | ||||
| 
 | ||||
|     def __init__(self, address, contentType, **kw): | ||||
|         self.address = address | ||||
|         self.contentType = contentType | ||||
|         for k, v in kw.items(): | ||||
|             setattr(self, k, v) | ||||
| 
 | ||||
|     def getData(self, num=None): | ||||
|         return '' | ||||
| 
 | ||||
|     data = property(getData) | ||||
| 
 | ||||
|     def getSize(self): | ||||
|         return len(self.data) | ||||
| 
 | ||||
| 
 | ||||
| def Image(File): | ||||
| 
 | ||||
|     implements(IImage) | ||||
| 
 | ||||
|     def getImageSize(self): | ||||
|         return 0, 0 | ||||
| 
 | ||||
| 
 | ||||
| # factory base (sample) classes | ||||
| 
 | ||||
| class Factory(object): | ||||
| 
 | ||||
|     proxyClass = ReadContainer | ||||
| 
 | ||||
|     def __call__(self, address, **kw): | ||||
|         return self.proxyClass(address, **kw) | ||||
| 
 | ||||
| 
 | ||||
| class ContainerFactory(Factory): | ||||
| 
 | ||||
|     implements(IContainerFactory) | ||||
| 
 | ||||
|     proxyClass = ReadContainer | ||||
| 
 | ||||
| 
 | ||||
| class FileFactory(Factory): | ||||
| 
 | ||||
|     implements(IFileFactory) | ||||
| 
 | ||||
|     proxyClass = File   # real implementations should also care about images | ||||
| 
 | ||||
							
								
								
									
										130
									
								
								integrator/filesystem.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								integrator/filesystem.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | |||
| # | ||||
| #  Copyright (c) 2008 Helmut Merz helmutm@cy55.de | ||||
| # | ||||
| #  This program is free software; you can redistribute it and/or modify | ||||
| #  it under the terms of the GNU General Public License as published by | ||||
| #  the Free Software Foundation; either version 2 of the License, or | ||||
| #  (at your option) any later version. | ||||
| # | ||||
| #  This program is distributed in the hope that it will be useful, | ||||
| #  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| #  GNU General Public License for more details. | ||||
| # | ||||
| #  You should have received a copy of the GNU General Public License | ||||
| #  along with this program; if not, write to the Free Software | ||||
| #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| 
 | ||||
| """ | ||||
| Access to objects in the file system. | ||||
| 
 | ||||
| $Id$ | ||||
| """ | ||||
| 
 | ||||
| import os, stat | ||||
| 
 | ||||
| from zope import component | ||||
| from zope.app.file.image import getImageInfo | ||||
| from zope.cachedescriptors.property import Lazy | ||||
| from zope.contenttype import guess_content_type | ||||
| from zope.interface import implements, Attribute | ||||
| 
 | ||||
| from cybertools.integrator.base import ContainerFactory, FileFactory | ||||
| from cybertools.integrator.base import ReadContainer, File, Image | ||||
| from cybertools.text import mimetypes | ||||
| 
 | ||||
| 
 | ||||
| # proxy classes | ||||
| 
 | ||||
| class ReadContainer(ReadContainer): | ||||
| 
 | ||||
|     factoryName = 'filesystem' | ||||
| 
 | ||||
|     @Lazy | ||||
|     def filenames(self): | ||||
|         return os.listdir(self.address) | ||||
| 
 | ||||
|     def keys(self): | ||||
|         return self.filenames | ||||
| 
 | ||||
|     def __iter__(self): | ||||
|         return iter(self.keys()) | ||||
| 
 | ||||
|     def __getitem__(self, key): | ||||
|         if key in self: | ||||
|             return self.get(key) | ||||
|         raise KeyError(key) | ||||
| 
 | ||||
|     def get(self, key, default=None): | ||||
|         if key not in self.keys(): | ||||
|             return default | ||||
|         path = os.path.join(self.address, key) | ||||
|         if os.path.isdir(path): | ||||
|             return self.containerFactory(path) | ||||
|         else: | ||||
|             return self.fileFactory(path) | ||||
| 
 | ||||
|     def values(self): | ||||
|         return [self.get(k) for k in self] | ||||
| 
 | ||||
|     def __len__(self): | ||||
|         return len(self.keys()) | ||||
| 
 | ||||
|     def items(self): | ||||
|         return [(k, self.get(k)) for k in self] | ||||
| 
 | ||||
|     def __contains__(self, key): | ||||
|         return key in self.keys() | ||||
| 
 | ||||
| 
 | ||||
| class File(File): | ||||
| 
 | ||||
|     contentType = None | ||||
|     data = None | ||||
| 
 | ||||
|     def getData(self, num=-1): | ||||
|         f = open(self.address, 'r') | ||||
|         data = f.read(num) | ||||
|         f.close() | ||||
|         return data | ||||
| 
 | ||||
|     data = property(getData) | ||||
| 
 | ||||
|     def getSize(self): | ||||
|         return os.stat(self.address)[stat.ST_SIZE] | ||||
| 
 | ||||
| 
 | ||||
| class Image(File): | ||||
| 
 | ||||
|     width = height = 0 | ||||
| 
 | ||||
|     def getImageSize(self): | ||||
|         return self.width, self.height | ||||
| 
 | ||||
| 
 | ||||
| # factory classes | ||||
| 
 | ||||
| class ContainerFactory(ContainerFactory): | ||||
| 
 | ||||
|     proxyClass = ReadContainer | ||||
| 
 | ||||
| 
 | ||||
| class FileFactory(FileFactory): | ||||
| 
 | ||||
|     def __call__(self, address, **kw): | ||||
|         contentType = kw.pop('contentType', None) | ||||
|         width = height = 0 | ||||
|         obj = File(address, contentType, **kw) | ||||
|         if not contentType: | ||||
|             data = obj.getData(50) | ||||
|             contentType, width, height = getImageInfo(data) | ||||
|         if not contentType: | ||||
|             name = os.path.basename(address) | ||||
|             contentType, encoding = guess_content_type(name, data, '') | ||||
|         if contentType.startswith('image/'): | ||||
|             return Image(address, contentType=contentType, | ||||
|                          width=width, height=height, **kw) | ||||
|         else: | ||||
|             obj.contentType = contentType | ||||
|             return obj | ||||
							
								
								
									
										59
									
								
								integrator/interfaces.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								integrator/interfaces.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| # | ||||
| #  Copyright (c) 2008 Helmut Merz helmutm@cy55.de | ||||
| # | ||||
| #  This program is free software; you can redistribute it and/or modify | ||||
| #  it under the terms of the GNU General Public License as published by | ||||
| #  the Free Software Foundation; either version 2 of the License, or | ||||
| #  (at your option) any later version. | ||||
| # | ||||
| #  This program is distributed in the hope that it will be useful, | ||||
| #  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| #  GNU General Public License for more details. | ||||
| # | ||||
| #  You should have received a copy of the GNU General Public License | ||||
| #  along with this program; if not, write to the Free Software | ||||
| #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| 
 | ||||
| """ | ||||
| External content integration interfaces. | ||||
| 
 | ||||
| $Id$ | ||||
| """ | ||||
| 
 | ||||
| from zope.app.container.interfaces import IReadContainer | ||||
| from zope.app.file.interfaces import IFile, IImage | ||||
| from zope.app.publication.interfaces import IFileContent | ||||
| from zope.interface import Interface, Attribute | ||||
| 
 | ||||
| 
 | ||||
| class IFile(IFile, IFileContent): | ||||
| 
 | ||||
|     def getData(num): | ||||
|         """ Return num bytes from the file`s data. | ||||
|         """ | ||||
| 
 | ||||
| 
 | ||||
| class IProxyFactory(Interface): | ||||
|     """ Creates proxy objects for external objects. | ||||
|     """ | ||||
| 
 | ||||
|     def __call__(address, **kw): | ||||
|         """ Return a proxy object based on an external object that | ||||
|             can be accessed using the address (and optional | ||||
|             keyword arguments) given. | ||||
|         """ | ||||
| 
 | ||||
| 
 | ||||
| class IContainerFactory(IProxyFactory): | ||||
|     """ Creates container proxy objects for the external specification | ||||
|         given. | ||||
|     """ | ||||
| 
 | ||||
| 
 | ||||
| class IFileFactory(IProxyFactory): | ||||
|     """ Creates file proxy objects for the external specification | ||||
|         given. | ||||
|     """ | ||||
| 
 | ||||
							
								
								
									
										9
									
								
								integrator/testdata/index.html
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								integrator/testdata/index.html
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| <html> | ||||
|   <head> | ||||
|   </head> | ||||
|   <body> | ||||
|     <img src="sub/loops_logo.png" /> | ||||
|     <a href="sub">Subdirectory</a> | ||||
|     <a href="sub/demo.tgz">Demo</a> | ||||
|   </body> | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								integrator/testdata/sub/demo.tgz
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								integrator/testdata/sub/demo.tgz
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										9
									
								
								integrator/testdata/sub/index.html
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								integrator/testdata/sub/index.html
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| <html> | ||||
|   <head> | ||||
|   </head> | ||||
|   <body> | ||||
|     <img src="loops_logo.png" /> | ||||
|     <a href="demo.tgz">Demo</a> | ||||
|     <a href="..">Up</a> | ||||
|   </body> | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								integrator/testdata/sub/loops_logo.png
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								integrator/testdata/sub/loops_logo.png
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										28
									
								
								integrator/tests.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										28
									
								
								integrator/tests.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| # $Id$ | ||||
| 
 | ||||
| import os | ||||
| import unittest, doctest | ||||
| from zope.testing.doctestunit import DocFileSuite | ||||
| from zope.interface.verify import verifyClass | ||||
| 
 | ||||
| 
 | ||||
| baseDir = os.path.dirname(__file__) | ||||
| testDir = os.path.join(baseDir, 'testdata') | ||||
| 
 | ||||
| 
 | ||||
| class Test(unittest.TestCase): | ||||
|     "Basic tests for the cybertools.integrator package." | ||||
| 
 | ||||
|     def testSomething(self): | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| def test_suite(): | ||||
|     flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS | ||||
|     return unittest.TestSuite(( | ||||
|                 unittest.makeSuite(Test), | ||||
|                 DocFileSuite('README.txt', optionflags=flags), | ||||
|             )) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     unittest.main(defaultTest='test_suite') | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm