docs: def to_json(record, extraneous=True, prop=None):
      """JSON conversion function: a 'visitor' function which implements marshall
      out (to JSON data form), honoring JSON property types/hints but does not
      require them.  To convert to an actual JSON document, pass the return value
      to ``json.dumps`` or a similar function.
  
      args:
          ``record=``\ *anything*
              This object can be of any type; a best-effort attempt is made to
              convert to a form which ``json.dumps`` can accept; this function
              will call itself recursively, respecting any types which define
              ``.json_data()`` as a method and calling that.
  
          ``extraneous=``\ *BOOL*
              This parameter is passed through to any ``json_data()`` methods
              which support it.
  
          ``prop=``\ *PROPNAME*\ |\ *PROPERTY*
              Specifies to return the given property from an object, calling any
              ``to_json`` mapping defined on the property.  Does not catch the
              ``AttributeError`` that is raised by the property not being set.
      """
      if prop:
          if isinstance(prop, basestring):
              prop = type(record).properties[prop]
          val = prop.__get__(record)
          if hasattr(prop, "to_json"):
              return prop.to_json(val, extraneous, _json_data)
          else:
              return _json_data(val, extraneous)
  
      elif isinstance(record, Collection):
          if isinstance(record, RecordDict):
              return dict(
                  (k, _json_data(v, extraneous)) for k, v in record.items()
              )
          else:
              return list(_json_data(x, extraneous) for x in record)
  
      elif isinstance(record, Record):
          rv_dict = {}
          for propname, prop in type(record).properties.iteritems():
              if not extraneous and prop.extraneous:
                  pass
              elif prop.slot_is_empty(record):
                  pass
              elif not hasattr(prop, "json_name") or prop.json_name is not None:
                  json_name = getattr(prop, "json_name", prop.name)
                  try:
                      rv_dict[json_name] = to_json(record, extraneous, prop)
                  except AttributeError:
                      pass
          return rv_dict
  
      elif isinstance(record, long):
          return str(record) if abs(record) > 2**50 else record
  
      elif isinstance(record, dict):
          return dict(
              (k, _json_data(v, extraneous)) for k, v in record.iteritems()
          )
  
      elif isinstance(record, (list, tuple, set, frozenset)):
          return list(_json_data(x, extraneous) for x in record)
  
      elif isinstance(record, (basestring, int, float, types.NoneType)):
          return record
  
      else:
          raise TypeError(
              "I don't know how to marshall a %s to JSON" %
              type(record).__name__
          )