Packaging
Summary
- Package:
- Doc-string:
documented
File |
Expected |
Covered |
Uncovered |
Coverage |
|---|---|---|---|---|
__init__.py |
56 |
54 |
2 |
96.4% |
Overall (1 files) |
56 |
54 |
2 |
96.4% |
Source
pyTooling/Packaging/__init__.pydocumentedundocumentedignoredexcludednot counted
31"""
32A set of helper functions to describe a Python package for setuptools.
33
34.. hint::
35
36 See :ref:`high-level help <PACKAGING>` for explanations and usage examples.
37
38.. seealso::
39
40 :mod:`pyTooling.Versioning`
41 |rarr| The version numbers read from a package's dunder variables.
42 :mod:`pyTooling.Licensing`
43 |rarr| The license names translated for setuptools.
44 :mod:`pyTooling.Testing`
45 |rarr| Testing the console scripts a package installs.
46"""
...
62
64__all__ = [
65 "STATUS", "DEFAULT_LICENSE", "DEFAULT_PY_VERSIONS", "DEFAULT_CLASSIFIERS", "DEFAULT_README", "DEFAULT_REQUIREMENTS",
66 "DEFAULT_DOCUMENTATION_REQUIREMENTS", "DEFAULT_TEST_REQUIREMENTS", "DEFAULT_PACKAGING_REQUIREMENTS",
67 "DEFAULT_VERSION_FILE"
68]
69
71@export
72class PackagingError(ToolingException):
73 """Base-exception of all exceptions raised by :mod:`pyTooling.Packaging`."""
74
76@export
77class DirectReferenceWarning(CriticalWarning):
78 """
79 A requirement of an extra names its distribution by a URL, a direct reference (``name @ URL``).
80
81 The Python Package Index rejects a package whose metadata contains a direct reference, therefore
82 :func:`DescribePythonPackage` leaves such a requirement out of the extra.
83
84 .. important::
85
86 As a critical warning, it must be collected by a :class:`~pyTooling.Warning.WarningCollector` up the
87 call-hierarchy, otherwise :exc:`~pyTooling.Warning.UnhandledCriticalWarningError` is raised.
88 """
89
90 _requirement: str #: The requirement left out, as stated.
91 _extra: str #: The extra the requirement was left out of.
92 _filePath: Nullable[Path] #: The requirements file stating it; ``None`` for parameter 'additionalRequirements'.
93
94 def __init__(
95 self,
96 message: str,
97 /, *,
98 requirement: str,
99 extra: str,
100 filePath: Nullable[Path]
101 ) -> None:
102 """
103 Initializes the warning with the requirement left out, its extra and where it was stated.
104
105 :param message: The warning's message.
106 :param requirement: The requirement left out, as stated.
107 :param extra: The extra the requirement was left out of.
108 :param filePath: The requirements file stating it; ``None`` for parameter 'additionalRequirements'.
109 """
...
114
115 @readonly
116 def Requirement(self) -> str:
117 """
118 Read-only property to access the requirement left out, as stated (:attr:`_requirement`).
119
120 :returns: The requirement.
121 """
...
123
124 @readonly
125 def Extra(self) -> str:
126 """
127 Read-only property to access the extra the requirement was left out of (:attr:`_extra`).
128
129 :returns: The extra's name.
130 """
...
132
133 @readonly
134 def FilePath(self) -> Nullable[Path]:
135 """
136 Read-only property to access the requirements file stating the requirement (:attr:`_filePath`).
137
138 :returns: The file's path, or ``None`` for a requirement from parameter 'additionalRequirements'.
139 """
...
141
143@export
144class Readme:
145 """Encapsulates the READMEs file content and MIME type."""
146
147 _content: str #: Content of the README file
148 _mimeType: str #: MIME type of the README content
149
150 def __init__(self, content: str, mimeType: str) -> None:
151 """
152 Initializes a README file wrapper.
153
154 :param content: Raw content of the README file.
155 :param mimeType: MIME type of the README file.
156 """
...
159
160 @readonly
161 def Content(self) -> str:
162 """
163 Read-only property to access the README's content.
164
165 :returns: Raw content of the README file.
166 """
...
168
169 @readonly
170 def MimeType(self) -> str:
171 """
172 Read-only property to access the README's MIME type.
173
174 :returns: The MIME type of the README file.
175 """
...
177
179@export
180def loadReadmeFile(readmeFile: Path) -> Readme:
181 """
182 Read the README file, so it can be used as long description for the package.
183
184 Supported formats:
185
186 * Plain text (``*.txt``)
187 * Markdown (``*.md``)
188 * ReStructured Text (``*.rst``)
189
190 :param readmeFile: Path to the `README` file as an instance of :class:`Path`.
191 :returns: A tuple containing the file content and the MIME type.
192 :raises TypeError: If parameter 'readmeFile' is not of type :class:`~pathlib.Path`.
193 :raises ValueError: If README file has an unsupported format.
194 :raises FileNotFoundError: If README file does not exist.
195 """
...
218
220@export
221def loadRequirementsFile(requirementsFile: Path, indent: int = 0, debug: bool = False) -> list[str]:
222 """
223 Reads a `requirements.txt` file (recursively) and extracts all specified dependencies into an array.
224
225 Special dependency entries like Git repository references are translates to match the syntax expected by setuptools.
226
227 .. hint::
228
229 Duplicates should be removed by converting the result to a :class:`set` and back to a :class:`list`.
230
231 .. code-block:: Python
232
233 requirements = list(set(loadRequirementsFile(requirementsFile)))
234
235 :param requirementsFile: Path to the ``requirements.txt`` file as an instance of :class:`Path`.
236 :param indent: Optional, indentation level used for the debug output of nested requirements files.
237 :param debug: Optional, if ``True``, print found dependencies and recursion.
238 :returns: A list of dependencies.
239 :raises TypeError: If parameter 'requirementsFile' is not of type :class:`~pathlib.Path`.
240 :raises FileNotFoundError: If requirements file does not exist.
241 """
...
246
247 def _loadRequirementsFile(requirementsFile: Path, indent: int) -> list[str]:
248 """
249 Recursive variant of :func:`loadRequirementsFile`.
250
251 :param requirementsFile: Path to the requirements file to read.
252 :param indent: Indentation level used for the debug output of nested requirements files.
253 :returns: List of requirements read from that file and every file it includes.
254 :raises FileNotFoundError: If the requirements file doesn't exist.
255 """
...
287
...
289
291@export
292class VersionInformation(metaclass=ExtendedType, slots=True):
293 """Encapsulates version information extracted from a Python source file."""
294
295 _author: str #: Author name(s).
296 _copyright: str #: Copyright information.
297 _email: str #: Author's email address.
298 _keywords: list[str] #: Keywords.
299 _license: str #: License name.
300 _description: str #: Description of the package.
301 _version: str #: Version number.
302
303 def __init__(
304 self,
305 author: str,
306 email: str,
307 copyright: str,
308 license: str,
309 version: str,
310 description: str,
311 keywords: Iterable[str]
312 ) -> None:
313 """
314 Initializes a Python package (version) information instance.
315
316 :param author: Author of the Python package.
317 :param email: The author's email address
318 :param copyright: The copyright notice of the Package.
319 :param license: The Python package's license.
320 :param version: The Python package's version.
321 :param description: The Python package's short description.
322 :param keywords: The Python package's list of keywords.
323 """
...
331
332 @readonly
333 def Author(self) -> str:
334 """
335 Read-only property to access the name(s) of the package author(s) (:attr:`_author`).
336
337 :returns: Name(s) of the package author(s).
338 """
...
340
341 @readonly
342 def Copyright(self) -> str:
343 """
344 Read-only property to access the package's copyright information (:attr:`_copyright`).
345
346 :returns: Copyright information.
347 """
...
349
350 @readonly
351 def Description(self) -> str:
352 """
353 Read-only property to access the package description (:attr:`_description`).
354
355 :returns: Package description text.
356 """
...
358
359 @readonly
360 def Email(self) -> str:
361 """
362 Read-only property to access the author's email address (:attr:`_email`).
363
364 :returns: Email address of the author.
365 """
...
367
368 @readonly
369 def Keywords(self) -> list[str]:
370 """
371 Read-only property to access the package's keywords (:attr:`_keywords`).
372
373 :returns: List of keywords.
374 """
...
376
377 @readonly
378 def License(self) -> str:
379 """
380 Read-only property to access the package's license (:attr:`_license`).
381
382 :returns: License name.
383 """
...
385
386 @readonly
387 def Version(self) -> str:
388 """
389 Read-only property to access the package's version number (:attr:`_version`).
390
391 :returns: Version number.
392 """
...
394
395 def __str__(self) -> str:
396 """
397 Return a string representation of this version information.
398
399 :returns: The version number.
400 """
...
402
404def _extractDescription(docString: Nullable[str]) -> str:
405 """
406 Read a package's short description from the first paragraph of its module doc-string.
407
408 A package's short description **is** the summary of its module doc-string - the first paragraph - so the two are
409 one text in two places, and :func:`~pyTooling.Documentation.splitDocString` reads it.
410
411 It is folded into a single line, because a short description is one line of plain text while a doc-string is
412 wrapped to the source file's line length. Strong emphasis around the whole paragraph is removed for the same
413 reason: ``**An abstract VHDL language model.**`` is markup for the rendered documentation, and nothing renders it
414 where a short description is displayed.
415
416 :param docString: The module's doc-string, or ``None`` if it has none.
417 :returns: The description as a single line, or an empty string if there is no doc-string.
418 :raises DocumentationError: If the first paragraph is too long to be a description.
419
420 .. seealso::
421
422 :func:`~pyTooling.Documentation.splitDocString`
423 |rarr| Reads the first paragraph, and rejects one that is too long to be a summary.
424 """
...
432
434@export
435def extractVersionInformation(sourceFile: Path) -> VersionInformation:
436 """
437 Extract double underscored variables from a Python source file, so these can be used for single-sourcing information.
438
439 Supported variables:
440
441 * ``__author__``
442 * ``__copyright__``
443 * ``__email__``
444 * ``__keywords__``
445 * ``__license__``
446 * ``__version__``
447
448 The package's short description is not a dunder variable - it is the first paragraph of the source file's module
449 doc-string, which is where a package already describes itself.
450
451 :param sourceFile: Path to a Python source file as an instance of :class:`Path`.
452 :returns: An instance of :class:`VersionInformation` with gathered variable contents.
453 :raises TypeError: If parameter 'sourceFile' is not of type :class:`~pathlib.Path`.
454 :raises PackagingError: If the given file doesn't exist.
455 :raises PackagingError: If the given file can't be parsed as Python source code.
456 :raises PackagingError: If a dunder variable has an unexpected format.
457 :raises AssertionError: If a dunder variable is missing in the given file.
458 """
...
539
541STATUS: dict[str, str] = {
542 "planning": "1 - Planning",
543 "pre-alpha": "2 - Pre-Alpha",
544 "alpha": "3 - Alpha",
545 "beta": "4 - Beta",
546 "stable": "5 - Production/Stable",
547 "mature": "6 - Mature",
548 "inactive": "7 - Inactive"
549}
550"""
551A dictionary of supported development status values.
552
553The mapping's value will be appended to ``Development Status :: `` to form a package classifier.
554
5551. Planning
5562. Pre-Alpha
5573. Alpha
5584. Beta
5595. Production/Stable
5606. Mature
5617. Inactive
562
563.. seealso::
564
565 `Python package classifiers <https://pypi.org/classifiers/>`__
566"""
567
568DEFAULT_LICENSE = Apache_2_0_License
569"""
570Default license (Apache License, 2.0) used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
571if parameter ``license`` is not assigned.
572"""
573
574DEFAULT_PY_VERSIONS = ("3.11", "3.12", "3.13", "3.14", "3.15")
575"""
576A tuple of supported CPython versions used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
577if parameter ``pythonVersions`` is not assigned.
578
579.. seealso::
580
581 `Status of Python versions <https://devguide.python.org/versions/>`__
582"""
583
584DEFAULT_CLASSIFIERS = (
585 "Operating System :: OS Independent",
586 "Intended Audience :: Developers",
587 "Topic :: Utilities"
588 )
589"""
590A list of Python package classifiers used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
591if parameter ``classifiers`` is not assigned.
592
593.. seealso::
594
595 `Python package classifiers <https://pypi.org/classifiers/>`__
596"""
597
598DEFAULT_README = Path("README.md")
599"""
600Path to the README file used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
601if parameter ``readmeFile`` is not assigned.
602"""
603
604DEFAULT_REQUIREMENTS = Path("requirements.txt")
605"""
606Path to the requirements file used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
607if parameter ``requirementsFile`` is not assigned.
608"""
609
610DEFAULT_DOCUMENTATION_REQUIREMENTS = Path("doc/requirements.txt")
611"""
612Path to the README requirements file used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
613if parameter ``documentationRequirementsFile`` is not assigned.
614"""
615
616DEFAULT_TEST_REQUIREMENTS = Path("tests/requirements.txt")
617"""
618Path to the README requirements file used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
619if parameter ``unittestRequirementsFile`` is not assigned.
620"""
621
622DEFAULT_PACKAGING_REQUIREMENTS = Path("build/requirements.txt")
623"""
624Path to the package requirements file used by :func:`DescribePythonPackage` and :func:`DescribePythonPackageHostedOnGitHub`
625if parameter ``packagingRequirementsFile`` is not assigned.
626"""
627
628DEFAULT_VERSION_FILE = Path("__init__.py")
629
630_DIRECT_REFERENCE_PATTERN = re_compile(r"^\s*[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?\s*(?:\[[^\]]*\])?\s*@")
631
633def _removeDirectReferences(requirements: Iterable[str], extra: str, filePath: Nullable[Path]) -> list[str]:
634 """
635 Remove direct references (``name @ URL``) from the requirements of an extra.
636
637 The Python Package Index rejects a package whose metadata contains a direct reference. Each removed requirement is
638 reported as a :exc:`DirectReferenceWarning` to a :class:`~pyTooling.Warning.WarningCollector`.
639
640 :param requirements: Requirements of the extra.
641 :param extra: Name of the extra.
642 :param filePath: The requirements file the requirements were read from, or ``None`` for
643 parameter 'additionalRequirements'.
644 :returns: The requirements, which aren't direct references.
645 :raises UnhandledCriticalWarningError: If a requirement is a direct reference and no
646 :class:`~pyTooling.Warning.WarningCollector` collects the warning.
647 """
...
665
667def _collectEntryPoints(
668 consoleScripts: Nullable[dict[str, str]],
669 guiScripts: Nullable[dict[str, str]],
670 pytestPlugins: Nullable[dict[str, str]]
671) -> Nullable[dict[str, list[str]]]:
672 """
673 Collect what a package advertises into setuptools' entry point groups.
674
675 Each parameter names one kind of thing a package can offer, so a caller says *what* it provides and this
676 function knows *how* it is declared - which group it belongs to, and setuptools' ``"name = entry.point"``
677 spelling.
678
679 :param consoleScripts: Command line programs, declared as ``console_scripts``.
680 :param guiScripts: Windowed programs, declared as ``gui_scripts``.
681 :param pytestPlugins: Pytest plugins, declared as ``pytest11``.
682 :returns: A dictionary mapping a group to its entry point lines, or ``None`` if a package
683 advertises nothing.
684 """
...
698
700@export
701def DescribePythonPackage(
702 packageName: str,
703 projectURL: str,
704 sourceCodeURL: str,
705 documentationURL: str,
706 issueTrackerCodeURL: str,
707 description: Nullable[str] = None,
708 keywords: Nullable[Iterable[str]] = None,
709 license: License = DEFAULT_LICENSE,
710 readmeFile: Path = DEFAULT_README,
711 requirementsFile: Path = DEFAULT_REQUIREMENTS,
712 documentationRequirementsFile: Path = DEFAULT_DOCUMENTATION_REQUIREMENTS,
713 unittestRequirementsFile: Path = DEFAULT_TEST_REQUIREMENTS,
714 packagingRequirementsFile: Path = DEFAULT_PACKAGING_REQUIREMENTS,
715 additionalRequirements: Nullable[dict[str, list[str]]] = None,
716 sourceFileWithVersion: Nullable[Path] = DEFAULT_VERSION_FILE,
717 classifiers: Iterable[str] = DEFAULT_CLASSIFIERS,
718 developmentStatus: str = "stable",
719 pythonVersions: Sequence[str] = DEFAULT_PY_VERSIONS,
720 consoleScripts: Nullable[dict[str, str]] = None,
721 guiScripts: Nullable[dict[str, str]] = None,
722 pytestPlugins: Nullable[dict[str, str]] = None,
723 dataFiles: Nullable[dict[str, list[str]]] = None,
724 debug: bool = False
725) -> dict[str, Any]:
726 """
727 Helper function to describe a Python package.
728
729 .. hint::
730
731 Some information will be gathered automatically from well-known files.
732
733 Examples: ``README.md``, ``requirements.txt``, ``__init__.py``
734
735 .. topic:: Handling of namespace packages
736
737 If parameter ``packageName`` contains a dot, a namespace package is assumed. Then
738 :func:`setuptools.find_namespace_packages` is used to discover package files. |br|
739 Otherwise, the package is considered a normal package and :func:`setuptools.find_packages` is used.
740
741 In both cases, the following packages (directories) are excluded from search:
742
743 * ``build``, ``build.*``
744 * ``dist``, ``dist.*``
745 * ``doc``, ``doc.*``
746 * ``tests``, ``tests.*``
747
748 .. topic:: Handling of minimal Python version
749
750 The minimal required Python version is selected from parameter ``pythonVersions``.
751
752 .. topic:: Handling of dunder variables
753
754 A Python source file specified by parameter ``sourceFileWithVersion`` will be analyzed with Pythons parser and the
755 resulting AST will be searched for the following dunder variables:
756
757 * ``__author__``: :class:`str`
758 * ``__copyright__``: :class:`str`
759 * ``__email__``: :class:`str`
760 * ``__keywords__``: :class:`typing.Iterable`[:class:`str`]
761 * ``__license__``: :class:`str`
762 * ``__version__``: :class:`str`
763
764 The gathered information be used to add further mappings in the result dictionary.
765
766 .. topic:: Handling of package classifiers
767
768 To reduce redundantly provided parameters to this function (e.g. supported ``pythonVersions``), only additional
769 classifiers should be provided via parameter ``classifiers``. The supported Python versions will be implicitly
770 converted to package classifiers, so no need to specify them in parameter ``classifiers``.
771
772 The following classifiers are implicitly handled:
773
774 license
775 The license specified by parameter ``license`` is translated into a classifier. |br|
776 See also :meth:`pyTooling.Licensing.License.PythonClassifier`
777
778 Python versions
779 Always add ``Programming Language :: Python :: 3 :: Only``. |br|
780 For each value in ``pythonVersions``, one ``Programming Language :: Python :: Major.Minor`` is added.
781
782 Development status
783 The development status specified by parameter ``developmentStatus`` is translated to a classifier and added.
784
785 .. topic:: Handling of extra requirements
786
787 If additional requirement files are provided, e.g. requirements to build the documentation, then *extra*
788 requirements are defined. These can be installed via ``pip install packageName[extraName]``. If so, an extra called
789 ``all`` is added, so developers can install all dependencies needed for package development.
790
791 ``doc``
792 If parameter ``documentationRequirementsFile`` is present, an extra requirements called ``doc`` will be defined.
793 ``test``
794 If parameter ``unittestRequirementsFile`` is present, an extra requirements called ``test`` will be defined.
795 ``build``
796 If parameter ``packagingRequirementsFile`` is present, an extra requirements called ``build`` will be defined.
797 User-defined
798 If parameter ``additionalRequirements`` is present, an extra requirements for every mapping entry in the
799 dictionary will be added.
800 ``all``
801 If any of the above was added, an additional extra requirement called ``all`` will be added, summarizing all
802 extra requirements.
803
804 A requirement with a direct reference (``name @ URL``, e.g. ``pyTooling.Sphinx @ git+https://...@dev``) is left out
805 of every extra, because the Python Package Index rejects a package whose metadata contains one. Each one is
806 reported as a critical :exc:`DirectReferenceWarning` to a :class:`~pyTooling.Warning.WarningCollector`; without
807 a collector up the call-hierarchy, :exc:`~pyTooling.Warning.UnhandledCriticalWarningError` is raised. So a project
808 can name a dependency, which isn't on PyPI yet, by its repository in e.g. ``doc/requirements.txt`` - the
809 documentation build installs it - and still be released, if its :file:`setup.py` collects the warnings. The base
810 requirements (``requirementsFile``) are kept as they are: without one of them, the package wouldn't work.
811
812 .. topic:: Handling of keywords
813
814 If parameter ``keywords`` is not specified, the dunder variable ``__keywords__`` from ``sourceFileWithVersion``
815 will be used. Otherwise, the content of the parameter, if not None or empty.
816
817 .. topic:: Handling of the description
818
819 If parameter ``description`` is not specified, the first paragraph of the module doc-string in
820 ``sourceFileWithVersion`` is used, so a package describes itself in one place. An explicitly passed description
821 always wins - including an empty one.
822
823 :param packageName: Name of the Python package.
824 :param projectURL: URL to the Python project.
825 :param sourceCodeURL: URL to the Python source code.
826 :param documentationURL: URL to the package's documentation.
827 :param issueTrackerCodeURL: URL to the projects issue tracker (ticket system).
828 :param description: Optional, short description of the package. (Default: the first paragraph
829 of the module doc-string in ``sourceFileWithVersion``.) The long description
830 is read from the README file.
831 :param keywords: Optional, a list of keywords.
832 :param license: Optional, the package's license. (Default: ``Apache License, 2.0``, see
833 :const:`DEFAULT_LICENSE`)
834 :param readmeFile: Optional, the path to the README file. (Default: ``README.md``, see
835 :const:`DEFAULT_README`)
836 :param requirementsFile: Optional, the path to the project's requirements file. (Default:
837 ``requirements.txt``, see :const:`DEFAULT_REQUIREMENTS`)
838 :param documentationRequirementsFile: Optional, the path to the project's requirements file for documentation.
839 (Default: ``doc/requirements.txt``, see
840 :const:`DEFAULT_DOCUMENTATION_REQUIREMENTS`)
841 :param unittestRequirementsFile: Optional, the path to the project's requirements file for unit tests. (Default:
842 ``tests/requirements.txt``, see :const:`DEFAULT_TEST_REQUIREMENTS`)
843 :param packagingRequirementsFile: Optional, the path to the project's requirements file for packaging. (Default:
844 ``build/requirements.txt``, see :const:`DEFAULT_PACKAGING_REQUIREMENTS`)
845 :param additionalRequirements: Optional, a dictionary of a lists with additional requirements. (default: None)
846 :param sourceFileWithVersion: Optional, the path to the project's source file containing dunder variables
847 like ``__version__``. (Default: ``__init__.py``, see
848 :const:`DEFAULT_VERSION_FILE`)
849 :param classifiers: Optional, a list of package classifiers. (Default: 3 classifiers, see
850 :const:`DEFAULT_CLASSIFIERS`)
851 :param developmentStatus: Optional, development status of the package. (Default: stable, see
852 :const:`STATUS` for supported status values)
853 :param pythonVersions: Optional, a list of supported Python 3 version. (Default: all currently
854 maintained CPython versions, see :const:`DEFAULT_PY_VERSIONS`)
855 :param consoleScripts: Optional, a dictionary mapping command line names to entry points, declared
856 as ``console_scripts``. (Default: None)
857 :param guiScripts: Optional, like ``consoleScripts``, but declared as ``gui_scripts`` - on
858 Windows such a program starts without a console window. (Default: None)
859 :param pytestPlugins: Optional, a dictionary mapping plugin names to entry points, declared as
860 ``pytest11``. The classifier ``Framework :: Pytest`` is added with it.
861 (Default: None)
862 :param dataFiles: Optional, a dictionary mapping package names to lists of additional data files.
863 :param debug: Optional, if ``True``, enable extended outputs for debugging.
864 :returns: A dictionary suitable for :func:`setuptools.setup`.
865 :raises TypeError: If parameter 'license' is not of type :class:`~pyTooling.Licensing.License`.
866 :raises TypeError: If parameter 'readmeFile' is not of type :class:`~pathlib.Path`.
867 :raises TypeError: If parameter 'requirementsFile' is not of type :class:`~pathlib.Path`.
868 :raises TypeError: If parameter 'documentationRequirementsFile' is not of type
869 :class:`~pathlib.Path`.
870 :raises TypeError: If parameter 'unittestRequirementsFile' is not of type :class:`~pathlib.Path`.
871 :raises TypeError: If parameter 'packagingRequirementsFile' is not of type :class:`~pathlib.Path`.
872 :raises TypeError: If parameter 'sourceFileWithVersion' is not of type :class:`~pathlib.Path`.
873 :raises MissingDependencyError: If package 'setuptools' is not available.
874 :raises FileNotFoundError: If README file doesn't exist.
875 :raises FileNotFoundError: If requirements file doesn't exist.
876 :raises FileNotFoundError: If package file with dunder variables doesn't exist.
877 :raises ValueError: If developmentStatus uses an unsupported value. (See :const:`STATUS`)
878 :raises ValueError: If the content type of the README file is not supported. (See
879 :func:`loadReadmeFile`)
880 :raises FileNotFoundError: If the README file doesn't exist. (See :func:`loadReadmeFile`)
881 :raises FileNotFoundError: If the requirements file doesn't exist. (See :func:`loadRequirementsFile`)
882 :raises Exception: If the package's directory doesn't exist, or if a requirements file is
883 malformed.
884 :raises PackagingError: If no description was given and the package file has no module doc-string.
885 :raises UnhandledCriticalWarningError: If an extra's requirement is a direct reference and no
886 :class:`~pyTooling.Warning.WarningCollector` collects the
887 :exc:`DirectReferenceWarning`.
888 """
...
1037
1038 def _naturalSorting(array: Iterable[str]) -> list[str]:
1039 """
1040 A simple natural sorting implementation.
1041
1042 :param array: The strings to sort.
1043 :returns: The strings, sorted with embedded numbers compared numerically.
1044 """
1046 def _toInt(text: str) -> Union[str, int]:
1047 """
1048 Try to convert a :class:`str` to :class:`int` if possible, otherwise preserve the string.
1049
1050 :param text: The text to convert.
1051 :returns: The converted integer, or the unchanged string.
1052 """
...
1054
1055 def _createKey(text: str) -> tuple[Union[str, float], ...]:
1056 """
1057 Split the text into a tuple of multiple :class:`str` and :class:`int` fields, so embedded numbers can be sorted by
1058 their value.
1059
1060 :param text: The text to split.
1061 :returns: Tuple of string and integer fields, usable as a sort key.
1062 """
...
1064
...
1068
...
1115
1117@export
1118def DescribePythonPackageHostedOnGitHub(
1119 packageName: str,
1120 gitHubNamespace: str,
1121 gitHubRepository: Nullable[str] = None,
1122 projectURL: Nullable[str] = None,
1123 description: Nullable[str] = None,
1124 keywords: Nullable[Iterable[str]] = None,
1125 license: License = DEFAULT_LICENSE,
1126 readmeFile: Path = DEFAULT_README,
1127 requirementsFile: Path = DEFAULT_REQUIREMENTS,
1128 documentationRequirementsFile: Path = DEFAULT_DOCUMENTATION_REQUIREMENTS,
1129 unittestRequirementsFile: Path = DEFAULT_TEST_REQUIREMENTS,
1130 packagingRequirementsFile: Path = DEFAULT_PACKAGING_REQUIREMENTS,
1131 additionalRequirements: Nullable[dict[str, list[str]]] = None,
1132 sourceFileWithVersion: Path = DEFAULT_VERSION_FILE,
1133 classifiers: Iterable[str] = DEFAULT_CLASSIFIERS,
1134 developmentStatus: str = "stable",
1135 pythonVersions: Sequence[str] = DEFAULT_PY_VERSIONS,
1136 consoleScripts: Nullable[dict[str, str]] = None,
1137 guiScripts: Nullable[dict[str, str]] = None,
1138 pytestPlugins: Nullable[dict[str, str]] = None,
1139 dataFiles: Nullable[dict[str, list[str]]] = None,
1140 debug: bool = False
1141) -> dict[str, Any]:
1142 """
1143 Helper function to describe a Python package when the source code is hosted on GitHub.
1144
1145 This is a wrapper for :func:`DescribePythonPackage`, because some parameters can be simplified by knowing the GitHub
1146 namespace and repository name: issue tracker URL, source code URL, ...
1147
1148 :param packageName: Name of the Python package.
1149 :param gitHubNamespace: Name of the GitHub namespace (organization or user).
1150 :param gitHubRepository: Optional, name of the GitHub repository.
1151 :param projectURL: Optional, URL to the Python project.
1152 :param description: Optional, short description of the package. (Default: the first paragraph
1153 of the module doc-string in ``sourceFileWithVersion``.) The long description
1154 is read from the README file.
1155 :param keywords: Optional, a list of keywords.
1156 :param license: Optional, the package's license. (Default: ``Apache License, 2.0``, see
1157 :const:`DEFAULT_LICENSE`)
1158 :param readmeFile: Optional, the path to the README file. (Default: ``README.md``, see
1159 :const:`DEFAULT_README`)
1160 :param requirementsFile: Optional, the path to the project's requirements file. (Default:
1161 ``requirements.txt``, see :const:`DEFAULT_REQUIREMENTS`)
1162 :param documentationRequirementsFile: Optional, the path to the project's requirements file for documentation.
1163 (Default: ``doc/requirements.txt``, see
1164 :const:`DEFAULT_DOCUMENTATION_REQUIREMENTS`)
1165 :param unittestRequirementsFile: Optional, the path to the project's requirements file for unit tests. (Default:
1166 ``tests/requirements.txt``, see :const:`DEFAULT_TEST_REQUIREMENTS`)
1167 :param packagingRequirementsFile: Optional, the path to the project's requirements file for packaging. (Default:
1168 ``build/requirements.txt``, see :const:`DEFAULT_PACKAGING_REQUIREMENTS`)
1169 :param additionalRequirements: Optional, a dictionary of a lists with additional requirements. (default: None)
1170 :param sourceFileWithVersion: Optional, the path to the project's source file containing dunder variables
1171 like ``__version__``. (Default: ``__init__.py``, see
1172 :const:`DEFAULT_VERSION_FILE`)
1173 :param classifiers: Optional, a list of package classifiers. (Default: 3 classifiers, see
1174 :const:`DEFAULT_CLASSIFIERS`)
1175 :param developmentStatus: Optional, development status of the package. (Default: stable, see
1176 :const:`STATUS` for supported status values)
1177 :param pythonVersions: Optional, a list of supported Python 3 version. (Default: all currently
1178 maintained CPython versions, see :const:`DEFAULT_PY_VERSIONS`)
1179 :param consoleScripts: Optional, a dictionary mapping command line names to entry points, declared
1180 as ``console_scripts``. (Default: None)
1181 :param guiScripts: Optional, like ``consoleScripts``, but declared as ``gui_scripts`` - on
1182 Windows such a program starts without a console window. (Default: None)
1183 :param pytestPlugins: Optional, a dictionary mapping plugin names to entry points, declared as
1184 ``pytest11``. The classifier ``Framework :: Pytest`` is added with it.
1185 (Default: None)
1186 :param dataFiles: Optional, a dictionary mapping package names to lists of additional data files.
1187 :param debug: Optional, if ``True``, enable extended outputs for debugging.
1188 :returns: A dictionary suitable for :func:`setuptools.setup`.
1189 :raises TypeError: If parameter 'license' is not of type :class:`~pyTooling.Licensing.License`.
1190 :raises TypeError: If parameter 'readmeFile' is not of type :class:`~pathlib.Path`.
1191 :raises TypeError: If parameter 'requirementsFile' is not of type :class:`~pathlib.Path`.
1192 :raises TypeError: If parameter 'documentationRequirementsFile' is not of type
1193 :class:`~pathlib.Path`.
1194 :raises TypeError: If parameter 'unittestRequirementsFile' is not of type :class:`~pathlib.Path`.
1195 :raises TypeError: If parameter 'packagingRequirementsFile' is not of type :class:`~pathlib.Path`.
1196 :raises TypeError: If parameter 'sourceFileWithVersion' is not of type :class:`~pathlib.Path`.
1197 :raises MissingDependencyError: If package 'setuptools' is not available.
1198 :raises FileNotFoundError: If README file doesn't exist.
1199 :raises FileNotFoundError: If requirements file doesn't exist.
1200 :raises FileNotFoundError: If package file with dunder variables doesn't exist.
1201 :raises ValueError: If developmentStatus uses an unsupported value. (See :const:`STATUS`)
1202 :raises ValueError: If the content type of the README file is not supported. (See
1203 :func:`loadReadmeFile`)
1204 :raises FileNotFoundError: If the README file doesn't exist. (See :func:`loadReadmeFile`)
1205 :raises FileNotFoundError: If the requirements file doesn't exist. (See :func:`loadRequirementsFile`)
1206 :raises PackagingError: If no description was given and the package file has no module doc-string.
1207 :raises UnhandledCriticalWarningError: If an extra's requirement is a direct reference and no
1208 :class:`~pyTooling.Warning.WarningCollector` collects the
1209 :exc:`DirectReferenceWarning`.
1210 """
...