You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@oodt.apache.org by ke...@apache.org on 2010/03/21 23:08:02 UTC
svn commit: r925913 [1/2] - in /incubator/oodt/agility/agile-oodt/trunk: ./
docs/ oodt/ oodt/tests/
Author: kelly
Date: Sun Mar 21 22:08:01 2010
New Revision: 925913
URL: http://svn.apache.org/viewvc?rev=925913&view=rev
Log:
Initial Apache drop of Agile OODT with test cases refactored, Python 2.6 compatibility, and ASF headers/license/notice.
Added:
incubator/oodt/agility/agile-oodt/trunk/NOTICE.txt
incubator/oodt/agility/agile-oodt/trunk/README.txt
incubator/oodt/agility/agile-oodt/trunk/distribute_setup.py
incubator/oodt/agility/agile-oodt/trunk/docs/
incubator/oodt/agility/agile-oodt/trunk/docs/HISTORY.txt
incubator/oodt/agility/agile-oodt/trunk/docs/INSTALL.txt
incubator/oodt/agility/agile-oodt/trunk/docs/LICENSE.txt
incubator/oodt/agility/agile-oodt/trunk/oodt/ (with props)
incubator/oodt/agility/agile-oodt/trunk/oodt/__init__.py
incubator/oodt/agility/agile-oodt/trunk/oodt/oodterrors.py
incubator/oodt/agility/agile-oodt/trunk/oodt/profile.py
incubator/oodt/agility/agile-oodt/trunk/oodt/query.py
incubator/oodt/agility/agile-oodt/trunk/oodt/tests/ (with props)
incubator/oodt/agility/agile-oodt/trunk/oodt/tests/__init__.py
incubator/oodt/agility/agile-oodt/trunk/oodt/tests/profileTest.py
incubator/oodt/agility/agile-oodt/trunk/oodt/tests/queryTest.py
incubator/oodt/agility/agile-oodt/trunk/oodt/tests/xmlutilsTest.py
incubator/oodt/agility/agile-oodt/trunk/oodt/webgrid.py
incubator/oodt/agility/agile-oodt/trunk/oodt/xmlutils.py
incubator/oodt/agility/agile-oodt/trunk/setup.cfg
incubator/oodt/agility/agile-oodt/trunk/setup.py
Modified:
incubator/oodt/agility/agile-oodt/trunk/ (props changed)
Propchange: incubator/oodt/agility/agile-oodt/trunk/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Mar 21 22:08:01 2010
@@ -0,0 +1,11 @@
+._*
+.DS_Store
+*.log
+*.pyc
+*.pyo
+*.egg-info
+dist
+build
+distribute-*.tar.gz
+distribute-*.egg
+doc.txt
Added: incubator/oodt/agility/agile-oodt/trunk/NOTICE.txt
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/NOTICE.txt?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/NOTICE.txt (added)
+++ incubator/oodt/agility/agile-oodt/trunk/NOTICE.txt Sun Mar 21 22:08:01 2010
@@ -0,0 +1,7 @@
+Agile Object Oriented Data Technology (OODT)
+Copyright 2010 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This is licensed software; see the docs/LICENSE.txt file.
Added: incubator/oodt/agility/agile-oodt/trunk/README.txt
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/README.txt?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/README.txt (added)
+++ incubator/oodt/agility/agile-oodt/trunk/README.txt Sun Mar 21 22:08:01 2010
@@ -0,0 +1,17 @@
+Agile OODT is a new version of `Object Oriented Data Technology`_. It
+improves upon the previous version by being easier to develop, maintain, and
+extend; simpler to integrate by; and faster to use.
+
+.. This is licensed software; see the files NOTICE.txt and docs/LICENSE.txt.
+
+.. For installation instructions, see docs/INSTALL.txt.
+
+.. References:
+.. _`Object Oriented Data Technology`: http://incubator.apache.org/projects/oodt.html
+
+.. meta::
+ :keywords: OODT, data, object, OO, discovery, metadata,
+ transfer, transformation, query, search, retrieval
+ :description lang=en: Agile OODT, the nimble version of
+ Object Oriented Data Technology
+
Added: incubator/oodt/agility/agile-oodt/trunk/distribute_setup.py
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/distribute_setup.py?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/distribute_setup.py (added)
+++ incubator/oodt/agility/agile-oodt/trunk/distribute_setup.py Sun Mar 21 22:08:01 2010
@@ -0,0 +1,477 @@
+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from distribute_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+ from site import USER_SITE
+except ImportError:
+ USER_SITE = None
+
+try:
+ import subprocess
+
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ return subprocess.call(args) == 0
+
+except ImportError:
+ # will be used for python 2.3
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ # quoting arguments if windows
+ if sys.platform == 'win32':
+ def quote(arg):
+ if ' ' in arg:
+ return '"%s"' % arg
+ return arg
+ args = [quote(arg) for arg in args]
+ return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.10"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # installing
+ log.warn('Installing Distribute')
+ if not _python_cmd('setup.py', 'install'):
+ log.warn('Something went wrong during the installation.')
+ log.warn('See the error message above.')
+ finally:
+ os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # building an egg
+ log.warn('Building a Distribute egg in %s', to_dir)
+ _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+ finally:
+ os.chdir(old_wd)
+ # returning the result
+ log.warn(egg)
+ if not os.path.exists(egg):
+ raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+ egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+ % (version, sys.version_info[0], sys.version_info[1]))
+ if not os.path.exists(egg):
+ tarball = download_setuptools(version, download_base,
+ to_dir, download_delay)
+ _build_egg(egg, tarball, to_dir)
+ sys.path.insert(0, egg)
+ import setuptools
+ setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, download_delay=15, no_fake=True):
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ was_imported = 'pkg_resources' in sys.modules or \
+ 'setuptools' in sys.modules
+ try:
+ try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ if not no_fake:
+ _fake_setuptools()
+ raise ImportError
+ except ImportError:
+ return _do_download(version, download_base, to_dir, download_delay)
+ try:
+ pkg_resources.require("distribute>="+version)
+ return
+ except pkg_resources.VersionConflict:
+ e = sys.exc_info()[1]
+ if was_imported:
+ sys.stderr.write(
+ "The required version of distribute (>=%s) is not available,\n"
+ "and can't be installed while this script is running. Please\n"
+ "install a more recent version first, using\n"
+ "'easy_install -U distribute'."
+ "\n\n(Currently using %r)\n" % (version, e.args[0]))
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ except pkg_resources.DistributionNotFound:
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ finally:
+ if not no_fake:
+ _create_fake_setuptools_pkg_info(to_dir)
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, delay=15):
+ """Download distribute from a specified location and return its filename
+
+ `version` should be a valid distribute version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download
+ attempt.
+ """
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+ tgz_name = "distribute-%s.tar.gz" % version
+ url = download_base + tgz_name
+ saveto = os.path.join(to_dir, tgz_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ log.warn("Downloading %s", url)
+ src = urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = src.read()
+ dst = open(saveto, "wb")
+ dst.write(data)
+ finally:
+ if src:
+ src.close()
+ if dst:
+ dst.close()
+ return os.path.realpath(saveto)
+
+
+def _patch_file(path, content):
+ """Will backup the file then patch it"""
+ existing_content = open(path).read()
+ if existing_content == content:
+ # already patched
+ log.warn('Already patched.')
+ return False
+ log.warn('Patching...')
+ _rename_path(path)
+ f = open(path, 'w')
+ try:
+ f.write(content)
+ finally:
+ f.close()
+ return True
+
+
+def _same_content(path, content):
+ return open(path).read() == content
+
+def _no_sandbox(function):
+ def __no_sandbox(*args, **kw):
+ try:
+ from setuptools.sandbox import DirectorySandbox
+ def violation(*args):
+ pass
+ DirectorySandbox._old = DirectorySandbox._violation
+ DirectorySandbox._violation = violation
+ patched = True
+ except ImportError:
+ patched = False
+
+ try:
+ return function(*args, **kw)
+ finally:
+ if patched:
+ DirectorySandbox._violation = DirectorySandbox._old
+ del DirectorySandbox._old
+
+ return __no_sandbox
+
+@_no_sandbox
+def _rename_path(path):
+ new_name = path + '.OLD.%s' % time.time()
+ log.warn('Renaming %s into %s', path, new_name)
+ os.rename(path, new_name)
+ return new_name
+
+def _remove_flat_installation(placeholder):
+ if not os.path.isdir(placeholder):
+ log.warn('Unkown installation at %s', placeholder)
+ return False
+ found = False
+ for file in os.listdir(placeholder):
+ if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+ found = True
+ break
+ if not found:
+ log.warn('Could not locate setuptools*.egg-info')
+ return
+
+ log.warn('Removing elements out of the way...')
+ pkg_info = os.path.join(placeholder, file)
+ if os.path.isdir(pkg_info):
+ patched = _patch_egg_dir(pkg_info)
+ else:
+ patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+ if not patched:
+ log.warn('%s already patched.', pkg_info)
+ return False
+ # now let's move the files out of the way
+ for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+ element = os.path.join(placeholder, element)
+ if os.path.exists(element):
+ _rename_path(element)
+ else:
+ log.warn('Could not find the %s element of the '
+ 'Setuptools distribution', element)
+ return True
+
+
+def _after_install(dist):
+ log.warn('After install bootstrap.')
+ placeholder = dist.get_command_obj('install').install_purelib
+ _create_fake_setuptools_pkg_info(placeholder)
+
+@_no_sandbox
+def _create_fake_setuptools_pkg_info(placeholder):
+ if not placeholder or not os.path.exists(placeholder):
+ log.warn('Could not find the install location')
+ return
+ pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+ setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+ (SETUPTOOLS_FAKED_VERSION, pyver)
+ pkg_info = os.path.join(placeholder, setuptools_file)
+ if os.path.exists(pkg_info):
+ log.warn('%s already exists', pkg_info)
+ return
+
+ log.warn('Creating %s', pkg_info)
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+
+ pth_file = os.path.join(placeholder, 'setuptools.pth')
+ log.warn('Creating %s', pth_file)
+ f = open(pth_file, 'w')
+ try:
+ f.write(os.path.join(os.curdir, setuptools_file))
+ finally:
+ f.close()
+
+def _patch_egg_dir(path):
+ # let's check if it's already patched
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ if os.path.exists(pkg_info):
+ if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+ log.warn('%s already patched.', pkg_info)
+ return False
+ _rename_path(path)
+ os.mkdir(path)
+ os.mkdir(os.path.join(path, 'EGG-INFO'))
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+ return True
+
+
+def _before_install():
+ log.warn('Before install bootstrap.')
+ _fake_setuptools()
+
+
+def _under_prefix(location):
+ if 'install' not in sys.argv:
+ return True
+ args = sys.argv[sys.argv.index('install')+1:]
+ for index, arg in enumerate(args):
+ for option in ('--root', '--prefix'):
+ if arg.startswith('%s=' % option):
+ top_dir = arg.split('root=')[-1]
+ return location.startswith(top_dir)
+ elif arg == option:
+ if len(args) > index:
+ top_dir = args[index+1]
+ return location.startswith(top_dir)
+ elif option == '--user' and USER_SITE is not None:
+ return location.startswith(USER_SITE)
+ return True
+
+
+def _fake_setuptools():
+ log.warn('Scanning installed packages')
+ try:
+ import pkg_resources
+ except ImportError:
+ # we're cool
+ log.warn('Setuptools or Distribute does not seem to be installed.')
+ return
+ ws = pkg_resources.working_set
+ try:
+ setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
+ replacement=False))
+ except TypeError:
+ # old distribute API
+ setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
+
+ if setuptools_dist is None:
+ log.warn('No setuptools distribution found')
+ return
+ # detecting if it was already faked
+ setuptools_location = setuptools_dist.location
+ log.warn('Setuptools installation detected at %s', setuptools_location)
+
+ # if --root or --preix was provided, and if
+ # setuptools is not located in them, we don't patch it
+ if not _under_prefix(setuptools_location):
+ log.warn('Not patching, --root or --prefix is installing Distribute'
+ ' in another location')
+ return
+
+ # let's see if its an egg
+ if not setuptools_location.endswith('.egg'):
+ log.warn('Non-egg installation')
+ res = _remove_flat_installation(setuptools_location)
+ if not res:
+ return
+ else:
+ log.warn('Egg installation')
+ pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+ if (os.path.exists(pkg_info) and
+ _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+ log.warn('Already patched.')
+ return
+ log.warn('Patching...')
+ # let's create a fake egg replacing setuptools one
+ res = _patch_egg_dir(setuptools_location)
+ if not res:
+ return
+ log.warn('Patched done.')
+ _relaunch()
+
+
+def _relaunch():
+ log.warn('Relaunching...')
+ # we have to relaunch the process
+ args = [sys.executable] + sys.argv
+ sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+ """Extract all members from the archive to the current working
+ directory and set owner, modification time and permissions on
+ directories afterwards. `path' specifies a different directory
+ to extract to. `members' is optional and must be a subset of the
+ list returned by getmembers().
+ """
+ import copy
+ import operator
+ from tarfile import ExtractError
+ directories = []
+
+ if members is None:
+ members = self
+
+ for tarinfo in members:
+ if tarinfo.isdir():
+ # Extract directories with a safe mode.
+ directories.append(tarinfo)
+ tarinfo = copy.copy(tarinfo)
+ tarinfo.mode = 448 # decimal for oct 0700
+ self.extract(tarinfo, path)
+
+ # Reverse sort directories.
+ if sys.version_info < (2, 4):
+ def sorter(dir1, dir2):
+ return cmp(dir1.name, dir2.name)
+ directories.sort(sorter)
+ directories.reverse()
+ else:
+ directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+ # Set correct owner, mtime and filemode on directories.
+ for tarinfo in directories:
+ dirpath = os.path.join(path, tarinfo.name)
+ try:
+ self.chown(tarinfo, dirpath)
+ self.utime(tarinfo, dirpath)
+ self.chmod(tarinfo, dirpath)
+ except ExtractError:
+ e = sys.exc_info()[1]
+ if self.errorlevel > 1:
+ raise
+ else:
+ self._dbg(1, "tarfile: %s" % e)
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ tarball = download_setuptools()
+ _install(tarball)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
Added: incubator/oodt/agility/agile-oodt/trunk/docs/HISTORY.txt
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/docs/HISTORY.txt?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/docs/HISTORY.txt (added)
+++ incubator/oodt/agility/agile-oodt/trunk/docs/HISTORY.txt Sun Mar 21 22:08:01 2010
@@ -0,0 +1,30 @@
+Changelog
+=========
+
+What follows is a history of changes to this software.
+
+
+1.0.0 - Initial Apache Release
+------------------------------
+
+This release marks the induction of Agile OODT into the Apache Software
+Foundation's Incubator_, and in celebration we call it version 1 (finally).
+
+
+0.0.1 - Package Cleanup
+-----------------------
+
+This release merely cleaned up the harsh edges in the packaging of Agile OODT.
+It made the package more amenable to setuptools.
+
+
+0.0.0 - FCS
+-----------
+
+The first customer ship of OODT Agility. This software was used to implement
+the Planetary Data Access Protocol (PDAP) for the IPDA_.
+
+
+.. References:
+.. _IPDA: http://planetarydata.org/
+.. _Incubator: http://incubator.apache.org/
\ No newline at end of file
Added: incubator/oodt/agility/agile-oodt/trunk/docs/INSTALL.txt
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/docs/INSTALL.txt?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/docs/INSTALL.txt (added)
+++ incubator/oodt/agility/agile-oodt/trunk/docs/INSTALL.txt Sun Mar 21 22:08:01 2010
@@ -0,0 +1,91 @@
+Installation
+============
+
+What follows are the installation instructions for Agile OODT.
+
+
+Quick Instructions
+------------------
+
+As a user with administrative privileges, run either::
+
+ pip oodt
+
+or::
+
+ easy_install oodt
+
+depending on what's available on your system. You're done!
+
+
+Full Instructions
+-----------------
+
+Agile OODT requires the Python_ programming language. We recommend version 2.4
+or later. As of this writing, 2.6 is the latest stable version. If Python is
+not yet installed on your system, you can find binary and and source
+distributions from the Python website.
+
+To test if a correct version of Python is available on your system, run::
+
+ python -V
+
+You should see output similar to::
+
+ Python 2.6
+
+indicating the version of Python installed. You may then proceed to install
+Agile OODT.
+
+By far the easiest, recommended, and encouraged way to install Agile OODT is
+either with Pip_ or EasyInstall_. If your Python installation has either of
+these installers available to it, then one command is all you need to run in
+order to download, build, install, and generate command-line tools all in one
+go for all users on your system. For Pip users, it's::
+
+ pip oodt
+
+And for EasyInstall users, it's::
+
+ easy_install oodt
+
+Be sure to run that command as an administrative user. For example, on Mac OS
+X and other Unix systems, you might need to run either of::
+
+ sudo pip oodt
+ sudo easy_install oodt
+
+
+Installing From Source
+~~~~~~~~~~~~~~~~~~~~~~
+
+If neither Pip nor EasyInstall are available, you can still make a proper
+installation of Agile OODT by building it from its source code. Just follow
+these instructions:
+
+1. Download the Agile OODT source distribution and extract the source
+ archive. The source distribution is packaged as a gzip'd tar archive.
+2. Change the current working directory to the newly extracted directory.
+3. As an administrative user, run: ``python setup.py install``
+
+
+For More Information
+--------------------
+
+Visit any of the following links for additional information, to ask questions,
+report bugs, and so forth:
+
+OODT Home Page
+ http://incubator.apache.org/projects/oodt.html
+Mailing List for OODT Development
+ mailto:oodt-dev@incubator.apache.org
+Package Page (Cheese Shop)
+ http://pypi.python.org/pypi/oodt/
+Issue Tracker (submit bug reports here)
+ https://issues.apache.org/jira/browse/OODT
+
+
+.. References:
+.. _EasyInstall: http://packages.python.org/distribute/easy_install.html
+.. _Pip: http://pip.openplans.org/
+.. _Python: http://python.org/
Added: incubator/oodt/agility/agile-oodt/trunk/docs/LICENSE.txt
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/docs/LICENSE.txt?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/docs/LICENSE.txt (added)
+++ incubator/oodt/agility/agile-oodt/trunk/docs/LICENSE.txt Sun Mar 21 22:08:01 2010
@@ -0,0 +1,179 @@
+License, Terms, and Conditions
+==============================
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
Propchange: incubator/oodt/agility/agile-oodt/trunk/oodt/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Mar 21 22:08:01 2010
@@ -0,0 +1,8 @@
+._*
+.DS_Store
+*.log
+*.pyc
+*.pyo
+*.egg-info
+dist
+build
Added: incubator/oodt/agility/agile-oodt/trunk/oodt/__init__.py
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/oodt/__init__.py?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/oodt/__init__.py (added)
+++ incubator/oodt/agility/agile-oodt/trunk/oodt/__init__.py Sun Mar 21 22:08:01 2010
@@ -0,0 +1,27 @@
+# encoding: utf-8
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE.txt file distributed with
+# this work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+'''Agile Object Oriented Data Technology (OODT).
+
+OODT is a set of software components that permit the discovery, correlation,
+search, and retrieval of data and metadata. For more information, see the
+OODT web site_.
+
+.. _site: http://incubator.apache.org/projects/oodt.html
+'''
+
+__docformat__ = 'restructuredtext'
Added: incubator/oodt/agility/agile-oodt/trunk/oodt/oodterrors.py
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/oodt/oodterrors.py?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/oodt/oodterrors.py (added)
+++ incubator/oodt/agility/agile-oodt/trunk/oodt/oodterrors.py Sun Mar 21 22:08:01 2010
@@ -0,0 +1,26 @@
+# encoding: utf-8
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE.txt file distributed with
+# this work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+'''Object Oriented Data Technology exceptions.
+'''
+
+__docformat__ = 'restructuredtext'
+
+class OODTException(Exception):
+ '''Common OODT exception base.
+ '''
+ pass
Added: incubator/oodt/agility/agile-oodt/trunk/oodt/profile.py
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/oodt/profile.py?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/oodt/profile.py (added)
+++ incubator/oodt/agility/agile-oodt/trunk/oodt/profile.py Sun Mar 21 22:08:01 2010
@@ -0,0 +1,502 @@
+# encoding: utf-8
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE.txt file distributed with
+# this work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+'''Profiles. A profile is a metadata description of a resource.
+
+Profiles capture:
+
+* Inception metadata. This includes items such as a resouce's title,
+ description, creators, contributors, publishers, language, and so on. This
+ set of metdata is based on the Dublin Core. Class `ResourceAttributes`
+ captures this metadata.
+
+* Composition metadata. This includes data elements that describe what
+ the resource contains, such as ranges of data values (high and low
+ temperature, latitude/longitude) or enumerated data values (zoning code,
+ genus/species, etc.). Subclasses of `ProfileElement` captures this
+ metadata.
+
+* Profile metadata. This is metadata describing the profile itself, such
+ as revision notes, ID number, etc. Class `ProfileAttributes` captures this
+ metadata.
+
+Objects of these classes are unified into a single `Profile` object.
+'''
+
+__docformat__ = 'restructuredtext'
+
+import xmlutils
+import xml.dom
+from xmlutils import DocumentableField
+
+class ProfileAttributes(xmlutils.Documentable):
+ '''Attributes of a profile. These are attributes not related to the
+ resource that a profile profiles, but rather the profile itself. In
+ most cases, simply constructing this object with no initializer
+ arguments will suffice.
+ '''
+ def __init__(self, id='UNKNOWN', version='1.0.0', type='profile', statusID='active', securityType='unclassified',
+ parentID='UNKNOWN', childIDs=None, regAuthority='UNKNOWN', revNotes=None, node=None):
+ '''Initialize profile attributes.
+
+ - `id` unique ID for the profile
+ - `version` number
+ - `type` should always be the string "profile"
+ - `statusID` should always be the string "active"
+ - `securityType` tells whether the profile is secret
+ - `parentID` gives the unique ID for any "parent" profile
+ - `childIDs` should be a sequnece of any "children" profiles
+ - `regAuthority` is a unique ID identifying the registration
+ authority responsible for the profile
+ - `revNotes` is a sequence of comments detailing historical
+ changes to the profile
+ - `node` is an XML DOM node. If the `node` argument is given,
+ it's used to initialize the object.
+ '''
+ self.id = id
+ self.version = version
+ self.type = type
+ self.statusID = statusID
+ self.securityType = securityType
+ self.parentID = parentID
+ self.childIDs = childIDs
+ self.regAuthority = regAuthority
+ self.revNotes = revNotes
+ if self.childIDs is None:
+ self.childIDs = []
+ if self.revNotes is None:
+ self.revNotes = []
+ if node is not None:
+ self.parse(node)
+
+ def getDocumentElementName(self):
+ '''Get the XML tag for objects of this class: `profAttributes`.
+ '''
+ return 'profAttributes'
+
+ def getDocumentableFields(self):
+ '''Get the attributes that are put into XML.
+ '''
+ return (DocumentableField('id', u'profId', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('version', u'profVersion', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('type', u'profType', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('statusID', u'profStatusId', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('securityType', u'profSecurityType', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('parentID', u'profParentId', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('childIDs', u'profChildId', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('regAuthority', u'profRegAuthority', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('revNotes', u'profRevisionNote', DocumentableField.MULTI_VALUED_KIND))
+
+ def __repr__(self):
+ return ('ProfileAttributes(id=%s,version=%s,type=%s,statusID=%s,securityType=%s,parentID=%s,childIDs=%s,' \
+ 'regAuthority=%s,revNotes=%s)') % (self.id, self.version, self.type, self.statusID, self.securityType,
+ self.parentID, self.childIDs, self.regAuthority, self.revNotes)
+
+ def __cmp__(self, other):
+ return cmp(self.id, other.id)
+
+ def __hash__(self):
+ return hash(self.id)
+
+
+class ResourceAttributes(xmlutils.Documentable):
+ '''Attributes of the resource. Objects of this class collect data about the resource's
+ inception and are based on Dublin Core.
+ '''
+ def __init__(self, identifier='UNKNOWN', title='UNKNOWN', formats=None, description='UNKNOWN', creators=None, subjects=None,
+ publishers=None, contributors=None, dates=None, types=None, sources=None, languages=None, relations=None,
+ coverages=None, rights=None, contexts=None, aggregation='UNKNOWN', resClass='UNKNOWN', locations=None, node=None):
+ '''Initialize ResourceAttributes.
+
+ The following arguments are required:
+
+ - `identifier` is a URI uniquely identifying the resource
+ - `title` names the resource
+ - `description` gives a summary or abstract of it
+ - `aggregation` tells the gross structure of the resource and
+ should be one of the following values:
+ - data.granule
+ - data.dataSet
+ - data.dataSetCollection
+ - `resClass` gives the kind of the resource (what to expect
+ when connecting to one of its locations)
+
+ All of the others should be initialized with sequences as the
+ resource attributes follows the Dublin Core recommendation on
+ multiplicity.
+
+ If `node` is given, it's treated as an XML DOM node and is used to
+ initialize the resource attributes.
+ '''
+ self.identifier = identifier
+ self.title = title
+ self.formats = formats
+ self.description = description
+ self.creators = creators
+ self.subjects = subjects
+ self.publishers = publishers
+ self.contributors = contributors
+ self.dates = dates
+ self.types = types
+ self.sources = sources
+ self.languages = languages
+ self.relations = relations
+ self.coverages = coverages
+ self.rights = rights
+ self.contexts = contexts
+ self.aggregation = aggregation
+ self.resClass = resClass
+ self.locations = locations
+ for attr in ('formats', 'creators', 'subjects', 'publishers', 'contributors', 'dates', 'sources', 'languages',
+ 'relations', 'coverages', 'rights', 'contexts', 'locations', 'types'):
+ if getattr(self, attr) is None:
+ setattr(self, attr, [])
+ if node is not None:
+ self.parse(node)
+
+ def getDocumentElementName(self):
+ '''Give the XML tag name: `resAttributes`.
+ '''
+ return 'resAttributes'
+
+ def __hash__(self):
+ return hash(self.identifier)
+
+ def __cmp__(self, other):
+ return cmp(self.identifier, other.identifier)
+
+ def getDocumentableFields(self):
+ '''Get the attributes that go into XML.
+ '''
+ return (DocumentableField('identifier', u'Identifier', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('title', u'Title', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('formats', u'Format', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('description', u'Description', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('creators', u'Creator', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('subjects', u'Subject', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('publishers', u'Publisher', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('contributors', u'Contributor', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('dates', u'Date', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('types', u'Type', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('sources', u'Source', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('languages', u'Language', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('relations', u'Relation', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('coverages', u'Coverage', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('rights', u'Rights', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('contexts', u'resContext', DocumentableField.MULTI_VALUED_KIND),
+ DocumentableField('aggregation', u'resAggregation', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('resClass', u'resClass', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('locations', u'resLocation', DocumentableField.MULTI_VALUED_KIND))
+
+
+class Profile(object):
+ '''A profile "profiles" a resource by describing it with metadata.
+ '''
+ def __init__(self, profAttr=None, resAttr=None, profElements=None, node=None):
+ '''Initialize a profile. The profElements should be a dicitonary that maps
+ from element name to instance of a `ProfileElement`.
+ '''
+ self.profAttr, self.resAttr, self.profElements = profAttr, resAttr, profElements
+ if self.profAttr is None:
+ self.profAttr = ProfileAttributes()
+ if self.resAttr is None:
+ self.resAttr = ResourceAttributes()
+ if self.profElements is None:
+ self.profElements = {}
+ if node is not None:
+ self.parse(node)
+
+ def parse(self, node):
+ '''Initialize this object from the given XML DOM `node`.
+ '''
+ if node.nodeName != 'profile':
+ raise ValueError('Expected profile element but got "%s"' % node.nodeName)
+ for child in filter(lambda node: node.nodeType == xml.dom.Node.ELEMENT_NODE, node.childNodes):
+ name = child.nodeName
+ if name == u'profAttributes':
+ self.profAttr = ProfileAttributes()
+ self.profAttr.parse(child)
+ elif name == u'resAttributes':
+ self.resAttr = ResourceAttributes()
+ self.resAttr.parse(child)
+ elif name == u'profElement':
+ elem = _parseProfileElement(child)
+ self.profElements[elem.name] = elem
+
+ def toXML(self, owner):
+ '''Convert this object into XML owned by the given `owner` document.
+ '''
+ root = owner.createElement(u'profile')
+ root.appendChild(self.profAttr.toXML(owner))
+ root.appendChild(self.resAttr.toXML(owner))
+ for elem in self.profElements.itervalues():
+ root.appendChild(elem.toXML(owner))
+ return root
+
+ def __cmp__(self, other):
+ profAttr = cmp(self.profAttr, other.profAttr)
+ if profAttr < 0:
+ return -1
+ elif profAttr == 0:
+ resAttr = cmp(self.resAttr, other.resAttr)
+ if resAttr < 0:
+ return -1
+ elif resAttr == 0:
+ return cmp(self.profElements, other.profElements)
+ return 1
+
+ def __hash__(self):
+ return hash(self.profAttr) ^ hash(self.resAttr)
+
+ def __repr__(self):
+ return 'Profile(profAttr=%s,resAttr=%s,profElements=%s)' % (self.profAttr, self.resAttr, self.profElements)
+
+
+class ProfileElement(object):
+ '''Abstract profile element.
+ '''
+ def __init__(self, name, description, type, units, synonyms, comment):
+ '''Initialize profile element.
+ '''
+ self.name = name
+ self.description = description
+ self.type = type
+ self.units = units
+ self.synonyms = synonyms
+ self.comment = comment
+
+ def __repr__(self):
+ return 'ProfileElement(name=%r,description=%r,type=%r,units=%r,synonyms=%r,comment=%r)' % (self.name,
+ self.description, self.type, self.units, self.synonyms, self.comment)
+
+ def __cmp__(self, other):
+ rc = cmp(self.name, other.name)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ rc = cmp(self.description, other.description)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ rc = cmp(self.type, other.type)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ rc = cmp(self.units, other.units)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ rc = cmp(self.synonyms, other.synonyms)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ return cmp(self.comment, other.comment)
+ return 1
+
+ def __hash__(self):
+ return reduce(lambda x, y: hash(x) ^ hash(y), [getattr(self, attr) for attr in ('name', 'description', 'type',
+ 'units', 'synonyms', 'comment')])
+
+ def isEnumerated(self):
+ '''Is this an enumerated element? Enumerated elements include those with
+ discrete values as well unspecified elements.
+ '''
+ return False;
+
+ def getValues(self):
+ '''Get the discrete values of this element, which may be empty.
+ '''
+ return []
+
+ def getMinValue(self):
+ '''Get the minimum value of this element, which may be zero.
+ '''
+ return 0.0
+
+ def getMaxValue(self):
+ '''Get the maximum value of this element, which may be zero.
+ '''
+ return 0.0
+
+ def toXML(self, owner):
+ '''Convert this object into XML owned by the given `owner` document.
+ '''
+ root = owner.createElement('profElement')
+ xmlutils.add(root, u'elemId', self.name)
+ xmlutils.add(root, u'elemName', self.name)
+ xmlutils.add(root, u'elemDesc', self.description)
+ xmlutils.add(root, u'elemType', self.type)
+ xmlutils.add(root, u'elemUnit', self.units)
+ if self.isEnumerated():
+ flag = 'T'
+ else:
+ flag = 'F'
+ xmlutils.add(root, u'elemEnumFlag', flag)
+ for value in self.getValues():
+ elem = owner.createElement('elemValue')
+ root.appendChild(elem)
+ elem.appendChild(owner.createCDATASection(value))
+ if not self.isEnumerated():
+ xmlutils.add(root, u'elemMinValue', str(self.getMinValue()))
+ xmlutils.add(root, u'elemMaxValue', str(self.getMaxValue()))
+ xmlutils.add(root, u'elemSynonym', self.synonyms)
+ xmlutils.add(root, u'elemComment', self.comment)
+ return root
+
+
+class UnspecifiedProfileElement(ProfileElement):
+ '''An unspecified profile element merely documents the existence of a element within a
+ dataset but says nothing about its actual values.
+ '''
+ def __init__(self, name, description, type, units, synonyms, comment):
+ '''Initialize an "unspecified" profile element.
+ '''
+ super(UnspecifiedProfileElement, self).__init__(name, description, type, units, synonyms, comment)
+
+ def isEnumerated(self):
+ '''An unspecified profile element is indeed enumerated. It just has no enumerated values.
+ '''
+ return True
+
+
+class EnumeratedProfileElement(ProfileElement):
+ '''An enumerated profile element describes set of discrete values.
+ '''
+ def __init__(self, name, description, type, units, synonyms, comment, values):
+ '''Initialize an enumerated profile element.
+ '''
+ super(EnumeratedProfileElement, self).__init__(name, description, type, units, synonyms, comment)
+ self.values = values
+
+ def isEnumerated(self):
+ '''An enumerated profile element is indeed enumerated.
+ '''
+ return True
+
+ def getValues(self):
+ '''Return the sequence of values.
+ '''
+ return self.values
+
+ def __cmp__(self, other):
+ rc = super(EnumeratedProfileElement, self).__cmp__(other)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ return cmp(self.values, other.values)
+ return 1
+
+
+class RangedProfileElement(ProfileElement):
+ '''A ranged profile element describes a value between two numeric ranges.
+ '''
+ def __init__(self, name, description, type, units, synonyms, comment, minValue, maxValue):
+ '''Initialize a ranged profile element.
+ '''
+ super(RangedProfileElement, self).__init__(name, description, type, units, synonyms, comment)
+ self.minValue = minValue
+ self.maxValue = maxValue
+
+ def getMinValue(self):
+ '''Get the minimum value.
+ '''
+ return self.minValue
+
+ def getMaxValue(self):
+ '''Get the maximum value.
+ '''
+ return self.maxValue
+
+ def __repr__(self):
+ return 'RangedProfileElement(%r,minValue=%r,maxValue=%r)' % (super(RangedProfileElement, self).__repr__(),
+ self.minValue, self.maxValue)
+
+ def __cmp__(self, other):
+ rc = super(RangedProfileElement, self).__cmp__(other)
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ rc = self.minValue - other.minValue
+ if rc < 0:
+ return -1
+ elif rc == 0:
+ return self.maxValue - other.maxValue
+ return 1
+
+
+def _parseProfileElement(node):
+ '''Construct an appropriate profile element from the given DOM node.
+ '''
+ if node.nodeName != u'profElement':
+ raise ValueError('Expected profElement element but got "%s"' % node.nodeName)
+ settings = dict(elemId=u'UNKNOWN', elemDesc=u'UNKNOWN', elemType=u'UNKNOWN', elemUnit=u'UNKNOWN', elemEnumFlag=u'F',
+ elemComment=u'UNKNOWN')
+ values, syns = [], []
+ for child in filter(lambda node: node.nodeType == xml.dom.Node.ELEMENT_NODE, node.childNodes):
+ text = xmlutils.text(child)
+ if child.nodeName == u'elemValue':
+ values.append(text)
+ elif child.nodeName == u'elemSynonym':
+ syns.append(text)
+ else:
+ settings[str(child.nodeName)] = text
+ if 'elemName' not in settings:
+ raise ValueError('profElement requires elemName but none specified')
+ if 'elemEnumFlag' not in settings:
+ raise ValueError('profElement requires elemEnumFlag but none specified')
+
+ # Normally I'd treat only those XML elements where elemEnumFlag as T as possibly producing
+ # unspecified or enumerated, and F producing *only* ranged elements. But PDS profile
+ # servers are producing profile elements with F for elemEnumFlag and yet NO elemMinValue
+ # and elemMaxValue. If they're using the Java profile code, I'd call that a bug in that
+ # code. If they're not, then I'd say they're producing profiles incorrectly.
+ if settings['elemEnumFlag'] == 'T':
+ if len(values) == 0:
+ return UnspecifiedProfileElement(settings['elemName'], settings['elemDesc'], settings['elemType'],
+ settings['elemUnit'], syns, settings['elemComment'])
+ else:
+ return EnumeratedProfileElement(settings['elemName'], settings['elemDesc'], settings['elemType'],
+ settings['elemUnit'], syns, settings['elemComment'], values)
+ else:
+ if 'elemMinValue' not in settings or 'elemMaxValue' not in settings:
+ return UnspecifiedProfileElement(settings['elemName'], settings['elemDesc'], settings['elemType'],
+ settings['elemUnit'], syns, settings['elemComment'])
+ else:
+ return RangedProfileElement(settings['elemName'], settings['elemDesc'], settings['elemType'],
+ settings['elemUnit'], syns, settings['elemComment'], float(settings['elemMinValue']),
+ float(settings['elemMaxValue']))
+
+
+# Some sample code:
+# if __name__ == '__main__':
+# import urllib2, xml.dom.minidom
+# x = urllib2.urlopen('http://starbrite.jpl.nasa.gov/q?object=urn%3Aeda%3Armi%3AJPL.PDS.MasterProd&type=profile&keywordQuery=TARGET_NAME+%3D+MARS')
+# d = xml.dom.minidom.parse(x)
+# x.close()
+# profiles = []
+# for i in d.documentElement.getElementsByTagName(u'profile'):
+# profiles.append(Profile(node=i))
+#
+# doc = xml.dom.minidom.getDOMImplementation().createDocument(None, None, None)
+# print '<?xml version="1.0" encoding="UTF-8"?>'
+# print '<!DOCTYPE profiles PUBLIC "-//JPL//DTD Profile 1.1//EN"'
+# print ' "http://oodt.jpl.nasa.gov/grid-profile/dtd/prof.dtd">'
+# print '<profiles>'
+# for profile in profiles:
+# print profile.toXML(doc).toxml()
+# print '</profiles>'
+#
Added: incubator/oodt/agility/agile-oodt/trunk/oodt/query.py
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/oodt/query.py?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/oodt/query.py (added)
+++ incubator/oodt/agility/agile-oodt/trunk/oodt/query.py Sun Mar 21 22:08:01 2010
@@ -0,0 +1,456 @@
+# encoding: utf-8
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE.txt file distributed with
+# this work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+'''
+Agile OODT Query Expressions.
+
+Query expressions in OODT are based on the "DIS" style expressions originally
+developed for the Planetary Data System. They consist of
+keyword/operator/literal-value triples, such as `targetName = Mars`, each
+linked with logical operators (and, or, not) and grouped with parentheses.
+For more information, see OODT_.
+
+This module defines classes that model the aspects of a query. In general,
+use the `Query` class, passing a string containing your keyword expression as
+the first constructor argument. From there, you have a `Query` object you can
+pass around to profile servers, product servers, and so forth.
+
+.. _OODT: http://incubator.apache.org/projects/oodt.html
+'''
+
+__docformat__ = 'restructuredtext'
+
+import oodterrors, shlex, xmlutils, xml.dom
+from xmlutils import DocumentableField
+
+class _QueryExpressionScanner(shlex.shlex):
+ '''Extend the shlex scanner but for the DIS-style query expressions we expect.
+ This means adding a dot to the characters that comprise a word so we can easily parse
+ floating-point numbers. Also, there's no comment character.
+ '''
+ def __init__(self, str):
+ '''Create scanner. `str` is the string to scan.
+ '''
+ shlex.shlex.__init__(self, str)
+ self.commenters = ''
+ self.wordchars = self.wordchars + '.-/:'
+
+
+ def get_token(self):
+ '''Get the next token. We strip quotes from strings, attach negative signs
+ to the numbers they're negating, and attach the = to <, >, and ! where needed.
+ '''
+ token = shlex.shlex.get_token(self)
+ if token == self.eof or token == None:
+ return None
+ if token[0] in self.quotes:
+ token = token[1:-1]
+ elif token in ('<', '>', '!'):
+ next = shlex.shlex.get_token(self)
+ if next == self.eof or next == None:
+ return None
+ elif next == '=':
+ token = token + next
+ else:
+ self.push_token(next)
+ return token
+
+
+class QueryException(oodterrors.OODTException):
+ '''Exceptions related to query expression or query services
+ '''
+ pass
+
+
+class ExpressionParseError(QueryException):
+ '''Error in parsing a query expression.
+ '''
+ pass
+
+
+class QueryElement(xmlutils.Documentable):
+ '''An element of a query.
+ '''
+ def __init__(self, role='UNKNOWN', value='UNKNOWN', node=None):
+ '''Create a QueryElement. You can provide role and value settings, or provide an XML
+ DOM node which will be parsed for role/value.
+ '''
+ self.role, self.value = role, value
+ if node != None:
+ self.parse(node)
+
+ def getDocumentElementName(self):
+ '''Give the XML tag name: `queryElement`.
+ '''
+ return 'queryElement'
+
+ def getDocumentableFields(self):
+ '''Get the attributes that go into XML.
+ '''
+ return (DocumentableField('role', u'tokenRole', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('value', u'tokenValue', DocumentableField.SINGLE_VALUE_KIND))
+
+ def __repr__(self):
+ return 'QueryElement(role="%s",value="%s")' % (self.role, self.value)
+
+
+class QueryHeader(xmlutils.Documentable):
+ '''Header of a query. Captures metadata like data dictionary in use, etc.
+ '''
+ def __init__(self, id='UNKNOWN', title='UNKNOWN', desc='UNKNOWN', type='QUERY', status='ACTIVE', security='UNKNOWN',
+ rev='2005-10-01 SCK v0.0.0 Under Development', dataDict='UNKNOWN', node=None):
+ '''Initialize a QueryHeader. Provide id, title, desc, type, status, security, rev,
+ and dataDict settings. Or, provide just an XML DOM node to be parsed.
+ '''
+ self.id, self.title, self.desc, self.type, self.status, self.security, self.rev, self.dataDict = \
+ id, title, desc, type, status, security, rev, dataDict
+ if node != None:
+ self.parse(node)
+
+ def getDocumentElementName(self):
+ '''Give the XML tag name: `queryAttributes`.
+ '''
+ return 'queryAttributes'
+
+ def getDocumentableFields(self):
+ '''Get the attributes that go into XML.
+ '''
+ return (DocumentableField('id', u'queryId', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('title', u'queryTitle', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('desc', u'queryDesc', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('type', u'queryType', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('status', u'queryStatusId', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('security', u'querySecurityType', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('rev', u'queryRevisionNote', DocumentableField.SINGLE_VALUE_KIND),
+ DocumentableField('dataDict', u'queryDataDictId', DocumentableField.SINGLE_VALUE_KIND))
+
+ def __repr__(self):
+ return 'QueryHeader(id="%s",title="%s",desc="%s",type="%s",status="%s",security="%s",rev="%s",dataDict="%s")' % (
+ self.id, self.title, self.desc, self.type, self.status, self.security, self.rev, self.dataDict
+ )
+
+ def __cmp__(self, other):
+ return cmp((self.id, self.title, self.desc, self.type, self.status, self.security, self.rev, self.dataDict),
+ (other.id, other.title, other.desc, other.type, other.status, other.security, other.rev, other.dataDict))
+
+
+class QueryResult(object):
+ '''Result of a query.
+ '''
+ def __init__(self, results=[], node=None):
+ '''Results of a query are captured as a sequence of generic objects.
+ '''
+ self.results = results
+ if node != None: self.parse(node)
+
+ def parse(self, node):
+ '''Initialize this object from the given XML DOM `node`.
+ '''
+ if 'queryResultSet' != node.nodeName:
+ raise ValueError('Expected queryResultSet but got "%s"' % node.nodeName)
+ for child in node.childNodes:
+ if child.nodeType == xml.dom.Node.ELEMENT_NODE and 'resultElement' == child.nodeName:
+ self.results.append(Result(node=child))
+
+ def toXML(self, owner):
+ '''Convert this object into XML owned by the given `owner` document.
+ '''
+ root = owner.createElement('queryResultSet')
+ for result in self.results:
+ root.appendChild(result.toXML(owner))
+ return root
+
+ def clear(self):
+ '''Remove all results.
+ '''
+ self.results = []
+
+ def __getitem__(self, i):
+ return self.results[i]
+
+ def __len__(self):
+ return len(self.results)
+
+ def __cmp__(self, other):
+ return cmp(self.results, other.results)
+
+
+_RELOPS = {
+ 'LT': 'LT',
+ 'lt': 'LT',
+ '<': 'LT',
+ 'LE': 'LE',
+ 'le': 'LE',
+ '<=': 'LE',
+ 'EQ': 'EQ',
+ 'eq': 'EQ',
+ '=': 'EQ',
+ 'GE': 'GE',
+ 'ge': 'GE',
+ '>=': 'GE',
+ 'GT': 'GT',
+ 'gt': 'GT',
+ '>': 'GT',
+ 'NE': 'NE',
+ 'ne': 'NE',
+ '!=': 'NE',
+ 'LIKE': 'LIKE',
+ 'like': 'LIKE',
+ 'NOTLIKE': 'NOTLIKE',
+ 'notlike': 'NOTLIKE',
+ 'notLike': 'NOTLIKE',
+ 'IS': 'IS',
+ 'is': 'is',
+ 'ISNOT': 'ISNOT',
+ 'isnot': 'isnot',
+ 'isNot': 'isnot'
+}
+
+_LOGOPS = {
+ 'AND': 'AND',
+ 'and': 'AND',
+ '&': 'AND',
+ 'OR': 'OR',
+ 'or': 'OR',
+ '|': 'OR',
+ 'NOT': 'NOT',
+ 'not': 'NOT',
+ '!': 'NOT'
+}
+
+_PRECEDENCE = {
+ 'NOT': 2,
+ 'AND': 1,
+ 'OR': 0,
+}
+
+class Query(object):
+ '''Query. In old OODT, this was called XMLQuery, even though XML was tagential to it.
+ Captures aspects of a query, including header, results, and so forth. Most importantly, it
+ captures the query expression, which contains the constraints on user's desiderata and
+ range on what to return.
+
+ As with other classes in this module, you can provide an XML DOM node to be parsed
+ for the query's settings, or provide each of them individually.
+ '''
+ def __init__(self, keywordQuery=None, header=QueryHeader(), resultModeID='ATTRIBUTE', propType='BROADCAST',
+ propLevels='N/A', maxResults=1, mimeAccept=[], parseQuery=True, node=None):
+ '''Initialize a query. Usually you provide just the `keywordQuery` argument
+ which should be a keyword/query expression in the DIS-style; or you provide
+ the `node` which is an XML DOM node describing a query.
+ '''
+ self.header, self.resultModeID, self.propType, self.propLevels, self.maxResults, self.mimeAccept = \
+ header, resultModeID, propType, propLevels, maxResults, mimeAccept
+ self.wheres, self.selects, self.froms, self.resultSet = [], [], [], QueryResult()
+ if keywordQuery != None:
+ self.keywordQuery = keywordQuery
+ if parseQuery:
+ self.wheres, self.selects = _parseQuery(keywordQuery)
+ else:
+ self.keywordQuery = ''
+ if node != None:
+ self.parse(node)
+
+ def toXML(self, owner):
+ '''Yield this query as an XML DOM.
+ '''
+ query = owner.createElement('query')
+ query.appendChild(self.header.toXML(owner))
+ xmlutils.add(query, u'queryResultModeId', self.resultModeID)
+ xmlutils.add(query, u'queryPropogationType', self.propType)
+ xmlutils.add(query, u'queryPropogationLevels', self.propLevels)
+ for mimeType in self.mimeAccept:
+ xmlutils.add(query, u'queryMimeAccept', mimeType)
+ xmlutils.add(query, u'queryMaxResults', str(self.maxResults))
+ xmlutils.add(query, u'queryKWQString', self.keywordQuery)
+ selects = owner.createElement(u'querySelectSet')
+ query.appendChild(selects)
+ for select in self.selects:
+ selects.appendChild(select.toXML(owner))
+ fromElement = owner.createElement(u'queryFromSet')
+ query.appendChild(fromElement)
+ for i in self.froms:
+ fromElement.appendChild(i.toXML(owner))
+ wheres = owner.createElement(u'queryWhereSet')
+ query.appendChild(wheres)
+ for where in self.wheres:
+ wheres.appendChild(where.toXML(owner))
+ query.appendChild(self.resultSet.toXML(owner))
+ return query
+
+ def parse(self, node):
+ '''Parse the XML DOM node as a query document.
+ '''
+ if 'query' != node.nodeName:
+ raise ValueError('Expected query but got "%s"' % node.nodeName)
+ self.mimeAccept, self.results = [], []
+ for child in node.childNodes:
+ if child.nodeType == xml.dom.Node.ELEMENT_NODE:
+ if child.nodeName == u'queryAttributes':
+ self.header = QueryHeader(node=child)
+ elif child.nodeName == u'resultModeID':
+ self.resultModeID = xmlutils.text(child)
+ elif child.nodeName == u'queryPropogationType':
+ self.propType = xmlutils.text(child)
+ elif child.nodeName == u'queryPropogationLevels':
+ self.propLevels = xmlutils.text(child)
+ elif child.nodeName == u'queryMimeAccept':
+ self.mimeAccept.append(xmlutils.text(child))
+ elif child.nodeName == u'queryMaxResults':
+ self.maxResults = int(xmlutils.text(child))
+ elif child.nodeName == u'queryKWQString':
+ self.keywordQuery = xmlutils.text(child)
+ elif child.nodeName == u'querySelectSet':
+ self.selects = _parseQueryElements(child)
+ elif child.nodeName == u'queryFromSet':
+ self.froms = _parseQueryElements(child)
+ elif child.nodeName == u'queryWhereSet':
+ self.wheres = _parseQueryElements(child)
+ elif child.nodeName == u'queryResultSet':
+ self.resultSet = QueryResult(node=child)
+
+ def __cmp__(self, other):
+ header = cmp(self.header, other.header)
+ if header < 0:
+ return -1
+ elif header == 0:
+ resultModeID = cmp(self.resultModeID, other.resultModeID)
+ if resultModeID < 0:
+ return -1
+ elif resultModeID == 0:
+ propType = cmp(self.propType, other.propType)
+ if propType < 0:
+ return -1
+ elif propType == 0:
+ propLevels = cmp(self.propLevels, other.propLevels)
+ if propLevels < 0:
+ return -1
+ elif propLevels == 0:
+ maxResults = self.maxResults - other.maxResults
+ if maxResults < 0:
+ return -1
+ elif maxResults == 0:
+ mimeAccept = cmp(self.mimeAccept, other.mimeAccept)
+ if mimeAccept < 0:
+ return -1
+ elif mimeAccept == 0:
+ selects = cmp(self.selects, other.selects)
+ if selects < 0:
+ return -1
+ elif selects == 0:
+ froms = cmp(self.froms, other.froms)
+ if froms < 0:
+ return -1
+ elif froms == 0:
+ wheres = cmp(self.wheres, other.wheres)
+ if wheres < 0:
+ return -1
+ elif wheres == 0:
+ return cmp(self.resultSet, other.resultSet)
+ return 1
+
+
+def _parseQueryElements(node):
+ '''The children of the given XML DOM node are a sequence of queryElements. Parse them
+ and return a list of QueryElement objects.
+ '''
+ a = []
+ for child in node.childNodes:
+ if child.nodeType == xml.dom.Node.ELEMENT_NODE:
+ a.append(QueryElement(node=child))
+ return a
+
+
+def _parseQuery(s):
+ '''Parse the query expression in `s`.
+ '''
+ if s is None:
+ return [], []
+ if len(s.strip()) == 0:
+ return [], []
+ if s.count('(') != s.count(')'):
+ raise ExpressionParseError('Unbalanced parentheses')
+ scanner = _QueryExpressionScanner(s)
+ return _buildQuery(scanner)
+
+
+def _buildQuery(scanner):
+ '''Build the query stacks using the given `scanner`.
+ '''
+ operators, expression, selectors = [], [], []
+ while True:
+ token = scanner.get_token()
+ if token is None: break
+ if token in _LOGOPS:
+ op = QueryElement('LOGOP', _LOGOPS[token])
+ if len(operators) == 0:
+ operators.append(op)
+ else:
+ while len(operators) > 0 and _PRECEDENCE[operators[-1].value] > _PRECEDENCE[op.value]:
+ expression.append(operators.pop())
+ operators.append(op)
+ elif token == '(':
+ subExpr, subSelectors = _buildQuery(scanner)
+ expression.extend(subExpr)
+ selectors.extend(subSelectors)
+ elif token == ')':
+ break
+ else:
+ _addTerm(token, scanner, expression, operators, selectors)
+ if len(operators) > 0 and len(expression) == 0:
+ raise ExpressionParseError('Query contains only logical operators')
+ operators.reverse()
+ expression.extend(operators)
+ return expression, selectors
+
+
+def _addTerm(elemName, scanner, expression, operators, selectors):
+ '''Add a term to the correct stack.
+ '''
+ relop = scanner.get_token()
+ if relop is None:
+ raise ExpressionParseError('Expected relational operator after element name "%s"' % elemName)
+ if relop not in _RELOPS:
+ raise ExpressionParseError('Unknown relational operator "%s"' % relop)
+ literal = scanner.get_token()
+ if literal is None:
+ raise ExpressionParseError('Expected literal value for "%s %s" comparison' % (elemName, relop))
+ if elemName == 'RETURN':
+ selectors.append(QueryElement('elemName', literal))
+ if len(operators) > 0:
+ operators.pop()
+ else:
+ scanner.get_token()
+ else:
+ expression.append(QueryElement('elemName', elemName))
+ expression.append(QueryElement('LITERAL', literal))
+ expression.append(QueryElement('RELOP', _RELOPS[relop]))
+
+
+# Sample code:
+# if __name__ == '__main__':
+# import urllib, xml.dom.minidom
+#
+# impl = xml.dom.minidom.getDOMImplementation()
+# doc = impl.createDocument(None, None, None) # nsURI, qName, docType
+#
+# q = Query('track = Innocente')
+# node = q.toXML(doc)
+# doc.appendChild(node)
+# q = doc.toxml()
+# f = urllib.urlopen('http://localhost:8080/pds/prof', urllib.urlencode(dict(xmlq=q)), {}) # url, postdata, proxies (none)
+# print f.read()
Propchange: incubator/oodt/agility/agile-oodt/trunk/oodt/tests/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Mar 21 22:08:01 2010
@@ -0,0 +1,8 @@
+._*
+.DS_Store
+*.log
+*.pyc
+*.pyo
+*.egg-info
+dist
+build
Added: incubator/oodt/agility/agile-oodt/trunk/oodt/tests/__init__.py
URL: http://svn.apache.org/viewvc/incubator/oodt/agility/agile-oodt/trunk/oodt/tests/__init__.py?rev=925913&view=auto
==============================================================================
--- incubator/oodt/agility/agile-oodt/trunk/oodt/tests/__init__.py (added)
+++ incubator/oodt/agility/agile-oodt/trunk/oodt/tests/__init__.py Sun Mar 21 22:08:01 2010
@@ -0,0 +1,38 @@
+# encoding: utf-8
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE.txt file distributed with
+# this work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+'''Agile OODT Tests.
+'''
+
+__docformat__ = 'restructuredtext'
+
+import unittest
+import profileTest, queryTest, xmlutilsTest
+
+def test_suite():
+ '''Create the suite of tests.
+ '''
+ suite = unittest.TestSuite()
+ suite.addTest(profileTest.test_suite())
+ suite.addTest(queryTest.test_suite())
+ suite.addTest(xmlutilsTest.test_suite())
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+