1
2# NOTE: Documentation is intended to be processed by epydoc and contains
3# epydoc markup.
4
5"""
6Overview
7========
8
9The ``grizzled.misc`` module contains miscellanous functions and classes that
10don't seem to fit well in other modules.
11"""
12
13__docformat__ = "restructuredtext en"
14
15# ---------------------------------------------------------------------------
16# Imports
17# ---------------------------------------------------------------------------
18
19import logging
20
21from grizzled.exception import ExceptionWithMessage
22
23# ---------------------------------------------------------------------------
24# Exports
25# ---------------------------------------------------------------------------
26
27__all__ = ['ReadOnly', 'ReadOnlyObjectError']
28
29# ---------------------------------------------------------------------------
30# Constants
31# ---------------------------------------------------------------------------
32
33# ---------------------------------------------------------------------------
34# Logging
35# ---------------------------------------------------------------------------
36
37log = logging.getLogger('grizzled.misc')
38
39# ---------------------------------------------------------------------------
40# Public classes
41# ---------------------------------------------------------------------------
42
43class ReadOnlyObjectError(ExceptionWithMessage):
44    """
45    Thrown by ``ReadOnly`` to indicate an attempt to set a field.
46
47    :IVariables:
48        field_name : str
49            name of the read-only field that could not be set
50
51        message : str
52            message to associated with the exception
53    """
54    def __init__(self, field_name, message):
55        ExceptionWithMessage.__init__(self, message)
56        self.field_name = field_name
57
58class ReadOnly(object):
59    """
60    A ``ReadOnly`` object wraps another object and prevents all the contained
61    object's fields from being written. Example use:
62
63    .. python::
64
65        from grizzled.misc import ReadOnly
66        from grizzled.config import Configuration
67
68        config = Configuration()
69        config.read('/path/to/some/file')
70        roConfig = ReadOnly(config)
71
72    Any attempt to set fields within ``roConfig`` will cause a
73    ``ReadOnlyObjectError`` to be raised.
74
75    The ``__class__`` member of the instantiate ``ReadOnly`` class will be the
76    class of the contained object, rather than ``ReadOnly``
77    (``Configuration`` in the example). Similarly, the ``isinstance()``
78    built-in function will compare against the contained object's class.
79    However, the ``type()`` built-in will return the ``ReadOnly`` class
80    object.
81    """
82    def __init__(self, wrapped):
83        """
84        Create a new ``ReadOnly`` object that wraps the ``wrapped`` object
85        and enforces read-only access to it.
86
87        :Parameters:
88            wrapped : object
89                the object to wrap
90        """
91        self.wrapped = wrapped
92
93    def __getattribute__(self, thing):
94        wrapped = object.__getattribute__(self, 'wrapped')
95        result = None
96        if thing == 'wrapped':
97            result = wrapped
98        else:
99            result = getattr(wrapped, thing)
100
101        return result
102
103    def __setattr__(self, thing, value):
104        if thing == 'wrapped':
105            object.__setattr__(self, thing, value)
106        else:
107            raise ReadOnlyObjectError(thing,
108                                      'Attempt to access field "%s" of '
109                                      'read-only %s object' %
110                                      (thing, self.wrapped.__class__.__name__))
111
112# ---------------------------------------------------------------------------
113# Public functions
114# ---------------------------------------------------------------------------
115
116# backward compatibality
117from grizzled.text import str2bool
118
119def bitcount(num):
120    """
121    Count the number of bits in a numeric (integer or long) value. This
122    method is adapted from the Hamming Weight algorithm, described (among
123    other places) at http://en.wikipedia.org/wiki/Hamming_weight
124
125    Works for up to 64 bits.
126
127    :Parameters:
128        num : int
129            The numeric value
130
131    :rtype: int
132    :return: The number of 1 bits in the binary representation of ``num``
133    """
134    # Put count of each 2 bits into those 2 bits.
135    num = num - ((num >> 1) & 0x5555555555555555)
136
137    # Put count of each 4 bits into those 4 bits.
138    num = (num & 0x3333333333333333) + ((num >> 2) & 0x3333333333333333)
139
140    # Put count of each 8 bits into those 8 bits.
141    num = (num + (num >> 4)) & 0x0f0f0f0f0f0f0f0f
142
143    # Left-most bits.
144    return int((num * 0x0101010101010101) >> 56)
145
146
147