[Zope3-checkins] CVS: zopeproducts/pypgsqlda/pgtypes - __init__.py:1.1.2.1 _geometry.py:1.1.2.1 _null.py:1.1.2.1

Christian 'Tiran' Heimes heimes@faho.rwth-aachen.de
Mon, 7 Apr 2003 12:18:51 -0400


Update of /cvs-repository/zopeproducts/pypgsqlda/pgtypes
In directory cvs.zope.org:/tmp/cvs-serv6910/pgtypes

Added Files:
      Tag: tiran-pypgsql_types-branch
	__init__.py _geometry.py _null.py 
Log Message:
* first test release of pgtypes

=== Added File zopeproducts/pypgsqlda/pgtypes/__init__.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""special types for the pyPgSQL Database Adapter

$Id: __init__.py,v 1.1.2.1 2003/04/07 16:18:50 tiran Exp $
"""
from _null import Null

from _geometry import Point2d, Box2d, Circle2d, OpenPath, ClosedPath, \
    isOpenPath, isClosedPath

=== Added File zopeproducts/pypgsqlda/pgtypes/_geometry.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Geometric object implementation

$Id: _geometry.py,v 1.1.2.1 2003/04/07 16:18:50 tiran Exp $
"""

from zope.proxy.context import ContextMethod
from interface import geometric
import re
from math import pi

# matching an open path e.g. [(0,0),(1,1)]
openPath = re.compile(r"^\[\(.*\)\]$")

# matching a closed path e.g. ((0,0),(1,1))
closedPath = re.compile(r"^\(\(.*\)\)$")

# group a circle e.g. <(1,1),0.5> into (1.0,1.0) as the middle point
# and 0.5 as the radius
groupCircle = re.compile(r"^<(\([\d.]+,[\d.]+\)),([\d.]+)>$")

# group a single point e.g. (0,1) into 0 as the x value and 1 as the y value
groupPoint = re.compile(r"^\(([\d.]+),([\d.]+)\)$")

# group a path or a box e.g.((0,0),(1,1)) or [(0,0),(1,1)] into a 
# list of points
groupPointList = re.compile(r"(\([\d.]+,[\d.]+\))")

def isOpenPath(data):
    return openPath.match(unicode(data))

def isClosedPath(data):
    return closedPath.match(unicode(data))

class GeometricError(Exception): 
    """XXX
    """
    pass

class GeometricInfinite(object):
    """
    """
    def __str__(self):
        return u"INF"
    
    __str__ = ContextMethod(__str__)
    
    def __call__(self):
        return self.__str__
    
    __call__ = ContextMethod(__call__)
    
    def __repr__(self):
        return self.__str__()
    
    __repr__ = ContextMethod(__repr__)


class Geometric2d(object):
    __implements__ = geometric.IGeometric2d
    
    def __init__(self):
        self._data = None
        return NotImplemented
    
    isClosed = property(lambda: False, None, None)
    isOpen   = property(lambda: False, None, None)
    length = property(lambda: 0, None, None)

    def __str__(self):
        return unicode(self._data)
    
    __str__ = ContextMethod(__str__)
    
    def __call__(self):
        return self.__str__
    
    __call__ = ContextMethod(__call__)
    
    def __repr__(self):
        return self.__str__()
    
    __repr__ = ContextMethod(__repr__)

    def __iter__(self):
        return self
    
    def next(self):
        """iterator function
        """
        return StopIteration
    
    def __len__(self):
        return 0
    
class Shape2d(Geometric2d):
    __implements__ = geometric.IShape2d, Geometric2d.__implements__
    
    area = property(lambda: 0, None, None, None)


class Point2d(Geometric2d):
    """Simple geometric point
    """

    __implements__ = geometric.IPoint2d, Geometric2d.__implements__
    
    def __init__(self, data):
        self._data = data
        self._x    = None
        self._y    = None
        self._iter = 0
        
    def _convert(self):
        """
        """
        if self._x and self._y: return # already converted data
        point = groupPoint.match(unicode(self._data)).groups()
        if len(point) != 2:
            raise GeometricError, u"'%s' has wrong size" % data
        self.x = point[0]
        self.y = point[1]

    def _getX(self):
        self._convert()
        return self._x

    def _setX(self, value):
        self._x = float(value)
    
    x = property(_getX, _setX, None, 'x coordinate as float')

    def _getY(self):
        self._convert()
        return self._y

    def _setY(self, value):
        self._y = float(value)

    y = property(_getY, _setY, None, 'y coordinate as float')

    def next(self):
        """next() support for iterator"""
        if self._iter == 0:
            self._iter = 1
            return self
        else:
            raise StopIteration
    
    def __len__(self):
        return 1

