diff --git a/.flake8 b/.flake8 index cfb0df1..1d29b64 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,2 @@ [flake8] -extend-ignore = E203,E501 +extend-ignore = E203,E501,D104 diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 0000000..ab64e37 --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,313 @@ +@import url('https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,400;0,700;0,800;1,400;1,800&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;700&display=swap'); + +div.document { + margin-top: 0 !important; +} + +div.body { + min-width: 0 !important; +} + +div.body p, div.body li { + line-height: 1.45; +} + +div.body li { + margin-bottom: 4px; +} + +div.topic { + margin: 0; + padding: 8px 12px; +} + +p.topic-title { + margin: 0; +} + +div.topic ul { + margin-top: 6px; +} +@media screen and (max-width: 870px) { + ul { + margin: 10px 0 10px 20px; + } +} + +div.sphinxsidebar h1.logo, +div.sphinxsidebar h3 { + font-family: 'Libre Franklin', "Helvetica", "Liberation Sans", Arial, sans-serif; +} + +div.sphinxsidebarwrapper h1 { + line-height: 1.25; +} + +div.sphinxsidebarwrapper h1.logo { + font-size: 1.85em; + font-weight: 800; +} + +div.sphinxsidebarwrapper h1 a, +div.sphinxsidebarwrapper h1 a:visited { + color: black; +} + +@media (min-width: 875px) { + div.sphinxsidebar { + margin-top: 85px; + } +} + +@media screen and (max-width: 875px) { + div.sphinxsidebar { + width: auto; + padding: 10px 20px; + margin: 50px 0 0 0; + } +} + +div.admonition { + padding: 15px; +} + +div.warning { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition p.admonition-title { + font-family: 'Libre Franklin', "Helvetica", "Liberation Sans", Arial, sans-serif; + margin: 0; +} + +div.related nav { + padding-right: 10px; +} + +body { + font-family: 'Libre Franklin', "Helvetica", "Liberation Sans", Arial, sans-serif; + font-size: 20px; + line-height: 1.45; + text-align: left; +} +@media screen and (max-width: 875px) { + body { + margin: 0; + padding: 0; + } + div.body > .section, + div.body > section { + padding: 0 20px; + } +} + +@media (max-width: 550px) { + body { + font-size: 0.85em; + } +} + +div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { + font-family: 'Libre Franklin', "Helvetica", "Liberation Sans", Arial, sans-serif; + font-weight: 700; +} + +div.body h1 { + font-weight: 800; + font-size: 220%; + line-height: 1.2; +} + +pre, tt, code { + background: none; + font-family: 'IBM Plex Mono', 'Droid Sans Mono', monospace; +} + +pre { + padding: 7px; +} + +.cell_output { + overflow: auto; +} + +.toctree-wrapper p.caption { + font-weight: 700; +} + +.toggle-details { + display: none; +} + +.row { + width: 100%; + max-width: 660px; + margin: 0 auto; + overflow: hidden; +} +.row .fivecol { + width: 43%; + float: right; + min-height: 1px; +} +.row .sevencol { + width: 37%; + float: left; + min-height: 1px; +} +@media (max-width: 550px) { + .row .fivecol, .row .sevencol { + padding: 0 20px; + } +} + +/* The header */ +nav { + display: block; + margin-top: 0.75em; + margin-bottom: 0.5em; + font-size: 1em; + line-height: 1.7em; +} +nav .shingle { + font-size: 1.7em; + font-weight: bold; + text-align: left; + padding-left: 0.15em; +} +nav .shingle a { + text-decoration: none; + font-weight: bold; + color: #000; +} +nav .shingle a:hover { + color: #686868; +} +@media (max-width: 550px) { + nav .shingle { + float: left; + margin-bottom: 5px; + padding-left: 0; + } +} +nav .links { + text-align: right; +} +nav .links ul { + float: right; + list-style-type: none; + margin: 4px 0 0 0; +} +nav .links li { + float: left; + list-style-position: inside; + margin-left: 0.5em; + font-size: 0.9em; + font-weight: 300; + margin-bottom: 0; +} +@media (max-width: 550px) { + nav .links li { + font-size: .825em; + } +} +nav .links li a { + text-decoration: none; +} +nav .links li a:hover { + text-decoration: underline; +} +.last { + margin-right: 0; +} + +.topbar { + border-bottom: solid 10px #e5e5e5; + margin-bottom: 20px; + width: 100%; +} + +a:link, +div.sphinxsidebar a, +div.sphinxsidebar a:link { + text-decoration: none; + color: #686868; + border-bottom: none; +} +a:visited, +div.sphinxsidebar a:visited { + text-decoration: none; + color: #686868; + border-bottom: none; +} +a:hover, +div.sphinxsidebar a:hover { + text-decoration: underline; + border-bottom: none; +} +a:active, +div.sphinxsidebar a:active { + text-decoration: underline; + color: #000; + border-bottom: none; +} +a.reference, +a.internal { + border-bottom: 0; +} +a.reference:hover, +a.internal:hover { + border-bottom: 0; +} +h1.logo a { + color: black; +} + +h2+p { + margin-top: 5px; +} + +table.align-default { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.latest-parent { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.latest-child { + width: 212px; + margin: 0 8px 8px 0; +} + +.latest-child p { + margin-top: 0; +} + +@media (max-width: 550px) { + .latest-child { + width: 190px; + } +} + +.table-container { + overflow-x: auto; +} + +#api-reference dd { + margin-left: 0; +} + +#api-reference dl.field-list > dt { + font-weight: 400 !important; + padding-left: 0; +} + +#api-reference p.rubric { + font-weight: 400 !important; +} diff --git a/docs/_templates/nav.html b/docs/_templates/nav.html new file mode 100644 index 0000000..10d22fd --- /dev/null +++ b/docs/_templates/nav.html @@ -0,0 +1,48 @@ + +
+
+
+ diff --git a/docs/conf.py b/docs/conf.py index df6a746..cb7e1fb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,7 +4,7 @@ from datetime import datetime # Insert the parent directory into the path -sys.path.insert(0, os.path.abspath("../reuters_style")) +sys.path.insert(0, os.path.abspath("../")) project = "reuters-style" year = datetime.now().year @@ -14,9 +14,22 @@ templates_path = ["_templates"] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] -html_theme = "sphinx_rtd_theme" +html_theme = "alabaster" html_baseurl = "/docs/" pygments_style = "sphinx" +html_sidebars = { + "**": [ + # "about.html", + # "navigation.html", + "relations.html", + "searchbox.html", + ] +} + +html_static_path = ["_static"] +html_css_files = [ + "css/custom.css", +] autodoc_member_order = "bysource" autodoc_default_options = { @@ -26,6 +39,7 @@ "undoc-members": True, "show-inheritance": True, } +autodoc_mock_imports = ["pytz"] extensions = [ "myst_parser", diff --git a/docs/index.md b/docs/index.md index e3925c6..d025f5d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,22 @@ -# Your package name +```{include} _templates/nav.html +``` -Your documention starts here ... +# reuters-style + +Format dates, numbers and text to conform with the Reuters Style Guide, the standards that guide the world's largest independent newsroom + +## Installation + +Install the package from the Python Package Index (PyPI) with pipenv: + +```bash +pipenv install reuters-style +``` + +## Usage + +The library currently features the following methods: + +```{eval-rst} +.. automodule:: reuters_style +``` diff --git a/reuters_style/__init__.py b/reuters_style/__init__.py index 1abeed0..39b764e 100644 --- a/reuters_style/__init__.py +++ b/reuters_style/__init__.py @@ -1,41 +1,27 @@ -"""Format dates, numbers and text to conform with the Reuters Style Guide, the standards that guide the world's largest independent newsroom.""" from __future__ import annotations from datetime import datetime, timezone -def dayofweek(dt: datetime, tabular: bool = False) -> str: - """Format the day of the week according to Reuters style. +def date(dt: datetime) -> str: + """Format a date according to Reuters style. - Args: - dt: The datetime to format. (datetime) - tabular: Whether to format the day of the week for a tabular display. (bool) + In text, use the sequence month/day/year, e.g., “Iraq’s invasion of Kuwait on + Aug. 2, 1990, led to...” or “the Aug. 2 invasion” or “the August 1990 invasion.” - Returns: - The formatted day of the week. (str) + If a specific date is used, put the year inside commas. Spell out months + in text, but abbreviate them followed by a full stop when they are used + with a specific date – Jan.1. - Example: - >>> import reuters_style - >>> reuters_style.dayofweek(datetime(2021, 9, 1)) - 'Wednesday' - """ - if tabular: - days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] - else: - days = [ - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - "Sunday", - ] - return days[dt.weekday()] + When spelling out duration, write, “The tournament runs from May 22 to 24,” + not “…runs from May 22-24.” Write “arrived on Monday,” not “arrived Monday” + and “on Tuesday,” rather than “yesterday,” “today,” “tomorrow.” Write + “the 1939-45 war” but “from 1939 to 1945,” not “from 1939-45.” Write 9/11, + not 9-11. In commodities stories, write “Brazil’s 2013/14 soybean crop” + (conventional use), not “2013-14.” - -def date(dt: datetime) -> str: - """Format a date according to Reuters style. + Abbreviate as follows, noting the dot after the abbreviation: Jan., Feb., + March, April, May, June, July, Aug., Sept., Oct., Nov., Dec. Args: dt: The datetime to format. (datetime) @@ -67,9 +53,63 @@ def date(dt: datetime) -> str: return f"{months[dt.month - 1]} {dt.strftime('%-d')}, {dt.strftime('%Y')}" +def dayofweek(dt: datetime, tabular: bool = False) -> str: + """Format the day of the week according to Reuters style. + + Always precede the day of the week with the word "on" as in she said on Monday, + not she said Monday. Do not abbreviate the days of the week, except in a + tabular format: Sun, Mon, Tue, Wed, Thu, Fri, Sat (three letters, without periods). + + Args: + dt: The datetime to format. (datetime) + tabular: Whether to format the day of the week for a tabular display. (bool) + + Returns: + The formatted day of the week. (str) + + Example: + >>> import reuters_style + >>> reuters_style.dayofweek(datetime(2021, 9, 1)) + 'Wednesday' + >>> reuters_style.dayofweek(datetime(2021, 9, 1), tabular=True) + 'Wed' + """ + if tabular: + days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + else: + days = [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", + ] + return days[dt.weekday()] + + def time(dt: datetime, include_timezone: bool = True) -> str: """Format a time according to Reuters style. + Abbreviations of time zones are acceptable providing the GMT equivalent is given. + BST (British Summer Time) = GMT +1 CET (Central European Time) = GMT +1 CDT + (Central Daylight Time) = GMT -5 CST (Central Standard Time) = GMT -6 EST + (Eastern Standard Time) = GMT -5 MDT (Mountain Daylight Time) = GMT -6 MST + (Mountain Standard Time) = GMT -7 PST (Pacific Standard Time) = GMT -8.and + + When referring to times, first give the local time by the 12-hour clock (without + using the words local time) and follow it with a bracketed conversion to a + 24-hour clock time for a specified time zone, e.g., “will meet at 10 a.m. + (1600 GMT).” + + Use figures except for noon and midnight. Use a colon to separate + hours and minutes, e.g., 3:15 p.m. Use the style “on Friday,” “on Saturday,” + rather than the looser “today,” “yesterday,” “tomorrow.” + + Do not use phrases like “several months ago” or “recently,” which suggest we do not know when something + happened or are too lazy to find out. Be precise – “last August” or “on Feb. 2.” + Args: dt: The datetime to format. (datetime) include_timezone: Whether to include the timezone in the result. (bool) @@ -87,6 +127,7 @@ def time(dt: datetime, include_timezone: bool = True) -> str: '12:30 p.m. GMT' >>> reuters_style.time(datetime(2021, 9, 1, 12, 30), include_timezone=False) '12:30 p.m.' + >>> import pytz >>> tz = pytz.timezone('Africa/Johannesburg') >>> reuters_style.time(tz.localize(datetime(2021, 9, 1, 12, 30))) '12:30 p.m. SAST'