<commit_before>import constants
from error import BucketFull

class KBucket(object):
    """ Description - later
    """

    def __init__(self, rangeMin, rangeMax, node_id):
        """
        @param rangeMin: The lower boundary for the range in the n-bit ID
                         space covered by this k-bucket
        @param rangeMax: The upper boundary for the range in the ID space
                         covered by this k-bucket
        """
        self.lastAccessed = 0
        self.rangeMin = rangeMin
        self.rangeMax = rangeMax
        self._contacts = list()
        self._node_id = node_id

    def addContact(self, contact):
        """ Add contact to _contact list in the right order. This will move the
        contact to the end of the k-bucket if it is already present.

        @raise kademlia.kbucket.BucketFull: Raised when the bucket is full and
                                            the contact isn't in the bucket
                                            already

        @param contact: The contact to add
        @type contact: kademlia.contact.Contact
        """
        if contact in self._contacts:
            # Move the existing contact to the end of the list
            # - using the new contact to allow add-on data
            #   (e.g. optimization-specific stuff) to pe updated as well
            self._contacts.remove(contact)
            self._contacts.append(contact)
        elif len(self._contacts) < constants.k:
            self._contacts.append(contact)
        else:
            raise BucketFull("No space in bucket to insert contact")

    def getContact(self, contactID):
        """Get the contact specified node ID

        @raise IndexError: raised if the contact is not in the bucket

        @param contactID: the node id of the contact to retrieve
        @type contactID: str

        @rtype: dht.contact._Contact
        """
        for contact in self._contacts:
            if contact.id == contactID:
                return contact
        raise IndexError(contactID)

    def getContacts(self, count=-1, excludeContact=None):
        """ Returns a list containing up to the first count number of contacts

        @param count: The amount of contacts to return (if 0 or less, return
                      all contacts)
        @type count: int
        @param excludeContact: A contact to exclude; if this contact is in
                               the list of returned values, it will be
                               discarded before returning. If a C{str} is
                               passed as this argument, it must be the
                               contact's ID.
        @type excludeContact: kademlia.contact.Contact or str

        @raise IndexError: If the number of requested contacts is too large

        @return: Return up to the first count number of contacts in a list
                If no contacts are present an empty is returned
        @rtype: list
        """
        # Return all contacts in bucket
        if count <= 0:
            count = len(self._contacts)

        # Get current contact number
        currentLen = len(self._contacts)

        # If count greater than k - return only k contacts
        if count > constants.k:
            count = constants.k

        # Check if count value in range and,
        # if count number of contacts are available
        if not currentLen:
            contactList = list()

        # length of list less than requested amount
        elif currentLen < count:
            contactList = self._contacts[0:currentLen]
        # enough contacts in list
        else:
            contactList = self._contacts[0:count]

        if excludeContact in contactList:
            contactList.remove(excludeContact)

    def getBadOrUnknownContacts(self):
        contacts = self.getContacts(sort_distance_to=False)
        results = [contact for contact in contacts if contact.contact_is_good is False]
        results.extend(contact for contact in contacts if contact.contact_is_good is None)
        return results
        return contactList

    def removeContact(self, contact):
        """ Remove the contact from the bucket

        @param contact: The contact to remove
        @type contact: dht.contact._Contact

        @raise ValueError: The specified contact is not in this bucket
        """
        self._contacts.remove(contact)

    def keyInRange(self, key):
        """ Tests whether the specified key (i.e. node ID) is in the range
        of the n-bit ID space covered by this k-bucket (in otherwords, it
        returns whether or not the specified key should be placed in this
        k-bucket)

        @param key: The key to test
        @type key: str or int

        @return: C{True} if the key is in this k-bucket's range, or C{False}
                 if not.
        @rtype: bool
        """
        if isinstance(key, str):
            key = long(key.encode('hex'), 16)
        return self.rangeMin <= key < self.rangeMax

    def __len__(self):
        return len(self._contacts)

    def __contains__(self, item):
        return item in self._contacts
<commit_msg>sort KBucket.getContacts<commit_after>import logging
import constants
from distance import Distance
from error import BucketFull

log = logging.getLogger(__name__)

class KBucket(object):
    """ Description - later
    """

    def __init__(self, rangeMin, rangeMax, node_id):
        """
        @param rangeMin: The lower boundary for the range in the n-bit ID
                         space covered by this k-bucket
        @param rangeMax: The upper boundary for the range in the ID space
                         covered by this k-bucket
        """
        self.lastAccessed = 0
        self.rangeMin = rangeMin
        self.rangeMax = rangeMax
        self._contacts = list()
        self._node_id = node_id

    def addContact(self, contact):
        """ Add contact to _contact list in the right order. This will move the
        contact to the end of the k-bucket if it is already present.

        @raise kademlia.kbucket.BucketFull: Raised when the bucket is full and
                                            the contact isn't in the bucket
                                            already

        @param contact: The contact to add
        @type contact: dht.contact._Contact
        """
        if contact in self._contacts:
            # Move the existing contact to the end of the list
            # - using the new contact to allow add-on data
            #   (e.g. optimization-specific stuff) to pe updated as well
            self._contacts.remove(contact)
            self._contacts.append(contact)
        elif len(self._contacts) < constants.k:
            self._contacts.append(contact)
        else:
            raise BucketFull("No space in bucket to insert contact")

    def getContact(self, contactID):
        """Get the contact specified node ID

        @raise IndexError: raised if the contact is not in the bucket

        @param contactID: the node id of the contact to retrieve
        @type contactID: str

        @rtype: dht.contact._Contact
        """
        for contact in self._contacts:
            if contact.id == contactID:
                return contact
        raise IndexError(contactID)

    def getContacts(self, count=-1, excludeContact=None, sort_distance_to=None):
        """ Returns a list containing up to the first count number of contacts

        @param count: The amount of contacts to return (if 0 or less, return
                      all contacts)
        @type count: int
        @param excludeContact: A node id to exclude; if this contact is in
                               the list of returned values, it will be
                               discarded before returning. If a C{str} is
                               passed as this argument, it must be the
                               contact's ID.
        @type excludeContact: str

        @param sort_distance_to: Sort distance to the id, defaulting to the parent node id. If False don't
                                 sort the contacts

        @raise IndexError: If the number of requested contacts is too large

        @return: Return up to the first count number of contacts in a list
                If no contacts are present an empty is returned
        @rtype: list
        """
        contacts = [contact for contact in self._contacts if contact.id != excludeContact]

        # Return all contacts in bucket
        if count <= 0:
            count = len(contacts)

        # Get current contact number
        currentLen = len(contacts)

        # If count greater than k - return only k contacts
        if count > constants.k:
            count = constants.k

        if not currentLen:
            return contacts

        if sort_distance_to is False:
            pass
        else:
            sort_distance_to = sort_distance_to or self._node_id
            contacts.sort(key=lambda c: Distance(sort_distance_to)(c.id))

        return contacts[:min(currentLen, count)]

    def getBadOrUnknownContacts(self):
        contacts = self.getContacts(sort_distance_to=False)
        results = [contact for contact in contacts if contact.contact_is_good is False]
        results.extend(contact for contact in contacts if contact.contact_is_good is None)
        return results

    def removeContact(self, contact):
        """ Remove the contact from the bucket

        @param contact: The contact to remove
        @type contact: dht.contact._Contact

        @raise ValueError: The specified contact is not in this bucket
        """
        self._contacts.remove(contact)

    def keyInRange(self, key):
        """ Tests whether the specified key (i.e. node ID) is in the range
        of the n-bit ID space covered by this k-bucket (in otherwords, it
        returns whether or not the specified key should be placed in this
        k-bucket)

        @param key: The key to test
        @type key: str or int

        @return: C{True} if the key is in this k-bucket's range, or C{False}
                 if not.
        @rtype: bool
        """
        if isinstance(key, str):
            key = long(key.encode('hex'), 16)
        return self.rangeMin <= key < self.rangeMax

    def __len__(self):
        return len(self._contacts)

    def __contains__(self, item):
        return item in self._contacts
<|endoftext|>


<commit_before>"""
This module contains the C{L{TrustRoot}} class, which helps handle
trust root checking.  This module is used by the
C{L{openid.server.server}} module, but it is also available to server
implementers who wish to use it for additional trust root checking.

It also implements relying party return_to URL verification, based on
the realm.
"""

__all__ = [
    'TrustRoot',
    'RP_RETURN_TO_URL_TYPE',
    'extractReturnToURLs',
    'returnToMatches',
    'verifyReturnTo',
    ]

from openid import oidutil
from openid.yadis import services
from urlparse import urlparse, urlunparse

############################################
_protocols = ['http', 'https']
_top_level_domains = (
    'com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|ad|ae|'
    'af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|'
    'bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|'
    'cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|'
    'fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|'
    'ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|'
    'kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|'
    'mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|'
    'nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|'
    'sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|sv|sy|sz|tc|td|tf|tg|th|'
    'tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|'
    'vn|vu|wf|ws|ye|yt|yu|za|zm|zw'
    ).split('|')

class RealmVerificationRedirected(Exception):
    """Attempting to verify this realm resulted in a redirect.
    """
    def __init__(self, relying_party_url, rp_url_after_redirects):
        self.relying_party_url = relying_party_url
        self.rp_url_after_redirects = rp_url_after_redirects

    def __str__(self):
        return ("Attempting to verify %r resulted in "
                "redirect to %r" %
                (self.relying_party_url,
                 self.rp_url_after_redirects))

def _parseURL(url):
    proto, netloc, path, params, query, frag = urlparse(url)
    if not path:
        # Python <2.4 does not parse URLs with no path properly
        if not query and '?' in netloc:
            netloc, query = netloc.split('?', 1)

        path = '/'

    path = urlunparse(('', '', path, params, query, frag))

    if ':' in netloc:
        try:
            host, port = netloc.split(':')
        except ValueError:
            return None
    else:
        host = netloc
        port = ''

    host = host.lower()
    return proto, host, port, path

