Example #1
0
    def test_read_metadata(self):
        fields = {
            'name': 'project',
            'version': '1.0',
            'description': 'desc',
            'summary': 'xxx',
            'download_url': 'http://example.com',
            'keywords': ['one', 'two'],
            'requires_dist': ['foo']
        }

        metadata = Metadata(mapping=fields)
        PKG_INFO = StringIO()
        metadata.write_file(PKG_INFO)
        PKG_INFO.seek(0)

        metadata = Metadata(fileobj=PKG_INFO)

        self.assertEqual(metadata['name'], 'project')
        self.assertEqual(metadata['version'], '1.0')
        self.assertEqual(metadata['summary'], 'xxx')
        self.assertEqual(metadata['download_url'], 'http://example.com')
        self.assertEqual(metadata['keywords'], ['one', 'two'])
        self.assertEqual(metadata['platform'], [])
        self.assertEqual(metadata['obsoletes'], [])
        self.assertEqual(metadata['requires-dist'], ['foo'])
Example #2
0
    def test_metadata_read_write(self):
        PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
        metadata = Metadata(PKG_INFO)
        out = StringIO()
        metadata.write_file(out)

        out.seek(0)
        res = Metadata()
        res.read_file(out)
        self.assertEqual(metadata.values(), res.values())
