Source code for traits.trait_base

#------------------------------------------------------------------------------
#
#  Copyright (c) 2005, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/LICENSE.txt and may be redistributed only
#  under the conditions described in the aforementioned license.  The license
#  is also available online at http://www.enthought.com/licenses/BSD.txt
#
#  Thanks for using Enthought open source!
#
#  Author: David C. Morrill
#  Date:   06/21/2002
#
#  Refactored into a separate module: 07/04/2003
#
#------------------------------------------------------------------------------

""" Defines common, low-level capabilities needed by the Traits package.
"""

#-------------------------------------------------------------------------------
#  Imports:
#-------------------------------------------------------------------------------

from __future__ import absolute_import

import os
import sys
from os import getcwd
from os.path import dirname, exists, join

from . import _py2to3
from .etsconfig.api import ETSConfig

# backwards compatibility: trait_base used to provide a patched enumerate
enumerate = enumerate

# Set the Python version being used:
vi = sys.version_info
python_version = vi[0] + (float( vi[1] ) / 10.0)

#-------------------------------------------------------------------------------
#  Constants:
#-------------------------------------------------------------------------------

ClassTypes    = _py2to3.ClassTypes

SequenceTypes = ( list, tuple )

ComplexTypes  = ( float, int )

TypeTypes     = ( str,  unicode, int, long, float, complex, list, tuple, dict, bool )

TraitNotifier = '__trait_notifier__'

# The standard Traits property cache prefix:
TraitsCache = '_traits_cache_'

#-------------------------------------------------------------------------------
#  Singleton 'Uninitialized' object:
#-------------------------------------------------------------------------------
Uninitialized = None

class _Uninitialized(object):
    """ The singleton value of this class represents the uninitialized state
        of a trait and is specified as the 'old' value in the trait change
        notification that occurs when the value of a trait is read before being
        set.
    """

    def __new__(cls):
        if Uninitialized is not None:
            return Uninitialized
        else:
            self = object.__new__(cls)
            return self

    def __repr__(self):
        return '<uninitialized>'

    def __reduce_ex__(self, protocol):
        return (_Uninitialized, ())

#: When the first reference to a trait is a 'get' reference, the default value of
#: the trait is implicitly assigned and returned as the value of the trait.
#: Because of this implicit assignment, a trait change notification is
#: generated with the Uninitialized object as the 'old' value of the trait, and
#: the default trait value as the 'new' value. This allows other parts of the
#: traits package to recognize the assignment as the implicit default value
#: assignment, and treat it specially.
Uninitialized = _Uninitialized()

#-------------------------------------------------------------------------------
#  Singleton 'Undefined' object (used as undefined trait name and/or value):
#-------------------------------------------------------------------------------

Undefined = None

class _Undefined(object):
    """ Singleton 'Undefined' object (used as undefined trait name and/or value)
    """
    def __new__(cls):
        if Undefined is not None:
            return Undefined
        else:
            self = object.__new__(cls)
            return self

    def __repr__(self):
        return '<undefined>'

    def __reduce_ex__(self, protocol):
        return (_Undefined, ())

    def __eq__(self, other):
        return type(self) is type(other)

    def __hash__(self):
        return hash(type(self))

    def __ne__(self, other):
        return type(self) is not type(other)

#: Singleton object that indicates that a trait attribute has not yet had a
#: value set (i.e., its value is undefined). This object is used instead of
#: None, because None often has other meanings, such as that a value is not
#: used. When a trait attribute is first assigned a value, and its associated
#: trait notification handlers are called, Undefined is passed as the *old*
#: parameter, to indicate that the attribute previously had no value.
Undefined = _Undefined()

# Tell the C-base code about singleton 'Undefined' and 'Uninitialized' objects:
from . import ctraits
ctraits._undefined( Undefined, Uninitialized )

#-------------------------------------------------------------------------------
#  Singleton 'Missing' object (used as missing method argument marker):
#-------------------------------------------------------------------------------

