From d92cba8c8a7f36e0a074db078601c2ede189ac06 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sun, 23 Sep 2012 01:17:17 -0700 Subject: Refactor reST conversion code in setup.py and strip HTML. --- setup.py | 120 +++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 42 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index c83768c..8e334d1 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,9 @@ to do this step: It helps to review this auto-generated file on GitHub prior to uploading because the long description will be sent to PyPI and appear there after -publishing. +publishing. PyPI attempts to convert this string to HTML before displaying +it on the PyPI project page. If PyPI finds any issues, it will render it +instead as plain-text, which we do not want. To check in advance that PyPI will accept and parse the reST file as HTML, you can use the rst2html program installed by the docutils package @@ -31,8 +33,8 @@ you can use the rst2html program installed by the docutils package $ pip install docutils -You will want to issue a command like the following and check that no -warnings are issued: +To check the file, run the following command and confirm that it reports +no warnings: $ python setup.py --long-description | rst2html.py -v --no-raw > out.html @@ -40,7 +42,6 @@ See here for more information: http://docs.python.org/distutils/uploading.html#pypi-package-display - (2) Push to PyPI. To release a new version of Pystache to PyPI-- http://pypi.python.org/pypi/pystache @@ -119,9 +120,9 @@ README_PATH = 'README.md' HISTORY_PATH = 'HISTORY.md' LICENSE_PATH = 'LICENSE' -DESCRIPTION_PATH = 'setup_description.rst' +RST_DESCRIPTION_PATH = 'setup_description.rst' -TEMP_REST_EXTENSION = '.temp.rst' +TEMP_EXTENSION = '.temp' PREP_COMMAND = 'prep' @@ -141,7 +142,7 @@ CLASSIFIERS = ( ) # Comments in reST begin with two dots. -LONG_DESCRIPTION_INTRO = """\ +RST_LONG_DESCRIPTION_INTRO = """\ .. Do not edit this file. This file is auto-generated for PyPI by setup.py .. using pandoc, so edits should go in the source files rather than here. """ @@ -168,7 +169,7 @@ def write(u, path): Write a unicode string to a file (as utf-8). """ - print("Writing to: %s" % path) + print("writing to: %s" % path) # This function implementation was chosen to be compatible across Python 2/3. f = open(path, "wb") try: @@ -178,36 +179,63 @@ def write(u, path): f.close() -def make_temp_path(path): +def make_temp_path(path, new_ext=None): + """ + Arguments: + + new_ext: the new file extension, including the leading dot. + Defaults to preserving the existing file extension. + + """ root, ext = os.path.splitext(path) - temp_path = root + TEMP_REST_EXTENSION + if new_ext is None: + new_ext = ext + temp_path = root + TEMP_EXTENSION + new_ext return temp_path -def convert_md_to_rst(md_path): - """ - Convert the given file from markdown to reStructuredText. +def strip_html_comments(text): + """Strip HTML comments from a unicode string.""" + lines = text.splitlines(True) # preserve line endings. + + # Remove HTML comments (which we only allow to take a special form). + new_lines = filter(lambda line: not line.startswith("%s" % (md_path, rst_temp_path, + command)) + + if os.path.exists(rst_temp_path): + os.remove(rst_temp_path) + os.system(command) - if not os.path.exists(temp_path): + if not os.path.exists(rst_temp_path): s = ("Error running: %s\n" - " Did you install pandoc per the %s docstring?" % (command, __file__)) + " Did you install pandoc per the %s docstring?" % (command, + __file__)) sys.exit(s) - return read(temp_path) + return read(rst_temp_path) # The long_description needs to be formatted as reStructuredText. @@ -218,50 +246,58 @@ def convert_md_to_rst(md_path): # def make_long_description(): """ - Generate the long_description for setup() from source files. + Generate the reST long_description for setup() from source files. - Returns the long_description as a unicode string. + Returns the generated long_description as a unicode string. """ - readme_section = convert_md_to_rst(README_PATH) - history_section = convert_md_to_rst(HISTORY_PATH) + readme_path = README_PATH - license_section = """\ + # Remove our HTML comments because PyPI does not allow it. + # See the setup.py docstring for more info on this. + readme_md = strip_html_comments(read(readme_path)) + history_md = strip_html_comments(read(HISTORY_PATH)) + license_md = """\ License ======= """ + read(LICENSE_PATH) - sections = [LONG_DESCRIPTION_INTRO, - readme_section, - history_section, - license_section] + sections = [readme_md, history_md, license_md] + md_description = '\n\n'.join(sections) + + # Write the combined Markdown file to a temp path. + md_ext = os.path.splitext(readme_path)[1] + md_description_path = make_temp_path(RST_DESCRIPTION_PATH, new_ext=md_ext) + write(md_description, md_description_path) - return '\n'.join(sections) + rst_temp_path = make_temp_path(RST_DESCRIPTION_PATH) + long_description = convert_md_to_rst(md_path=md_description_path, + rst_temp_path=rst_temp_path) + + return "\n".join([RST_LONG_DESCRIPTION_INTRO, long_description]) def prep(): + """Update the reST long_description file.""" long_description = make_long_description() - write(long_description, DESCRIPTION_PATH) + write(long_description, RST_DESCRIPTION_PATH) def publish(): - """ - Publish this package to PyPI (aka "the Cheeseshop"). - - """ + """Publish this package to PyPI (aka "the Cheeseshop").""" long_description = make_long_description() - if long_description != read(DESCRIPTION_PATH): + if long_description != read(RST_DESCRIPTION_PATH): print("""\ Description file not up-to-date: %s Run the following command and commit the changes-- python setup.py %s -""" % (DESCRIPTION_PATH, PREP_COMMAND)) +""" % (RST_DESCRIPTION_PATH, PREP_COMMAND)) sys.exit() - print("Description up-to-date: %s" % DESCRIPTION_PATH) + print("Description up-to-date: %s" % RST_DESCRIPTION_PATH) answer = raw_input("Are you sure you want to publish to PyPI (yes/no)?") @@ -339,7 +375,7 @@ def main(sys_argv): prep() sys.exit() - long_description = read(DESCRIPTION_PATH) + long_description = read(RST_DESCRIPTION_PATH) template_files = ['*.mustache', '*.txt'] extra_args = get_extra_args() -- cgit v1.2.1