This file is indexed.

/usr/share/pyshared/graphy/common.py is in python-graphy 1.0+dfsg-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#!/usr/bin/python2.4
#
# Copyright 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Code common to all chart types."""

import copy
import warnings

from graphy import formatters
from graphy import util


class Marker(object):

  """Represents an abstract marker, without position.  You can attach these to
  a DataSeries.

  Object attributes:
    shape: One of the shape codes (Marker.arrow, Marker.diamond, etc.)
    color: color (as hex string, f.ex. '0000ff' for blue)
    size:  size of the marker
  """
  # TODO: Write an example using markers.

  # Shapes:
  arrow = 'a'
  cross = 'c'
  diamond = 'd'
  circle = 'o'
  square = 's'
  x = 'x'

  # Note: The Google Chart API also knows some other markers ('v', 'V', 'r',
  # 'b') that I think would fit better into a grid API.
  # TODO: Make such a grid API

  def __init__(self, shape, color, size):
    """Construct a Marker.  See class docstring for details on args."""
    # TODO: Shapes 'r' and 'b' would be much easier to use if they had a
    # special-purpose API (instead of trying to fake it with markers)
    self.shape = shape
    self.color = color
    self.size = size


class _BasicStyle(object):
  """Basic style object.  Used internally."""

  def __init__(self, color):
    self.color = color


class DataSeries(object):

  """Represents one data series for a chart (both data & presentation
  information).

  Object attributes:
    points:  List of numbers representing y-values (x-values are not specified
             because the Google Chart API expects even x-value spacing).
    label:   String with the series' label in the legend.  The chart will only
             have a legend if at least one series has a label.  If some series
             do not have a label then they will have an empty description in
             the legend.  This is currently a limitation in the Google Chart
             API.
    style:   A chart-type-specific style object.  (LineStyle for LineChart,
             BarsStyle for BarChart, etc.)
    markers: List of (x, m) tuples where m is a Marker object and x is the
             x-axis value to place it at.

             The "fill" markers ('r' & 'b') are a little weird because they
             aren't a point on a line.  For these, you can fake it by
             passing slightly weird data (I'd like a better API for them at
             some point):
               For 'b', you attach the marker to the starting series, and set x
               to the index of the ending line.  Size is ignored, I think.

               For 'r', you can attach to any line, specify the starting
               y-value for x and the ending y-value for size.  Y, in this case,
               is becase 0.0 (bottom) and 1.0 (top).
    color:   DEPRECATED
  """

  # TODO: Should we require the points list to be non-empty ?
  # TODO: Do markers belong here?  They are really only used for LineCharts
  def __init__(self, points, label=None, style=None, markers=None, color=None):
    """Construct a DataSeries.  See class docstring for details on args."""
    if label is not None and util._IsColor(label):
      warnings.warn('Your code may be broken! Label is a hex triplet.  Maybe '
                    'it is a color? The old argument order (color & style '
                    'before label) is deprecated.', DeprecationWarning,
                    stacklevel=2)
    if color is not None:
      warnings.warn('Passing color is deprecated.  Pass a style object '
                    'instead.', DeprecationWarning, stacklevel=2)
      # Attempt to fix it for them.  If they also passed a style, honor it.
      if style is None:
        style = _BasicStyle(color)
    if style is not None and isinstance(style, basestring):
      warnings.warn('Your code is broken! Style is a string, not an object. '
                    'Maybe you are passing a color?  Passing color is '
                    'deprecated; pass a style object instead.',
                    DeprecationWarning, stacklevel=2)
    if style is None:
      style = _BasicStyle(None)
    self.data = points
    self.style = style
    self.markers = markers or []
    self.label = label

  def _GetColor(self):
    warnings.warn('DataSeries.color is deprecated, use '
                  'DataSeries.style.color instead.', DeprecationWarning,
                  stacklevel=2)
    return self.style.color

  def _SetColor(self, color):
    warnings.warn('DataSeries.color is deprecated, use '
                  'DataSeries.style.color instead.', DeprecationWarning,
                  stacklevel=2)
    self.style.color = color

  color = property(_GetColor, _SetColor)


class AxisPosition(object):
  """Represents all the available axis positions.

  The available positions are as follows:
    AxisPosition.TOP
    AxisPosition.BOTTOM
    AxisPosition.LEFT
    AxisPosition.RIGHT
  """
  LEFT = 'y'
  RIGHT = 'r'
  BOTTOM = 'x'
  TOP = 't'