class TrustRoot(object):
    """
    This class represents an OpenID trust root.  The C{L{parse}}
    classmethod accepts a trust root string, producing a
    C{L{TrustRoot}} object.  The method OpenID server implementers
    would be most likely to use is the C{L{isSane}} method, which
    checks the trust root for given patterns that indicate that the
    trust root is too broad or points to a local network resource.

    @sort: parse, isSane
    """

    def __init__(self, unparsed, proto, wildcard, host, port, path):
        self.unparsed = unparsed
        self.proto = proto
        self.wildcard = wildcard
        self.host = host
        self.port = port
        self.path = path

    def isSane(self):
        """
        This method checks the to see if a trust root represents a
        reasonable (sane) set of URLs.  'http://*.com/', for example
        is not a reasonable pattern, as it cannot meaningfully specify
        the site claiming it.  This function attempts to find many
        related examples, but it can only work via heuristics.
        Negative responses from this method should be treated as
        advisory, used only to alert the user to examine the trust
        root carefully.

        @return: Whether the trust root is sane

        @rtype: C{bool}
        """

        if self.host == 'localhost':
            return True

        host_parts = self.host.split('.')
        if self.wildcard:
            assert host_parts[0] == '', host_parts
            del host_parts[0]

        # If it's an absolute domain name, remove the empty string
        # from the end.
        if host_parts and not host_parts[-1]:
            del host_parts[-1]

        if not host_parts:
            return False

        # Do not allow adjacent dots
        if '' in host_parts:
            return False

        tld = host_parts[-1]
        if tld not in _top_level_domains:
            return False

        if len(host_parts) == 1:
            return False

        if self.wildcard:
            if len(tld) == 2 and len(host_parts[-2]) <= 3:
                # It's a 2-letter tld with a short second to last segment
                # so there needs to be more than two segments specified
                # (e.g. *.co.uk is insane)
                return len(host_parts) > 2

        # Passed all tests for insanity.
        return True

    def validateURL(self, url):
        """
        Validates a URL against this trust root.

        @param url: The URL to check

        @type url: C{str}

        @return: Whether the given URL is within this trust root.

        @rtype: C{bool}
        """

        url_parts = _parseURL(url)
        if url_parts is None:
            return False

        proto, host, port, path = url_parts

        if proto != self.proto:
            return False

        if port != self.port:
            return False

        if '*' in host:
            return False

        if not self.wildcard:
            if host != self.host:
                return False
        elif ((not host.endswith(self.host)) and
              ('.' + host) != self.host):
            return False

        if path != self.path:
            path_len = len(self.path)
            trust_prefix = self.path[:path_len]
            url_prefix = path[:path_len]

            # must be equal up to the length of the path, at least
            if trust_prefix != url_prefix:
                return False

            # These characters must be on the boundary between the end
            # of the trust root's path and the start of the URL's
            # path.
            if '?' in self.path:
                allowed = '&'
            else:
                allowed = '?/'

            return (self.path[-1] in allowed or
                path[path_len] in allowed)

        return True

    def parse(cls, trust_root):
        """
        This method creates a C{L{TrustRoot}} instance from the given
        input, if possible.

        @param trust_root: This is the trust root to parse into a
        C{L{TrustRoot}} object.

        @type trust_root: C{str}

        @return: A C{L{TrustRoot}} instance if trust_root parses as a
        trust root, C{None} otherwise.

        @rtype: C{NoneType} or C{L{TrustRoot}}
        """
        if not isinstance(trust_root, (str, unicode)):
            return None

        url_parts = _parseURL(trust_root)
        if url_parts is None:
            return None

        proto, host, port, path = url_parts

        # check for valid prototype
        if proto not in _protocols:
            return None

        # check for URI fragment
        if path.find('#') != -1:
            return None

        # extract wildcard if it is there
        if host.find('*', 1) != -1:
            # wildcard must be at start of domain:  *.foo.com, not foo.*.com
            return None

        if host.startswith('*'):
            # Starts with star, so must have a dot after it (if a
            # domain is specified)
            if len(host) > 1 and host[1] != '.':
                return None

            host = host[1:]
            wilcard = True
        else:
            wilcard = False

        # we have a valid trust root
        tr = cls(trust_root, proto, wilcard, host, port, path)

        return tr

    parse = classmethod(parse)

    def checkSanity(cls, trust_root_string):
        """str -> bool

        is this a sane trust root?
        """
        return cls.parse(trust_root_string).isSane()

    checkSanity = classmethod(checkSanity)

    def checkURL(cls, trust_root, url):
        """quick func for validating a url against a trust root.  See the
        TrustRoot class if you need more control."""
        tr = cls.parse(trust_root)
        return tr is not None and tr.validateURL(url)

    checkURL = classmethod(checkURL)

    def buildDiscoveryURL(self):
        """Return a discovery URL for this realm.

        This function does not check to make sure that the realm is
        valid. Its behaviour on invalid inputs is undefined.

        @param return_to: The relying party return URL of the OpenID
            authentication request

        @rtype: str

        @returns: The URL upon which relying party discovery should be run
            in order to verify the return_to URL
        """
        if self.wildcard:
            # Use "www." in place of the star
            assert self.host.startswith('.'), self.host
            www_domain = 'www' + self.host
            return '%s://%s%s' % (self.proto, www_domain, self.path)
        else:
            return self.unparsed

    def __repr__(self):
        return "TrustRoot('%s', '%s', '%s', '%s', '%s', '%s')" % (
            self.unparsed, self.proto, self.wildcard, self.host, self.port,
            self.path)

    def __str__(self):
        return repr(self)

# The URI for relying party discovery, used in realm verification.
#
# XXX: This should probably live somewhere else (like in
# openid.consumer or openid.yadis somewhere)
RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to'

def _extractReturnURL(endpoint):
    """If the endpoint is a relying party OpenID return_to endpoint,
    return the endpoint URL. Otherwise, return None.

    This function is intended to be used as a filter for the Yadis
    filtering interface.

    @see: C{L{openid.yadis.services}}
    @see: C{L{openid.yadis.filters}}

    @param endpoint: An XRDS BasicServiceEndpoint, as returned by
        performing Yadis dicovery.

    @returns: The endpoint URL or None if the endpoint is not a
        relying party endpoint.
    @rtype: str or NoneType
    """
    if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE]):
        return endpoint.uri
    else:
        return None

def returnToMatches(allowed_return_to_urls, return_to):
    """Is the return_to URL under one of the supplied allowed
    return_to URLs?"""

    for allowed_return_to in allowed_return_to_urls:
        # A return_to pattern works the same as a realm, except that
        # it's not allowed to use a wildcard. We'll model this by
        # parsing it as a realm, and not trying to match it if it has
        # a wildcard.

        return_realm = TrustRoot.parse(allowed_return_to)
        if (# Parses as a trust root
            return_realm is not None and

            # Does not have a wildcard
            not return_realm.wildcard and

            # Matches the return_to that we passed in with it
            return_realm.validateURL(return_to)
            ):
            return True

    # No URL in the list matched
    return False

def getAllowedReturnURLs(relying_party_url):
    """Given a relying party discovery URL return a list of return_to URLs.
    """
    (rp_url_after_redirects, return_to_urls) = services.getServiceEndpoints(
        relying_party_url, _extractReturnURL)

    if rp_url_after_redirects != relying_party_url:
        # Verification caused a redirect
        raise RealmVerificationRedirected(
            relying_party_url, rp_url_after_redirects)

    return return_to_urls

# _vrfy parameter is there to make testing easier
def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs):
    """Verify that a return_to URL is valid for the given realm.

    This function builds a discovery URL, performs Yadis discovery on
    it, makes sure that the URL does not redirect, parses out the
    return_to URLs, and finally checks to see if the current return_to
    URL matches the return_to.

    @raises DiscoveryFailure: When Yadis discovery fails
    @returns: True if the return_to URL is valid for the realm
    """
    realm = TrustRoot.parse(realm_str)
    if realm is None:
        # The realm does not parse as a URL pattern
        return False

    try:
        allowable_urls = _vrfy(realm.buildDiscoveryURL())
    except RealmVerificationRedirected, err:
        oidutil.log(str(err))
        return False

    if returnToMatches(allowable_urls, return_to):
        return True
    else:
        oidutil.log("Failed to validate return_to %r for realm %r, was not "
                    "in %s" % (return_to, realm_str, allowable_urls))
        return False
<commit_msg>[project @ whitespace]<commit_after>"""
This module contains the C{L{TrustRoot}} class, which helps handle
trust root checking.  This module is used by the
C{L{openid.server.server}} module, but it is also available to server
implementers who wish to use it for additional trust root checking.

It also implements relying party return_to URL verification, based on
the realm.
"""

__all__ = [
    'TrustRoot',
    'RP_RETURN_TO_URL_TYPE',
    'extractReturnToURLs',
    'returnToMatches',
    'verifyReturnTo',
    ]

from openid import oidutil
from openid.yadis import services
from urlparse import urlparse, urlunparse

############################################
_protocols = ['http', 'https']
_top_level_domains = (
    'com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|ad|ae|'
    'af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|'
    'bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|'
    'cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|'
    'fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|'
    'ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|'
    'kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|'
    'mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|'
    'nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|'
    'sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|sv|sy|sz|tc|td|tf|tg|th|'
    'tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|'
    'vn|vu|wf|ws|ye|yt|yu|za|zm|zw'
    ).split('|')

class RealmVerificationRedirected(Exception):
    """Attempting to verify this realm resulted in a redirect.
    """
    def __init__(self, relying_party_url, rp_url_after_redirects):
        self.relying_party_url = relying_party_url
        self.rp_url_after_redirects = rp_url_after_redirects

    def __str__(self):
        return ("Attempting to verify %r resulted in "
                "redirect to %r" %
                (self.relying_party_url,
                 self.rp_url_after_redirects))

def _parseURL(url):
    proto, netloc, path, params, query, frag = urlparse(url)
    if not path:
        # Python <2.4 does not parse URLs with no path properly
        if not query and '?' in netloc:
            netloc, query = netloc.split('?', 1)

        path = '/'

    path = urlunparse(('', '', path, params, query, frag))

    if ':' in netloc:
        try:
            host, port = netloc.split(':')
        except ValueError:
            return None
    else:
        host = netloc
        port = ''

    host = host.lower()
    return proto, host, port, path

