Exemple #1
0
  def test_exported_thrift_issues_2005(self):
    # Issue #2005 highlighted the fact the PythonThriftBuilder was building both a given
    # PythonThriftLibrary's thrift files as well as its transitive dependencies thrift files.
    # We test here to ensure that independently published PythonThriftLibraries each only own their
    # own thrift stubs and the proper dependency links exist between the distributions.

    self.create_file(relpath='src/thrift/exported/exported.thrift', contents=dedent("""
      namespace py exported

      const set<string> VALID_IDENTIFIERS = ["Hello", "World", "!"]
    """))
    target1 = self.make_target(spec='src/thrift/exported',
                               target_type=PythonThriftLibrary,
                               sources=['exported.thrift'],
                               provides=PythonArtifact(name='test.exported', version='0.0.0'))

    self.create_file(relpath='src/thrift/exported_dependee/exported_dependee.thrift',
                     contents=dedent("""
                       namespace py exported_dependee

                       include "exported/exported.thrift"

                       const set<string> ALIASED_IDENTIFIERS = exported.VALID_IDENTIFIERS
                     """))
    target2 = self.make_target(spec='src/thrift/exported_dependee',
                               target_type=PythonThriftLibrary,
                               sources=['exported_dependee.thrift'],
                               dependencies=[target1],
                               provides=PythonArtifact(name='test.exported_dependee',
                                                       version='0.0.0'))

    with self.run_execute(target2, recursive=True) as created:
      self.assertEqual({target2, target1}, set(created.keys()))

      with self.extracted_sdist(sdist=created[target1],
                                expected_prefix='test.exported-0.0.0') as (py_files, path):
        self.assertEqual({path('setup.py'),
                          path('src/__init__.py'),
                          path('src/exported/__init__.py'),
                          path('src/exported/constants.py'),
                          path('src/exported/ttypes.py')},
                         py_files)

        self.assertFalse(os.path.exists(path('src/test.exported.egg-info/requires.txt')))

      with self.extracted_sdist(sdist=created[target2],
                                expected_prefix='test.exported_dependee-0.0.0') as (py_files, path):
        self.assertEqual({path('setup.py'),
                          path('src/__init__.py'),
                          path('src/exported_dependee/__init__.py'),
                          path('src/exported_dependee/constants.py'),
                          path('src/exported_dependee/ttypes.py')},
                         py_files)

        requirements = path('src/test.exported_dependee.egg-info/requires.txt')
        self.assertTrue(os.path.exists(requirements))
        with open(requirements) as fp:
          self.assertEqual('test.exported==0.0.0', fp.read().strip())
Exemple #2
0
    def test_exported_antlr(self):
        SourceRoot.register('src/antlr', PythonThriftLibrary)
        self.create_file(relpath='src/antlr/exported/exported.g',
                         contents=dedent("""
      grammar exported;

      options {
        language = Python;
      }

      WORD: ('a'..'z'|'A'..'Z'|'0'..'9'|'-'|'_')+;

      static: WORD;
    """))
        target = self.make_target(spec='src/antlr/exported',
                                  target_type=PythonAntlrLibrary,
                                  antlr_version='3.1.3',
                                  sources=['exported.g'],
                                  module='exported',
                                  provides=PythonArtifact(name='test.exported',
                                                          version='0.0.0.'))
        # TODO(John Sirois): Find a way to get easy access to pants option defaults.
        self.set_options_for_scope(
            'ivy',
            ivy_profile='2.4.0',
            ivy_settings=None,
            cache_dir=os.path.expanduser('~/.ivy2/pants'),
            http_proxy=None,
            https_proxy=None)
        with self.run_execute(target) as created:
            self.assertEqual([target], created)