class Axis(object):

  """Represents one axis.

  Object setings:
    min:    Minimum value for the bottom or left end of the axis
    max:    Max value.
    labels: List of labels to show along the axis.
    label_positions: List of positions to show the labels at.  Uses the scale
                     set by min & max, so if you set min = 0 and max = 10, then
                     label positions [0, 5, 10] would be at the bottom,
                     middle, and top of the axis, respectively.
    grid_spacing:  Amount of space between gridlines (in min/max scale).
                   A value of 0 disables gridlines.
    label_gridlines: If True, draw a line extending from each label
                   on the axis all the way across the chart.
  """

  def __init__(self, axis_min=None, axis_max=None):
    """Construct a new Axis.

    Args:
      axis_min: smallest value on the axis
      axis_max: largest value on the axis
    """
    self.min = axis_min
    self.max = axis_max
    self.labels = []
    self.label_positions = []
    self.grid_spacing = 0
    self.label_gridlines = False

# TODO: Add other chart types.  Order of preference:
# - scatter plots
# - us/world maps

class BaseChart(object):
  """Base chart object with standard behavior for all other charts.

  Object attributes:
    data: List of DataSeries objects. Chart subtypes provide convenience
          functions (like AddLine, AddBars, AddSegment) to add more series
          later.
    left/right/bottom/top: Axis objects for the 4 different axes.
    formatters: A list of callables which will be used to format this chart for
                display.  TODO: Need better documentation for how these
                work.
    auto_scale, auto_color, auto_legend:
      These aliases let users access the default formatters without poking
      around in self.formatters.  If the user removes them from
      self.formatters then they will no longer be enabled, even though they'll
      still be accessible through the aliases.  Similarly, re-assigning the
      aliases has no effect on the contents of self.formatters.
    display: This variable is reserved for backends to populate with a display
             object.  The intention is that the display object would be used to
             render this chart.  The details of what gets put here depends on
             the specific backend you are using.
  """

  # Canonical ordering of position keys
  _POSITION_CODES = 'yrxt'

  # TODO: Add more inline args to __init__ (esp. labels).
  # TODO: Support multiple series in the constructor, if given.
  def __init__(self):
    """Construct a BaseChart object."""
    self.data = []

    self._axes = {}
    for code in self._POSITION_CODES:
      self._axes[code] = [Axis()]
    self._legend_labels = []  # AutoLegend fills this out
    self._show_legend = False  # AutoLegend fills this out

    # Aliases for default formatters
    self.auto_color = formatters.AutoColor()
    self.auto_scale = formatters.AutoScale()
    self.auto_legend = formatters.AutoLegend
    self.formatters = [self.auto_color, self.auto_scale, self.auto_legend]
    # display is used to convert the chart into something displayable (like a
    # url or img tag).
    self.display = None

  def AddFormatter(self, formatter):
    """Add a new formatter to the chart (convenience method)."""
    self.formatters.append(formatter)

  def AddSeries(self, points, color=None, style=None, markers=None,
                label=None):
    """DEPRECATED

    Add a new series of data to the chart; return the DataSeries object."""
    warnings.warn('AddSeries is deprecated.  Instead, call AddLine for '
                  'LineCharts, AddBars for BarCharts, AddSegment for '
                  'PieCharts ', DeprecationWarning, stacklevel=2)
    series = DataSeries(points, color=color, style=style, markers=markers,
                        label=label)
    self.data.append(series)
    return series

  def GetDependentAxes(self):
    """Return any dependent axes ('left' and 'right' by default for LineCharts,
    although bar charts would use 'bottom' and 'top').
    """
    return self._axes[AxisPosition.LEFT] + self._axes[AxisPosition.RIGHT]

  def GetIndependentAxes(self):
    """Return any independent axes (normally top & bottom, although horizontal
    bar charts use left & right by default).
    """
    return self._axes[AxisPosition.TOP] + self._axes[AxisPosition.BOTTOM]

  def GetDependentAxis(self):
    """Return this chart's main dependent axis (often 'left', but
    horizontal bar-charts use 'bottom').
    """
    return self.left

  def GetIndependentAxis(self):
    """Return this chart's main independent axis (often 'bottom', but
    horizontal bar-charts use 'left').
    """
    return self.bottom

  def _Clone(self):
    """Make a deep copy this chart.

    Formatters & display will be missing from the copy, due to limitations in
    deepcopy.
    """
    orig_values = {}
    # Things which deepcopy will likely choke on if it tries to copy.
    uncopyables = ['formatters', 'display', 'auto_color', 'auto_scale',
                   'auto_legend']
    for name in uncopyables:
      orig_values[name] = getattr(self, name)
      setattr(self, name, None)
    clone = copy.deepcopy(self)
    for name, orig_value in orig_values.iteritems():
      setattr(self, name, orig_value)
    return clone

  def GetFormattedChart(self):
    """Get a copy of the chart with formatting applied."""
    # Formatters need to mutate the chart, but we don't want to change it out
    # from under the user.  So, we work on a copy of the chart.
    scratchpad = self._Clone()
    for formatter in self.formatters:
      formatter(scratchpad)
    return scratchpad

  def GetMinMaxValues(self):
    """Get the largest & smallest values in this chart, returned as
    (min_value, max_value).  Takes into account complciations like stacked data
    series.

    For example, with non-stacked series, a chart with [1, 2, 3] and [4, 5, 6]
    would return (1, 6).  If the same chart was stacking the data series, it
    would return (5, 9).
    """
    MinPoint = lambda data: min(x for x in data if x is not None)
    MaxPoint = lambda data: max(x for x in data if x is not None)
    mins  = [MinPoint(series.data) for series in self.data if series.data]
    maxes = [MaxPoint(series.data) for series in self.data if series.data]
    if not mins or not maxes:
      return None, None # No data, just bail.
    return min(mins), max(maxes)

  def AddAxis(self, position, axis):
    """Add an axis to this chart in the given position.

    Args:
      position: an AxisPosition object specifying the axis's position
      axis: The axis to add, an Axis object
    Returns:
      the value of the axis parameter
    """
    self._axes.setdefault(position, []).append(axis)
    return axis

  def GetAxis(self, position):
    """Get or create the first available axis in the given position.

    This is a helper method for the left, right, top, and bottom properties.
    If the specified axis does not exist, it will be created.

    Args:
      position: the position to search for
    Returns:
      The first axis in the given position
    """
    # Not using setdefault here just in case, to avoid calling the Axis()
    # constructor needlessly
    if position in self._axes:
      return self._axes[position][0]
    else:
      axis = Axis()
      self._axes[position] = [axis]
      return axis

  def SetAxis(self, position, axis):
    """Set the first axis in the given position to the given value.

    This is a helper method for the left, right, top, and bottom properties.

    Args:
      position: an AxisPosition object specifying the axis's position
      axis: The axis to set, an Axis object
    Returns:
      the value of the axis parameter
    """
    self._axes.setdefault(position, [None])[0] = axis
    return axis

  def _GetAxes(self):
    """Return a generator of (position_code, Axis) tuples for this chart's axes.

    The axes will be sorted by position using the canonical ordering sequence,
    _POSITION_CODES.
    """
    for code in self._POSITION_CODES:
      for axis in self._axes.get(code, []):
        yield (code, axis)

  def _GetBottom(self):
    return self.GetAxis(AxisPosition.BOTTOM)

  def _SetBottom(self, value):
    self.SetAxis(AxisPosition.BOTTOM, value)

  bottom = property(_GetBottom, _SetBottom,
                    doc="""Get or set the bottom axis""")

  def _GetLeft(self):
    return self.GetAxis(AxisPosition.LEFT)

  def _SetLeft(self, value):
    self.SetAxis(AxisPosition.LEFT, value)

  left = property(_GetLeft, _SetLeft,
                  doc="""Get or set the left axis""")

  def _GetRight(self):
    return self.GetAxis(AxisPosition.RIGHT)

  def _SetRight(self, value):
    self.SetAxis(AxisPosition.RIGHT, value)

  right = property(_GetRight, _SetRight,
                   doc="""Get or set the right axis""")

  def _GetTop(self):
    return self.GetAxis(AxisPosition.TOP)

  def _SetTop(self, value):
    self.SetAxis(AxisPosition.TOP, value)

  top = property(_GetTop, _SetTop,
                 doc="""Get or set the top axis""")