class TrustRoot(object):
    """
    This class represents an OpenID trust root.  The C{L{parse}}
    classmethod accepts a trust root string, producing a
    C{L{TrustRoot}} object.  The method OpenID server implementers
    would be most likely to use is the C{L{isSane}} method, which
    checks the trust root for given patterns that indicate that the
    trust root is too broad or points to a local network resource.

    @sort: parse, isSane
    """

    def __init__(self, unparsed, proto, wildcard, host, port, path):
        self.unparsed = unparsed
        self.proto = proto
        self.wildcard = wildcard
        self.host = host
        self.port = port
        self.path = path

    def isSane(self):
        """
        This method checks the to see if a trust root represents a
        reasonable (sane) set of URLs.  'http://*.com/', for example
        is not a reasonable pattern, as it cannot meaningfully specify
        the site claiming it.  This function attempts to find many
        related examples, but it can only work via heuristics.
        Negative responses from this method should be treated as
        advisory, used only to alert the user to examine the trust
        root carefully.

        @return: Whether the trust root is sane

        @rtype: C{bool}
        """

        if self.host == 'localhost':
            return True

        host_parts = self.host.split('.')
        if self.wildcard:
            assert host_parts[0] == '', host_parts
            del host_parts[0]

        # If it's an absolute domain name, remove the empty string
        # from the end.
        if host_parts and not host_parts[-1]:
            del host_parts[-1]

        if not host_parts:
            return False

        # Do not allow adjacent dots
        if '' in host_parts:
            return False

        tld = host_parts[-1]
        if tld not in _top_level_domains:
            return False

        if len(host_parts) == 1:
            return False

        if self.wildcard:
            if len(tld) == 2 and len(host_parts[-2]) <= 3:
                # It's a 2-letter tld with a short second to last segment
                # so there needs to be more than two segments specified
                # (e.g. *.co.uk is insane)
                return len(host_parts) > 2

        # Passed all tests for insanity.
        return True

    def validateURL(self, url):
        """
        Validates a URL against this trust root.

        @param url: The URL to check

        @type url: C{str}

        @return: Whether the given URL is within this trust root.

        @rtype: C{bool}
        """

        url_parts = _parseURL(url)
        if url_parts is None:
            return False

        proto, host, port, path = url_parts

        if proto != self.proto:
            return False

        if port != self.port:
            return False

        if '*' in host:
            return False

        if not self.wildcard:
            if host != self.host:
                return False
        elif ((not host.endswith(self.host)) and
              ('.' + host) != self.host):
            return False

        if path != self.path:
            path_len = len(self.path)
            trust_prefix = self.path[:path_len]
            url_prefix = path[:path_len]

            # must be equal up to the length of the path, at least
            if trust_prefix != url_prefix:
                return False

            # These characters must be on the boundary between the end
            # of the trust root's path and the start of the URL's
            # path.
            if '?' in self.path:
                allowed = '&'
            else:
                allowed = '?/'

            return (self.path[-1] in allowed or
                path[path_len] in allowed)

        return True

    def parse(cls, trust_root):
        """
        This method creates a C{L{TrustRoot}} instance from the given
        input, if possible.

        @param trust_root: This is the trust root to parse into a
        C{L{TrustRoot}} object.

        @type trust_root: C{str}

        @return: A C{L{TrustRoot}} instance if trust_root parses as a
        trust root, C{None} otherwise.

        @rtype: C{NoneType} or C{L{TrustRoot}}
        """
        if not isinstance(trust_root, (str, unicode)):
            return None

        url_parts = _parseURL(trust_root)
        if url_parts is None:
            return None

        proto, host, port, path = url_parts

        # check for valid prototype
        if proto not in _protocols:
            return None

        # check for URI fragment
        if path.find('#') != -1:
            return None

        # extract wildcard if it is there
        if host.find('*', 1) != -1:
            # wildcard must be at start of domain:  *.foo.com, not foo.*.com
            return None

        if host.startswith('*'):
            # Starts with star, so must have a dot after it (if a
            # domain is specified)
            if len(host) > 1 and host[1] != '.':
                return None

            host = host[1:]
            wilcard = True
        else:
            wilcard = False

        # we have a valid trust root
        tr = cls(trust_root, proto, wilcard, host, port, path)

        return tr

    parse = classmethod(parse)

    def checkSanity(cls, trust_root_string):
        """str -> bool

        is this a sane trust root?
        """
        return cls.parse(trust_root_string).isSane()

    checkSanity = classmethod(checkSanity)

    def checkURL(cls, trust_root, url):
        """quick func for validating a url against a trust root.  See the
        TrustRoot class if you need more control."""
        tr = cls.parse(trust_root)
        return tr is not None and tr.validateURL(url)

    checkURL = classmethod(checkURL)

    def buildDiscoveryURL(self):
        """Return a discovery URL for this realm.

        This function does not check to make sure that the realm is
        valid. Its behaviour on invalid inputs is undefined.

        @param return_to: The relying party return URL of the OpenID
            authentication request

        @rtype: str

        @returns: The URL upon which relying party discovery should be run
            in order to verify the return_to URL
        """
        if self.wildcard:
            # Use "www." in place of the star
            assert self.host.startswith('.'), self.host
            www_domain = 'www' + self.host
            return '%s://%s%s' % (self.proto, www_domain, self.path)
        else:
            return self.unparsed

    def __repr__(self):
        return "TrustRoot('%s', '%s', '%s', '%s', '%s', '%s')" % (
            self.unparsed, self.proto, self.wildcard, self.host, self.port,
            self.path)

    def __str__(self):
        return repr(self)

# The URI for relying party discovery, used in realm verification.
#
# XXX: This should probably live somewhere else (like in
# openid.consumer or openid.yadis somewhere)
RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to'

def _extractReturnURL(endpoint):
    """If the endpoint is a relying party OpenID return_to endpoint,
    return the endpoint URL. Otherwise, return None.

    This function is intended to be used as a filter for the Yadis
    filtering interface.

    @see: C{L{openid.yadis.services}}
    @see: C{L{openid.yadis.filters}}

    @param endpoint: An XRDS BasicServiceEndpoint, as returned by
        performing Yadis dicovery.

    @returns: The endpoint URL or None if the endpoint is not a
        relying party endpoint.
    @rtype: str or NoneType
    """
    if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE]):
        return endpoint.uri
    else:
        return None

def returnToMatches(allowed_return_to_urls, return_to):
    """Is the return_to URL under one of the supplied allowed
    return_to URLs?"""

    for allowed_return_to in allowed_return_to_urls:
        # A return_to pattern works the same as a realm, except that
        # it's not allowed to use a wildcard. We'll model this by
        # parsing it as a realm, and not trying to match it if it has
        # a wildcard.

        return_realm = TrustRoot.parse(allowed_return_to)
        if (# Parses as a trust root
            return_realm is not None and

            # Does not have a wildcard
            not return_realm.wildcard and

            # Matches the return_to that we passed in with it
            return_realm.validateURL(return_to)
            ):
            return True

    # No URL in the list matched
    return False

def getAllowedReturnURLs(relying_party_url):
    """Given a relying party discovery URL return a list of return_to URLs.
    """
    (rp_url_after_redirects, return_to_urls) = services.getServiceEndpoints(
        relying_party_url, _extractReturnURL)

    if rp_url_after_redirects != relying_party_url:
        # Verification caused a redirect
        raise RealmVerificationRedirected(
            relying_party_url, rp_url_after_redirects)

    return return_to_urls

# _vrfy parameter is there to make testing easier
def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs):
    """Verify that a return_to URL is valid for the given realm.

    This function builds a discovery URL, performs Yadis discovery on
    it, makes sure that the URL does not redirect, parses out the
    return_to URLs, and finally checks to see if the current return_to
    URL matches the return_to.

    @raises DiscoveryFailure: When Yadis discovery fails
    @returns: True if the return_to URL is valid for the realm
    """
    realm = TrustRoot.parse(realm_str)
    if realm is None:
        # The realm does not parse as a URL pattern
        return False

    try:
        allowable_urls = _vrfy(realm.buildDiscoveryURL())
    except RealmVerificationRedirected, err:
        oidutil.log(str(err))
        return False

    if returnToMatches(allowable_urls, return_to):
        return True
    else:
        oidutil.log("Failed to validate return_to %r for realm %r, was not "
                    "in %s" % (return_to, realm_str, allowable_urls))
        return False
<|endoftext|>


<commit_before>import datetime
from py2neo import authenticate
from wikitools import wiki
from wikitools import category
import re
from wikitools.page import NoPage, Page
from py2neo import neo4j, node, rel
import logging
from nltk.tag.stanford import StanfordNERTagger as NER

logging.basicConfig(level=logging.WARNING)
authenticate("localhost:7474", "neo4j", "10p13dd0053")
needless = re.compile(r' \(')
site = wiki.Wiki("http://en.wikipedia.org/w/api.php")

graph_db = neo4j.Graph("http://localhost:7474/db/data")

db_categories = graph_db.legacy.get_or_create_index(neo4j.Node, "Categories")
db_pages = graph_db.legacy.get_or_create_index(neo4j.Node, "Pages")

def log(msg):
    print("{} {}".format(str(datetime.datetime.now()), msg))

def WTree(name, visitedCategories=set(), dbcat=None):
    """
    For a given category, query subcategories and get categories and pages.
    Query subcategories recursively
    :type name: str
    :type visitedCategories: set
    """

    visitedCategories.add(name)

    cat = category.Category(site, "Category:"+name)
    if dbcat is None:
        dbcat = db_categories.get_or_create("name", name, {"name": name, "pageid": cat.pageid})
        dbcat.add_labels('Category')
    else:
        dbcat["pageid"] = cat.pageid

    catlist = cat.getAllMembers(namespaces=[14], titleonly=True)
    pagelist = cat.getAllMembers(namespaces=[0], titleonly=True)

    for page in pagelist:
        try:

            title = page.encode('ascii', 'ignore')

            db_page = db_pages.get("name", title)
            if not len(db_page):
                db_page = db_pages.create("name", title, {"name": title, "is": "page"})
                db_page.add_labels('Pages')
            else:
                db_page = db_page[0]

            graph_db.create(rel(dbcat, "has page", db_page))

        except Exception as ex:
            if ex is NoPage:
                log("Page not found! {}".format(page))
            else:
                log('exception occured! page: {}, msg: {}'.format(page, ex.message))

    log("       {} pages saved".format(len(pagelist)))

    for catname in catlist:
        new = False
        catname = catname[9:]
        cat1= category.Category(site, "Category:"+catname)
        childcat = db_categories.get("name", catname)
        if not len(childcat):
            new = True
            childcat = db_categories.create("name", catname, {"name": catname, "is": "category", "pageid": cat1.pageid})
            childcat.add_labels('Category')
        else:
            childcat = childcat[0]

        graph_db.create(rel(dbcat, "has category", childcat))

        if new is False and ('d' in childcat or catname in visitedCategories ):
            continue

        WTree(catname, visitedCategories, childcat)
        childcat['d'] = datetime.datetime.now()

if __name__ == "__main__":

    CategoryTree = {}

    cat = 'Main topic classifications'

    print("{} Started processing category '{}'".format(str(datetime.datetime.now()), cat))

    WTree(cat)

    print("{} Finished processing category '{}'".format(str(datetime.datetime.now()), cat))

<commit_msg>1234 for all categories<commit_after>import datetime
from py2neo import authenticate
from wikitools import wiki
from wikitools import category
import re
from wikitools.page import NoPage, Page
from py2neo import neo4j, node, rel
import logging
from nltk.tag.stanford import StanfordNERTagger as NER

