Example #1
0
 def test_invalid_field_name(self):
   with self.assertRaisesWithMessage(
       ValueError,
       "Type names and field names must be valid identifiers: '0isntanallowedfirstchar'"
       if PY3 else
       "Type names and field names cannot start with a number: '0isntanallowedfirstchar'"):
     datatype(['0isntanallowedfirstchar'])
   with self.assertRaisesWithMessage(
       ValueError,
       "Field names cannot start with an underscore: '_no_leading_underscore'"):
     datatype(['_no_leading_underscore'])
Example #2
0
  def test_subclasses_not_equal(self):
    foo = datatype(['val'])
    class Bar(foo):
      pass

    self.assertFalse(foo(1) == Bar(1))
    self.assertTrue(foo(1) != Bar(1))
Example #3
0
 def test_double_passed_arg(self):
   bar = datatype(['val', 'zal'])
   with self.assertRaisesWithMessageContaining(
       TypeError,
       "__new__() got multiple values for {kw}argument 'val'"
       .format(kw='' if PY3 else 'keyword ')):
     bar(1, val=1)
Example #4
0
  def test_repr(self):
    bar = datatype(['val', 'zal'], superclass_name='Bar')
    self.assertEqual('Bar(val=1, zal=1)', repr(bar(1, 1)))

    class Foo(datatype(['val'], superclass_name='F'), AbsClass):
      pass

    self.assertEqual('Foo(val=1)', repr(Foo(1)))
Example #5
0
 def test_too_many_args(self):
   bar = datatype(['val', 'zal'])
   with self.assertRaisesWithMessageContaining(
       TypeError,
       '__new__() takes 3 positional arguments but 4 were given'
       if PY3 else
       '__new__() takes exactly 3 arguments (4 given)'):
     bar(1, 1, 1)
Example #6
0
  def of(cls, element_type, fields=('dependencies',)):
    type_name = b'{}({})'.format(cls.__name__, element_type.__name__)

    collection_of_type = type(type_name, (cls, datatype("{}s".format(element_type.__name__), fields)), {})

    # Expose the custom class type at the module level to be pickle compatible.
    setattr(sys.modules[cls.__module__], type_name, collection_of_type)

    return collection_of_type
Example #7
0
  def test_repr(self):
    bar = datatype('Bar', ['val', 'zal'])
    self.assertEqual('Bar(val=1, zal=1)', repr(bar(1, 1)))

    class Foo(datatype('F', ['val']), AbsClass):
      pass

    # Maybe this should be 'Foo(val=1)'?
    self.assertEqual('F(val=1)', repr(Foo(1)))
Example #8
0
  def of(cls, *element_types):
    union = '|'.join(element_type.__name__ for element_type in element_types)
    type_name = b'{}.of({})'.format(cls.__name__, union)
    supertypes = (cls, datatype('Collection', ['dependencies']))
    properties = {'element_types': element_types}
    collection_of_type = type(type_name, supertypes, properties)

    # Expose the custom class type at the module level to be pickle compatible.
    setattr(sys.modules[cls.__module__], type_name, collection_of_type)

    return collection_of_type
Example #9
0
  def of(cls, *element_types):
    union = '|'.join(element_type.__name__ for element_type in element_types)
    type_name = '{}.of({})'.format(cls.__name__, union)
    if PY2:
      type_name = type_name.encode('utf-8')
    type_checked_collection_class = datatype([
      # Create a datatype with a single field 'dependencies' which is type-checked on construction
      # to be a collection containing elements of only the exact `element_types` specified.
      ('dependencies', TypedCollection(Exactly(*element_types)))
    ], superclass_name=cls.__name__)
    supertypes = (cls, type_checked_collection_class)
    properties = {'element_types': element_types}
    collection_of_type = type(type_name, supertypes, properties)

    # Expose the custom class type at the module level to be pickle compatible.
    setattr(sys.modules[cls.__module__], type_name, collection_of_type)

    return collection_of_type
Example #10
0
 def test_not_iterable(self):
   bar = datatype(['val'])
   with self.assertRaisesWithMessageContaining(TypeError, 'datatype object is not iterable'):
     for x in bar(1):
       pass
Example #11
0
 def test_unexpect_kwarg(self):
   bar = datatype('Bar', ['val'])
   with self.assertRaises(TypeError):
     bar(other=1)
