コード例 #1
0
ファイル: mapper.py プロジェクト: RobinTec/pants
  def parse(cls, filepath, filecontent, symbol_table_cls, parser_cls):
    """Parses a source for addressable Serializable objects.

    No matter the parser used, the parsed and mapped addressable objects are all 'thin'; ie: any
    objects they point to in other namespaces or even in the same namespace but from a seperate
    source are left as unresolved pointers.

    :param string path: The path to the byte source containing serialized objects.
    :param parser_cls: The parser cls to use.
    :type parser_cls: A :class:`pants.engine.parser.Parser`
    """
    try:
      objects = parser_cls.parse(filepath, filecontent, symbol_table_cls)
    except Exception as e:
      raise MappingError('Failed to parse {}:\n{}'.format(filepath, e))
    objects_by_name = {}
    for obj in objects:
      if not Serializable.is_serializable(obj):
        raise UnaddressableObjectError('Parsed a non-serializable object: {!r}'.format(obj))
      attributes = obj._asdict()

      name = attributes.get('name')
      if not name:
        raise UnaddressableObjectError('Parsed a non-addressable object: {!r}'.format(obj))

      if name in objects_by_name:
        raise DuplicateNameError('An object already exists at {!r} with name {!r}: {!r}.  Cannot '
                                 'map {!r}'.format(filepath, name, objects_by_name[name], obj))

      objects_by_name[name] = obj
    return cls(filepath, OrderedDict(sorted(objects_by_name.items())))
コード例 #2
0
    def parse(cls, filepath, filecontent, symbol_table_cls, parser_cls):
        """Parses a source for addressable Serializable objects.

    No matter the parser used, the parsed and mapped addressable objects are all 'thin'; ie: any
    objects they point to in other namespaces or even in the same namespace but from a seperate
    source are left as unresolved pointers.

    :param string path: The path to the byte source containing serialized objects.
    :param parser_cls: The parser cls to use.
    :type parser_cls: A :class:`pants.engine.parser.Parser`
    """
        try:
            objects = parser_cls.parse(filepath, filecontent, symbol_table_cls)
        except Exception as e:
            raise MappingError('Failed to parse {}:\n{}'.format(filepath, e))
        objects_by_name = {}
        for obj in objects:
            if not Serializable.is_serializable(obj):
                raise UnaddressableObjectError(
                    'Parsed a non-serializable object: {!r}'.format(obj))
            attributes = obj._asdict()

            name = attributes.get('name')
            if not name:
                raise UnaddressableObjectError(
                    'Parsed a non-addressable object: {!r}'.format(obj))

            if name in objects_by_name:
                raise DuplicateNameError(
                    'An object already exists at {!r} with name {!r}: {!r}.  Cannot '
                    'map {!r}'.format(filepath, name, objects_by_name[name],
                                      obj))

            objects_by_name[name] = obj
        return cls(filepath, OrderedDict(sorted(objects_by_name.items())))
コード例 #3
0
ファイル: addressable.py プロジェクト: grimreaper/pants
    def _checked_value(self, instance, value):
        # We allow five forms of value:
        # 0. None.
        # 1. An opaque (to us) address pointing to a value that can be resolved by external
        #    means.
        # 2. A `Resolvable` value that we can lazily resolve and type-check in `__get__`.
        # 3. A concrete instance that meets our type constraint.
        # 4. A dict when our type constraint has exactly one Serializable subject type - we convert the
        #    dict into an instance of that type.
        if value is None:
            return None

        if isinstance(value, (str, Address, Resolvable)):
            return value

        # Support untyped dicts that we deserialize on-demand here into the required type.
        # This feature allows for more brevity in the JSON form (local type inference) and an alternate
        # construction style in the python forms.
        type_constraint = self._get_type_constraint(instance)
        if (isinstance(value, dict) and len(type_constraint.types) == 1 and
                Serializable.is_serializable_type(type_constraint.types[0])):
            if not value:
                # TODO(John Sirois): Is this the right thing to do?  Or should an empty serializable_type
                # be constructed?
                return None  # {} -> None.
            else:
                serializable_type = type_constraint.types[0]
                return serializable_type(**value)

        try:
            return type_constraint.validate_satisfied_by(value)
        except TypeConstraintError as e:
            raise AddressableTypeValidationError(
                "The value for the {} attribute of {} was invalid".format(
                    self._name, instance), e)