logging.basicConfig(level=logging.WARNING)
authenticate("localhost:7474", "neo4j", "10p13dd0053")
needless = re.compile(r' \(')
site = wiki.Wiki("http://en.wikipedia.org/w/api.php")

graph_db = neo4j.Graph("http://localhost:7474/db/data")
graph_db.delete_all()

db_categories = graph_db.legacy.get_or_create_index(neo4j.Node, "Categories")
db_pages = graph_db.legacy.get_or_create_index(neo4j.Node, "Pages")

def log(msg):
    print("{} {}".format(str(datetime.datetime.now()), msg))

def WTree(name, visitedCategories=set(), dbcat=None):
    """
    For a given category, query subcategories and get categories and pages.
    Query subcategories recursively
    :type name: str
    :type visitedCategories: set
    """

    visitedCategories.add(name)

    cat = category.Category(site, "Category:"+name)
    if dbcat is None:
        dbcat = db_categories.get_or_create("name", name, {"name": name, "pageid": cat.pageid})
        dbcat.add_labels('Category')
    else:
        dbcat["pageid"] = cat.pageid

    catlist = cat.getAllMembers(namespaces=[14], titleonly=True)
    pagelist = cat.getAllMembers(namespaces=[0], titleonly=True)

    for page in pagelist:
        try:

            title = page.encode('ascii', 'ignore')

            db_page = db_pages.get("name", title)
            if not len(db_page):
                db_page = db_pages.create("name", title, {"name": title, "is": "page"})
                db_page.add_labels('Pages')
            else:
                db_page = db_page[0]

            graph_db.create(rel(dbcat, "has page", db_page))

        except Exception as ex:
            if ex is NoPage:
                log("Page not found! {}".format(page))
            else:
                log('exception occured! page: {}, msg: {}'.format(page, ex.message))

    log("       {} pages saved".format(len(pagelist)))

    for catname in catlist:
        new = False
        catname = catname[9:]
        cat1= category.Category(site, "Category:"+catname)
        childcat = db_categories.get("name", catname)
        if not len(childcat):
            new = True
            childcat = db_categories.create("name", catname, {"name": catname, "is": "category", "pageid": cat1.pageid})
            childcat.add_labels('Category')
        else:
            childcat = childcat[0]

        graph_db.create(rel(dbcat, "has category", childcat))

        if new is False and ('d' in childcat or catname in visitedCategories ):
            continue

        WTree(catname, visitedCategories, childcat)
        childcat['d'] = datetime.datetime.now()

if __name__ == "__main__":

    CategoryTree = {}

    cat = 'Main topic classifications'

    print("{} Started processing category '{}'".format(str(datetime.datetime.now()), cat))

    WTree(cat)

    print("{} Finished processing category '{}'".format(str(datetime.datetime.now()), cat))

<|endoftext|>


<commit_before>#
# Copyright (c) 2004 Specifix, Inc.
# All rights reserved
#

"""Classes for version structures and strings"""

import copy
import time
import string

class AbstractVersion:

    """
    Ancestor class for all versions (as opposed to branches)
    """

    def __init__(self):
	pass

class AbstractBranch:

    """
    Ancestor class for all branches (as opposed to versions)
    """

    def __init__(self):
	pass

class VersionRelease(AbstractVersion):

    """
    Version element for a version/release pair. These are formatted as
    "version-release", with no hyphen allowed in either portion. The
    release must be a simple integer or two integers separated by a
    decimal point.
    """

    def __str__(self):
	"""
	Returns a string representation of a version/release pair.
	"""
	if self.buildCount != None:
	    return "%s-%d.%d" % (self.version, self.release, self.buildCount)

	return self.version + '-' + str(self.release)

    def getVersion(self):
	"""
	Returns the version string of a version/release pair.
	"""

	return self.version

    def equal(self, version):
	"""
	Compares two version-type objects and tells if they are the same
	or not.

	@rtype: boolean
	"""
	if (type(self) == type(version) and self.version == version.version
		and self.release == version.release):
	    return 1
	return 0

    def incrementRelease(self):
	"""
	Incremements the release number.
	"""
	self.release += 1

    def incrementBuildCount(self):
	"""
	Incremements the build count
	"""
	if self.buildCount:
	    self.buildCount += 1
	else:
	    self.buildCount = 1

    def __init__(self, value):
	"""
	Initialize a VersionRelease object from a string representation
	of a version release. ParseError exceptions are thrown if the
	string representation is ill-formed.

	@param value: String representation of a VersionRelease
	@type value: string
	"""
	if value.find("@") != -1:
	    raise ParseError, "version/release pairs may not contain @ signs"
	cut = value.find("-")
	if cut == -1:
	    raise ParseError, ("version/release pair was expected")
	self.version = value[:cut]

	try:
	    int(self.version[0])
	except:
	    raise ParseError, \
		("version numbers must be begin with a digit: %s" % value)

	fullRelease = value[cut + 1:]
	cut = fullRelease.find(".")
	if cut != -1:
	    self.release = fullRelease[:cut]
	    self.buildCount = fullRelease[cut + 1:]
	else:
	    self.release = fullRelease
	    self.buildCount = None

	try:
	    self.release = int(self.release)
	except:
	    raise ParseError, ("release numbers must be all numeric: %s" % value)
	if self.buildCount:
	    try:
		self.buildCount = int(self.buildCount)
	    except:
		raise ParseError, \
		    ("build count numbers must be all numeric: %s" % value)

class BranchName(AbstractBranch):

    """
    Stores a branch name, which is the same as a nickname. Branch names
    are of the form hostname@branch.
    """

    def __str__(self):
	"""
	Returns the string representation of a branch name.
	"""
	return self.host + '@' + str(self.branch)

    def equal(self, version):
	"""
	Compares the BranchName object to another object, and returns
	true if they refer to the same branch.

	@param version: version to compare against
	@type version: instance
	@rtype: boolean
	"""
	if (self.__class__ == version.__class__
	     and self.host == version.host and self.branch == version.branch):
	    return 1
	return 0

    def __init__(self, value):
	"""
	Parses a branch name string into a BranchName object. A ParseError is
	thrown if the BranchName is not well formed.

	@param value: String representation of a BranchName
	@type value: str
	"""
	if value.find("@") == -1:
	    raise ParseError, "@ expected between hostname and branch name"
	if value.find("/") != -1:
	    raise ParseError, "/ should not appear in a branch name"

	(self.host, self.branch) = value.split("@", 1)
	if self.branch.find("@") != -1:
	    raise ParseError, ("branch names may not have @ signs: %s" % value)

class LocalBranch(BranchName):

    """
    Class defining the local branch.
    """

    def __init__(self):
	BranchName.__init__(self, "localhost@LOCAL")

class Version:

    """
    Class representing a version. Versions are a list of AbstractBranch,
    AbstractVersion sequences. If the last item is an AbstractBranch (meaning
    an odd number of objects are in the list, the version represents
    a branch. A version includes a time stamp, which is used for
    ordering.
    """

    def appendVersionRelease(self, version, release):
	"""
	Converts a branch to a version. The version/release passed in
	are converted to a VersionRelease object and appended to the
	branch this object represented. The time stamp is reset as
	a new version has been created.

	@param version: string representing a version
	@type version: str
	@param release: release number
	@type release: int
	"""
	assert(self.isBranch())
	self.versions.append(VersionRelease("%s-%d" % (version, release)))
	self.timeStamp = time.time()

    def appendVersionReleaseObject(self, verRel):
	"""
	Converts a branch to a version. The version/release passed in
	are appended to the branch this object represented. The time
	stamp is reset as a new version has been created.

	@param version: object for the version and release
	@type version: VersionRelease
	@param release: release number
	@type release: int
	"""
	assert(self.isBranch())
	self.versions.append(verRel)
	self.timeStamp = time.time()

    def incrementRelease(self):
	"""
	The release number for the final element in the version is
	incremented by one and the time stamp is reset.
	"""
	assert(self.isVersion())

	self.versions[-1].incrementRelease()
	self.timeStamp = time.time()

    def incrementBuildCount(self):
	"""
	The build count number for the final element in the version is
	incremented by one and the time stamp is reset.
	"""
	assert(self.isVersion())

	self.versions[-1].incrementBuildCount()
	self.timeStamp = time.time()

    def trailingVersion(self):
	"""
	Returns the AbstractVersion object at the end of the version.

	@rtype: AbstactVersion
	"""
	assert(self.isVersion())

	return self.versions[-1]

    def _listsEqual(self, list, other):
	if len(other.versions) != len(list): return 0

	for i in range(0, len(list)):
	    if not list[i].equal(other.versions[i]): return 0

	return 1

    def equal(self, other):
	"""
	Compares this object to another Version object to see if they
	are the same.

	@rtype: boolean
	"""
	return self._listsEqual(self.versions, other)

    def asString(self, defaultBranch = None):
	"""
	Returns a string representation of the version.

	@param defaultBranch: If set this is stripped fom the beginning
	of the version to give a shorter string representation.
	@type defaultBranch: Version
	@rtype: str
	"""
	list = self.versions
	s = "/"

	if defaultBranch and len(defaultBranch.versions) < len(self.versions):
	    start = Version(self.versions[0:len(defaultBranch.versions)], 0)
	    if start.equal(defaultBranch):
		list = self.versions[len(defaultBranch.versions):]
		s = ""

	for version in list:
	    s = s + ("%s/" % version)

	return s[:-1]

    def freeze(self, defaultBranch = None):
	"""
	Returns a complete string representation of the version, including
	the time stamp.

	@rtype: str
	"""
	return ("%.3f:" % self.timeStamp) + self.asString(defaultBranch)

    def isBranch(self):
	"""
	Tests whether or not the current object is a branch.

	@rtype: boolean
	"""
	return isinstance(self.versions[-1], BranchName)

    def isVersion(self):
	"""
	Tests whether or not the current object is a version (not a branch).

	@rtype: boolean
	"""
	return isinstance(self.versions[-1], VersionRelease)

    def isLocal(self):
    	"""
	Tests whether this is the local branch, or is a version on
	the local branch

	@rtype: boolean
	"""
	return isinstance(self.versions[-1], LocalBranch) or    \
	    (len(self.versions) > 1 and
	     isinstance(self.versions[-2], LocalBranch))

    def onBranch(self, branch):
	"""
	Tests whether or not the current object is a version on the
	specified branch.

	@rtype: boolean
	"""
	if self.isBranch(): return 0
	return self._listsEqual(self.versions[:-1], branch)

    def branch(self):
	"""
	Returns the branch this version is part of.

	@rtype: Version
	"""
	assert(not self.isBranch())
	return Version(self.versions[:-1], 0)

    def branchNickname(self):
	"""
	Returns the BranchName object at the end of a branch. This is
	known as the branch nick name, as is used in VersionedFiles as
	an index.

	@rtype: BranchName
	"""
	assert(self.isBranch())
	return self.versions[-1]

    def parent(self):
	"""
	Returns the parent version for this version (the version this
	object's branch branched from.

	@rtype: Version
	"""
	assert(self.isVersion())
	assert(len(self.versions) > 3)
	return Version(self.versions[:-2], 0)

    def parentNode(self):
	"""
	Returns the parent version of a branch.

	@rtype: Version
	"""
	assert(self.isBranch())
	assert(len(self.versions) >= 3)
	return Version(self.versions[:-1], 0)

    def hasParent(self):
	"""
	Tests whether or not the current branch or version has a parent.
	True for all versions other then those on trunks.

	@rtype: boolean
	"""
	return(len(self.versions) >= 3)

    def isBefore(self, other):
	"""
	Tests whether the parameter is a version earlier then this object.

	@param other: Object to test against
	@type other: Version
	@rtype: boolean
	"""
	return self.timeStamp < other.timeStamp

    def isAfter(self, other):
	"""
	Tests whether the parameter is a version later then this object.

	@param other: Object to test against
	@type other: Version
	@rtype: boolean
	"""
	return self.timeStamp > other.timeStamp

    def copy(self):
	"""
	Returns a Version object which is a copy of this object. The
	result can be modified without affecting this object in any way.j

	@rtype: Version
	"""

        return copy.deepcopy(self)

    def fork(self, branch, sameVerRel = True):
	"""
	Creates a new branch from this version.

	@param branch: Branch to create for this version
	@type branch: AbstractBranch
	@param sameVerRel: If set, the new branch is turned into a version
	on the branch using the same version and release as the original
	verison.
	@type sameVerRel: boolean
	@rtype: Version
	"""
	assert(isinstance(branch, AbstractBranch))
	newlist = [ branch ]

	if sameVerRel:
	    newlist.append(self.versions[-1])

	return Version(self.versions + newlist, time.time())

    def parseVersionString(self, ver, defaultBranch = None):
	"""
	Converts a string representation of a version into a VersionRelease
	object.

	@param ver: version string
	@type ver: str
	@param defaultBranch: if provided and the ver parameter is not
	fully-qualified (it doesn't begin with a /), ver is taken to
	be relative to this branch.
	@type defaultBranch: Version
	"""
	if ver[0] != "/":
            # XXX broken code, no defaultBranch in this scope
	    if not defaultBranch:
		raise KeyError, "relative version given without a default " \
			        "branch"
	    ver = defaultBranch.asString() + "/" + ver

	parts = ver.split("/")
	del parts[0]	# absolute versions start with a /

	v = []
	while parts:
	    if parts[0] == "localhost@LOCAL":
		v.append(LocalBranch())
	    else:
		v.append(BranchName(parts[0]))

	    if len(parts) >= 2:
		v.append(VersionRelease(parts[1]))
		parts = parts[2:]
	    else:
		parts = None

	return v

    """
    Creates a Version object from a list of AbstractBranch and AbstractVersion
    objects.
    """
    def __init__(self, versionList, timeStamp):
	self.versions = versionList
	self.timeStamp = timeStamp