Example #12
0
class _Snapshots(datatype('_Snapshots', ['root'])):
    """Private singleton value to expose the snapshot directory (managed by rust) to python.
Example #13
0
class SelectNode(datatype('SelectNode', ['subject', 'product', 'variants', 'variant_key']), Node):
  """A Node that selects a product for a subject.

  A Select can be satisfied by multiple sources, but fails if multiple sources produce a value. The
  'variants' field represents variant configuration that is propagated to dependencies. When
  a task needs to consume a product as configured by the variants map, it uses the SelectVariant
  selector, which introduces the 'variant' value to restrict the names of values selected by a
  SelectNode.
  """
  is_cacheable = False
  is_inlineable = True

  def _variants_node(self):
    if type(self.subject) is Address and self.product is not Variants:
      return SelectNode(self.subject, Variants, self.variants, None)
    return None

  def _select_literal(self, candidate, variant_value):
    """Looks for has-a or is-a relationships between the given value and the requested product.

    Returns the resulting product value, or None if no match was made.
    """
    def items():
      # Check whether the subject is-a instance of the product.
      yield candidate
      # Else, check whether it has-a instance of the product.
      if isinstance(candidate, HasProducts):
        for subject in candidate.products:
          yield subject

    # TODO: returning only the first literal configuration of a given type/variant. Need to
    # define mergeability for products.
    for item in items():
      if not isinstance(item, self.product):
        continue
      if variant_value and not getattr(item, 'name', None) == variant_value:
        continue
      return item
    return None

  def step(self, step_context):
    # Request default Variants for the subject, so that if there are any we can propagate
    # them to task nodes.
    variants = self.variants
    variants_node = self._variants_node()
    if variants_node:
      dep_state = step_context.get(variants_node)
      if type(dep_state) is Waiting:
        return dep_state
      elif type(dep_state) is Return:
        # A subject's variants are overridden by any dependent's requested variants, so
        # we merge them left to right here.
        variants = Variants.merge(dep_state.value.default.items(), variants)

    # If there is a variant_key, see whether it has been configured.
    variant_value = None
    if self.variant_key:
      variant_values = [value for key, value in variants
                        if key == self.variant_key] if variants else None
      if not variant_values:
        # Select cannot be satisfied: no variant configured for this key.
        return Noop('Variant key {} was not configured in variants {}', self.variant_key, variants)
      variant_value = variant_values[0]

    # If the Subject "is a" or "has a" Product, then we're done.
    literal_value = self._select_literal(self.subject, variant_value)
    if literal_value is not None:
      return Return(literal_value)

    # Else, attempt to use a configured task to compute the value.
    dependencies = []
    matches = []
    for dep in step_context.gen_nodes(self.subject, self.product, variants):
      dep_state = step_context.get(dep)
      if type(dep_state) is Waiting:
        dependencies.extend(dep_state.dependencies)
      elif type(dep_state) is Return:
        # We computed a value: see whether we can use it.
        literal_value = self._select_literal(dep_state.value, variant_value)
        if literal_value is not None:
          matches.append((dep, literal_value))
      elif type(dep_state) is Throw:
        return dep_state
      elif type(dep_state) is Noop:
        continue
      else:
        State.raise_unrecognized(dep_state)

    # If any dependencies were unavailable, wait for them; otherwise, determine whether
    # a value was successfully selected.
    if dependencies:
      return Waiting(dependencies)
    elif len(matches) == 0:
      return Noop('No source of {}.', self)
    elif len(matches) > 1:
      # TODO: Multiple successful tasks are not currently supported. We should allow for this
      # by adding support for "mergeable" products. see:
      #   https://github.com/pantsbuild/pants/issues/2526
      return Throw(ConflictingProducersError.create(self.subject, self.product, matches))
    else:
      return Return(matches[0][1])
Example #14
0
 def test_double_passed_arg(self):
   bar = datatype('Bar', ['val', 'zal'])
   with self.assertRaises(TypeError):
     bar(1, val=1)
Example #15
0
      class NonStringField(datatype([3])): pass

    expected_msg = "Type names and field names must be valid identifiers: '32'"
Example #16
0
      class InvalidTypeSpec(datatype([('a_field', 2)])): pass

  def test_instance_construction_by_repr(self):
Example #17
0
class Link(datatype('Link', ['path']), Stat):
    """A symbolic link."""
    def __new__(cls, path):
        return super(Link, cls).__new__(cls, six.binary_type(path))
Example #18
0
class BuildDirs(datatype('BuildDirs', ['dependencies'])):
    """A list of Stat objects for directories containing build files."""
Example #19
0
class File(datatype('File', ['path']), Stat):
    """A file."""
    def __new__(cls, path):
        return super(File, cls).__new__(cls, six.binary_type(path))
Example #20
0
class Dir(datatype('Dir', ['path']), Stat):
    """A directory."""
    def __new__(cls, path):
        return super(Dir, cls).__new__(cls, six.binary_type(path))
Example #21
0
class JVMPackageName(datatype(['name'])):
    """A typedef to represent a fully qualified JVM package name."""
    pass
Example #22
0
class Scrooge(datatype(['tool_address'])):
    """Placeholder for a Scrooge subsystem."""
Example #23
0
class SourceRoots(datatype(['srcroots'])):
    """Placeholder for the SourceRoot subsystem."""
Example #24
0
 def test_atrs(self):
   bar = datatype(['val'])
   self.assertEqual(1, bar(1).val)
Example #25
0
class BuildFiles(datatype('BuildFiles', ['files_content'])):
    """The FileContents of BUILD files in some directory"""
Example #26
0
  def test_replace_non_iterable(self):
    bar = datatype(['val', 'zal'])

    self.assertEqual(bar(1, 3), bar(1, 2)._replace(zal=3))
Example #27
0
class BuildFileGlobs(datatype('BuildFilesGlobs', ['path_globs'])):
    """A wrapper around PathGlobs that are known to match a build file pattern."""
Example #28
0
      class JustTypeField(datatype([str])): pass

    expected_msg = "Type names and field names must be valid identifiers: '3'"
Example #29
0
class BundlesField(
        datatype(['address', 'bundles', 'filespecs_list', 'path_globs_list']),
        Field):
    """Represents the `bundles` argument, each of which has a PathGlobs to represent its `fileset`."""
    def __hash__(self):
        return hash(self.address)
Example #30
0
class HostLibcDev(datatype(['crti_object', 'fingerprint'])):
    pass
Example #31
0
 def test_not_iterable(self):
   bar = datatype('Bar', ['val'])
   with self.assertRaises(TypeError):
     for x in bar(1):
       pass
Example #32
0
class LegacyBuildGraphNode(
        datatype('LegacyGraphNode',
                 ['target_adaptor', 'dependency_addresses'])):
    """A Node to represent a node in the legacy BuildGraph.
