Modernize packaging

Switch to pyproject.toml packaging, using hatchling.

- Replace all uses of setup.py with updated equivalent
- BREAKING: Change extra name `amazon_ses` to
  `amazon-ses`, to comply with Python packaging
  name normalization
- Use hatch custom build hook to freeze version number
  in readme (previously custom setup.py code)
- Move separate requirements for dev, docs, tests
  into their own requirements.txt files
- Fix AnymailImproperlyInstalled to correctly refer
  to package extra name
- Update testing documentation
- Update docs readme rendering to match PyPI
  (and avoid setup.py)
- In tox tests, use isolated builds and update pip
- Remove AUTHORS.txt (it just referred to GitHub)
This commit is contained in:
Mike Edmunds
2023-05-03 16:55:08 -07:00
committed by GitHub
parent 9fba58237d
commit e8df0ec8e0
31 changed files with 418 additions and 292 deletions

View File

@@ -1,30 +0,0 @@
# docutils (rst2html) config for generating static HTML that approximates
# PyPI package description rendering (as of 3/2018).
#
# Usage (in package root dir):
# python setup.py --long-description | rst2html.py --config=docs/_readme/docutils.cfg > ${OUTDIR}/readme.html
#
# Requires docutils and pygments (both are installed with Sphinx)
[general]
# Duplicate docutils config used by PyPA readme_renderer.
# https://github.com/pypa/readme_renderer/blob/master/readme_renderer/rst.py
cloak_email_addresses = True
doctitle_xform = True
sectsubtitle_xform = True
initial_header_level = 2
file_insertion_enabled = False
math_output = MathJax
raw_enabled = False
smart_quotes = True
strip_comments = True
syntax_highlight = short
# Halt rendering and throw an exception if there was any errors or warnings from docutils.
halt_level = 2
# DON'T Disable all system messages from being reported.
# (We're not running inside readme_renderer, so *do* want to see warnings and errors.)
# report_level = 5
# Approximate PyPI's layout and styles:
template = docs/_readme/template.txt

109
docs/_readme/render.py Normal file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python
# Render a README file (roughly) as it would appear on PyPI
import argparse
import sys
from importlib.metadata import PackageNotFoundError, metadata
from pathlib import Path
from typing import Dict, Optional
import readme_renderer.rst
from docutils.core import publish_string
from docutils.utils import SystemMessage
# Docutils template.txt in our directory:
DEFAULT_TEMPLATE_FILE = Path(__file__).with_name("template.txt").absolute()
def get_package_readme(package: str) -> str:
# Note: "description" was added to metadata in Python 3.10
return metadata(package)["description"]
class ReadMeHTMLWriter(readme_renderer.rst.Writer):
translator_class = readme_renderer.rst.ReadMeHTMLTranslator
def interpolation_dict(self) -> Dict[str, str]:
result = super().interpolation_dict()
# clean the same parts as readme_renderer.rst.render:
clean = readme_renderer.rst.clean
result["docinfo"] = clean(result["docinfo"])
result["body"] = result["fragment"] = clean(result["fragment"])
return result
def render(source_text: str, warning_stream=sys.stderr) -> Optional[str]:
# Adapted from readme_renderer.rst.render
settings = readme_renderer.rst.SETTINGS.copy()
settings.update(
{
"warning_stream": warning_stream,
"template": DEFAULT_TEMPLATE_FILE,
# Input and output are text str (we handle decoding/encoding):
"input_encoding": "unicode",
"output_encoding": "unicode",
# Exit with error on docutils warning or above.
# (There's discussion of having readme_renderer ignore warnings;
# this ensures they'll be treated as errors here.)
"halt_level": 2, # (docutils.utils.Reporter.WARNING_LEVEL)
# Report all docutils warnings or above.
# (The readme_renderer default suppresses this output.)
"report_level": 2, # (docutils.utils.Reporter.WARNING_LEVEL)
}
)
writer = ReadMeHTMLWriter()
try:
return publish_string(
source_text,
writer=writer,
settings_overrides=settings,
)
except SystemMessage:
warning_stream.write("Error rendering readme source.\n")
return None
def main(argv=None):
parser = argparse.ArgumentParser(
description="Render readme file as it would appear on PyPI"
)
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument(
"-p", "--package", help="Source readme from package's metadata"
)
input_group.add_argument(
"-i",
"--input",
help="Source readme.rst file ('-' for stdin)",
type=argparse.FileType("r"),
)
parser.add_argument(
"-o",
"--output",
help="Output file (default: stdout)",
type=argparse.FileType("w"),
default="-",
)
args = parser.parse_args(argv)
if args.package:
try:
source_text = get_package_readme(args.package)
except PackageNotFoundError:
print(f"Package not installed: {args.package!r}", file=sys.stderr)
sys.exit(2)
if source_text is None:
print(f"No metadata readme for {args.package!r}", file=sys.stderr)
sys.exit(2)
else:
source_text = args.input.read()
rendered = render(source_text)
if rendered is None:
sys.exit(2)
args.output.write(rendered)
if __name__ == "__main__":
main()

View File

@@ -1,11 +1,13 @@
%(head_prefix)s
<!--
This approximates PyPI.org project page styling as of 8/2020,
This approximates PyPI.org project page styling as of 5/2023,
and loads their compiled CSS that was in use at that time.
(Styling seems to change more often than basic page structure,
so to update, it may be sufficient to copy in the current
<link rel="stylesheet" ...> tags from any live package page.)
<link rel="stylesheet" ...> tags from any live package page.
Be sure to convert or escape any percent chars in copied urls,
to avoid "not enough arguments for format string" errors.)
This extends the docutils base template found at
${SITE_PACKAGES}/docutils/writers/html5_polyglot/template.txt
@@ -15,13 +17,13 @@
%(head)s
<!-- template (stylesheet) omitted -->
<link rel="stylesheet" href="/static/css/warehouse-ltr.f2d4f304.css">
<link rel="stylesheet" href="/static/css/fontawesome.6002a161.css">
<link rel="stylesheet" href="/static/css/regular.98fbf39a.css">
<link rel="stylesheet" href="/static/css/solid.c3b5f0b5.css">
<link rel="stylesheet" href="/static/css/brands.2c303be1.css">
<link rel="stylesheet" href="/static/css/warehouse-ltr.a42ccb04.css">
<link rel="stylesheet" href="/static/css/fontawesome.d37999f3.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600,600italic,700,700italic|Source+Code+Pro:500">
<link rel="icon" href="/static/images/favicon.6a76275d.ico" type="image/x-icon">
<noscript>
<link rel="stylesheet" href="/static/css/noscript.0673c9ea.css">
</noscript>
<link rel="icon" href="/static/images/favicon.35549fe8.ico" type="image/x-icon">
%(body_prefix)s