Example #3
0
    def __init__(self, path):
        self.path = path
        if _cache_enabled and path in _cache_path_egg:
            self.metadata = _cache_path_egg[path].metadata
            self.name = self.metadata['Name']
            self.version = self.metadata['Version']
            return

        requires = None

        if path.endswith('.egg'):
            if os.path.isdir(path):
                meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
                self.metadata = Metadata(path=meta_path)
                req_path = os.path.join(path, 'EGG-INFO', 'requires.txt')
                requires = parse_requires(req_path)
            else:
                # FIXME handle the case where zipfile is not available
                zipf = zipimport.zipimporter(path)
                fileobj = StringIO(
                    zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8'))
                self.metadata = Metadata(fileobj=fileobj)
                try:
                    requires = zipf.get_data('EGG-INFO/requires.txt')
                except IOError:
                    requires = None
            self.name = self.metadata['Name']
            self.version = self.metadata['Version']

        elif path.endswith('.egg-info'):
            if os.path.isdir(path):
                path = os.path.join(path, 'PKG-INFO')
                req_path = os.path.join(path, 'requires.txt')
                requires = parse_requires(req_path)
            self.metadata = Metadata(path=path)
            self.name = self.metadata['Name']
            self.version = self.metadata['Version']

        else:
            raise ValueError('path must end with .egg-info or .egg, got %r' %
                             path)

        if requires:
            if self.metadata['Metadata-Version'] == '1.1':
                # we can't have 1.1 metadata *and* Setuptools requires
                for field in ('Obsoletes', 'Requires', 'Provides'):
                    if field in self.metadata:
                        del self.metadata[field]
            self.metadata['Requires-Dist'] += requires

        if _cache_enabled:
            _cache_path_egg[self.path] = self
Example #4
0
    def test_project_url(self):
        metadata = Metadata()
        metadata['Project-URL'] = [('one', 'http://ok')]
        self.assertEqual(metadata['Project-URL'], [('one', 'http://ok')])
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.2')

        # make sure this particular field is handled properly when written
        fp = StringIO()
        metadata.write_file(fp)
        self.assertIn('Project-URL: one,http://ok', fp.getvalue().split('\n'))

        fp.seek(0)
        metadata = Metadata()
        metadata.read_file(fp)
        self.assertEqual(metadata['Project-Url'], [('one', 'http://ok')])
    def test_empty_install(self):
        pkg_dir, dist = self.create_dist(name='foo', version='1.0')
        install_dir = self.mkdtemp()

        install = DummyInstallCmd(dist)
        dist.command_obj['install_dist'] = install

        cmd = install_distinfo(dist)
        dist.command_obj['install_distinfo'] = cmd

        cmd.install_dir = install_dir
        cmd.ensure_finalized()
        cmd.run()

        self.checkLists(os.listdir(install_dir), ['foo-1.0.dist-info'])

        dist_info = os.path.join(install_dir, 'foo-1.0.dist-info')
        self.checkLists(os.listdir(dist_info),
                        ['METADATA', 'RECORD', 'REQUESTED', 'INSTALLER'])
        with open(os.path.join(dist_info, 'INSTALLER')) as fp:
            self.assertEqual(fp.read(), 'distutils')

        with open(os.path.join(dist_info, 'REQUESTED')) as fp:
            self.assertEqual(fp.read(), '')
        meta_path = os.path.join(dist_info, 'METADATA')
        self.assertTrue(Metadata(path=meta_path).check())
Example #6
0
    def __init__(self,
                 name,
                 version,
                 metadata=None,
                 hidden=False,
                 index=None,
                 **kwargs):
        """
        :param name: the name of the distribution
        :param version: the version of the distribution
        :param metadata: the metadata fields of the release.
        :type metadata: dict
        :param kwargs: optional arguments for a new distribution.
        """
        self.set_index(index)
        self.name = name
        self._version = None
        self.version = version
        if metadata:
            self.metadata = Metadata(mapping=metadata)
        else:
            self.metadata = None
        self.dists = {}
        self.hidden = hidden

        if 'dist_type' in kwargs:
            dist_type = kwargs.pop('dist_type')
            self.add_distribution(dist_type, **kwargs)
Example #7
0
 def __init__(self, name, version, deps):
     self.metadata = Metadata()
     self.name = name
     self.version = version
     self.metadata['Name'] = name
     self.metadata['Version'] = version
     self.metadata['Requires-Dist'] = deps
Example #8
0
 def test_check_name_strict(self):
     metadata = Metadata()
     metadata['Version'] = '1.0'
     metadata['Home-page'] = 'http://pypi.python.org'
     metadata['Author'] = 'Monty Python'
     metadata.docutils_support = False
     self.assertRaises(MetadataMissingError, metadata.check, strict=True)
Example #9
0
 def test_description_invalid_rst(self):
     # make sure bad rst is well handled in the description attribute
     metadata = Metadata()
     description = ':funkie:`str`'  # mimic Sphinx-specific markup
     metadata['description'] = description
     missing, warnings = metadata.check(restructuredtext=True)
     warning = warnings[0][1]
     self.assertIn('funkie', warning)
Example #10
0
 def test_check_homepage(self):
     metadata = Metadata()
     metadata['Version'] = '1.0'
     metadata['Name'] = 'vimpdb'
     metadata['Author'] = 'Monty Python'
     metadata.docutils_support = False
     missing, warnings = metadata.check()
     self.assertEqual(missing, ['Home-page'])
Example #11
0
 def test_check_author(self):
     metadata = Metadata()
     metadata['Version'] = '1.0'
     metadata['Name'] = 'vimpdb'
     metadata['Home-page'] = 'http://pypi.python.org'
     metadata.docutils_support = False
     missing, warnings = metadata.check()
     self.assertEqual(missing, ['Author'])
Example #12
0
    def test_metadata_markers(self):
        # see if we can be platform-aware
        PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
        with open(PKG_INFO, 'r', encoding='utf-8') as f:
            content = f.read() % sys.platform
        metadata = Metadata(platform_dependent=True)

        metadata.read_file(StringIO(content))
        self.assertEqual(metadata['Requires-Dist'], ['bar'])
        metadata['Name'] = "baz; sys.platform == 'blah'"
        # FIXME is None or 'UNKNOWN' correct here?
        # where is that documented?
        self.assertEqual(metadata['Name'], None)

        # test with context
        context = {'sys.platform': 'okook'}
        metadata = Metadata(platform_dependent=True, execution_context=context)
        metadata.read_file(StringIO(content))
        self.assertEqual(metadata['Requires-Dist'], ['foo'])
Example #13
0
 def test_version(self):
     Metadata(mapping={
         'author': 'xxx',
         'name': 'xxx',
         'version': 'xxx',
         'home_page': 'xxxx'
     })
     logs = self.get_logs()
     self.assertEqual(1, len(logs))
     self.assertIn('not a valid version', logs[0])
Example #14
0
    def get_metadata(self, project_name, version):
        """Return the metadatas from the simple index.

        Currently, download one archive, extract it and use the PKG-INFO file.
        """
        release = self.get_distributions(project_name, version)
        if not release.metadata:
            location = release.get_distribution().unpack()
            pkg_info = os.path.join(location, 'PKG-INFO')
            release.metadata = Metadata(pkg_info)
        return release
Example #15
0
 def test_check_predicates(self):
     metadata = Metadata()
     metadata['Version'] = 'rr'
     metadata['Name'] = 'vimpdb'
     metadata['Home-page'] = 'http://pypi.python.org'
     metadata['Author'] = 'Monty Python'
     metadata['Requires-dist'] = ['Foo (a)']
     metadata['Obsoletes-dist'] = ['Foo (a)']
     metadata['Provides-dist'] = ['Foo (a)']
     missing, warnings = metadata.check()
     self.assertEqual(len(warnings), 4)
Example #16
0
 def test_provides_dist(self):
     fields = {
         'name': 'project',
         'version': '1.0',
         'provides_dist': ['project', 'my.project']
     }
     metadata = Metadata(mapping=fields)
     self.assertEqual(metadata['Provides-Dist'], ['project', 'my.project'])
     self.assertEqual(metadata['Metadata-Version'], '1.2', metadata)
     self.assertNotIn('Requires', metadata)
     self.assertNotIn('Obsoletes', metadata)
Example #17
0
    def test_write_metadata(self):
        # check support of non-ASCII values
        tmp_dir = self.mkdtemp()
        my_file = os.path.join(tmp_dir, 'f')

        metadata = Metadata(
            mapping={
                'author': 'Mister Café',
                'name': 'my.project',
                'author': 'Café Junior',
                'summary': 'Café torréfié',
                'description': 'Héhéhé',
                'keywords': ['café', 'coffee']
            })
        metadata.write(my_file)

        # the file should use UTF-8
        metadata2 = Metadata()
        with open(my_file, encoding='utf-8') as fp:
            metadata2.read_file(fp)

        # XXX when keywords are not defined, metadata will have
        # 'Keywords': [] but metadata2 will have 'Keywords': ['']
        # because of a value.split(',') in Metadata.get
        self.assertEqual(metadata.items(), metadata2.items())

        # ASCII also works, it's a subset of UTF-8
        metadata = Metadata(
            mapping={
                'author': 'Mister Cafe',
                'name': 'my.project',
                'author': 'Cafe Junior',
                'summary': 'Cafe torrefie',
                'description': 'Hehehe'
            })
        metadata.write(my_file)

        metadata2 = Metadata()
        with open(my_file, encoding='utf-8') as fp:
            metadata2.read_file(fp)
Example #18
0
    def test_description(self):
        PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
        with open(PKG_INFO, 'r', encoding='utf-8') as f:
            content = f.read() % sys.platform
        metadata = Metadata()
        metadata.read_file(StringIO(content))

        # see if we can read the description now
        DESC = os.path.join(os.path.dirname(__file__), 'LONG_DESC.txt')
        with open(DESC) as f:
            wanted = f.read()
        self.assertEqual(wanted, metadata['Description'])

        # save the file somewhere and make sure we can read it back
        out = StringIO()
        metadata.write_file(out)
        out.seek(0)

        out.seek(0)
        metadata = Metadata()
        metadata.read_file(out)
        self.assertEqual(wanted, metadata['Description'])
Example #19
0
    def __init__(self, path):
        if _cache_enabled and path in _cache_path:
            self.metadata = _cache_path[path].metadata
        else:
            metadata_path = os.path.join(path, 'METADATA')
            self.metadata = Metadata(path=metadata_path)

        self.name = self.metadata['Name']
        self.version = self.metadata['Version']
        self.path = path

        if _cache_enabled and path not in _cache_path:
            _cache_path[path] = self
Example #20
0
    def test_instantiation(self):
        PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
        with open(PKG_INFO, 'r', encoding='utf-8') as f:
            contents = f.read()
        fp = StringIO(contents)

        m = Metadata()
        self.assertRaises(MetadataUnrecognizedVersionError, m.items)

        m = Metadata(PKG_INFO)
        self.assertEqual(len(m.items()), 22)

        m = Metadata(fileobj=fp)
        self.assertEqual(len(m.items()), 22)

        m = Metadata(mapping=dict(name='Test', version='1.0'))
        self.assertEqual(len(m.items()), 17)

        d = dict(m.items())
        self.assertRaises(TypeError, Metadata, PKG_INFO, fileobj=fp)
        self.assertRaises(TypeError, Metadata, PKG_INFO, mapping=d)
        self.assertRaises(TypeError, Metadata, fileobj=fp, mapping=d)
        self.assertRaises(TypeError, Metadata, PKG_INFO, mapping=m, fileobj=fp)
Example #21
0
    def test_requires_dist(self):
        fields = {
            'name': 'project',
            'version': '1.0',
            'requires_dist': ['other', 'another (==1.0)']
        }
        metadata = Metadata(mapping=fields)
        self.assertEqual(metadata['Requires-Dist'],
                         ['other', 'another (==1.0)'])
        self.assertEqual(metadata['Metadata-Version'], '1.2')
        self.assertNotIn('Provides', metadata)
        self.assertEqual(metadata['Requires-Dist'],
                         ['other', 'another (==1.0)'])
        self.assertNotIn('Obsoletes', metadata)

        # make sure write_file uses one RFC 822 header per item
        fp = StringIO()
        metadata.write_file(fp)
        lines = fp.getvalue().split('\n')
        self.assertIn('Requires-Dist: other', lines)
        self.assertIn('Requires-Dist: another (==1.0)', lines)

        # test warnings for invalid version predicates
        # XXX this would cause no warnings if we used update (or the mapping
        # argument of the constructor), see comment in Metadata.update
        metadata = Metadata()
        metadata['Requires-Dist'] = 'Funky (Groovie)'
        metadata['Requires-Python'] = '1-4'
        self.assertEqual(len(self.get_logs()), 2)

        # test multiple version predicates
        metadata = Metadata()

        # XXX check PEP and see if 3 == 3.0
        metadata['Requires-Python'] = '>=2.6, <3.0'
        metadata['Requires-Dist'] = ['Foo (>=2.6, <3.0)']
        self.assertEqual(self.get_logs(), [])
Example #22
0
    def test_description_folding(self):
        # make sure the indentation is preserved
        out = StringIO()
        desc = dedent("""\
        example::
              We start here
            and continue here
          and end here.
        """)

        metadata = Metadata()
        metadata['description'] = desc
        metadata.write_file(out)

        folded_desc = desc.replace('\n', '\n' + (7 * ' ') + '|')
        self.assertIn(folded_desc, out.getvalue())
Example #23
0
    def test_mapping_api(self):
        PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
        with open(PKG_INFO, 'r', encoding='utf-8') as f:
            content = f.read() % sys.platform
        metadata = Metadata(fileobj=StringIO(content))
        self.assertIn('Version', metadata.keys())
        self.assertIn('0.5', metadata.values())
        self.assertIn(('Version', '0.5'), metadata.items())

        metadata.update({'version': '0.6'})
        self.assertEqual(metadata['Version'], '0.6')
        metadata.update([('version', '0.7')])
        self.assertEqual(metadata['Version'], '0.7')

        # make sure update method checks values like the set method does
        metadata.update({'version': '1--2'})
        self.assertEqual(len(self.get_logs()), 1)

        # XXX caveat: the keys method and friends are not 3.x-style views
        # should be changed or documented
        self.assertEqual(list(metadata), metadata.keys())
Example #24
0
    def __init__(self, attrs=None):
        """Construct a new Distribution instance: initialize all the
        attributes of a Distribution, and then use 'attrs' (a dictionary
        mapping attribute names to values) to assign some of those
        attributes their "real" values.  (Any attributes not mentioned in
        'attrs' will be assigned to some null value: 0, None, an empty list
        or dictionary, etc.)  Most importantly, initialize the
        'command_obj' attribute to the empty dictionary; this will be
        filled in with real command objects by 'parse_command_line()'.
        """

        # Default values for our command-line options
        self.dry_run = False
        self.help = False
        for attr in self.display_option_names:
            setattr(self, attr, False)

        # Store the configuration
        self.config = Config(self)

        # Store the distribution metadata (name, version, author, and so
        # forth) in a separate object -- we're getting to have enough
        # information here (and enough command-line options) that it's
        # worth it.
        self.metadata = Metadata()

        # 'cmdclass' maps command names to class objects, so we
        # can 1) quickly figure out which class to instantiate when
        # we need to create a new command object, and 2) have a way
        # for the setup script to override command classes
        self.cmdclass = {}

        # 'script_name' and 'script_args' are usually set to sys.argv[0]
        # and sys.argv[1:], but they can be overridden when the caller is
        # not necessarily a setup script run from the command line.
        self.script_name = None
        self.script_args = None

        # 'command_options' is where we store command options between
        # parsing them (from config files, the command line, etc.) and when
        # they are actually needed -- ie. when the command in question is
        # instantiated.  It is a dictionary of dictionaries of 2-tuples:
        #   command_options = { command_name : { option : (source, value) } }
        self.command_options = {}

        # 'dist_files' is the list of (command, pyversion, file) that
        # have been created by any dist commands run so far. This is
        # filled regardless of whether the run is dry or not. pyversion
        # gives sysconfig.get_python_version() if the dist file is
        # specific to a Python version, 'any' if it is good for all
        # Python versions on the target platform, and '' for a source
        # file. pyversion should not be used to specify minimum or
        # maximum required Python versions; use the metainfo for that
        # instead.
        self.dist_files = []

        # These options are really the business of various commands, rather
        # than of the Distribution itself.  We provide aliases for them in
        # Distribution as a convenience to the developer.
        self.packages = []
        self.package_data = {}
        self.package_dir = None
        self.py_modules = []
        self.libraries = []
        self.headers = []
        self.ext_modules = []
        self.ext_package = None
        self.include_dirs = []
        self.extra_path = None
        self.scripts = []
        self.data_files = {}
        self.password = ''
        self.use_2to3 = False
        self.convert_2to3_doctests = []
        self.extra_files = []

        # And now initialize bookkeeping stuff that can't be supplied by
        # the caller at all.  'command_obj' maps command names to
        # Command instances -- that's how we enforce that every command
        # class is a singleton.
        self.command_obj = {}

        # 'have_run' maps command names to boolean values; it keeps track
        # of whether we have actually run a particular command, to make it
        # cheap to "run" a command whenever we think we might need to -- if
        # it's already been done, no need for expensive filesystem
        # operations, we just check the 'have_run' dictionary and carry on.
        # It's only safe to query 'have_run' for a command class that has
        # been instantiated -- a false value will be inserted when the
        # command object is created, and replaced with a true value when
        # the command is successfully run.  Thus it's probably best to use
        # '.get()' rather than a straight lookup.
        self.have_run = {}

        # Now we'll use the attrs dictionary (ultimately, keyword args from
        # the setup script) to possibly override any or all of these
        # distribution options.

        if attrs is not None:
            # Pull out the set of command options and work on them
            # specifically.  Note that this order guarantees that aliased
            # command options will override any supplied redundantly
            # through the general options dictionary.
            options = attrs.get('options')
            if options is not None:
                del attrs['options']
                for command, cmd_options in options.items():
                    opt_dict = self.get_option_dict(command)
                    for opt, val in cmd_options.items():
                        opt_dict[opt] = ("setup script", val)

            # Now work on the rest of the attributes.  Any attribute that's
            # not already defined is invalid!
            for key, val in attrs.items():
                if self.metadata.is_metadata_field(key):
                    self.metadata[key] = val
                elif hasattr(self, key):
                    setattr(self, key, val)
                else:
                    logger.warning(
                        'unknown argument given to Distribution: %r', key)

        # no-user-cfg is handled before other command line args
        # because other args override the config files, and this
        # one is needed before we can load the config files.
        # If attrs['script_args'] wasn't passed, assume false.
        #
        # This also make sure we just look at the global options
        self.want_user_cfg = True

        if self.script_args is not None:
            for arg in self.script_args:
                if not arg.startswith('-'):
                    break
                if arg == '--no-user-cfg':
                    self.want_user_cfg = False
                    break

        self.finalize_options()
Example #25
0
    def test_metadata_versions(self):
        metadata = Metadata(mapping={'name': 'project', 'version': '1.0'})
        self.assertEqual(metadata['Metadata-Version'],
                         PKG_INFO_PREFERRED_VERSION)
        self.assertNotIn('Provides', metadata)
        self.assertNotIn('Requires', metadata)
        self.assertNotIn('Obsoletes', metadata)

        metadata['Classifier'] = ['ok']
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        metadata = Metadata()
        metadata['Download-URL'] = 'ok'
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        metadata = Metadata()
        metadata['Obsoletes'] = 'ok'
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        del metadata['Obsoletes']
        metadata['Obsoletes-Dist'] = 'ok'
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.2')
        metadata.set('Obsoletes', 'ok')
        self.assertRaises(MetadataConflictError, metadata.set_metadata_version)

        del metadata['Obsoletes']
        del metadata['Obsoletes-Dist']
        metadata.set_metadata_version()
        metadata['Version'] = '1'
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        # make sure the _best_version function works okay with
        # non-conflicting fields from 1.1 and 1.2 (i.e. we want only the
        # requires/requires-dist and co. pairs to cause a conflict, not all
        # fields in _314_MARKERS)
        metadata = Metadata()
        metadata['Requires-Python'] = '3'
        metadata['Classifier'] = ['Programming language :: Python :: 3']
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.2')

        PKG_INFO = os.path.join(os.path.dirname(__file__),
                                'SETUPTOOLS-PKG-INFO')
        metadata = Metadata(PKG_INFO)
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        PKG_INFO = os.path.join(os.path.dirname(__file__),
                                'SETUPTOOLS-PKG-INFO2')
        metadata = Metadata(PKG_INFO)
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        # make sure an empty list for Obsoletes and Requires-dist gets ignored
        metadata['Obsoletes'] = []
        metadata['Requires-dist'] = []
        metadata.set_metadata_version()
        self.assertEqual(metadata['Metadata-Version'], '1.1')

        # Update the _fields dict directly to prevent 'Metadata-Version'
        # from being updated by the _set_best_version() method.
        metadata._fields['Metadata-Version'] = '1.618'
        self.assertRaises(MetadataUnrecognizedVersionError, metadata.keys)
Example #26
0
 def set_metadata(self, metadata):
     if not self.metadata:
         self.metadata = Metadata()
     self.metadata.update(metadata)