Example #33
0
 def test_invalid_field_name(self):
   with self.assertRaises(ValueError):
     datatype('Bar', ['0isntanallowedfirstchar'])
Example #34
0
 def test_too_many_args(self):
   bar = datatype('Bar', ['val', 'zal'])
   with self.assertRaises(TypeError):
     bar(1, 1, 1)
Example #35
0
 class MultipleSameName(datatype([
     'field_a',
     'field_b',
     'field_a',
 ])):
   pass
Example #36
0
class LegacyTarget(datatype('LegacyTarget', ['adaptor', 'dependencies'])):
  """A class to represent a node and edges in the legacy BuildGraph.
Example #37
0
class SnapshottedProcessResult(
        datatype('SnapshottedProcessResult',
                 ['stdout', 'stderr', 'exit_code'])):
    """Contains the stdout, stderr and exit code from executing a process."""
Example #38
0
 def test_properties_not_assignable(self):
   bar = datatype('Bar', ['val'])
   bar_inst = bar(1)
   with self.assertRaises(AttributeError):
     bar_inst.val = 2
Example #39
0
class HydratedField(datatype('HydratedField', ['name', 'value'])):
  """A wrapper for a fully constructed replacement kwarg for a LegacyTarget."""
Example #40
0
  def test_type_included_in_eq(self):
    foo = datatype(['val'])
    bar = datatype(['val'])

    self.assertFalse(foo(1) == bar(1))
    self.assertTrue(foo(1) != bar(1))
Example #41
0
class UnpackedArchives(
        datatype([('found_files', tuple), ('rel_unpack_dir', text_type)])):
    def __new__(cls, found_files, rel_unpack_dir):
        return super(UnpackedArchives, cls).__new__(cls, tuple(found_files),
                                                    text_type(rel_unpack_dir))
Example #42
0
      class NonStringTypeField(datatype([(32, int)])): pass

    expected_msg = "Encountered duplicate field name: 'field_a'"
Example #43
0
 class Handle(datatype([('pid', int), ('port', int)])):
     """A handle to a "probably running" pantsd instance.
Example #44
0
  def test_deep_copy(self):
    # deep copy calls into __getnewargs__, which namedtuple defines as implicitly using __iter__.

    bar = datatype(['val'])

    self.assertEqual(bar(1), copy.deepcopy(bar(1)))
Example #45
0
 def test_unexpect_kwarg(self):
   bar = datatype(['val'])
   with self.assertRaisesWithMessageContaining(
       TypeError,
       "__new__() got an unexpected keyword argument 'other'"):
     bar(other=1)
Example #46
0
  def test_as_dict(self):
    bar = datatype(['val'])

    self.assertEqual({'val': 1}, bar(1)._asdict())
Example #47
0
      class NoFields(datatype()): pass

    expected_msg = "Type names and field names must be valid identifiers: \"<class 'str'>\""
Example #48
0
 def test_properties_not_assignable(self):
   bar = datatype(['val'])
   bar_inst = bar(1)
   with self.assertRaisesWithMessage(AttributeError, "can't set attribute"):
     bar_inst.val = 2
Example #49
0
class CToolchain(datatype([('c_compiler', CCompiler), ('c_linker', Linker)])):
    pass
