Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-titlecase for openSUSE:Factory checked in at 2022-10-12 18:24:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-titlecase (Old) and /work/SRC/openSUSE:Factory/.python-titlecase.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-titlecase" Wed Oct 12 18:24:30 2022 rev:6 rq:1009881 version:2.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-titlecase/python-titlecase.changes 2021-01-13 18:36:28.150349429 +0100 +++ /work/SRC/openSUSE:Factory/.python-titlecase.new.2275/python-titlecase.changes 2022-10-12 18:26:06.361876509 +0200 @@ -1,0 +2,8 @@ +Tue Oct 11 16:00:24 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to version 2.4 + * Add `preserve_blank_lines` option (#88) + * Add Py3.10, Drop Py3.6 + * Update unit testing framework + +------------------------------------------------------------------- Old: ---- titlecase-1.1.1.tar.gz New: ---- titlecase-2.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-titlecase.spec ++++++ --- /var/tmp/diff_new_pack.XtCccK/_old 2022-10-12 18:26:06.809877628 +0200 +++ /var/tmp/diff_new_pack.XtCccK/_new 2022-10-12 18:26:06.813877638 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-titlecase # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-titlecase -Version: 1.1.1 +Version: 2.4 Release: 0 Summary: Python library to capitalize strings License: MIT @@ -31,7 +31,7 @@ BuildRequires: python-rpm-macros Requires: python-regex >= 2020.4.4 Requires(post): update-alternatives -Requires(postun): update-alternatives +Requires(postun):update-alternatives BuildArch: noarch # SECTION test requirements BuildRequires: %{python_module pytest} ++++++ titlecase-1.1.1.tar.gz -> titlecase-2.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/.github/workflows/ci.yml new/titlecase-2.4/.github/workflows/ci.yml --- old/titlecase-1.1.1/.github/workflows/ci.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/.github/workflows/ci.yml 2022-08-09 10:57:43.000000000 +0200 @@ -0,0 +1,44 @@ +name: ci + +on: [pull_request, push] + +jobs: + build-with-required-deps: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.7', '3.8', '3.9', '3.10'] + steps: + - uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install + run: python setup.py install + - name: Tests + run: | + python -m unittest + + build-with-optional-deps: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.7', '3.8', '3.9', '3.10'] + steps: + - uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install with optional dependencies + run: | + pip install regex + python setup.py install + - name: Tests + run: | + python -m unittest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/.github/workflows/coverage.yml new/titlecase-2.4/.github/workflows/coverage.yml --- old/titlecase-1.1.1/.github/workflows/coverage.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/.github/workflows/coverage.yml 2022-08-09 10:57:43.000000000 +0200 @@ -0,0 +1,24 @@ +name: CodeCov +on: [push, pull_request] +jobs: + codecov-build-with-regex: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: '2' + + - name: Setup Python + uses: actions/setup-python@master + with: + python-version: '3.x' + - name: Install Dependencies + run: | + pip install regex + python setup.py install + - name: Generate Coverage Report + run: | + pip install coverage + coverage run -m unittest + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/.gitignore new/titlecase-2.4/.gitignore --- old/titlecase-1.1.1/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/.gitignore 2016-03-07 18:28:08.000000000 +0100 @@ -0,0 +1,11 @@ +.eggs +.coverage +.tox +build +dist +temp +titlecase.egg-info +*.swp +*.swo +*.pyc +*$py.class diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/AUTHORS.rst new/titlecase-2.4/AUTHORS.rst --- old/titlecase-1.1.1/AUTHORS.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/AUTHORS.rst 2021-07-01 19:27:34.000000000 +0200 @@ -0,0 +1,8 @@ +************ +Contributors +************ + +* John Gruber +* Stuart Colville +* Pat Pannuto +* Sam Brockie diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/LICENSE.txt new/titlecase-2.4/LICENSE.txt --- old/titlecase-1.1.1/LICENSE.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/LICENSE.txt 2021-07-01 19:27:34.000000000 +0200 @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2021 Patrick William Pannuto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/PKG-INFO new/titlecase-2.4/PKG-INFO --- old/titlecase-1.1.1/PKG-INFO 2020-06-12 19:53:54.000000000 +0200 +++ new/titlecase-2.4/PKG-INFO 2022-08-15 22:09:19.000000000 +0200 @@ -1,139 +1,142 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: titlecase -Version: 1.1.1 +Version: 2.4 Summary: Python Port of John Gruber's titlecase.pl Home-page: https://github.com/ppannuto/python-titlecase -Author: Pat Pannuto, Stuart Colville, John Gruber -Author-email: pat.pannuto+titlec...@gmail.com +Author: Stuart Colville +Maintainer: Pat Pannuto +Maintainer-email: pat.pannuto+titlec...@gmail.com License: MIT -Description: Titlecase - ========= - - .. image:: https://travis-ci.org/ppannuto/python-titlecase.svg?branch=master - :target: https://travis-ci.org/ppannuto/python-titlecase - .. image:: https://coveralls.io/repos/github/ppannuto/python-titlecase/badge.svg?branch=master - :target: https://coveralls.io/github/ppannuto/python-titlecase?branch=master - - This filter changes a given text to Title Caps, and attempts to be clever - about SMALL words like a/an/the in the input. - The list of "SMALL words" which are not capped comes from the New York - Times Manual of Style, plus some others like 'vs' and 'v'. - - The filter employs some heuristics to guess abbreviations that don't need conversion. - - +------------------+----------------+ - | Original | Conversion | - +==================+================+ - | this is a test | This Is a Test | - +------------------+----------------+ - | THIS IS A TEST | This Is a Test | - +------------------+----------------+ - | this is a TEST | This Is a TEST | - +------------------+----------------+ - - More examples and expected behavior for corner cases are available in the - `package test suite <https://github.com/ppannuto/python-titlecase/blob/master/titlecase/tests.py>`__. - - This library is a resurrection of `Stuart Colville's - titlecase.py <https://muffinresearch.co.uk/titlecasepy-titlecase-in-python/>`__, - which was in turn a port of `John Gruber's - titlecase.pl <http://daringfireball.net/2008/05/title_case>`__. - - Issues, updates, pull requests, etc should be directed - `to github <https://github.com/ppannuto/python-titlecase>`__. - - - Installation - ------------ - - The easiest method is to simply use pip: - - :: - - (sudo) pip install titlecase - - - Usage - ----- - - Titlecase provides only one function, simply: - - .. code-block:: python - - >>> from titlecase import titlecase - >>> titlecase('a thing') - 'A Thing' - - A callback function may also be supplied, which will be called for every word: - - .. code-block:: python - - >>> def abbreviations(word, **kwargs): - ... if word.upper() in ('TCP', 'UDP'): - ... return word.upper() - ... - >>> titlecase.titlecase('a simple tcp and udp wrapper', callback=abbreviations) - 'A Simple TCP and UDP Wrapper' - - The callback function is supplied with an ``all_caps`` keyword argument, indicating - whether the entire line of text was entirely capitalized. Returning ``None`` from - the callback function will allow titlecase to process the word as normal. - - - Command Line Usage - ------------------ - - Titlecase also provides a command line utility ``titlecase``: - - :: - - $ titlecase make me a title - Make Me a Title - $ echo "Can pipe and/or whatever else" | titlecase - Can Pipe and/or Whatever Else - # Or read/write files: - $ titlecase -f infile -o outfile - - In addition, commonly used acronyms can be kept in a local file - at `~/.titlecase.txt`. This file contains one acronym per line. - The acronym will be maintained in the title as it is provided. - Once there is e.g. one line saying `TCP`, then it will be automatically - used when used from the command line. - - :: - - $ titlecase I LOVE TCP - I Love TCP - - - Limitations - ----------- - - This is a best-effort library that uses regexes to try to do intelligent - things, but will have limitations. For example, it does not have the contextual - awareness to distinguish acronyms from words: us (we) versus US (United States). - - The regexes and titlecasing rules were written for American English. While - there is basic support for Unicode characters, such that something like - "El Ni??o" will work, it is likely that accents or non-English phrases will - not be handled correctly. - - If anyone has concrete solutions to improve these or other shortcomings of the - library, pull requests are very welcome! - -Keywords: string formatting -Platform: UNKNOWN +Project-URL: PyPI, https://pypi.org/project/titlecase/ +Project-URL: conda-forge, https://anaconda.org/conda-forge/titlecase +Project-URL: Source Code, https://github.com/ppannuto/python-titlecase +Project-URL: Bug Tracker, https://github.com/ppannuto/python-titlecase/issues Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Topic :: Text Processing :: Filters +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +Provides-Extra: regex + +Titlecase +========= + +.. image:: https://codecov.io/gh/ppannuto/python-titlecase/branch/main/graph/badge.svg?token=J1Li8uhB8q + :target: https://codecov.io/gh/ppannuto/python-titlecase + +This filter changes a given text to Title Caps, and attempts to be clever +about SMALL words like a/an/the in the input. +The list of "SMALL words" which are not capped comes from the New York +Times Manual of Style, plus some others like 'vs' and 'v'. + +The filter employs some heuristics to guess abbreviations that don't need conversion. + ++------------------+----------------+ +| Original | Conversion | ++==================+================+ +| this is a test | This Is a Test | ++------------------+----------------+ +| THIS IS A TEST | This Is a Test | ++------------------+----------------+ +| this is a TEST | This Is a TEST | ++------------------+----------------+ + +More examples and expected behavior for corner cases are available in the +`package test suite <https://github.com/ppannuto/python-titlecase/blob/main/titlecase/tests.py>`__. + +This library is a resurrection of `Stuart Colville's +titlecase.py <https://muffinresearch.co.uk/titlecasepy-titlecase-in-python/>`__, +which was in turn a port of `John Gruber's +titlecase.pl <http://daringfireball.net/2008/05/title_case>`__. + +Issues, updates, pull requests, etc should be directed +`to github <https://github.com/ppannuto/python-titlecase>`__. + + +Installation +------------ + +The easiest method is to simply use pip: + +:: + + (sudo) pip install titlecase + + +Usage +----- + +Titlecase provides only one function, simply: + +.. code-block:: python + + >>> from titlecase import titlecase + >>> titlecase('a thing') + 'A Thing' + +A callback function may also be supplied, which will be called for every word: + +.. code-block:: python + + >>> def abbreviations(word, **kwargs): + ... if word.upper() in ('TCP', 'UDP'): + ... return word.upper() + ... + >>> titlecase.titlecase('a simple tcp and udp wrapper', callback=abbreviations) + 'A Simple TCP and UDP Wrapper' + +The callback function is supplied with an ``all_caps`` keyword argument, indicating +whether the entire line of text was entirely capitalized. Returning ``None`` from +the callback function will allow titlecase to process the word as normal. + + +Command Line Usage +------------------ + +Titlecase also provides a command line utility ``titlecase``: + +:: + + $ titlecase make me a title + Make Me a Title + $ echo "Can pipe and/or whatever else" | titlecase + Can Pipe and/or Whatever Else + # Or read/write files: + $ titlecase -f infile -o outfile + +In addition, commonly used acronyms can be kept in a local file +at `~/.titlecase.txt`. This file contains one acronym per line. +The acronym will be maintained in the title as it is provided. +Once there is e.g. one line saying `TCP`, then it will be automatically +used when used from the command line. + +:: + + $ titlecase I LOVE TCP + I Love TCP + + +Limitations +----------- + +This is a best-effort library that uses regexes to try to do intelligent +things, but will have limitations. For example, it does not have the contextual +awareness to distinguish acronyms from words: us (we) versus US (United States). + +The regexes and titlecasing rules were written for American English. While +there is basic support for Unicode characters, such that something like +"El Ni??o" will work, it is likely that accents or non-English phrases will +not be handled correctly. + +If anyone has concrete solutions to improve these or other shortcomings of the +library, pull requests are very welcome! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/README.rst new/titlecase-2.4/README.rst --- old/titlecase-1.1.1/README.rst 2020-06-12 18:38:25.000000000 +0200 +++ new/titlecase-2.4/README.rst 2021-07-01 19:42:22.000000000 +0200 @@ -1,10 +1,8 @@ Titlecase ========= -.. image:: https://travis-ci.org/ppannuto/python-titlecase.svg?branch=master - :target: https://travis-ci.org/ppannuto/python-titlecase -.. image:: https://coveralls.io/repos/github/ppannuto/python-titlecase/badge.svg?branch=master - :target: https://coveralls.io/github/ppannuto/python-titlecase?branch=master +.. image:: https://codecov.io/gh/ppannuto/python-titlecase/branch/main/graph/badge.svg?token=J1Li8uhB8q + :target: https://codecov.io/gh/ppannuto/python-titlecase This filter changes a given text to Title Caps, and attempts to be clever about SMALL words like a/an/the in the input. @@ -24,7 +22,7 @@ +------------------+----------------+ More examples and expected behavior for corner cases are available in the -`package test suite <https://github.com/ppannuto/python-titlecase/blob/master/titlecase/tests.py>`__. +`package test suite <https://github.com/ppannuto/python-titlecase/blob/main/titlecase/tests.py>`__. This library is a resurrection of `Stuart Colville's titlecase.py <https://muffinresearch.co.uk/titlecasepy-titlecase-in-python/>`__, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/pyproject.toml new/titlecase-2.4/pyproject.toml --- old/titlecase-1.1.1/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/pyproject.toml 2021-07-01 19:27:34.000000000 +0200 @@ -0,0 +1,12 @@ +[build-system] +# The assumed default build requirements from pip are: "setuptools>=40.8.0", +# "wheel" +# See: https://pip.pypa.io/en/stable/reference/pip/#pep-517-and-518-support +# These are taken from the PyScaffold example +# See: https://github.com/pyscaffold/pyscaffold-demo +requires = ["setuptools>=46.1.0", "setuptools_scm[toml]>=5", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +# See configuration details in https://github.com/pypa/setuptools_scm +version_scheme = "no-guess-dev" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/setup.cfg new/titlecase-2.4/setup.cfg --- old/titlecase-1.1.1/setup.cfg 2020-06-12 19:53:54.000000000 +0200 +++ new/titlecase-2.4/setup.cfg 2022-08-15 22:09:19.000000000 +0200 @@ -1,3 +1,57 @@ +[metadata] +name = titlecase +author = Stuart Colville +maintainer = Pat Pannuto +maintainer_email = pat.pannuto+titlec...@gmail.com +description = Python Port of John Gruber's titlecase.pl +long_description = file: README.rst +long_description_content_type = text/x-rst +url = https://github.com/ppannuto/python-titlecase +project_urls = + PyPI = https://pypi.org/project/titlecase/ + conda-forge = https://anaconda.org/conda-forge/titlecase + Source Code = https://github.com/ppannuto/python-titlecase + Bug Tracker = https://github.com/ppannuto/python-titlecase/issues +classifiers = + Development Status :: 5 - Production/Stable + Intended Audience :: Developers + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: Implementation :: CPython + License :: OSI Approved :: MIT License + Natural Language :: English + Topic :: Text Processing :: Filters +license = MIT +license_files = [LICENSE.txt] +keyword = + string formatting + +[options] +zip_safe = False +include_package_data = True +packages = find: +python_requires = >=3.7 + +[options.extras_require] +regex = + regex >=2020.4.4 + +[options.entry_points] +console_scripts = + titlecase = titlecase.__init__:cmd + +[bdist_wheel] +universal = 1 + +[devpi:upload] +no_vcs = 1 +formats = bdist_wheel + [egg_info] tag_build = tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/setup.py new/titlecase-2.4/setup.py --- old/titlecase-1.1.1/setup.py 2020-06-12 19:52:37.000000000 +0200 +++ new/titlecase-2.4/setup.py 2021-07-01 19:41:16.000000000 +0200 @@ -1,57 +1,21 @@ -import os -import sys +"""Setup file for Titlecase. -from setuptools import setup, find_packages +This is based on the example from PyScaffold (https://pyscaffold.org/). +`setup.cfg` is used to configure the project. -def read_file(rel_path): - abs_dir_path = os.path.abspath(os.path.dirname(__file__)) - abs_path = os.path.join(abs_dir_path, rel_path) - with open(abs_path) as f: - return f.read() +""" -def read_version(rel_path): - for line in read_file(rel_path).splitlines(): - if line.startswith('__version__'): - delim = '"' if '"' in line else "'" - return line.split(delim)[1] - else: - raise RuntimeError('No version string found') - -setup(name='titlecase', - version=read_version('titlecase/__init__.py'), - description="Python Port of John Gruber's titlecase.pl", - long_description=read_file('README.rst'), - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: Implementation :: CPython", - "License :: OSI Approved :: MIT License", - "Natural Language :: English", - "Topic :: Text Processing :: Filters", - ], - keywords='string formatting', - author="Pat Pannuto, Stuart Colville, John Gruber", - author_email="pat.pannuto+titlec...@gmail.com", - url="https://github.com/ppannuto/python-titlecase", - license="MIT", - packages=find_packages(), - include_package_data=True, - zip_safe=False, - tests_require=['nose>=1.0', 'regex>=2020.4.4'], - install_requires=['regex>=2020.4.4'], - test_suite="titlecase.tests", - entry_points = { - 'console_scripts': [ - 'titlecase = titlecase.__init__:cmd', - ], - }, -) +from setuptools import setup +if __name__ == "__main__": + try: + setup(use_scm_version={"version_scheme": "no-guess-dev"}) + except Exception: + msg = ( + "\n\nAn error occurred while building the project, " + "please ensure you have the most updated version of setuptools, " + "setuptools_scm and wheel with:\n" + " pip install -U setuptools setuptools_scm wheel\n\n" + ) + print(msg) + raise diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/titlecase/__init__.py new/titlecase-2.4/titlecase/__init__.py --- old/titlecase-1.1.1/titlecase/__init__.py 2020-06-12 19:52:57.000000000 +0200 +++ new/titlecase-2.4/titlecase/__init__.py 2022-08-15 22:02:33.000000000 +0200 @@ -11,28 +11,43 @@ import logging logger = logging.getLogger(__name__) import os -import re import string import sys -import regex +try: + import regex +except ImportError: + import re as regex + REGEX_AVAILABLE = False +else: + REGEX_AVAILABLE = True __all__ = ['titlecase'] -__version__ = '1.1.1' +__version__ = '2.4.0' SMALL = r'a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via|vs\.?' PUNCT = r"""!"???#$%&'???()*+,\-????????????./:;?@[\\\]_`{|}~""" SMALL_WORDS = regex.compile(r'^(%s)$' % SMALL, regex.I) -INLINE_PERIOD = regex.compile(r'[\p{Letter}][.][\p{Letter}]', regex.I) -UC_ELSEWHERE = regex.compile(r'[%s]*?[\p{Letter}]+[\p{Uppercase_Letter}]+?' % PUNCT) -CAPFIRST = regex.compile(r"^[%s]*?([\p{Letter}])" % PUNCT) + SMALL_FIRST = regex.compile(r'^([%s]*)(%s)\b' % (PUNCT, SMALL), regex.I) SMALL_LAST = regex.compile(r'\b(%s)[%s]?$' % (SMALL, PUNCT), regex.I) SUBPHRASE = regex.compile(r'([:.;?!\-????????????][ ])(%s)' % SMALL) -APOS_SECOND = regex.compile(r"^[dol]{1}['???]{1}[\p{Letter}]+(?:['s]{2})?$", regex.I) -UC_INITIALS = regex.compile(r"^(?:[\p{Uppercase_Letter}]{1}\.{1}|[\p{Uppercase_Letter}]{1}\.{1}[\p{Uppercase_Letter}]{1})+$") MAC_MC = regex.compile(r"^([Mm]c|MC)(\w.+)") +MR_MRS_MS_DR = regex.compile(r"^((m((rs?)|s))|Dr)$", regex.I) + +if REGEX_AVAILABLE: + INLINE_PERIOD = regex.compile(r'[\p{Letter}][.][\p{Letter}]', regex.I) + UC_ELSEWHERE = regex.compile(r'[%s]*?[\p{Letter}]+[\p{Uppercase_Letter}]+?' % PUNCT) + CAPFIRST = regex.compile(r"^[%s]*?([\p{Letter}])" % PUNCT) + APOS_SECOND = regex.compile(r"^[dol]{1}['???]{1}[\p{Letter}]+(?:['s]{2})?$", regex.I) + UC_INITIALS = regex.compile(r"^(?:[\p{Uppercase_Letter}]{1}\.{1}|[\p{Uppercase_Letter}]{1}\.{1}[\p{Uppercase_Letter}]{1})+$") +else: + INLINE_PERIOD = regex.compile(r'[\w][.][\w]', regex.I) + UC_ELSEWHERE = regex.compile(r'[%s]*?[a-zA-Z]+[A-Z]+?' % PUNCT) + CAPFIRST = regex.compile(r"^[%s]*?([\w])" % PUNCT) + APOS_SECOND = regex.compile(r"^[dol]['???][\w]+(?:['s]{2})?$", regex.I) + UC_INITIALS = regex.compile(r"^(?:[A-Z]\.|[A-Z]\.[A-Z])+$") class Immutable(object): @@ -62,28 +77,7 @@ SUBPHRASE = regex.compile(r'([:.;?!][ ])(%s)' % small) -def create_wordlist_filter(path_to_config=None): - """ - This function checks for a default list of abbreviations which need to - remain as they are (e.g. uppercase only or mixed case). - The file is retrieved from ~/.titlecase.txt (platform independent) - """ - if path_to_config is None: - path_to_config = os.path.join(os.path.expanduser('~'), ".titlecase.txt") - if not os.path.isfile(str(path_to_config)): - logger.debug('No config file found at ' + str(path_to_config)) - return lambda word, **kwargs : None - with open(str(path_to_config)) as f: - logger.debug('Config file used from ' + str(path_to_config)) - abbreviations = [abbr.strip() for abbr in f.read().splitlines() if abbr] - abbreviations_capitalized = [abbr.upper() for abbr in abbreviations] - for abbr in abbreviations: - logger.debug("This acronym will be kept as written here: " + abbr) - return lambda word, **kwargs : (abbreviations[abbreviations_capitalized.index(word.upper())] - if word.upper() in abbreviations_capitalized else None) - - -def titlecase(text, callback=None, small_first_last=True, wordlist_file=None): +def titlecase(text, callback=None, small_first_last=True, preserve_blank_lines=False): """ :param text: Titlecases input text :param callback: Callback function that returns the titlecase version of a specific word @@ -99,9 +93,10 @@ the New York Times Manual of Style, plus 'vs' and 'v'. """ - wordlist_filter = create_wordlist_filter(wordlist_file) - - lines = regex.split('[\r\n]+', text) + if preserve_blank_lines: + lines = regex.split('[\r\n]', text) + else: + lines = regex.split('[\r\n]+', text) processed = [] for line in lines: all_caps = line.upper() == line @@ -116,12 +111,6 @@ tc_line.append(_mark_immutable(new_word)) continue - # If the user has a custom wordlist, defer to that - new_word = wordlist_filter(word, all_caps=all_caps) - if new_word: - tc_line.append(_mark_immutable(new_word)) - continue - if all_caps: if UC_INITIALS.match(word): tc_line.append(word) @@ -138,7 +127,13 @@ match = MAC_MC.match(word) if match: tc_line.append("%s%s" % (match.group(1).capitalize(), - titlecase(match.group(2), callback, small_first_last))) + titlecase(match.group(2), callback, True))) + continue + + match = MR_MRS_MS_DR.match(word) + if match: + word = word[0].upper() + word[1:] + tc_line.append(word) continue if INLINE_PERIOD.search(word) or (not all_caps and UC_ELSEWHERE.match(word)): @@ -158,7 +153,7 @@ if '-' in word: hyphenated = map( - lambda t: titlecase(t, callback, small_first_last), + lambda t: titlecase(t, callback, False), word.split('-') ) tc_line.append("-".join(hyphenated)) @@ -207,6 +202,30 @@ return result +def create_wordlist_filter_from_file(file_path): + ''' + Load a list of abbreviations from the file with the provided path, + reading one abbreviation from each line, and return a callback to + be passed to the `titlecase` function for preserving their given + canonical capitalization during title-casing. + ''' + if file_path is None: + logger.debug('No abbreviations file path given') + return lambda word, **kwargs: None + file_path_str = str(file_path) + if not os.path.isfile(file_path_str): + logger.debug('No abbreviations file found at ' + file_path_str) + return lambda word, **kwargs: None + with open(file_path_str) as f: + logger.debug('Reading abbreviations from file ' + file_path_str) + abbrevs_gen = (line.strip() for line in f.read().splitlines() if line) + abbrevs = {abbr.upper(): abbr for abbr in abbrevs_gen} + if logger.isEnabledFor(logging.DEBUG): + for abbr in abbrevs.values(): + logger.debug('Registered abbreviation: ' + abbr) + return lambda word, **kwargs: abbrevs.get(word.upper()) + + def cmd(): '''Handler for command line invocation''' @@ -214,7 +233,7 @@ # Consume '-f' and '-o' as input/output, allow '-' for stdin/stdout # and treat any subsequent arguments as a space separated string to # be titlecased (so it still works if people forget quotes) - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser(allow_abbrev=False) in_group = parser.add_mutually_exclusive_group() in_group.add_argument('string', nargs='*', default=[], help='String to titlecase') @@ -224,6 +243,8 @@ help='File to write titlecased output to') parser.add_argument('-w', '--wordlist', help='Wordlist for acronyms') + parser.add_argument('--preserve-blank-lines', action='store_true', + help='Do not skip blank lines in input') args = parser.parse_args() @@ -249,5 +270,12 @@ with ifile: in_string = ifile.read() + if args.wordlist is not None: + wordlist_file = args.wordlist + else: + wordlist_file = os.path.join(os.path.expanduser('~'), '.titlecase.txt') + wordlist_filter = create_wordlist_filter_from_file(wordlist_file) + with ofile: - ofile.write(titlecase(in_string, wordlist_file=args.wordlist)) + ofile.write(titlecase(in_string, callback=wordlist_filter, + preserve_blank_lines=args.preserve_blank_lines)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/titlecase/tests.py new/titlecase-2.4/titlecase/tests.py --- old/titlecase-1.1.1/titlecase/tests.py 2020-06-12 18:38:25.000000000 +0200 +++ new/titlecase-2.4/titlecase/tests.py 2022-08-09 10:32:57.000000000 +0200 @@ -3,14 +3,13 @@ """Tests for titlecase""" -from __future__ import print_function, unicode_literals - import os import sys import tempfile -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) +import unittest -from titlecase import titlecase, set_small_word_list +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) +from titlecase import titlecase, set_small_word_list, create_wordlist_filter_from_file # (executed by `test_input_output` below) @@ -32,6 +31,10 @@ "Dance With Me/Let???s Face the Music and Dance" ), ( + "a-b end-to-end two-not-three/three-by-four/five-and", + "A-B End-to-End Two-Not-Three/Three-by-Four/Five-And" + ), + ( "34th 3rd 2nd", "34th 3rd 2nd" ), @@ -247,6 +250,14 @@ "o'melveny/o'doyle o'Melveny/o'doyle O'melveny/o'doyle o'melveny/o'Doyle o'melveny/O'doyle", "O'Melveny/O'Doyle O'Melveny/O'Doyle O'Melveny/O'Doyle O'Melveny/O'Doyle O'Melveny/O'Doyle", ), + # These 'Mc' cases aim to ensure more consistent/predictable behavior. + # The examples here are somewhat contrived, and are subject to change + # if there is a compelling argument for updating their behavior. + # See https://github.com/ppannuto/python-titlecase/issues/64 + ( + "mccay-mcbut-mcdo mcdonalds/mcby", + "McCay-McBut-McDo McDonalds/McBy" + ), ( "oblon, spivak, mcclelland, maier & neustadt", "Oblon, Spivak, McClelland, Maier & Neustadt", @@ -291,81 +302,133 @@ "???? ????", "???? ????", ), + # https://github.com/ppannuto/python-titlecase/pull/67 + ( + "Mr mr Mrs Ms Mss Dr dr , Mr. and Mrs. Person", + "Mr Mr Mrs Ms MSS Dr Dr , Mr. And Mrs. Person", + ), ) -def test_initials_regex(): - """Test - uppercase initials regex with A.B""" - from titlecase import UC_INITIALS - assert bool(UC_INITIALS.match('A.B')) is True +class TestStringSuite(unittest.TestCase): + """Generated tests from strings""" + def test_specific_string(self): + for data in TEST_DATA: + with self.subTest(): + self.assertEqual(titlecase(data[0]), data[1]) + + +class TestInitialsRegex(unittest.TestCase): + def test_initials_regex(self): + """Test - uppercase initials regex with A.B""" + from titlecase import UC_INITIALS + #assert bool(UC_INITIALS.match('A.B')) is True + self.assertRegex('A.B', UC_INITIALS) + + def test_initials_regex_2(self): + """Test - uppercase initials regex with A.B.""" + from titlecase import UC_INITIALS + #assert bool(UC_INITIALS.match('A.B.')) is True + self.assertRegex('A.B.', UC_INITIALS) + + def test_initials_regex_3(self): + """Test - uppercase initials regex with ABCD""" + from titlecase import UC_INITIALS + #assert bool(UC_INITIALS.match('ABCD')) is False + self.assertNotRegex('ABCD', UC_INITIALS) -def test_initials_regex_2(): - """Test - uppercase initials regex with A.B.""" - from titlecase import UC_INITIALS - assert bool(UC_INITIALS.match('A.B.')) is True - -def test_initials_regex_3(): - """Test - uppercase initials regex with ABCD""" - from titlecase import UC_INITIALS - assert bool(UC_INITIALS.match('ABCD')) is False - - -def check_input_matches_expected_output(in_, out): - """Function yielded by test generator""" - try: - assert titlecase(in_) == out - except AssertionError: - print("{0} != {1}".format(titlecase(in_), out)) - raise - - -def test_at_and_t(): +class TestSymbols(unittest.TestCase): + @staticmethod def at_n_t(word, **kwargs): if word.upper() == "AT&T": return word.upper() - print(titlecase("at&t", callback=at_n_t)) - assert titlecase("at&t", callback=at_n_t) == "AT&T" - -def test_input_output(): - """Generated tests""" - for data in TEST_DATA: - yield check_input_matches_expected_output, data[0], data[1] + def test_at_n_t(self): + self.assertEqual(titlecase("at&t", callback=TestSymbols.at_n_t), "AT&T") -def test_callback(): +class TestCallback(unittest.TestCase): + @staticmethod def abbreviation(word, **kwargs): if word.upper() in ('TCP', 'UDP'): return word.upper() - s = 'a simple tcp and udp wrapper' - # Note: this library is able to guess that all-consonant words are acronyms, so TCP - # works naturally, but others will require the custom list - assert titlecase(s) == 'A Simple TCP and Udp Wrapper' - assert titlecase(s, callback=abbreviation) == 'A Simple TCP and UDP Wrapper' - assert titlecase(s.upper(), callback=abbreviation) == 'A Simple TCP and UDP Wrapper' - assert titlecase(u'cr??me br??l??e', callback=lambda x, **kw: x.upper()) == u'CR??ME BR??L??E' - - -def test_set_small_word_list(): - assert titlecase('playing the game "words with friends"') == 'Playing the Game "Words With Friends"' - set_small_word_list('a|an|the|with') - assert titlecase('playing the game "words with friends"') == 'Playing the Game "Words with Friends"' - - -def test_custom_abbreviations(): - with tempfile.NamedTemporaryFile(mode='w') as f: - f.write('UDP\nPPPoE\n') - f.flush() + + def test_callback(self): + s = 'a simple tcp and udp wrapper' + # Note: this library is able to guess that all-consonant words are acronyms, so TCP + # works naturally, but others will require the custom list + self.assertEqual(titlecase(s), + 'A Simple TCP and Udp Wrapper') + self.assertEqual(titlecase(s, callback=TestCallback.abbreviation), + 'A Simple TCP and UDP Wrapper') + self.assertEqual(titlecase(s.upper(), callback=TestCallback.abbreviation), + 'A Simple TCP and UDP Wrapper') + self.assertEqual(titlecase(u'cr??me br??l??e', callback=lambda x, **kw: x.upper()), + u'CR??ME BR??L??E') + + +# It looks like set_small_word_list uses different regexs that the original +# setup code path :/. It really should be the case that one could call +# titlecase.set_small_word_list() and reset to the original behavior (it +# _really_ should be the case that there aren't all these ugly globals around). +# +# It seems that `nose` ran every test in isolation, or just in a different +# order, so the global state bug wasn't caught before. This should be fixed, +# but one thingg at a time. +@unittest.skip("FIXME: Converting to unittest exposed a bug") +class TestSmallWordList(unittest.TestCase): + def test_set_small_word_list(self): + self.assertEqual(titlecase('playing the game "words with friends"'), + 'Playing the Game "Words With Friends"') + set_small_word_list('a|an|the|with') + self.assertEqual(titlecase('playing the game "words with friends"'), + 'Playing the Game "Words with Friends"') + + +class TestCustomAbbreviations(unittest.TestCase): + def setUp(self): + # Do not delete on close, instead do manually for Windows (see #86). + self.f = tempfile.NamedTemporaryFile(mode='w', delete=False) + self.f.write('UDP\nPPPoE\n') + self.f.flush() + + def tearDown(self): + self.f.close() # manually close + os.unlink(self.f.name) # manually delete + + def test_technical_acronyms(self): # This works without a wordlist, because it begins mixed case - assert titlecase('sending UDP packets over PPPoE works great') == 'Sending UDP Packets Over PPPoE Works Great' + self.assertEqual(titlecase('sending UDP packets over PPPoE works great'), + 'Sending UDP Packets Over PPPoE Works Great') # Without a wordlist, this will do the "wrong" thing for the context - assert titlecase('SENDING UDP PACKETS OVER PPPOE WORKS GREAT') == 'Sending Udp Packets Over Pppoe Works Great' + self.assertEqual(titlecase('SENDING UDP PACKETS OVER PPPOE WORKS GREAT'), + 'Sending Udp Packets Over Pppoe Works Great') # A wordlist can provide custom acronyms - assert titlecase('sending UDP packets over PPPoE works great', wordlist_file=f.name) == 'Sending UDP Packets Over PPPoE Works Great' + self.assertEqual(titlecase( + 'sending UDP packets over PPPoE works great', + callback=create_wordlist_filter_from_file(self.f.name)), + 'Sending UDP Packets Over PPPoE Works Great') + + +class TestBlankLines(unittest.TestCase): + # Really, it's a bit odd that the default behavior is to delete blank lines, + # but that's what it was from day one, so we're kind of stuck with that. + # This ensures folks can opt-out of that behavior if they want. + + def test_one_blank(self): + s = 'Line number one\n\nand Line three\n' + self.assertEqual(titlecase(s), 'Line Number One\nAnd Line Three\n') + self.assertEqual(titlecase(s, preserve_blank_lines=True), 'Line Number One\n\nAnd Line Three\n') + + def test_complex_blanks(self): + s = '\n\nLeading blank\n\n\nMulti-blank\n\n\n\n\nTrailing Blank\n\n' + self.assertEqual(titlecase(s), + '\nLeading Blank\nMulti-Blank\nTrailing Blank\n') + self.assertEqual(titlecase(s, preserve_blank_lines=True), + '\n\nLeading Blank\n\n\nMulti-Blank\n\n\n\n\nTrailing Blank\n\n') -if __name__ == "__main__": - import nose - nose.main() +if __name__ == '__main__': + unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/titlecase.egg-info/PKG-INFO new/titlecase-2.4/titlecase.egg-info/PKG-INFO --- old/titlecase-1.1.1/titlecase.egg-info/PKG-INFO 2020-06-12 19:53:54.000000000 +0200 +++ new/titlecase-2.4/titlecase.egg-info/PKG-INFO 2022-08-15 22:09:19.000000000 +0200 @@ -1,139 +1,142 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: titlecase -Version: 1.1.1 +Version: 2.4 Summary: Python Port of John Gruber's titlecase.pl Home-page: https://github.com/ppannuto/python-titlecase -Author: Pat Pannuto, Stuart Colville, John Gruber -Author-email: pat.pannuto+titlec...@gmail.com +Author: Stuart Colville +Maintainer: Pat Pannuto +Maintainer-email: pat.pannuto+titlec...@gmail.com License: MIT -Description: Titlecase - ========= - - .. image:: https://travis-ci.org/ppannuto/python-titlecase.svg?branch=master - :target: https://travis-ci.org/ppannuto/python-titlecase - .. image:: https://coveralls.io/repos/github/ppannuto/python-titlecase/badge.svg?branch=master - :target: https://coveralls.io/github/ppannuto/python-titlecase?branch=master - - This filter changes a given text to Title Caps, and attempts to be clever - about SMALL words like a/an/the in the input. - The list of "SMALL words" which are not capped comes from the New York - Times Manual of Style, plus some others like 'vs' and 'v'. - - The filter employs some heuristics to guess abbreviations that don't need conversion. - - +------------------+----------------+ - | Original | Conversion | - +==================+================+ - | this is a test | This Is a Test | - +------------------+----------------+ - | THIS IS A TEST | This Is a Test | - +------------------+----------------+ - | this is a TEST | This Is a TEST | - +------------------+----------------+ - - More examples and expected behavior for corner cases are available in the - `package test suite <https://github.com/ppannuto/python-titlecase/blob/master/titlecase/tests.py>`__. - - This library is a resurrection of `Stuart Colville's - titlecase.py <https://muffinresearch.co.uk/titlecasepy-titlecase-in-python/>`__, - which was in turn a port of `John Gruber's - titlecase.pl <http://daringfireball.net/2008/05/title_case>`__. - - Issues, updates, pull requests, etc should be directed - `to github <https://github.com/ppannuto/python-titlecase>`__. - - - Installation - ------------ - - The easiest method is to simply use pip: - - :: - - (sudo) pip install titlecase - - - Usage - ----- - - Titlecase provides only one function, simply: - - .. code-block:: python - - >>> from titlecase import titlecase - >>> titlecase('a thing') - 'A Thing' - - A callback function may also be supplied, which will be called for every word: - - .. code-block:: python - - >>> def abbreviations(word, **kwargs): - ... if word.upper() in ('TCP', 'UDP'): - ... return word.upper() - ... - >>> titlecase.titlecase('a simple tcp and udp wrapper', callback=abbreviations) - 'A Simple TCP and UDP Wrapper' - - The callback function is supplied with an ``all_caps`` keyword argument, indicating - whether the entire line of text was entirely capitalized. Returning ``None`` from - the callback function will allow titlecase to process the word as normal. - - - Command Line Usage - ------------------ - - Titlecase also provides a command line utility ``titlecase``: - - :: - - $ titlecase make me a title - Make Me a Title - $ echo "Can pipe and/or whatever else" | titlecase - Can Pipe and/or Whatever Else - # Or read/write files: - $ titlecase -f infile -o outfile - - In addition, commonly used acronyms can be kept in a local file - at `~/.titlecase.txt`. This file contains one acronym per line. - The acronym will be maintained in the title as it is provided. - Once there is e.g. one line saying `TCP`, then it will be automatically - used when used from the command line. - - :: - - $ titlecase I LOVE TCP - I Love TCP - - - Limitations - ----------- - - This is a best-effort library that uses regexes to try to do intelligent - things, but will have limitations. For example, it does not have the contextual - awareness to distinguish acronyms from words: us (we) versus US (United States). - - The regexes and titlecasing rules were written for American English. While - there is basic support for Unicode characters, such that something like - "El Ni??o" will work, it is likely that accents or non-English phrases will - not be handled correctly. - - If anyone has concrete solutions to improve these or other shortcomings of the - library, pull requests are very welcome! - -Keywords: string formatting -Platform: UNKNOWN +Project-URL: PyPI, https://pypi.org/project/titlecase/ +Project-URL: conda-forge, https://anaconda.org/conda-forge/titlecase +Project-URL: Source Code, https://github.com/ppannuto/python-titlecase +Project-URL: Bug Tracker, https://github.com/ppannuto/python-titlecase/issues Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Topic :: Text Processing :: Filters +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +Provides-Extra: regex + +Titlecase +========= + +.. image:: https://codecov.io/gh/ppannuto/python-titlecase/branch/main/graph/badge.svg?token=J1Li8uhB8q + :target: https://codecov.io/gh/ppannuto/python-titlecase + +This filter changes a given text to Title Caps, and attempts to be clever +about SMALL words like a/an/the in the input. +The list of "SMALL words" which are not capped comes from the New York +Times Manual of Style, plus some others like 'vs' and 'v'. + +The filter employs some heuristics to guess abbreviations that don't need conversion. + ++------------------+----------------+ +| Original | Conversion | ++==================+================+ +| this is a test | This Is a Test | ++------------------+----------------+ +| THIS IS A TEST | This Is a Test | ++------------------+----------------+ +| this is a TEST | This Is a TEST | ++------------------+----------------+ + +More examples and expected behavior for corner cases are available in the +`package test suite <https://github.com/ppannuto/python-titlecase/blob/main/titlecase/tests.py>`__. + +This library is a resurrection of `Stuart Colville's +titlecase.py <https://muffinresearch.co.uk/titlecasepy-titlecase-in-python/>`__, +which was in turn a port of `John Gruber's +titlecase.pl <http://daringfireball.net/2008/05/title_case>`__. + +Issues, updates, pull requests, etc should be directed +`to github <https://github.com/ppannuto/python-titlecase>`__. + + +Installation +------------ + +The easiest method is to simply use pip: + +:: + + (sudo) pip install titlecase + + +Usage +----- + +Titlecase provides only one function, simply: + +.. code-block:: python + + >>> from titlecase import titlecase + >>> titlecase('a thing') + 'A Thing' + +A callback function may also be supplied, which will be called for every word: + +.. code-block:: python + + >>> def abbreviations(word, **kwargs): + ... if word.upper() in ('TCP', 'UDP'): + ... return word.upper() + ... + >>> titlecase.titlecase('a simple tcp and udp wrapper', callback=abbreviations) + 'A Simple TCP and UDP Wrapper' + +The callback function is supplied with an ``all_caps`` keyword argument, indicating +whether the entire line of text was entirely capitalized. Returning ``None`` from +the callback function will allow titlecase to process the word as normal. + + +Command Line Usage +------------------ + +Titlecase also provides a command line utility ``titlecase``: + +:: + + $ titlecase make me a title + Make Me a Title + $ echo "Can pipe and/or whatever else" | titlecase + Can Pipe and/or Whatever Else + # Or read/write files: + $ titlecase -f infile -o outfile + +In addition, commonly used acronyms can be kept in a local file +at `~/.titlecase.txt`. This file contains one acronym per line. +The acronym will be maintained in the title as it is provided. +Once there is e.g. one line saying `TCP`, then it will be automatically +used when used from the command line. + +:: + + $ titlecase I LOVE TCP + I Love TCP + + +Limitations +----------- + +This is a best-effort library that uses regexes to try to do intelligent +things, but will have limitations. For example, it does not have the contextual +awareness to distinguish acronyms from words: us (we) versus US (United States). + +The regexes and titlecasing rules were written for American English. While +there is basic support for Unicode characters, such that something like +"El Ni??o" will work, it is likely that accents or non-English phrases will +not be handled correctly. + +If anyone has concrete solutions to improve these or other shortcomings of the +library, pull requests are very welcome! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/titlecase.egg-info/SOURCES.txt new/titlecase-2.4/titlecase.egg-info/SOURCES.txt --- old/titlecase-1.1.1/titlecase.egg-info/SOURCES.txt 2020-06-12 19:53:54.000000000 +0200 +++ new/titlecase-2.4/titlecase.egg-info/SOURCES.txt 2022-08-15 22:09:19.000000000 +0200 @@ -1,5 +1,13 @@ +.gitignore +AUTHORS.rst +LICENSE.txt README.rst +pyproject.toml +setup.cfg setup.py +tox.ini +.github/workflows/ci.yml +.github/workflows/coverage.yml titlecase/__init__.py titlecase/tests.py titlecase.egg-info/PKG-INFO diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/titlecase.egg-info/entry_points.txt new/titlecase-2.4/titlecase.egg-info/entry_points.txt --- old/titlecase-1.1.1/titlecase.egg-info/entry_points.txt 2020-06-12 19:53:54.000000000 +0200 +++ new/titlecase-2.4/titlecase.egg-info/entry_points.txt 2022-08-15 22:09:19.000000000 +0200 @@ -1,3 +1,2 @@ [console_scripts] titlecase = titlecase.__init__:cmd - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/titlecase.egg-info/requires.txt new/titlecase-2.4/titlecase.egg-info/requires.txt --- old/titlecase-1.1.1/titlecase.egg-info/requires.txt 2020-06-12 19:53:54.000000000 +0200 +++ new/titlecase-2.4/titlecase.egg-info/requires.txt 2022-08-15 22:09:19.000000000 +0200 @@ -1 +1,3 @@ + +[regex] regex>=2020.4.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/titlecase-1.1.1/tox.ini new/titlecase-2.4/tox.ini --- old/titlecase-1.1.1/tox.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/titlecase-2.4/tox.ini 2022-08-09 10:32:57.000000000 +0200 @@ -0,0 +1,23 @@ +# Tox (http://tox.testrun.org/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +envlist = py36, py37, py38, py39, py310 + +[base] +deps = + coveralls >=1.1 +commands = + coverage run -m unittest + coveralls + +[testenv:re] +deps = + {[base]deps} + +[testenv:regex] +deps = + regex >=2020.4.4 + {[base]deps}