class ThawVersion(Version):

    """
    Provides a version object from a frozen version string.
    """

    def __init__(self, fullString):
	"""
	Initializes a ThawVersion object.

	@param fullString: Frozen representation of a Version object.
	@type fullString: str
	"""
	(timeStr, ver) = fullString.split(":")

	timeVal = float(timeStr)
	v = self.parseVersionString(ver)

	Version.__init__(self, v, timeVal)

class VersionFromString(Version):

    """
    Provides a version object from a string representation of a version.
    The time stamp is set to 0, so this object cannot be properly ordered
    with respect to other versions.
    """

    def __init__(self, ver, defaultBranch = None):
	"""
	Initializes a VersionFromString object.

	@param ver: string representation of a version
	@type ver: str
	@param defaultBranch: if provided and the ver parameter is not
	fully-qualified (it doesn't begin with a /), ver is taken to
	be relative to this branch.
	@type defaultBranch: Version
	"""
	if ver[0] != "/":
	    ver = defaultBranch.asString() + "/" + ver

	v = self.parseVersionString(ver, defaultBranch)

	Version.__init__(self, v, 0)

class VersionsError(Exception):

    """
    Ancestor for all exceptions raised by the versions module.
    """

    pass

class ParseError(VersionsError):

    """
    Indicates that an error occured turning a string into an object
    in the versions module.
    """

    def __repr__(self):
	return self.str

    def __str__(self):
	return self.str

    def __init__(self, str):
	self.str = str
<commit_msg>compare builtCount when comparing VersionRelease objects<commit_after>#
# Copyright (c) 2004 Specifix, Inc.
# All rights reserved
#

"""Classes for version structures and strings"""

import copy
import time
import string

class AbstractVersion:

    """
    Ancestor class for all versions (as opposed to branches)
    """

    def __init__(self):
	pass

class AbstractBranch:

    """
    Ancestor class for all branches (as opposed to versions)
    """

    def __init__(self):
	pass

class VersionRelease(AbstractVersion):

    """
    Version element for a version/release pair. These are formatted as
    "version-release", with no hyphen allowed in either portion. The
    release must be a simple integer or two integers separated by a
    decimal point.
    """

    def __str__(self):
	"""
	Returns a string representation of a version/release pair.
	"""
	if self.buildCount != None:
	    return "%s-%d.%d" % (self.version, self.release, self.buildCount)

	return self.version + '-' + str(self.release)

    def getVersion(self):
	"""
	Returns the version string of a version/release pair.
	"""

	return self.version

    def equal(self, version):
	"""
	Compares two version-type objects and tells if they are the same
	or not.

	@rtype: boolean
	"""
	if (type(self) == type(version) and self.version == version.version
		and self.release == version.release
		and self.buildCount == version.buildCount):
	    return 1
	return 0

    def incrementRelease(self):
	"""
	Incremements the release number.
	"""
	self.release += 1

    def incrementBuildCount(self):
	"""
	Incremements the build count
	"""
	if self.buildCount:
	    self.buildCount += 1
	else:
	    self.buildCount = 1

    def __init__(self, value):
	"""
	Initialize a VersionRelease object from a string representation
	of a version release. ParseError exceptions are thrown if the
	string representation is ill-formed.

	@param value: String representation of a VersionRelease
	@type value: string
	"""
	if value.find("@") != -1:
	    raise ParseError, "version/release pairs may not contain @ signs"
	cut = value.find("-")
	if cut == -1:
	    raise ParseError, ("version/release pair was expected")
	self.version = value[:cut]

	try:
	    int(self.version[0])
	except:
	    raise ParseError, \
		("version numbers must be begin with a digit: %s" % value)

	fullRelease = value[cut + 1:]
	cut = fullRelease.find(".")
	if cut != -1:
	    self.release = fullRelease[:cut]
	    self.buildCount = fullRelease[cut + 1:]
	else:
	    self.release = fullRelease
	    self.buildCount = None

	try:
	    self.release = int(self.release)
	except:
	    raise ParseError, ("release numbers must be all numeric: %s" % value)
	if self.buildCount:
	    try:
		self.buildCount = int(self.buildCount)
	    except:
		raise ParseError, \
		    ("build count numbers must be all numeric: %s" % value)

class BranchName(AbstractBranch):

    """
    Stores a branch name, which is the same as a nickname. Branch names
    are of the form hostname@branch.
    """

    def __str__(self):
	"""
	Returns the string representation of a branch name.
	"""
	return self.host + '@' + str(self.branch)

    def equal(self, version):
	"""
	Compares the BranchName object to another object, and returns
	true if they refer to the same branch.

	@param version: version to compare against
	@type version: instance
	@rtype: boolean
	"""
	if (self.__class__ == version.__class__
	     and self.host == version.host and self.branch == version.branch):
	    return 1
	return 0

    def __init__(self, value):
	"""
	Parses a branch name string into a BranchName object. A ParseError is
	thrown if the BranchName is not well formed.

	@param value: String representation of a BranchName
	@type value: str
	"""
	if value.find("@") == -1:
	    raise ParseError, "@ expected between hostname and branch name"
	if value.find("/") != -1:
	    raise ParseError, "/ should not appear in a branch name"

	(self.host, self.branch) = value.split("@", 1)
	if self.branch.find("@") != -1:
	    raise ParseError, ("branch names may not have @ signs: %s" % value)

class LocalBranch(BranchName):

    """
    Class defining the local branch.
    """

    def __init__(self):
	BranchName.__init__(self, "localhost@LOCAL")