コード例 #4
0
ファイル: parsers.py プロジェクト: tpasternak/pants
    def parse(self, filepath, filecontent):
        parse_globals = self._globals

        python = filecontent
        symbols = {}
        exec(python, parse_globals, symbols)

        objects = []
        for name, obj in symbols.items():
            if isinstance(obj, type):
                # Allow type imports
                continue

            if not Serializable.is_serializable(obj):
                raise ParseError(
                    f'Found a non-serializable top-level object: {obj}')

            attributes = obj._asdict()
            if 'name' in attributes:
                attributes = attributes.copy()
                redundant_name = attributes.pop('name', None)
                if redundant_name and redundant_name != name:
                    raise ParseError(
                        'The object named {!r} is assigned to a mismatching name {!r}'
                        .format(redundant_name, name))
            obj_type = type(obj)
            named_obj = obj_type(name=name, **attributes)
            objects.append(named_obj)
        return objects
コード例 #5
0
ファイル: parsers.py プロジェクト: foursquare/pants
  def parse(self, filepath, filecontent):
    parse_globals = self._globals

    python = filecontent
    symbols = {}
    six.exec_(python, parse_globals, symbols)

    objects = []
    for name, obj in symbols.items():
      if isinstance(obj, type):
        # Allow type imports
        continue

      if not Serializable.is_serializable(obj):
        raise ParseError('Found a non-serializable top-level object: {}'.format(obj))

      attributes = obj._asdict()
      if 'name' in attributes:
        attributes = attributes.copy()
        redundant_name = attributes.pop('name', None)
        if redundant_name and redundant_name != name:
          raise ParseError('The object named {!r} is assigned to a mismatching name {!r}'
                          .format(redundant_name, name))
      obj_type = type(obj)
      named_obj = obj_type(name=name, **attributes)
      objects.append(named_obj)
    return objects
コード例 #6
0
ファイル: mapper.py プロジェクト: tushar19/pants
    def parse(cls, filepath: str, filecontent: bytes,
              parser: Parser) -> "AddressMap":
        """Parses a source for addressable Serializable objects.

        No matter the parser used, the parsed and mapped addressable objects are all 'thin'; ie: any
        objects they point to in other namespaces or even in the same namespace but from a separate
        source are left as unresolved pointers.

        :param filepath: The path to the byte source containing serialized objects.
        :param filecontent: The content of byte source containing serialized objects to be parsed.
        :param parser: The parser cls to use.
        """
        try:
            objects = parser.parse(filepath, filecontent)
        except Exception as e:
            raise MappingError(f"Failed to parse {filepath}:\n{e!r}")
        objects_by_name: Dict[str, ThinAddressableObject] = {}
        for obj in objects:
            if not Serializable.is_serializable(obj):
                raise UnaddressableObjectError(
                    "Parsed a non-serializable object: {!r}".format(obj))
            attributes = obj._asdict()

            name = attributes.get("name")
            if not name:
                raise UnaddressableObjectError(
                    "Parsed a non-addressable object: {!r}".format(obj))

            if name in objects_by_name:
                raise DuplicateNameError(
                    "An object already exists at {!r} with name {!r}: {!r}.  Cannot "
                    "map {!r}".format(filepath, name, objects_by_name[name],
                                      obj))
            objects_by_name[name] = obj
        return cls(filepath, dict(sorted(objects_by_name.items())))
コード例 #7
0
ファイル: parsers.py プロジェクト: tpasternak/pants
 def registered(type_name, object_type, name=None, **kwargs):
     if name:
         obj = object_type(name=name, type_alias=type_name, **kwargs)
         if Serializable.is_serializable(obj):
             objects.append(obj)
         return obj
     else:
         return object_type(type_alias=type_name, **kwargs)
コード例 #8
0
ファイル: parsers.py プロジェクト: foursquare/pants
 def registered(type_name, object_type, name=None, **kwargs):
   if name:
     obj = object_type(name=name, type_alias=type_name, **kwargs)
     if Serializable.is_serializable(obj):
       objects.append(obj)
     return obj
   else:
     return object_type(type_alias=type_name, **kwargs)
コード例 #9
0
ファイル: parsers.py プロジェクト: foursquare/pants
def _object_encoder(obj, inline):
  if isinstance(obj, Resolvable):
    return obj.resolve() if inline else obj.address
  if isinstance(obj, Address):
    return obj.reference()
  if not Serializable.is_serializable(obj):
    raise ParseError('Can only encode Serializable objects in JSON, given {!r} of type {}'
                     .format(obj, type(obj).__name__))

  encoded = obj._asdict()
  if 'type_alias' not in encoded:
    encoded = encoded.copy()
    encoded['type_alias'] = '{}.{}'.format(inspect.getmodule(obj).__name__, type(obj).__name__)
  return {k: v for k, v in encoded.items() if v}