[docs]class Missing ( object ): """ Singleton 'Missing' object (used as missing method argument marker). """ def __repr__ ( self ): return '<missing>'
#: Singleton object that indicates that a method argument is missing from a #: type-checked method signature. Missing = Missing() #------------------------------------------------------------------------------- # Singleton 'Self' object (used as object reference to current 'object'): #-------------------------------------------------------------------------------
[docs]class Self ( object ): """ Singleton 'Self' object (used as object reference to current 'object'). """ def __repr__ ( self ): return '<self>'
#: Singleton object that references the current 'object'. Self = Self() #------------------------------------------------------------------------------- # Define a special 'string' coercion function: #-------------------------------------------------------------------------------
[docs]def strx ( arg ): """ Wraps the built-in str() function to raise a TypeError if the argument is not of a type in StringTypes. """ if isinstance( arg, StringTypes ): return str( arg ) raise TypeError
#------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- StringTypes = ( str, unicode, int, long, float, complex ) #------------------------------------------------------------------------------- # Define a mapping of coercable types: #------------------------------------------------------------------------------- # Mapping of coercable types. CoercableTypes = { long: ( 11, long, int ), float: ( 11, float, int ), complex: ( 11, complex, float, int ), unicode: ( 11, unicode, str ) } #------------------------------------------------------------------------------- # Return a string containing the class name of an object with the correct # article (a or an) preceding it (e.g. 'an Image', 'a PlotValue'): #-------------------------------------------------------------------------------
[docs]def class_of ( object ): """ Returns a string containing the class name of an object with the correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image', 'a PlotValue'). """ if isinstance( object, basestring ): return add_article( object ) return add_article( object.__class__.__name__ )
#------------------------------------------------------------------------------- # Return a string containing the right article (i.e. 'a' or 'an') prefixed to # a specified string: #-------------------------------------------------------------------------------
[docs]def add_article ( name ): """ Returns a string containing the correct indefinite article ('a' or 'an') prefixed to the specified string. """ if name[:1].lower() in 'aeiou': return 'an ' + name return 'a ' + name
#---------------------------------------------------------------------------- # Return a 'user-friendly' name for a specified trait: #----------------------------------------------------------------------------
[docs]def user_name_for ( name ): """ Returns a "user-friendly" version of a string, with the first letter capitalized and with underscore characters replaced by spaces. For example, ``user_name_for('user_name_for')`` returns ``'User name for'``. """ name = name.replace( '_', ' ' ) result = '' last_lower = False for c in name: if c.isupper() and last_lower: result += ' ' last_lower = c.islower() result += c return result.capitalize()
#------------------------------------------------------------------------------- # Gets the path to the traits home directory: #------------------------------------------------------------------------------- _traits_home = None
[docs]def traits_home ( ): """ Gets the path to the Traits home directory. """ global _traits_home if _traits_home is None: _traits_home = verify_path( join( ETSConfig.application_data, 'traits' ) ) return _traits_home
#------------------------------------------------------------------------------- # Verify that a specified path exists, and try to create it if it doesn't: #-------------------------------------------------------------------------------
[docs]def verify_path ( path ): """ Verify that a specified path exists, and try to create it if it does not exist. """ if not exists( path ): try: os.mkdir( path ) except: pass return path
#------------------------------------------------------------------------------- # Returns the name of the module the caller's caller is located in: #-------------------------------------------------------------------------------
[docs]def get_module_name ( level = 2 ): """ Returns the name of the module that the caller's caller is located in. """ return sys._getframe( level ).f_globals.get( '__name__', '__main__' )
#------------------------------------------------------------------------------- # Returns a resource path calculated from the caller's stack: #-------------------------------------------------------------------------------
[docs]def get_resource_path ( level = 2 ): """Returns a resource path calculated from the caller's stack. """ module = sys._getframe( level ).f_globals.get( '__name__', '__main__' ) path = None if module != '__main__': # Return the path to the module: try: path = dirname( getattr( sys.modules.get( module ), '__file__' ) ) except: # Apparently 'module' is not a registered module...treat it like # '__main__': pass if path is None: # '__main__' is not a real module, so we need a work around: for path in [ dirname( sys.argv[0] ), getcwd() ]: if exists( path ): break # Handle application bundlers. Since the python source files may be placed # in a zip file and therefore won't be directly accessable using standard # open/read commands, the app bundlers will look for resources (i.e. data # files, images, etc.) in specific locations. For py2app, this is in the # [myapp].app/Contents/Resources directory. For py2exe, this is the same # directory as the [myapp].exe executable file generated by py2exe. frozen = getattr(sys, 'frozen', False) if frozen: if frozen == 'macosx_app': root = os.environ['RESOURCEPATH'] elif frozen in ('dll', 'windows_exe', 'console_exe'): root = os.path.dirname(sys.executable) else: # Unknown app bundler, but try anyway root = os.path.dirname(sys.executable) if ".zip/" in path: zippath, image_path = path.split(".zip/") path = os.path.join(root, image_path) return path
#------------------------------------------------------------------------------- # Returns the value of an extended object attribute name of the form: # name[.name2[.name3...]]: #-------------------------------------------------------------------------------
[docs]def xgetattr( object, xname, default = Undefined ): """ Returns the value of an extended object attribute name of the form: name[.name2[.name3...]]. """ names = xname.split( '.' ) for name in names[:-1]: if default is Undefined: object = getattr( object, name ) else: object = getattr( object, name, None ) if object is None: return default if default is Undefined: return getattr( object, names[-1] ) return getattr( object, names[-1], default )
#------------------------------------------------------------------------------- # Sets the value of an extended object attribute name of the form: # name[.name2[.name3...]]: #-------------------------------------------------------------------------------
[docs]def xsetattr( object, xname, value ): """ Sets the value of an extended object attribute name of the form: name[.name2[.name3...]]. """ names = xname.split( '.' ) for name in names[:-1]: object = getattr( object, name ) setattr( object, names[-1], value )
#------------------------------------------------------------------------------- # Traits metadata selection functions: #-------------------------------------------------------------------------------
[docs]def is_none ( value ): return (value is None)
[docs]def not_none ( value ): return (value is not None)
[docs]def not_false ( value ): return (value is not False)
[docs]def not_event ( value ): return (value != 'event')
[docs]def is_str ( value ): return isinstance( value, basestring )