class Version:

    """
    Class representing a version. Versions are a list of AbstractBranch,
    AbstractVersion sequences. If the last item is an AbstractBranch (meaning
    an odd number of objects are in the list, the version represents
    a branch. A version includes a time stamp, which is used for
    ordering.
    """

    def appendVersionRelease(self, version, release):
	"""
	Converts a branch to a version. The version/release passed in
	are converted to a VersionRelease object and appended to the
	branch this object represented. The time stamp is reset as
	a new version has been created.

	@param version: string representing a version
	@type version: str
	@param release: release number
	@type release: int
	"""
	assert(self.isBranch())
	self.versions.append(VersionRelease("%s-%d" % (version, release)))
	self.timeStamp = time.time()

    def appendVersionReleaseObject(self, verRel):
	"""
	Converts a branch to a version. The version/release passed in
	are appended to the branch this object represented. The time
	stamp is reset as a new version has been created.

	@param version: object for the version and release
	@type version: VersionRelease
	@param release: release number
	@type release: int
	"""
	assert(self.isBranch())
	self.versions.append(verRel)
	self.timeStamp = time.time()

    def incrementRelease(self):
	"""
	The release number for the final element in the version is
	incremented by one and the time stamp is reset.
	"""
	assert(self.isVersion())

	self.versions[-1].incrementRelease()
	self.timeStamp = time.time()

    def incrementBuildCount(self):
	"""
	The build count number for the final element in the version is
	incremented by one and the time stamp is reset.
	"""
	assert(self.isVersion())

	self.versions[-1].incrementBuildCount()
	self.timeStamp = time.time()

    def trailingVersion(self):
	"""
	Returns the AbstractVersion object at the end of the version.

	@rtype: AbstactVersion
	"""
	assert(self.isVersion())

	return self.versions[-1]

    def _listsEqual(self, list, other):
	if len(other.versions) != len(list): return 0

	for i in range(0, len(list)):
	    if not list[i].equal(other.versions[i]): return 0

	return 1

    def equal(self, other):
	"""
	Compares this object to another Version object to see if they
	are the same.

	@rtype: boolean
	"""
	return self._listsEqual(self.versions, other)

    def asString(self, defaultBranch = None):
	"""
	Returns a string representation of the version.

	@param defaultBranch: If set this is stripped fom the beginning
	of the version to give a shorter string representation.
	@type defaultBranch: Version
	@rtype: str
	"""
	list = self.versions
	s = "/"

	if defaultBranch and len(defaultBranch.versions) < len(self.versions):
	    start = Version(self.versions[0:len(defaultBranch.versions)], 0)
	    if start.equal(defaultBranch):
		list = self.versions[len(defaultBranch.versions):]
		s = ""

	for version in list:
	    s = s + ("%s/" % version)

	return s[:-1]

    def freeze(self, defaultBranch = None):
	"""
	Returns a complete string representation of the version, including
	the time stamp.

	@rtype: str
	"""
	return ("%.3f:" % self.timeStamp) + self.asString(defaultBranch)

    def isBranch(self):
	"""
	Tests whether or not the current object is a branch.

	@rtype: boolean
	"""
	return isinstance(self.versions[-1], BranchName)

    def isVersion(self):
	"""
	Tests whether or not the current object is a version (not a branch).

	@rtype: boolean
	"""
	return isinstance(self.versions[-1], VersionRelease)

    def isLocal(self):
    	"""
	Tests whether this is the local branch, or is a version on
	the local branch

	@rtype: boolean
	"""
	return isinstance(self.versions[-1], LocalBranch) or    \
	    (len(self.versions) > 1 and
	     isinstance(self.versions[-2], LocalBranch))

    def onBranch(self, branch):
	"""
	Tests whether or not the current object is a version on the
	specified branch.

	@rtype: boolean
	"""
	if self.isBranch(): return 0
	return self._listsEqual(self.versions[:-1], branch)

    def branch(self):
	"""
	Returns the branch this version is part of.

	@rtype: Version
	"""
	assert(not self.isBranch())
	return Version(self.versions[:-1], 0)

    def branchNickname(self):
	"""
	Returns the BranchName object at the end of a branch. This is
	known as the branch nick name, as is used in VersionedFiles as
	an index.

	@rtype: BranchName
	"""
	assert(self.isBranch())
	return self.versions[-1]

    def parent(self):
	"""
	Returns the parent version for this version (the version this
	object's branch branched from.

	@rtype: Version
	"""
	assert(self.isVersion())
	assert(len(self.versions) > 3)
	return Version(self.versions[:-2], 0)

    def parentNode(self):
	"""
	Returns the parent version of a branch.

	@rtype: Version
	"""
	assert(self.isBranch())
	assert(len(self.versions) >= 3)
	return Version(self.versions[:-1], 0)

    def hasParent(self):
	"""
	Tests whether or not the current branch or version has a parent.
	True for all versions other then those on trunks.

	@rtype: boolean
	"""
	return(len(self.versions) >= 3)

    def isBefore(self, other):
	"""
	Tests whether the parameter is a version earlier then this object.

	@param other: Object to test against
	@type other: Version
	@rtype: boolean
	"""
	return self.timeStamp < other.timeStamp

    def isAfter(self, other):
	"""
	Tests whether the parameter is a version later then this object.

	@param other: Object to test against
	@type other: Version
	@rtype: boolean
	"""
	return self.timeStamp > other.timeStamp

    def copy(self):
	"""
	Returns a Version object which is a copy of this object. The
	result can be modified without affecting this object in any way.j

	@rtype: Version
	"""

        return copy.deepcopy(self)

    def fork(self, branch, sameVerRel = True):
	"""
	Creates a new branch from this version.

	@param branch: Branch to create for this version
	@type branch: AbstractBranch
	@param sameVerRel: If set, the new branch is turned into a version
	on the branch using the same version and release as the original
	verison.
	@type sameVerRel: boolean
	@rtype: Version
	"""
	assert(isinstance(branch, AbstractBranch))
	newlist = [ branch ]

	if sameVerRel:
	    newlist.append(self.versions[-1])

	return Version(self.versions + newlist, time.time())

    def parseVersionString(self, ver, defaultBranch = None):
	"""
	Converts a string representation of a version into a VersionRelease
	object.

	@param ver: version string
	@type ver: str
	@param defaultBranch: if provided and the ver parameter is not
	fully-qualified (it doesn't begin with a /), ver is taken to
	be relative to this branch.
	@type defaultBranch: Version
	"""
	if ver[0] != "/":
            # XXX broken code, no defaultBranch in this scope
	    if not defaultBranch:
		raise KeyError, "relative version given without a default " \
			        "branch"
	    ver = defaultBranch.asString() + "/" + ver

	parts = ver.split("/")
	del parts[0]	# absolute versions start with a /

	v = []
	while parts:
	    if parts[0] == "localhost@LOCAL":
		v.append(LocalBranch())
	    else:
		v.append(BranchName(parts[0]))

	    if len(parts) >= 2:
		v.append(VersionRelease(parts[1]))
		parts = parts[2:]
	    else:
		parts = None

	return v

    """
    Creates a Version object from a list of AbstractBranch and AbstractVersion
    objects.
    """
    def __init__(self, versionList, timeStamp):
	self.versions = versionList
	self.timeStamp = timeStamp

class ThawVersion(Version):

    """
    Provides a version object from a frozen version string.
    """

    def __init__(self, fullString):
	"""
	Initializes a ThawVersion object.

	@param fullString: Frozen representation of a Version object.
	@type fullString: str
	"""
	(timeStr, ver) = fullString.split(":")

	timeVal = float(timeStr)
	v = self.parseVersionString(ver)

	Version.__init__(self, v, timeVal)

class VersionFromString(Version):

    """
    Provides a version object from a string representation of a version.
    The time stamp is set to 0, so this object cannot be properly ordered
    with respect to other versions.
    """

    def __init__(self, ver, defaultBranch = None):
	"""
	Initializes a VersionFromString object.

	@param ver: string representation of a version
	@type ver: str
	@param defaultBranch: if provided and the ver parameter is not
	fully-qualified (it doesn't begin with a /), ver is taken to
	be relative to this branch.
	@type defaultBranch: Version
	"""
	if ver[0] != "/":
	    ver = defaultBranch.asString() + "/" + ver

	v = self.parseVersionString(ver, defaultBranch)

	Version.__init__(self, v, 0)

class VersionsError(Exception):

    """
    Ancestor for all exceptions raised by the versions module.
    """

    pass

class ParseError(VersionsError):

    """
    Indicates that an error occured turning a string into an object
    in the versions module.
    """

    def __repr__(self):
	return self.str

    def __str__(self):
	return self.str

    def __init__(self, str):
	self.str = str
<|endoftext|>


<commit_before>global_default = {
'general_poll_interval': 3
}

incoming_default = {
'require_arrival_monitor': False,
'control_file_extension': 'stager-ctrl-bss',
'receipt_file_extension': 'stager-rcpt-bss',
'thankyou_file_extension': 'stager-thanks-bss',
'stop_file': '.stop'
}

outgoing_default = {
'target_uses_arrival_monitor':  False,
'control_file_extension': 'stager-ctrl-bss',
'receipt_file_extension': 'stager-rcpt-bss',
'thankyou_file_extension': 'stager-thanks-bss',
'retry_count': 3,
'stop_file': '.stop',
'stop_file_poll_interval': 600
}

<commit_msg>added more defaults<commit_after>global_default = {
'general_poll_interval': 3
}

incoming_default = {
'require_arrival_monitor': False,
'control_file_extension': 'stager-ctrl-bss',
'receipt_file_extension': 'stager-rcpt-bss',
'thankyou_file_extension': 'stager-thanks-bss',
'stop_file': '.stop'
}

outgoing_default = {
'target_uses_arrival_monitor':  False,
'control_file_extension': 'stager-ctrl-bss',
'receipt_file_extension': 'stager-rcpt-bss',
'thankyou_file_extension': 'stager-thanks-bss',
'retry_count': 3,
'receipt_file_poll_count': 100,
'receipt_file_poll_interval': 5,
'stop_file': '.stop',
'stop_file_poll_interval': 600
}

<|endoftext|>


<commit_before>"""
RenderParameterWidget

:Authors:
	Berend Klein Haneveld
"""

import sys
from PySide.QtGui import QLabel
from PySide.QtGui import QComboBox
from PySide.QtGui import QWidget
from PySide.QtGui import QGridLayout
from PySide.QtGui import QScrollArea
from PySide.QtGui import QFrame
from PySide.QtCore import Slot
from PySide.QtCore import SIGNAL
from PySide.QtCore import Qt

class RenderParameterWidget(QWidget):
	"""
	RenderParameterWidget is a widget that is shown in the render property
	widget. It holds a combo box with which different visualizations can be
	chosen. Beneath the combo box it displays a widget in a scroll view that
	contains widgets with which parameters of the visualization can be adjusted.
	"""

	def __init__(self, renderController, parent=None):
		super(RenderParameterWidget, self).__init__(parent=parent)

		self.renderController = renderController
		self.renderController.visualizationChanged.connect(self.visualizationLoaded)

		self.paramWidget = None

		self.visTypeComboBox = QComboBox()
		for visualizationType in self.renderController.visualizationTypes:
			self.visTypeComboBox.addItem(visualizationType)

		layout = QGridLayout()
		layout.setAlignment(Qt.AlignTop)
		layout.addWidget(QLabel("Visualization type"), 0, 0)
		layout.addWidget(self.visTypeComboBox, 0, 1)
		self.setLayout(layout)

		self.scrollArea = QScrollArea()
		self.scrollArea.setFrameShape(QFrame.NoFrame)
		self.scrollArea.setAutoFillBackground(False)
		self.scrollArea.setAttribute(Qt.WA_TranslucentBackground)
		self.scrollArea.setWidgetResizable(True)

		self.visTypeComboBox.currentIndexChanged.connect(self.visTypeComboBoxChanged)

	def UpdateWidgetFromRenderWidget(self):
		"""
		Update the parameter widget with a widget from the render widget.
		"""
		# Add the scroll area for the parameter widget if it is not there yet
		layout = self.layout()
		if layout.indexOf(self.scrollArea) == -1:
			layout.addWidget(self.scrollArea, 1, 0, 1, 2)
			self.setLayout(layout)

		# Clear the previous parameter widget
		if self.paramWidget is not None:
			self.paramWidget.setParent(None)
			if self.renderController.visualization is not None:
				self.renderController.visualization.disconnect(SIGNAL("updatedTransferFunction"), self.transferFunctionChanged)

		# Get a new parameter widget from the render widget
		self.paramWidget = self.renderController.getParameterWidget()
		if sys.platform.startswith("darwin"):
			# default background of tabs on OSX is 237, 237, 237
			self.paramWidget.setStyleSheet("background: rgb(229, 229, 229)")
		self.scrollArea.setWidget(self.paramWidget)

		if self.renderController.visualization is not None:
			self.renderController.visualization.updatedTransferFunction.connect(self.transferFunctionChanged)

		self.visTypeComboBox.setCurrentIndex(self.visTypeComboBox.findText(self.renderController.visualizationType))

	@Slot(int)
	def visTypeComboBoxChanged(self, index):
		"""
		Slot that changes the render type. Also updates parameters and makes
		sure that the renderWidget renders with the new visualizationType.
		:type index: any
		"""
		self.renderController.setVisualizationType(self.visTypeComboBox.currentText())
		self.UpdateWidgetFromRenderWidget()
		self.renderController.updateVisualization()

	def visualizationLoaded(self, visualization):
		self.UpdateWidgetFromRenderWidget()

	@Slot()
	def transferFunctionChanged(self):
		"""
		Slot that can be used when a transfer function has changed so that
		the render will be updated afterwards.
		Should be called on valueChanged by the widgets from the parameter widget.
		"""
		self.renderController.updateVisualization()