コード例 #10
0
def _object_encoder(obj, inline):
  if isinstance(obj, Resolvable):
    return obj.resolve() if inline else obj.address
  if isinstance(obj, Address):
    return obj.reference()
  if not Serializable.is_serializable(obj):
    raise ParseError('Can only encode Serializable objects in JSON, given {!r} of type {}'
                     .format(obj, type(obj).__name__))

  encoded = obj._asdict()
  if 'type_alias' not in encoded:
    encoded = encoded.copy()
    encoded['type_alias'] = '{}.{}'.format(inspect.getmodule(obj).__name__, type(obj).__name__)
  return {k: v for k, v in encoded.items() if v}
コード例 #11
0
ファイル: addressable.py プロジェクト: baroquebobcat/pants
  def _checked_value(self, instance, value):
    # We allow five forms of value:
    # 0. None.
    # 1. An opaque (to us) address pointing to a value that can be resolved by external
    #    means.
    # 2. A `Resolvable` value that we can lazily resolve and type-check in `__get__`.
    # 3. A concrete instance that meets our type constraint.
    # 4. A dict when our type constraint has exactly one Serializable subject type - we convert the
    #    dict into an instance of that type.
    if value is None:
      return None

    if isinstance(value, (six.string_types, Address, Resolvable)):
      return value

    # Support untyped dicts that we deserialize on-demand here into the required type.
    # This feature allows for more brevity in the JSON form (local type inference) and an alternate
    # construction style in the python forms.
    type_constraint = self._get_type_constraint(instance)
    if (isinstance(value, dict) and
        len(type_constraint.types) == 1 and
        Serializable.is_serializable_type(type_constraint.types[0])):
      if not value:
        # TODO(John Sirois): Is this the right thing to do?  Or should an empty serializable_type
        # be constructed?
        return None  # {} -> None.
      else:
        serializable_type = type_constraint.types[0]
        return serializable_type(**value)

    try:
      return type_constraint.validate_satisfied_by(value)
    except TypeConstraintError as e:
      raise AddressableTypeValidationError(
        "The value for the {} attribute of {} was invalid"
        .format(self._name, instance),
        e)

    return value
コード例 #12
0
ファイル: addressable.py プロジェクト: wisechengyi/pants
    def __set__(self, instance, value):
        if not Serializable.is_serializable(instance):
            raise NotSerializableError(
                "The addressable descriptor {} can only be applied to methods or "
                "properties of Serializable objects, applied to method {} of "
                "type {}".format(type(self).__name__, self._name, type(instance).__name__)
            )

        instance_dict = instance._asdict()
        if self._name in instance_dict:
            raise MutationError(
                "Attribute {} of {} has already been set to {}, rejecting attempt to "
                "re-set with {}".format(self._name, instance, instance_dict[self._name], value)
            )

        value = self._checked_value(instance, value)

        self._register(instance, self)

        # We mutate the instance dict, which is only OK if used in the conventional idiom of setting
        # the value via this data descriptor in the instance's constructor.
        instance_dict[self._name] = value
コード例 #13
0
ファイル: addressable.py プロジェクト: kwlzn/pants
  def __set__(self, instance, value):
    if not Serializable.is_serializable(instance):
      raise NotSerializableError('The addressable descriptor {} can only be applied to methods or '
                                 'properties of Serializable objects, applied to method {} of '
                                 'type {}'.format(type(self).__name__,
                                                  self._name,
                                                  type(instance).__name__))

    instance_dict = instance._asdict()
    if self._name in instance_dict:
      raise MutationError('Attribute {} of {} has already been set to {}, rejecting attempt to '
                          're-set with {}'.format(self._name,
                                                  instance,
                                                  instance_dict[self._name],
                                                  value))

    value = self._checked_value(instance, value)

    self._register(instance, self)

    # We mutate the instance dict, which is only OK if used in the conventional idiom of setting
    # the value via this data descriptor in the instance's constructor.
    instance_dict[self._name] = value
コード例 #14
0
 def __init__(self, parse_context, type_alias, object_type):
     self._parse_context = parse_context
     self._type_alias = type_alias
     self._object_type = object_type
     self._serializable = Serializable.is_serializable_type(
         self._object_type)
コード例 #15
0
 def __init__(self, type_alias, object_type):
   self._type_alias = type_alias
   self._object_type = object_type
   self._serializable = Serializable.is_serializable_type(self._object_type)
コード例 #16
0
ファイル: parser.py プロジェクト: foursquare/pants
 def __init__(self, parse_context, type_alias, object_type):
   self._parse_context = parse_context
   self._type_alias = type_alias
   self._object_type = object_type
   self._serializable = Serializable.is_serializable_type(self._object_type)