Browse Source

add Package.readme field, if it points to a relative file theoutside the package directory the setup.py script will copy it to the package directory temporarily

shut
Niklas Rosenstein 10 months ago
parent
commit
935cc83586
No known key found for this signature in database GPG Key ID: 6D269B33D25F6C6
3 changed files with 51 additions and 20 deletions
  1. + 5
    - 0
      src/shore/model.py
  2. + 14
    - 12
      src/shore/plugins/_util.py
  3. + 32
    - 8
      src/shore/plugins/setuptools.py

+ 5
- 0
src/shore/model.py

@ -682,6 +682,11 @@ class Package(BaseObject):
#: The default "use" field is populated with setuptools and pypi.
use = Field([PluginConfig], default=list)
#: Path to the README file. If the file points to a directory outside of the
#: directory of the package manifest, this file will be copied to the package
#: directory temporarily by the `setup.py` script.
readme = Field(str, default=None)
#: The long description of the package. If this is not defined, the
#: setuptools plugin will load the README file.
long_description = Field(str, FieldName('long-description'), default=None)

+ 14
- 12
src/shore/plugins/_util.py

@ -19,26 +19,28 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
from nr.fs import getsuffix
from typing import Optional
import ast
import collections
import os
Readme = collections.namedtuple('Readme', 'file,content_type')
def find_readme_file(directory):
preferred = {
'README.md': 'text/markdown',
'README.rst': 'text/x-rst',
'README.txt': 'text/plain',
'README': 'text/plain'
}
def find_readme_file(directory: str) -> Optional[str]:
preferred = set(['README.md', 'README.rst', 'README.txt', 'README'])
choices = []
for name in os.listdir(directory):
for name in sorted(os.listdir(directory)):
if name in preferred:
return Readme(name, preferred[name])
return name
if name.startswith('README.'):
choices.append(name)
if choices:
return Readme(sorted(choices)[0], 'text/plain')
return choices[0]
return None
def readme_content_type(filename: str) -> str:
return {
'md': 'text/markdown',
'rst': 'text/x-rst',
}.get(getsuffix(filename), 'text/plain')

+ 32
- 8
src/shore/plugins/setuptools.py

@ -22,7 +22,8 @@
""" A plugin that generates setuptools files (setup.py, MANIFEST.in). This
plugin is used by default in packages. """
from ._util import find_readme_file, Readme
from ._util import find_readme_file, readme_content_type
from nr.fs import issub as issubpath
from nr.interface import implements, override
from shore.core.plugins import (
BuildResult,
@ -211,7 +212,9 @@ class SetuptoolsRenderer:
command.insert(0, sys.executable)
env = os.environ.copy()
env['SHORE_INSTALL_HOOK_EVENT'] = event
subprocess.call(command, env=env)
res = subprocess.call(command, env=env)
if res != 0:
raise RuntimeError('command {!r} returned exit code {}'.format(command, res))
'''))
if has_install_hooks:
fp.write(textwrap.dedent('''
@ -240,22 +243,40 @@ class SetuptoolsRenderer:
''').format(entrypoint_file=_normpath(entry_file)))
# Write the part that reads the readme for the long description.
readme = find_readme_file(package.directory)
if package.readme:
rel_readme = package.readme
abs_readme = os.path.abspath(os.path.join(package.directory, rel_readme))
if issubpath(os.path.relpath(abs_readme, package.directory)):
rel_readme, readme = None, rel_readme
else:
readme = os.path.basename(rel_readme)
else:
rel_readme = None
readme = find_readme_file(package.directory)
if readme:
fp.write('\nreadme_file = {!r}\n'.format(readme))
if rel_readme:
# Copy the relative README file if it exists.
fp.write(textwrap.dedent('''
source_readme_file = {!r}
if not os.path.isfile(readme_file) and os.path.isfile(source_readme_file):
import shutil; shutil.copyfile(source_readme_file, readme_file)
import atexit; atexit.register(lambda: os.remove(readme_file))
''').format(rel_readme).lstrip())
fp.write(textwrap.dedent('''
readme_file = {readme!r}
if os.path.isfile(readme_file):
with io.open(readme_file, encoding='utf8') as fp:
long_description = fp.read()
else:
print("warning: file \\"{{}}\\" does not exist.".format(readme_file), file=sys.stderr)
print("warning: file \\"{}\\" does not exist.".format(readme_file), file=sys.stderr)
long_description = None
''').format(readme=readme.file))
'''))
else:
fp.write(textwrap.dedent('''
long_description = {long_description!r}
'''.format(long_description=package.long_description)))
readme = Readme(None, 'text/plain')
readme = None
# Write the install requirements.
fp.write('\n')
@ -326,7 +347,10 @@ class SetuptoolsRenderer:
url=package.get_url(),
license=package.get_license(),
description=package.description.replace('\n\n', '%%%%').replace('\n', ' ').replace('%%%%', '\n').strip(),
long_description_content_type=readme.content_type,
long_description_content_type=(
package.long_description_content_type or
(readme_content_type(readme) if readme else 'text/plain')
),
extras_require=extras_require,
tests_require=tests_require,
python_requires=package.requirements.python.to_setuptools() if package.requirements.python else None,

Loading…
Cancel
Save