Exemple #3
0
    def test_exported_antlr(self):
        self.create_file(relpath='src/antlr/exported/exported.g',
                         contents=dedent("""
      grammar exported;

      options {
        language = Python;
      }

      WORD: ('a'..'z'|'A'..'Z'|'0'..'9'|'-'|'_')+;

      static: WORD;
    """))
        target = self.make_target(spec='src/antlr/exported',
                                  target_type=PythonAntlrLibrary,
                                  antlr_version='3.1.3',
                                  sources=['exported.g'],
                                  module='exported',
                                  provides=PythonArtifact(name='test.exported',
                                                          version='0.0.0'))

        # TODO(John Sirois): This hacks around a direct but undeclared dependency
        # `pants.java.distribution.distribution.Distribution` gained in
        # https://rbcommons.com/s/twitter/r/2657
        # Remove this once proper Subsystem dependency chains are re-established.
        with subsystem_instance(JVM):
            with self.run_execute(target) as created:
                self.assertEqual([target], created.keys())
    def test_validation(self):
        internal_repo = Repository(url=None, push_db_basedir=None)
        # Adding a JVM Artifact as a provides on a PythonTarget doesn't make a lot of sense.
        # This test sets up that very scenario, and verifies that pants throws a
        # TargetDefinitionException.
        with self.assertRaises(TargetDefinitionException):
            self.make_target(target_type=PythonTarget,
                             spec=":one",
                             provides=Artifact(org='com.twitter',
                                               name='one-jar',
                                               repo=internal_repo))

        spec = "//:test-with-PythonArtifact"
        pa = PythonArtifact(name='foo', version='1.0', description='foo')

        # This test verifies that adding a 'setup_py' provides to a PythonTarget is okay.
        pt_with_artifact = self.make_target(spec=spec,
                                            target_type=PythonTarget,
                                            provides=pa)
        self.assertEqual(pt_with_artifact.address.spec, spec)

        spec = "//:test-with-none"
        # This test verifies that having no provides is okay.
        pt_no_artifact = self.make_target(spec=spec,
                                          target_type=PythonTarget,
                                          provides=None)
        self.assertEqual(pt_no_artifact.address.spec, spec)
Exemple #5
0
    def test_binary_target_injected_into_minified_dependencies(self):
        foo_bin_dep = self.make_target(
            spec=':foo_bin_dep',
            target_type=PythonLibrary,
        )

        foo_bin = self.make_target(spec=':foo_bin',
                                   target_type=PythonBinary,
                                   entry_point='foo.bin.foo',
                                   dependencies=[
                                       foo_bin_dep,
                                   ])

        foo = self.make_target(spec=':foo',
                               target_type=PythonLibrary,
                               provides=PythonArtifact(
                                   name='foo',
                                   version='0.0.0',
                               ).with_binaries(foo_binary=':foo_bin', ))

        self.assertEqual(PythonSetup.minified_dependencies(foo),
                         OrderedSet([foo_bin, foo_bin_dep]))
        entry_points = dict(PythonSetup.iter_entry_points(foo))
        self.assertEqual(entry_points, {'foo_binary': 'foo.bin.foo'})

        with self.run_execute(foo, recursive=False) as setup_py_command:
            setup_py_command.run_one.assert_called_with(foo)

        with self.run_execute(foo, recursive=True) as setup_py_command:
            setup_py_command.run_one.assert_called_with(foo)
def test_list_provides() -> None:
    sample_artifact = PythonArtifact(name="project.demo", version="0.0.0.1")
    targets = [
        MockTarget({ProvidesField.alias: sample_artifact}, address=Address.parse(":provided")),
        MockTarget({}, address=Address.parse(":not_provided")),
    ]
    stdout, _ = run_goal(targets, show_provides=True)
    assert stdout.strip() == f"//:provided {sample_artifact}"
Exemple #7
0
  def test_binary_target_injected_into_minified_dependencies_with_provider(self):
    bar_bin_dep = self.make_target(
      spec = ':bar_bin_dep',
      target_type = PythonLibrary,
      provides = PythonArtifact(
        name = 'bar_bin_dep',
        version = '0.0.0',
      )
    )

    bar_bin = self.make_target(
      spec = ':bar_bin',
      target_type = PythonBinary,
      entry_point = 'bar.bin.bar',
      dependencies = [
        bar_bin_dep,
      ],
    )

    bar = self.make_target(
      spec = ':bar',
      target_type = PythonLibrary,
      provides = PythonArtifact(
        name = 'bar',
        version = '0.0.0',
      ).with_binaries(
        bar_binary = ':bar_bin'
      )
    )

    # TODO(pl): Why is this set ordered?  Does the order actually matter?
    assert PythonSetup.minified_dependencies(bar) == OrderedSet([bar_bin, bar_bin_dep])
    assert PythonSetup.install_requires(bar) == set(['bar_bin_dep==0.0.0'])
    entry_points = dict(PythonSetup.iter_entry_points(bar))
    assert entry_points == {'bar_binary': 'bar.bin.bar'}

    with self.run_execute(bar, recursive=False) as setup_py_command:
      setup_py_command.run_one.assert_called_with(bar)

    with self.run_execute(bar, recursive=True) as setup_py_command:
      setup_py_command.run_one.assert_has_calls([
          call(bar),
          call(bar_bin_dep)
      ], any_order=True)
