Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept all content types for README files already in code #176

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
79 changes: 55 additions & 24 deletions lib/vsc/install/shared_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def _log(self, level, msg, args):

RELOAD_VSC_MODS = False

VERSION = '0.17.24'
VERSION = '0.17.25'

log.info('This is (based on) vsc.install.shared_setup %s' % VERSION)
log.info('(using setuptools version %s located at %s)' % (setuptools.__version__, setuptools.__file__))
Expand Down Expand Up @@ -207,7 +207,16 @@ def _log(self, level, msg, args):


# location of README file
README = 'README.md'
README_BASE = ['README']
# see https://packaging.python.org/guides/making-a-pypi-friendly-readme/
README_EXT = ('.md', '.rst', '.txt', '')
README_TYPES = {
'.md': 'text/markdown',
'.rst': 'text/x-rst',
'.txt': 'text/plain',
'': 'text/plain', # fallback in case README file has no extension
}
README = ['%s%s' % (base, ext) for base in README_BASE for ext in README_EXT]

# location of LICENSE file
LICENSE = 'LICENSE'
Expand Down Expand Up @@ -657,7 +666,7 @@ def make_release_tree(self, base_dir, files):
self._add_shared_setup(base_dir)

# Add mandatory files
for fn in [LICENSE, README]:
for fn in [LICENSE] + README:
self.copy_file(os.path.join(self.setup.REPO_BASE_DIR, fn), os.path.join(base_dir, fn))

class vsc_sdist_rpm(vsc_sdist):
Expand Down Expand Up @@ -1331,6 +1340,25 @@ def get_license(self, license_name=None):
log.info("Found license name %s and classifier %s", lic_short, data[1])
return lic_short, data[1]

def locate_readme(self):
"""
Returns path to README file in the package from allowed options in README global
The highest option in README global is preferred
lexming marked this conversation as resolved.
Show resolved Hide resolved
"""
readme = None

for readme_path in [os.path.join(self.REPO_BASE_DIR, readme) for readme in README]:
if os.path.exists(readme_path):
readme = readme_path
break

# README is required
if readme is None:
raise Exception('README is missing (was looking for: %s)' % ", ".join(README))

log.info('found README file at %s' % readme)
return readme

def parse_target(self, target, urltemplate=None):
"""
Add some fields
Expand Down Expand Up @@ -1388,17 +1416,23 @@ def parse_target(self, target, urltemplate=None):
if 'github' in urltemplate:
new_target['download_url'] = "%s/tarball/master" % new_target['url']

# Readme are required
readme = os.path.join(self.REPO_BASE_DIR, README)
if not os.path.exists(readme):
raise Exception('README is missing (was looking for %s)' % readme)
# Use description file from target and remove attribute (not needed any more)
readme_file = target.pop('description_file', None)

# set description from README
vsc_description = target.pop('vsc_description', True)
if vsc_description:

if not readme_file:
# locate the README file
readme_file = self.locate_readme()

if 'long_description' in target:
log.info(('Going to ignore the provided long_descripton.'
'Set it in the %s or disable vsc_description') % README)
readmetxt = _read(readme)
log.warn(('Ignoring the provided long_descripton.'
'Please set it in the %s or disable vsc_description') % os.path.basename(readme_file))
del(target['long_description'])

readmetxt = _read(readme_file)

# look for description block, read text until double empty line or new block
# allow 'words with === on next line' or comment-like block '# title'
Expand All @@ -1415,24 +1449,16 @@ def parse_target(self, target, urltemplate=None):
descr = re.sub(r'\s+', ' ', descr) # squash whitespace
except IndexError:
raise Exception('Could not find a Description block in the README %s to create the long description' %
readme)
readme_file)
log.info('using long_description %s' % descr)
new_target['description'] = descr # summary in PKG-INFO
new_target['long_description'] = readmetxt # description in PKG-INFO

readme_ext = os.path.splitext(readme)[-1]
# see https://packaging.python.org/guides/making-a-pypi-friendly-readme/
readme_content_types = {
'.md': 'text/markdown',
'.rst': 'text/x-rst',
'.txt': 'text/plain',
# fallback in case README file has no extension
'': 'text/plain',
}
if readme_ext in readme_content_types:
new_target['long_description_content_type'] = readme_content_types[readme_ext]
readme_ext = os.path.splitext(readme_file)[-1]
if readme_ext in README_TYPES:
new_target['long_description_content_type'] = README_TYPES[readme_ext]
else:
raise Exception("Failed to derive content type for README file '%s' based on extension" % readme)
raise Exception("Failed to derive content type for README file '%s' based on extension" % readme_file)

vsc_scripts = target.pop('vsc_scripts', True)
if vsc_scripts:
Expand Down Expand Up @@ -1632,7 +1658,9 @@ def build_setup_cfg_for_bdist_rpm(target):
txt.extend(["build_requires = %s" % (klass.sanitize(target['setup_requires']))])

# add metadata
txt += ['', '[metadata]', '', 'description-file = %s' % README, '']
if 'description_file' in target:
description_file = os.path.basename(target['description_file'])
txt += ['', '[metadata]', '', 'description-file = %s' % description_file, '']

setup_cfg.write("\n".join(txt+['']))
setup_cfg.close()
Expand Down Expand Up @@ -1682,6 +1710,9 @@ def action_target(self, target, setupfn=None, extra_sdist=None, urltemplate=None
if do_cleanup:
self.cleanup()

# add location of README to target
target['description_file'] = self.locate_readme()

self.prepare_rpm(target)

new_target = self.parse_target(target, urltemplate)
Expand Down
6 changes: 5 additions & 1 deletion test/shared_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,10 @@ def read_setup_cfg():
os.chdir(self.tmpdir)

# test with minimal target
vsc_setup.build_setup_cfg_for_bdist_rpm({})
target = {
'description_file': 'README.md',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to set this. it's the default value right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only needed in this unit test with an artificial target. In a real scenario the description_file attribute will be set by the call to locate_readme() in action_target(), which looks for the actual README file in the repo directory. The only case where a target would have no description_file is if there is no README, which will error out before reaching build_setup_cfg_for_bdist_rpm().

}
vsc_setup.build_setup_cfg_for_bdist_rpm(target)
expected = '\n'.join([
'[bdist_rpm]',
'',
Expand All @@ -325,6 +328,7 @@ def read_setup_cfg():

# realistic target
target = {
'description_file': 'README.md',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why this is needed? we're not going to change all the setup.py to add the old default...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to change any existing setup.py, as explained in my previous comment, this is only needed for this artificial target. From now on all targets will be generated with a description_file attribute pointing to the actual README file in the repo.

'install_requires': ['vsc-base >= 3.1.0', 'vsc-ldap', 'requests', 'foobar < 1.0'],
'setup_requires': ['vsc-install >= 0.17.11'],
}
Expand Down