class Box2d(Shape2d):
    __implements__ = geometric.IBox2d, Shape2d.__implements__
    
    def __init__(self, data):
        self._data   = data
        self._points = []
        self._iter   = 0
        
    def _convert(self):
        if self._points: return
        box = groupPointList.findall(unicode(data))
        if len(box) != 2:
            raise GeometricError, u"'%s' has wrong size" % data
        for p in box:
            self._points.append(Point2d(p))

    def _getUR(self):
        self._convert()
        return self._points[0]
    
    def _setUR(self, value):
        if not isinstance(value, Point2d):
            raise TypeError, u"type must be Point2d"
        self._points[0] = value
        
    upperRight = property(_getUR, _setUR, None)

    def _getLL(self):
        self._convert()
        return self._points[1]
    
    def _setLL(self, value):
        if not isinstance(value, Point2d):
            raise TypeError, u"type must be Point2d"
        self._points[1] = value
        
    lowerLeft = property(_getLL, _setLL, None)
    
    def _getArea(self):
        return (upperRight.x - lowerLeft.x) * (upperRight.y - lowerLeft.y)
    
    area = property(_getArea, None, None)
    
    def _getLength(self):
        return 2*((upperRight.x - lowerLeft.x) + (upperRight.y - lowerLeft.y))
    
    length = property(_getLength, None, None)

    isClosed = property(lambda: True, None, None)

    def __len__(self):
        return 2
    
    def next(self):
        if self._iter < 2:
            return self._points[self._iter]
            self._iter += 1
        else:
            raise StopIteration    
    
class Circle2d(Shape2d):
    __implements__ = geometric.ICircle2d, Shape2d.__implements__
    
    def __init__(self, data):
        self._data   = data
        self._center = None
        self._radius = None
        
    def _convert(self):
        if self._center and self._radius: return
        circle = groupCircle.match(unicode(data)).groups()
        if len(circle) != 2:
            raise GeometricError, u"'%s' has wrong size" % data
        self._center = Point2d(circle[0])
        self._radius = float(circle[1])
        
    def _getCenter(self):
        self._convert()
        return self._center
    
    def _setCenter(self, value):
        if not isinstance(value, Point2d):
            return TypeError, u"type must be Point2d"
        self._center = value
        
    center = property(_getCenter, _setCenter, None)
    
    def _getRadius(self):
        self._convert()
        return self._radius
    
    def _setRadius(self, value):
        self._radius = float(value)
        
    radius = property(_getRadius, _setRadius, None)
    
    def _getArea(self):
        return pi*self.radius**2

    area = property(_getArea, None, None)

    def _getLength(self):
        return 2*pi*self.radius
    
    length = property(_getLength, None, None)
    
    isClosed = property(lambda: True, None, None)
    
    def __len__(self):
        return 1

    def next(self):
        if self._iter == 0:
            self._iter = 1
            return self.center
        else:
            raise StopIteration


class OpenPath(Geometric2d):
    __implements__ = geometric.IBox2d, Geometric2d.__implements__
    
    def __init__(self, data):
        self._data = data
        self._iter = 0
        self._points = None
    
class ClosedPath(Geometric2d):
    __implements__ = geometric.IBox2d, Geometric2d.__implements__
    
    def __init__(self, data):
        self._data = data
        self._iter = 0
        self._points = None


=== Added File zopeproducts/pypgsqlda/pgtypes/_null.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: _null.py,v 1.1.2.1 2003/04/07 16:18:50 tiran Exp $

taken from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205

>From the original documentation:
********************************

This is a sample implementation of the 'Null Object' design pattern.

Roughly, the goal with Null objects is to provide an 'intelligent'
replacement for the often used primitive data type None in Python or
Null (or Null pointers) in other languages. These are used for many
purposes including the important case where one member of some group 
of otherwise similar elements is special for whatever reason. Most 
often this results in conditional statements to distinguish between
ordinary elements and the primitive Null value.

Among the advantages of using Null objects are the following:

  - Superfluous conditional statements can be avoided 
    by providing a first class object alternative for 
    the primitive value None.

  - Code readability is improved.

  - Null objects can act as a placeholder for objects 
    with behaviour that is not yet implemented.

  - Null objects can be replaced for any other class.

  - Null objects are very predictable at what they do.

To cope with the disadvantage of creating large numbers of passive 
objects that do nothing but occupy memory space Null objects are 
often combined with the Singleton pattern.

For more information use any internet search engine and look for 
combinations of these words: Null, object, design and pattern.

Dinu C. Gherman,
August 2001
"""
from interface.null import INull
from zope.proxy.context import ContextMethod

class Null(object):
    """Postgres NULL type
    
    From the original documentation:
    ********************************
    
    A class for implementing Null objects.

    This class ignores all parameters passed when constructing or 
    calling instances and traps all attribute and method requests. 
    Instances of it always (and reliably) do 'nothing'.

    The code might benefit from implementing some further special 
    Python methods depending on the context in which its instances 
    are used. Especially when comparing and coercing Null objects
    the respective methods' implementation will depend very much
    on the environment and, hence, these special methods are not
    provided here.
    """
    
    __implements__ = INull

    def __init__(self, *args, **kwargs):
        "Ignore parameters."
        return None

    def __call__(self, *args, **kwargs):
        "Ignore method calls."
        return self.__str__
    
    __call__ = ContextMethod(__call__)

    def __getattr__(self, mname):
        "Ignore attribute requests."
        return self

    def __setattr__(self, name, value):
        "Ignore attribute setting."
        return self

    def __delattr__(self, name):
        "Ignore deleting attributes."
        return self

    def __repr__(self):
        "Return a string representation."
        return u"<NULL>"

    def __str__(self):
        "Convert to a string and return it."
        return u"NULL"
    
    __str__ = ContextMethod(__str__)
        
    def __nonzero__(self):
        """
	    from the 'Python Cockbook', even Null() == Null() is false
	    """
        return 0