<commit_msg>Hack for background color of parameter widget<commit_after>"""
RenderParameterWidget

:Authors:
	Berend Klein Haneveld
"""

import sys
from PySide.QtGui import QLabel
from PySide.QtGui import QComboBox
from PySide.QtGui import QWidget
from PySide.QtGui import QGridLayout
from PySide.QtGui import QScrollArea
from PySide.QtGui import QFrame
from PySide.QtCore import Slot
from PySide.QtCore import SIGNAL
from PySide.QtCore import Qt

class RenderParameterWidget(QWidget):
	"""
	RenderParameterWidget is a widget that is shown in the render property
	widget. It holds a combo box with which different visualizations can be
	chosen. Beneath the combo box it displays a widget in a scroll view that
	contains widgets with which parameters of the visualization can be adjusted.
	"""

	def __init__(self, renderController, parent=None):
		super(RenderParameterWidget, self).__init__(parent=parent)

		self.renderController = renderController
		self.renderController.visualizationChanged.connect(self.visualizationLoaded)

		self.paramWidget = None

		self.visTypeComboBox = QComboBox()
		for visualizationType in self.renderController.visualizationTypes:
			self.visTypeComboBox.addItem(visualizationType)

		layout = QGridLayout()
		layout.setAlignment(Qt.AlignTop)
		layout.addWidget(QLabel("Visualization type"), 0, 0)
		layout.addWidget(self.visTypeComboBox, 0, 1)
		self.setLayout(layout)

		self.scrollArea = QScrollArea()
		self.scrollArea.setFrameShape(QFrame.NoFrame)
		self.scrollArea.setAutoFillBackground(False)
		self.scrollArea.setAttribute(Qt.WA_TranslucentBackground)
		self.scrollArea.setWidgetResizable(True)

		self.visTypeComboBox.currentIndexChanged.connect(self.visTypeComboBoxChanged)

	def UpdateWidgetFromRenderWidget(self):
		"""
		Update the parameter widget with a widget from the render widget.
		"""
		# Add the scroll area for the parameter widget if it is not there yet
		layout = self.layout()
		if layout.indexOf(self.scrollArea) == -1:
			layout.addWidget(self.scrollArea, 1, 0, 1, 2)
			self.setLayout(layout)

		# Clear the previous parameter widget
		if self.paramWidget is not None:
			self.paramWidget.setParent(None)
			if self.renderController.visualization is not None:
				self.renderController.visualization.disconnect(SIGNAL("updatedTransferFunction"), self.transferFunctionChanged)

		# Get a new parameter widget from the render widget
		self.paramWidget = self.renderController.getParameterWidget()
		if sys.platform.startswith("darwin"):
			# default background of tabs on OSX is 237, 237, 237
			self.paramWidget.setStyleSheet("background: rgb(229, 229, 229)")
		elif sys.platform.startswith("linux"):
			# TODO: read background property from tab widget
			self.parent().setStyleSheet("background: rgb(236, 236, 236)")
		self.scrollArea.setWidget(self.paramWidget)

		if self.renderController.visualization is not None:
			self.renderController.visualization.updatedTransferFunction.connect(self.transferFunctionChanged)

		self.visTypeComboBox.setCurrentIndex(self.visTypeComboBox.findText(self.renderController.visualizationType))

	@Slot(int)
	def visTypeComboBoxChanged(self, index):
		"""
		Slot that changes the render type. Also updates parameters and makes
		sure that the renderWidget renders with the new visualizationType.
		:type index: any
		"""
		self.renderController.setVisualizationType(self.visTypeComboBox.currentText())
		self.UpdateWidgetFromRenderWidget()
		self.renderController.updateVisualization()

	def visualizationLoaded(self, visualization):
		self.UpdateWidgetFromRenderWidget()

	@Slot()
	def transferFunctionChanged(self):
		"""
		Slot that can be used when a transfer function has changed so that
		the render will be updated afterwards.
		Should be called on valueChanged by the widgets from the parameter widget.
		"""
		self.renderController.updateVisualization()
<|endoftext|>


<commit_before>from ViDE.Project.Description import *
from Tools.Cairo import Cairomm, PyCairo
from Tools.Boost import BoostPython, BoostProgramOptions

################################################################################
#################################################################### Libraries #
################################################################################

turkshead = CppDynamicLibrary(
    name = "turkshead",
    sources = [ "src/TurksHead/TurksHead.cpp" ],
    headers = [ "src/TurksHead/TurksHead.hpp" ],
    stripHeaders = lambda h: h[4:],
    localLibraries = [],
    externalLibraries = [ Cairomm ]
)

PythonPackage(
    name = "turkshead",
    sources = [ "src/PythonPackage/turkshead.py" ],
    strip = lambda f: f[18:],
    modules = [
        CppPythonModule(
            name = "_turkshead",
            sources = [ "src/PythonPackage/module.cpp" ],
            localLibraries = [ turkshead ],
            externalLibraries = [ Cairomm, BoostPython, PyCairo ]
        )
    ]
)

################################################################################
######################################################### Executables examples #
################################################################################

# C++
CppExecutable(
    name = "draw_turkshead_cpp",
    sources = [ "src/draw_turkshead_cpp.cpp" ],
    localLibraries = [ turkshead ],
    externalLibraries = [ Cairomm, BoostProgramOptions ]
)

# Python
PythonScript(
    source = "src/draw_turkshead_python.py"
)
<commit_msg>Add the draw_mosaic.py script in videfile.py<commit_after>from ViDE.Project.Description import *
from Tools.Cairo import Cairomm, PyCairo
from Tools.Boost import BoostPython, BoostProgramOptions

################################################################################
#################################################################### Libraries #
################################################################################

turkshead = CppDynamicLibrary(
    name = "turkshead",
    sources = [ "src/TurksHead/TurksHead.cpp" ],
    headers = [ "src/TurksHead/TurksHead.hpp" ],
    stripHeaders = lambda h: h[4:],
    localLibraries = [],
    externalLibraries = [ Cairomm ]
)

PythonPackage(
    name = "turkshead",
    sources = [ "src/PythonPackage/turkshead.py" ],
    strip = lambda f: f[18:],
    modules = [
        CppPythonModule(
            name = "_turkshead",
            sources = [ "src/PythonPackage/module.cpp" ],
            localLibraries = [ turkshead ],
            externalLibraries = [ Cairomm, BoostPython, PyCairo ]
        )
    ]
)

################################################################################
######################################################### Executables examples #
################################################################################

# C++
CppExecutable(
    name = "draw_turkshead_cpp",
    sources = [ "src/draw_turkshead_cpp.cpp" ],
    localLibraries = [ turkshead ],
    externalLibraries = [ Cairomm, BoostProgramOptions ]
)

# Python
PythonScript(
    source = "src/draw_turkshead_python.py"
)

PythonScript(
    source = "src/draw_mosaic.py"
)
<|endoftext|>


<commit_before><commit_msg>testing<commit_after>import curses

from random import randrange, choice

from collections import defaultdict

actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']

letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']

actions_dict = dict((zip(letter_codes, actions*2)))

def get_user_action(keyboard):
    char = "N"
    while char not in actions_dict:
       char = keyboard.getch()
    return actions_dict[char]

def transpose(field):
    return [list(row) for row in zip(*field)]

def invert(field):
    return [row[::-1] for row in field]

class GameField(object):
    def __init__(self, height=4, width=4, win=2048):
        self.height = height
        self.width = width
        self.win_value = 2048
        self.score = 0
        self.highscore = 0
        self.reset()

    def spawn(self):
        if randrange(100)>89:
            new_element = 4
        else:
            new_element = 2
        (i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])
        self.field[i][j] = new_element

<|endoftext|>


<commit_before>"""
utils
=====

Low-level functionality NOT intended for users to EVER use.

"""

import json
import os.path
import sys
import threading
import re
import datetime

### incase people are using threading, we lock file reads
lock = threading.Lock()

### general file setup tools ###

def load_json_dict(filename, *args):
    """Checks if file exists. Returns {} if something fails."""
    data = {}
    if os.path.exists(filename):
        lock.acquire()
        with open(filename, "r") as f:
            try:
                data = json.load(f)
                if not isinstance(data, dict):
                    data = {}
            except:
                data = {}  # TODO: issue a warning and bubble it up
        lock.release()
        if args:
            d = dict()
            for key in args:
                if key in data:
                    d[key] = data[key]
            return d
            # TODO: replace with below if we drop Python 2.6 compatibility
            # return {key: data[key] for key in args if key in data}
    return data

def save_json_dict(filename, json_dict):
    """Save json to file. Error if path DNE, not a dict, or invalid json."""
    if isinstance(json_dict, dict):
        # this will raise a TypeError if something goes wrong
        json_string = json.dumps(json_dict, indent=4)
        lock.acquire()
        with open(filename, "w") as f:
            f.write(json_string)
        lock.release()
    else:
        raise TypeError("json_dict was not a dictionary. not saving.")