Example #50
0
 def test_mixed_argument_types(self):
   bar = datatype(['val', 'zal'])
   self.assertEqual(bar(1, 2), bar(val=1, zal=2))
   self.assertEqual(bar(1, 2), bar(zal=2, val=1))
Example #51
0
class CppToolchain(
        datatype([('cpp_compiler', CppCompiler), ('cpp_linker', Linker)])):
    pass
Example #52
0
class JarDependency(
        datatype([
            'org', 'base_name', 'rev', 'force', 'ext', 'url', 'apidocs',
            'classifier', 'mutable', 'intransitive', 'excludes', 'base_path'
        ])):
    """A pre-built Maven repository dependency.

  This is the developer facing api, compared to the context wrapper class
  `JarDependencyParseContextWrapper`, which exposes api through build file to users.

  The only additional parameter `base_path` here is so that we can retrieve the file URL
  in its absolute (for ivy) or relative (for fingerprinting) form. The context wrapper class
  determines the `base_path` from where `jar` is defined at.

  If a relative file url is provided, its absolute form will be (`buildroot` + `base_path` + relative url).

  :API: public
  """
    @staticmethod
    def _prepare_excludes(excludes):
        return tuple(
            assert_list(excludes,
                        expected_type=Exclude,
                        can_be_none=True,
                        key_arg='excludes',
                        allowable=(
                            tuple,
                            list,
                        )))

    def __new__(cls,
                org,
                name,
                rev=None,
                force=False,
                ext=None,
                url=None,
                apidocs=None,
                classifier=None,
                mutable=None,
                intransitive=False,
                excludes=None,
                base_path=None):
        """

    :param string base_path: base path that's relative to the build root.
    """
        excludes = JarDependency._prepare_excludes(excludes)
        base_path = base_path or '.'
        if os.path.isabs(base_path):
            base_path = os.path.relpath(base_path, get_buildroot())
        return super(JarDependency, cls).__new__(cls,
                                                 org=org,
                                                 base_name=name,
                                                 rev=rev,
                                                 force=force,
                                                 ext=ext,
                                                 url=url,
                                                 apidocs=apidocs,
                                                 classifier=classifier,
                                                 mutable=mutable,
                                                 intransitive=intransitive,
                                                 excludes=excludes,
                                                 base_path=base_path)

    @property
    def name(self):
        return self.base_name

    @memoized_method
    def get_url(self, relative=False):
        if self.url:
            parsed_url = parse.urlparse(self.url)
            if parsed_url.scheme == 'file':
                if relative and os.path.isabs(parsed_url.path):
                    relative_path = os.path.relpath(
                        parsed_url.path,
                        os.path.join(get_buildroot(), self.base_path))
                    return 'file:{path}'.format(
                        path=os.path.normpath(relative_path))
                if not relative and not os.path.isabs(parsed_url.path):
                    abs_path = os.path.join(get_buildroot(), self.base_path,
                                            parsed_url.path)
                    return 'file://{path}'.format(
                        path=os.path.normpath(abs_path))
        return self.url

    @property
    def transitive(self):
        return not self.intransitive

    def copy(self, **replacements):
        """Returns a clone of this JarDependency with the given replacements kwargs overlaid."""
        cls = type(self)
        kwargs = self._asdict()
        for key, val in replacements.items():
            if key == 'excludes':
                val = JarDependency._prepare_excludes(val)
            kwargs[key] = val
        org = kwargs.pop('org')
        base_name = kwargs.pop('base_name')
        return cls(org, base_name, **kwargs)

    def __str__(self):
        return 'JarDependency({})'.format(self.coordinate)

    @memoized_property
    def coordinate(self):
        """Returns the maven coordinate of this jar.

    :rtype: :class:`pants.java.jar.M2Coordinate`
    """
        return M2Coordinate(org=self.org,
                            name=self.name,
                            rev=self.rev,
                            classifier=self.classifier,
                            ext=self.ext)

    def cache_key(self):
        excludes = [(e.org, e.name) for e in self.excludes]
        return stable_json_hash(
            dict(org=self.org,
                 name=self.name,
                 rev=self.rev,
                 force=self.force,
                 ext=self.ext,
                 url=self.get_url(relative=True),
                 classifier=self.classifier,
                 transitive=self.transitive,
                 mutable=self.mutable,
                 excludes=excludes))
Example #53
0
 class MultipleSameNameWithType(datatype([
       'field_a',
       ('field_a', int),
     ])):
   pass
Example #54
0
class Assembler(datatype([
        'path_entries',
        'exe_filename',
        'library_dirs',
]), Executable):
    pass
Example #55
0
 def _synthesize_goal_product(name):
   product_type_name = '{}GoalExecution'.format(name.capitalize())
   if PY2:
     product_type_name = product_type_name.encode('utf-8')
   return type(product_type_name, (datatype(['result']),), {})