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

Upgrade from datalad core as of 0.18.1-24-gabc454d4f #3

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

import argparse
import datetime
import os
import re
import time
from textwrap import wrap


class ManPageFormatter(argparse.HelpFormatter):
Expand All @@ -24,7 +27,7 @@ def __init__(self,
authors=None,
version=None
):

from datalad import cfg
super(ManPageFormatter, self).__init__(
prog,
indent_increment=indent_increment,
Expand All @@ -33,7 +36,9 @@ def __init__(self,

self._prog = prog
self._section = 1
self._today = datetime.date.today().strftime('%Y\\-%m\\-%d')
self._today = datetime.datetime.utcfromtimestamp(
cfg.obtain('datalad.source.epoch')
).strftime('%Y\\-%m\\-%d')
self._ext_sections = ext_sections
self._version = version

Expand Down Expand Up @@ -75,7 +80,7 @@ def _mk_title(self, prog):

def _mk_name(self, prog, desc):
"""
this method is in consitent with others ... it relies on
this method is in consistent with others ... it relies on
distribution
"""
desc = desc.splitlines()[0] if desc else 'it is in the name'
Expand Down Expand Up @@ -195,7 +200,9 @@ def _mk_synopsis(self, parser):
parser._mutually_exclusive_groups, '')

usage = usage.replace('%s ' % self._prog, '')
usage = 'Synopsis\n--------\n::\n\n %s %s\n' \
usage = '\n'.join(wrap(
usage, break_on_hyphens=False, subsequent_indent=6*' '))
usage = 'Synopsis\n--------\n::\n\n %s %s\n\n' \
% (self._markup(self._prog), usage)
return usage

Expand Down Expand Up @@ -251,7 +258,7 @@ def _mk_options(self, parser):

def _format_action(self, action):
# determine the required width and the entry label
action_header = self._format_action_invocation(action, doubledash='-\\\\-')
action_header = self._format_action_invocation(action, doubledash='-\\-')

if action.help:
help_text = self._expand_help(action)
Expand Down
140 changes: 134 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,50 @@

import datetime
import os

from os.path import (
dirname,
join as opj,
sep as pathsep,
splitext,
)
from setuptools import Command, DistutilsOptionError
from setuptools.config import read_configuration

import setuptools
Copy link
Member

Choose a reason for hiding this comment

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

isn't this a duplicate import? (see lines 20 and following)

Copy link

Choose a reason for hiding this comment

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

I see one usage, in line 306; if Version(setuptools.__version__) >= Version('38.6.0'):

(that being said, setuptools 38.6.0 is March 2018, so positively ancient)

import versioneer
from packaging.version import Version
from setuptools import (
Command,
DistutilsOptionError,
find_namespace_packages,
findall,
setup,
)

from . import formatters as fmt


def _path_rel2file(*p):
# dirname instead of joining with pardir so it works if
# datalad_build_support/ is just symlinked into some extension
# while developing
return opj(dirname(dirname(__file__)), *p)


def get_version(name):
"""Determine version via importlib_metadata

Parameters
----------
name: str
Name of the folder (package) where from to read version.py
"""
# delay import so we do not require it for a simple setup stage
try:
from importlib.metadata import version as importlib_version
except ImportError:
# TODO - remove whenever python >= 3.8
Copy link
Member

Choose a reason for hiding this comment

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

bearing the official metadata tag and ci upgrade, Python 3.7 is EOL and we should switch to require Py>=3.8

from importlib_metadata import version as importlib_version
return importlib_version(name)


class BuildManPage(Command):
# The BuildManPage code was originally distributed
# under the same License of Python
Expand All @@ -46,7 +77,7 @@ class BuildManPage(Command):
def initialize_options(self):
self.manpath = opj('build', 'man')
self.rstpath = opj('docs', 'source', 'generated', 'man')
self.parser = 'datalad.cmdline.main:setup_parser'
self.parser = 'datalad.cli.parser:setup_parser'
self.cmdsuite = None

def finalize_options(self):
Expand Down Expand Up @@ -210,8 +241,8 @@ def run(self):
if not os.path.exists(opath):
os.makedirs(opath)

from datalad.interface.common_cfg import definitions as cfgdefs
from datalad.dochelpers import _indent
from datalad.interface.common_cfg import definitions as cfgdefs

categories = {
'global': {},
Expand Down Expand Up @@ -252,3 +283,100 @@ def run(self):
desc_tmpl += 'undocumented\n'
v.update(docs)
rst.write(_indent(desc_tmpl.format(**v), ' '))


def get_long_description_from_README():
"""Read README.md, convert to .rst using pypandoc

If pypandoc is not available or fails - just output original .md.

Returns
-------
dict
with keys long_description and possibly long_description_content_type
for newer setuptools which support uploading of markdown as is.
"""
# PyPI used to not render markdown. Workaround for a sane appearance
# https://github.com/pypa/pypi-legacy/issues/148#issuecomment-227757822
# is still in place for older setuptools

README = opj(_path_rel2file('README.md'))

ret = {}
if Version(setuptools.__version__) >= Version('38.6.0'):
# check than this
ret['long_description'] = open(README).read()
ret['long_description_content_type'] = 'text/markdown'
return ret

# Convert or fall-back
try:
import pypandoc
return {'long_description': pypandoc.convert(README, 'rst')}
except (ImportError, OSError) as exc:
# attempting to install pandoc via brew on OSX currently hangs and
# pypandoc imports but throws OSError demanding pandoc
print(
"WARNING: pypandoc failed to import or thrown an error while "
"converting"
" README.md to RST: %r .md version will be used as is" % exc
)
return {'long_description': open(README).read()}


def findsome(subdir, extensions):
"""Find files under subdir having specified extensions

Leading directory (datalad) gets stripped
"""
return [
f.split(pathsep, 1)[1] for f in findall(opj('datalad', subdir))
if splitext(f)[-1].lstrip('.') in extensions
]


def datalad_setup(name, **kwargs):
"""A helper for a typical invocation of setuptools.setup.

If not provided in kwargs, following fields will be autoset to the defaults
or obtained from the present on the file system files:

- author
- author_email
- packages -- all found packages which start with `name`
- long_description -- converted to .rst using pypandoc README.md
- version -- parsed `__version__` within `name/version.py`

Parameters
----------
name: str
Name of the Python package
**kwargs:
The rest of the keyword arguments passed to setuptools.setup as is
"""
# Simple defaults
for k, v in {
'author': "The DataLad Team and Contributors",
'author_email': "team@datalad.org"
}.items():
if kwargs.get(k) is None:
kwargs[k] = v

# More complex, requiring some function call

# Only recentish versions of find_packages support include
# packages = find_packages('.', include=['datalad*'])
# so we will filter manually for maximal compatibility
if kwargs.get('packages') is None:
# Use find_namespace_packages() in order to include folders that
# contain data files but no Python code
kwargs['packages'] = [pkg for pkg in find_namespace_packages('.') if pkg.startswith(name)]
if kwargs.get('long_description') is None:
kwargs.update(get_long_description_from_README())

cmdclass = kwargs.get('cmdclass', {})
# Check if command needs some module specific handling
for v in cmdclass.values():
if hasattr(v, 'handle_module'):
getattr(v, 'handle_module')(name, **kwargs)
return setup(name=name, **kwargs)