Exemple #8
0
  def test_exported_thrift(self):
    self.create_file(relpath='src/thrift/exported/exported.thrift', contents=dedent("""
      namespace py pants.constants_only

      const set<string> VALID_IDENTIFIERS = ["Hello", "World", "!"]
    """))
    target = self.make_target(spec='src/thrift/exported',
                              target_type=PythonThriftLibrary,
                              sources=['exported.thrift'],
                              provides=PythonArtifact(name='test.exported', version='0.0.0'))
    with self.run_execute(target) as created:
      self.assertEqual([target], created.keys())
Exemple #9
0
def pants_setup_py(name: str,
                   description: str,
                   additional_classifiers: Optional[List[str]] = None,
                   **kwargs) -> PythonArtifact:
    """Creates the setup_py for a Pants artifact.

    :param name: The name of the package.
    :param description: A brief description of what the package provides.
    :param additional_classifiers: Any additional trove classifiers that apply to the package,
                                        see: https://pypi.org/pypi?%3Aaction=list_classifiers
    :param kwargs: Any additional keyword arguments to be passed to `setuptools.setup
                   <https://pythonhosted.org/setuptools/setuptools.html>`_.
    :returns: A setup_py suitable for building and publishing Pants components.
    """
    if not name.startswith("pantsbuild.pants"):
        raise ValueError(
            f"Pants distribution package names must start with 'pantsbuild.pants', given {name}"
        )

    standard_classifiers = [
        "Intended Audience :: Developers",
        "License :: OSI Approved :: Apache Software License",
        # We know for a fact these OSs work but, for example, know Windows
        # does not work yet.  Take the conservative approach and only list OSs
        # we know pants works with for now.
        "Operating System :: MacOS :: MacOS X",
        "Operating System :: POSIX :: Linux",
        "Programming Language :: Python",
        "Topic :: Software Development :: Build Tools",
    ]
    classifiers = FrozenOrderedSet(standard_classifiers +
                                   (additional_classifiers or []))

    notes = PantsReleases.global_instance().notes_for_version(PANTS_SEMVER)

    return PythonArtifact(
        name=name,
        version=VERSION,
        description=description,
        long_description=Path("src/python/pants/ABOUT.rst").read_text() +
        notes,
        long_description_content_type="text/x-rst",
        url="https://github.com/pantsbuild/pants",
        project_urls={
            "Documentation": "https://www.pantsbuild.org/",
            "Source": "https://github.com/pantsbuild/pants",
            "Tracker": "https://github.com/pantsbuild/pants/issues",
        },
        license="Apache License, Version 2.0",
        zip_safe=True,
        classifiers=list(classifiers),
        **kwargs,
    )
Exemple #10
0
 def create_dependencies(self, depmap):
     target_map = {}
     for name, deps in depmap.items():
         target_map[name] = self.make_target(
             spec=name,
             target_type=PythonLibrary,
             provides=PythonArtifact(name=name, version='0.0.0'))
     for name, deps in depmap.items():
         target = target_map[name]
         dep_targets = [target_map[name] for name in deps]
         for dep in dep_targets:
             self.build_graph.inject_dependency(target.address, dep.address)
     return target_map