def ensure_file_exists(filename):
    """Given a valid filename, make sure it exists (will create if DNE)."""
    if not os.path.exists(filename):
        head, tail = os.path.split(filename)
        ensure_dir_exists(head)
        with open(filename, 'w') as f:
            pass  # just create the file

def ensure_dir_exists(directory):
    """Given a valid directory path, make sure it exists."""
    if dir:
        if not os.path.isdir(directory):
            os.makedirs(directory)

### Custom JSON encoders ###
class NotEncodable(Exception):
    pass

class _plotlyJSONEncoder(json.JSONEncoder):
    def numpyJSONEncoder(self, obj):
        try:
            import numpy
        except:
            raise NotEncodable

        if type(obj).__module__.split('.')[0] == numpy.__name__:
            l = obj.tolist()
            try:
                return self.datetimeJSONEncoder(l)
            except NotEncodable:
                return l
        else:
            raise NotEncodable

    def datetimeJSONEncoder(self, obj):
        '''
        if datetime or iterable of datetimes,
        convert to a string that plotly understands
        format as %Y-%m-%d %H:%M:%S.%f,
                  %Y-%m-%d %H:%M:%S, or
                  %Y-%m-%d
        depending on what non-zero resolution was provided
        '''
        try:
            import pandas
            pandas_importable = True
        except:
            pandas_importable = False

        if pandas_importable and obj is pandas.NaT:
            return None

        if isinstance(obj, (datetime.datetime, datetime.date)):
            if obj.microsecond != 0:
                return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
            elif obj.second != 0 or obj.minute != 0 or obj.hour != 0:
                return obj.strftime('%Y-%m-%d %H:%M:%S')
            else:
                return obj.strftime('%Y-%m-%d')
        elif isinstance(obj[0], (datetime.datetime, datetime.date)):
            return [o.strftime(
                    '%Y-%m-%d %H:%M:%S.%f') if o.microsecond != 0 else
                    o.strftime('%Y-%m-%d %H:%M:%S') if o.second != 0 or o.minute != 0 or o.hour != 0 else
                    o.strftime('%Y-%m-%d')
                    for o in obj]
        else:
            raise NotEncodable

    def pandasJSONEncoder(self, obj):
        try:
            import pandas
        except:
            raise NotEncodable

        if isinstance(obj, pandas.Series):
            serializable_list = []
            for li in list(obj):
                try:
                    json.dumps(li)
                    serializable_list.append(li)
                except TypeError:
                    serializable_list.append(self.default(li))

            return serializable_list
        elif isinstance(obj, pandas.Index):
            return obj.tolist()
        elif obj is pandas.NaT:
            return None
        else:
            raise NotEncodable

    def sageJSONEncoder(self, obj):
        try:
            from sage.all import RR, ZZ
        except:
            raise NotEncodable

        if obj in RR:
            return float(obj)
        elif obj in ZZ:
            return int(obj)
        else:
            raise NotEncodable

    def builtinJSONEncoder(self, obj):
        try:
            return obj.to_plotly_json()
        except AttributeError:
            raise NotEncodable

    def default(self, obj):
        encoders = (self.builtinJSONEncoder,
                    self.datetimeJSONEncoder,
                    self.numpyJSONEncoder,
                    self.pandasJSONEncoder,
                    self.sageJSONEncoder)
        for encoder in encoders:
            try:
                return encoder(obj)
            except NotEncodable:
                pass

        raise TypeError(repr(obj) + " is not JSON serializable")

### unicode stuff ###
def decode_unicode(coll):
    if isinstance(coll, list):
        for no, entry in enumerate(coll):
            if isinstance(entry, (dict, list)):
                coll[no] = decode_unicode(entry)
            else:
                if isinstance(entry, str):
                    try:
                        coll[no] = str(entry)
                    except UnicodeEncodeError:
                        pass
    elif isinstance(coll, dict):
        keys, vals = list(coll.keys()), list(coll.values())
        for key, val in zip(keys, vals):
            if isinstance(val, (dict, list)):
                coll[key] = decode_unicode(val)
            elif isinstance(val, str):
                try:
                    coll[key] = str(val)
                except UnicodeEncodeError:
                    pass
            coll[str(key)] = coll.pop(key)
    return coll

### docstring templating ###
def template_doc(**names):
    def _decorator(func):
        if sys.version[:3] != '3.2':
            if func.__doc__ is not None:
                func.__doc__ = func.__doc__.format(**names)
        return func
    return _decorator

def get_first_duplicate(items):
    seen = set()
    for item in items:
        if item not in seen:
            seen.add(item)
        else:
            return item
    return None

### source key
def is_source_key(key):
    src_regex = re.compile(r'.+src$')
    if src_regex.match(key) is not None:
        return True
    else:
        return False
<commit_msg>:lipstick:<commit_after>"""
utils
=====

Low-level functionality NOT intended for users to EVER use.

"""

import json
import os.path
import sys
import threading
import re
import datetime

### incase people are using threading, we lock file reads
lock = threading.Lock()

### general file setup tools ###

def load_json_dict(filename, *args):
    """Checks if file exists. Returns {} if something fails."""
    data = {}
    if os.path.exists(filename):
        lock.acquire()
        with open(filename, "r") as f:
            try:
                data = json.load(f)
                if not isinstance(data, dict):
                    data = {}
            except:
                data = {}  # TODO: issue a warning and bubble it up
        lock.release()
        if args:
            d = dict()
            for key in args:
                if key in data:
                    d[key] = data[key]
            return d
            # TODO: replace with below if we drop Python 2.6 compatibility
            # return {key: data[key] for key in args if key in data}
    return data

def save_json_dict(filename, json_dict):
    """Save json to file. Error if path DNE, not a dict, or invalid json."""
    if isinstance(json_dict, dict):
        # this will raise a TypeError if something goes wrong
        json_string = json.dumps(json_dict, indent=4)
        lock.acquire()
        with open(filename, "w") as f:
            f.write(json_string)
        lock.release()
    else:
        raise TypeError("json_dict was not a dictionary. not saving.")

def ensure_file_exists(filename):
    """Given a valid filename, make sure it exists (will create if DNE)."""
    if not os.path.exists(filename):
        head, tail = os.path.split(filename)
        ensure_dir_exists(head)
        with open(filename, 'w') as f:
            pass  # just create the file

def ensure_dir_exists(directory):
    """Given a valid directory path, make sure it exists."""
    if dir:
        if not os.path.isdir(directory):
            os.makedirs(directory)

### Custom JSON encoders ###
class NotEncodable(Exception):
    pass

class _plotlyJSONEncoder(json.JSONEncoder):
    def numpyJSONEncoder(self, obj):
        try:
            import numpy
        except:
            raise NotEncodable

        if type(obj).__module__.split('.')[0] == numpy.__name__:
            l = obj.tolist()
            try:
                return self.datetimeJSONEncoder(l)
            except NotEncodable:
                return l
        else:
            raise NotEncodable

    def datetimeJSONEncoder(self, obj):
        """
        if datetime or iterable of datetimes,
        convert to a string that plotly understands
        format as %Y-%m-%d %H:%M:%S.%f,
                  %Y-%m-%d %H:%M:%S, or
                  %Y-%m-%d
        depending on what non-zero resolution was provided
        """
        try:
            import pandas
            pandas_importable = True
        except:
            pandas_importable = False

        if pandas_importable and obj is pandas.NaT:
            return None

        if isinstance(obj, (datetime.datetime, datetime.date)):
            if obj.microsecond != 0:
                return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
            elif obj.second != 0 or obj.minute != 0 or obj.hour != 0:
                return obj.strftime('%Y-%m-%d %H:%M:%S')
            else:
                return obj.strftime('%Y-%m-%d')
        elif isinstance(obj[0], (datetime.datetime, datetime.date)):
            return [o.strftime(
                    '%Y-%m-%d %H:%M:%S.%f') if o.microsecond != 0 else
                    o.strftime('%Y-%m-%d %H:%M:%S') if o.second != 0 or o.minute != 0 or o.hour != 0 else
                    o.strftime('%Y-%m-%d')
                    for o in obj]
        else:
            raise NotEncodable

    def pandasJSONEncoder(self, obj):
        try:
            import pandas
        except:
            raise NotEncodable

        if isinstance(obj, pandas.Series):
            serializable_list = []
            for li in list(obj):
                try:
                    json.dumps(li)
                    serializable_list.append(li)
                except TypeError:
                    serializable_list.append(self.default(li))

            return serializable_list
        elif isinstance(obj, pandas.Index):
            return obj.tolist()
        elif obj is pandas.NaT:
            return None
        else:
            raise NotEncodable

    def sageJSONEncoder(self, obj):
        try:
            from sage.all import RR, ZZ
        except:
            raise NotEncodable

        if obj in RR:
            return float(obj)
        elif obj in ZZ:
            return int(obj)
        else:
            raise NotEncodable

    def builtinJSONEncoder(self, obj):
        try:
            return obj.to_plotly_json()
        except AttributeError:
            raise NotEncodable

    def default(self, obj):
        encoders = (self.builtinJSONEncoder,
                    self.datetimeJSONEncoder,
                    self.numpyJSONEncoder,
                    self.pandasJSONEncoder,
                    self.sageJSONEncoder)
        for encoder in encoders:
            try:
                return encoder(obj)
            except NotEncodable:
                pass

        raise TypeError(repr(obj) + " is not JSON serializable")

### unicode stuff ###
def decode_unicode(coll):
    if isinstance(coll, list):
        for no, entry in enumerate(coll):
            if isinstance(entry, (dict, list)):
                coll[no] = decode_unicode(entry)
            else:
                if isinstance(entry, str):
                    try:
                        coll[no] = str(entry)
                    except UnicodeEncodeError:
                        pass
    elif isinstance(coll, dict):
        keys, vals = list(coll.keys()), list(coll.values())
        for key, val in zip(keys, vals):
            if isinstance(val, (dict, list)):
                coll[key] = decode_unicode(val)
            elif isinstance(val, str):
                try:
                    coll[key] = str(val)
                except UnicodeEncodeError:
                    pass
            coll[str(key)] = coll.pop(key)
    return coll

### docstring templating ###
def template_doc(**names):
    def _decorator(func):
        if sys.version[:3] != '3.2':
            if func.__doc__ is not None:
                func.__doc__ = func.__doc__.format(**names)
        return func
    return _decorator

def get_first_duplicate(items):
    seen = set()
    for item in items:
        if item not in seen:
            seen.add(item)
        else:
            return item
    return None

### source key
def is_source_key(key):
    src_regex = re.compile(r'.+src$')
    if src_regex.match(key) is not None:
        return True
    else:
        return False
<|endoftext|>