Exemple #11
0
def pants_setup_py(name, description, additional_classifiers=None, **kwargs):
    """Creates the setup_py for a pants artifact.

  :param str name: The name of the package.
  :param str description: A brief description of what the package provides.
  :param list additional_classifiers: Any additional trove classifiers that apply to the package,
                                      see: https://pypi.org/pypi?%3Aaction=list_classifiers
  :param kwargs: Any additional keyword arguments to be passed to `setuptools.setup
                 <https://pythonhosted.org/setuptools/setuptools.html>`_.
  :returns: A setup_py suitable for building and publishing pants components.
  """
    if not name.startswith('pantsbuild.pants'):
        raise ValueError(
            f"Pants distribution package names must start with 'pantsbuild.pants', given {name}"
        )

    standard_classifiers = [
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        # We know for a fact these OSs work but, for example, know Windows
        # does not work yet.  Take the conservative approach and only list OSs
        # we know pants works with for now.
        'Operating System :: MacOS :: MacOS X',
        'Operating System :: POSIX :: Linux',
        'Programming Language :: Python',
        'Topic :: Software Development :: Build Tools'
    ]
    classifiers = OrderedSet(standard_classifiers +
                             (additional_classifiers or []))

    notes = PantsReleases.global_instance().notes_for_version(PANTS_SEMVER)

    return PythonArtifact(
        name=name,
        version=VERSION,
        description=description,
        long_description=Path('src/python/pants/ABOUT.rst').read_text() +
        notes,
        url='https://github.com/pantsbuild/pants',
        project_urls={
            'Documentation': 'https://www.pantsbuild.org/',
            'Source': 'https://github.com/pantsbuild/pants',
            'Tracker': 'https://github.com/pantsbuild/pants/issues',
        },
        license='Apache License, Version 2.0',
        zip_safe=True,
        classifiers=list(classifiers),
        **kwargs)
Exemple #12
0
def pants_setup_py(name, description, additional_classifiers=None, **kwargs):
    """Creates the setup_py for a pants artifact.

  :param str name: The name of the package.
  :param str description: A brief description of what the package provides.
  :param list additional_classifiers: Any additional trove classifiers that apply to the package,
                                      see: https://pypi.python.org/pypi?%3Aaction=list_classifiers
  :param kwargs: Any additional keyword arguments to be passed to `setuptools.setup
                 <https://pythonhosted.org/setuptools/setuptools.html>`_.
  :returns: A setup_py suitable for building and publishing pants components.
  """
    if not name.startswith('pantsbuild.pants'):
        raise ValueError(
            "Pants distribution package names must start with 'pantsbuild.pants', "
            "given {}".format(name))

    standard_classifiers = [
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        # We know for a fact these OSs work but, for example, know Windows
        # does not work yet.  Take the conservative approach and only list OSs
        # we know pants works with for now.
        'Operating System :: MacOS :: MacOS X',
        'Operating System :: POSIX :: Linux',
        'Programming Language :: Python',
        'Topic :: Software Development :: Build Tools'
    ]
    classifiers = OrderedSet(standard_classifiers +
                             (additional_classifiers or []))

    def _read_contents(path):
        with open(os.path.join(get_buildroot(), path), 'rb') as fp:
            return fp.read()

    return PythonArtifact(
        name=name,
        version=pants_version(),
        description=description,
        long_description=(_read_contents('src/python/pants/ABOUT.rst') +
                          _read_contents('src/python/pants/CHANGELOG.rst')),
        url='https://github.com/pantsbuild/pants',
        license='Apache License, Version 2.0',
        zip_safe=True,
        classifiers=list(classifiers),
        **kwargs)
Exemple #13
0
    def test_binary_cycle(self):
        foo = self.make_target(spec=':foo',
                               target_type=PythonLibrary,
                               provides=PythonArtifact(
                                   name='foo',
                                   version='0.0.0',
                               ).with_binaries(foo_binary=':foo_bin', ))

        foo_bin = self.make_target(
            spec=':foo_bin',
            target_type=PythonBinary,
            entry_point='foo.bin.foo',
            dependencies=[
                foo,
            ],
        )

        with self.assertRaises(TargetDefinitionException):
            PythonSetup.minified_dependencies(foo)
Exemple #14
0
    def test_exported_thrift(self):
        SourceRoot.register('src/thrift', PythonThriftLibrary)
        self.create_file(relpath='src/thrift/exported/exported.thrift',
                         contents=dedent("""
      namespace py pants.constants_only

      const set<string> VALID_IDENTIFIERS = ["Hello", "World", "!"]
    """))
        target = self.make_target(spec='src/thrift/exported',
                                  target_type=PythonThriftLibrary,
                                  sources=['exported.thrift'],
                                  provides=PythonArtifact(name='test.exported',
                                                          version='0.0.0.'))
        # TODO(John Sirois): Find a way to get easy access to pants option defaults.
        self.set_options_for_scope(
            'binaries',
            baseurls=['https://dl.bintray.com/pantsbuild/bin/build-support'],
            fetch_timeout_secs=30)
        with self.run_execute(target) as created:
            self.assertEqual([target], created)