├── .btd.yml
├── .editorconfig
├── .github
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ └── Pipeline.yml
├── .gitignore
├── .idea
├── .name
├── inspectionProfiles
│ └── profiles_settings.xml
├── markdown.xml
├── misc.xml
├── modules.xml
├── pyTooling.TerminalUI.iml
└── vcs.xml
├── .vscode
└── settings.json
├── LICENSE.md
├── README.md
├── dist
└── requirements.txt
├── doc
├── Dependencies.rst
├── Doc-License.rst
├── ILineTerminal.rst
├── Installation.rst
├── License.rst
├── Line.rst
├── LineTerminal.rst
├── Makefile
├── Severity.rst
├── Terminal.rst
├── _extensions
│ ├── DocumentMember.py
│ └── autoapi
│ │ ├── __init__.py
│ │ ├── apinode.py
│ │ └── sphinx.py
├── _static
│ └── .gitempty
├── _templates
│ └── autoapi
│ │ └── module.rst
├── conf.py
├── genindex.rst
├── index.rst
├── make.bat
├── prolog.inc
├── py-modindex.rst
├── requirements.txt
└── shields.inc
├── pyTooling
└── TerminalUI
│ ├── __init__.py
│ └── py.typed
├── pyproject.toml
├── requirements.txt
├── setup.py
└── tests
├── __init__.py
├── requirements.txt
└── unit
├── TerminalUI.py
└── __init__.py
/.btd.yml:
--------------------------------------------------------------------------------
1 | input: doc
2 | output: _build
3 | requirements: requirements.txt
4 | target: gh-pages
5 | formats: [ html ]
6 | images:
7 | base: btdi/sphinx:pytooling
8 | latex: btdi/latex
9 | theme: https://codeload.GitHub.com/buildthedocs/sphinx.theme/tar.gz/v1
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | # end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | indent_style = tab
9 | indent_size = 2
10 | tab_width = 2
11 |
12 |
13 | [*.py]
14 | indent_style = tab
15 | indent_size = 2
16 |
17 | [*.{yml,yaml}]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | [*.{json,ini}]
22 | indent_style = tab
23 | indent_size = 2
24 |
25 | [*.md]
26 | trim_trailing_whitespace = false
27 |
28 | [*.rst]
29 | indent_style = space
30 | indent_size = 3
31 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Maintain Python packages
4 | - package-ecosystem: "pip"
5 | directory: "/"
6 | target-branch: dev
7 | commit-message:
8 | prefix: "[Dependabot]"
9 | labels:
10 | - Dependencies
11 | assignees:
12 | - Paebbels
13 | reviewers:
14 | - Paebbels
15 | schedule:
16 | interval: "daily" # Checks on Monday trough Friday.
17 |
18 | # Maintain GitHub Action runners
19 | - package-ecosystem: "github-actions"
20 | directory: "/"
21 | target-branch: dev
22 | commit-message:
23 | prefix: "[Dependabot]"
24 | labels:
25 | - Dependencies
26 | assignees:
27 | - Paebbels
28 | reviewers:
29 | - Paebbels
30 | schedule:
31 | interval: "weekly"
32 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # New Features
2 | * tbd
3 |
4 | # Changes
5 | * tbd
6 |
7 | # Bug Fixes
8 | * tbd
9 |
--------------------------------------------------------------------------------
/.github/workflows/Pipeline.yml:
--------------------------------------------------------------------------------
1 | name: Pipeline
2 |
3 | on:
4 | push:
5 | workflow_dispatch:
6 |
7 | jobs:
8 |
9 | Params:
10 | uses: pyTooling/Actions/.github/workflows/Parameters.yml@r0
11 | with:
12 | name: pyTooling.TerminalUI
13 |
14 |
15 | UnitTesting:
16 | uses: pyTooling/Actions/.github/workflows/UnitTesting.yml@r0
17 | needs:
18 | - Params
19 | with:
20 | jobs: ${{ needs.Params.outputs.python_jobs }}
21 | artifact: ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}
22 |
23 | Coverage:
24 | uses: pyTooling/Actions/.github/workflows/CoverageCollection.yml@r0
25 | needs:
26 | - Params
27 | with:
28 | python_version: ${{ fromJson(needs.Params.outputs.params).python_version }}
29 | artifact: ${{ fromJson(needs.Params.outputs.params).artifacts.coverage }}
30 | secrets:
31 | codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }}
32 |
33 | StaticTypeCheck:
34 | uses: pyTooling/Actions/.github/workflows/StaticTypeCheck.yml@r0
35 | needs:
36 | - Params
37 | with:
38 | python_version: ${{ fromJson(needs.Params.outputs.params).python_version }}
39 | commands: |
40 | cd pyTooling
41 | mypy --html-report ../htmlmypy -p TerminalUI
42 | report: 'htmlmypy'
43 | artifact: ${{ fromJson(needs.Params.outputs.params).artifacts.typing }}
44 |
45 | PublishTestResults:
46 | uses: pyTooling/Actions/.github/workflows/PublishTestResults.yml@r0
47 | needs:
48 | - UnitTesting
49 |
50 | Package:
51 | uses: pyTooling/Actions/.github/workflows/Package.yml@r0
52 | needs:
53 | - Params
54 | - Coverage
55 | with:
56 | python_version: ${{ fromJson(needs.Params.outputs.params).python_version }}
57 | artifact: ${{ fromJson(needs.Params.outputs.params).artifacts.package }}
58 |
59 | Release:
60 | uses: pyTooling/Actions/.github/workflows/Release.yml@r0
61 | if: startsWith(github.ref, 'refs/tags')
62 | needs:
63 | - UnitTesting
64 | - Coverage
65 | - StaticTypeCheck
66 | - Package
67 |
68 | PublishOnPyPI:
69 | uses: pyTooling/Actions/.github/workflows/PublishOnPyPI.yml@r0
70 | if: startsWith(github.ref, 'refs/tags')
71 | needs:
72 | - Params
73 | - Release
74 | - Package
75 | with:
76 | python_version: ${{ fromJson(needs.Params.outputs.params).python_version }}
77 | requirements: -r dist/requirements.txt
78 | artifact: ${{ fromJson(needs.Params.outputs.params).artifacts.package }}
79 | secrets:
80 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
81 |
82 | # VerifyDocs:
83 | # uses: pyTooling/Actions/.github/workflows/VerifyDocs.yml@r0
84 | # needs:
85 | # - Params
86 | # with:
87 | # python_version: ${{ fromJson(needs.Params.outputs.params).python_version }}
88 |
89 | BuildTheDocs:
90 | uses: pyTooling/Actions/.github/workflows/BuildTheDocs.yml@r0
91 | needs:
92 | - Params
93 | # - VerifyDocs
94 | with:
95 | artifact: ${{ fromJson(needs.Params.outputs.params).artifacts.doc }}
96 |
97 | PublishToGitHubPages:
98 | uses: pyTooling/Actions/.github/workflows/PublishToGitHubPages.yml@r0
99 | needs:
100 | - Params
101 | - BuildTheDocs
102 | - Coverage
103 | - StaticTypeCheck
104 | with:
105 | doc: ${{ fromJson(needs.Params.outputs.params).artifacts.doc }}
106 | coverage: ${{ fromJson(needs.Params.outputs.params).artifacts.coverage }}
107 | typing: ${{ fromJson(needs.Params.outputs.params).artifacts.typing }}
108 |
109 | ArtifactCleanUp:
110 | uses: pyTooling/Actions/.github/workflows/ArtifactCleanUp.yml@r0
111 | needs:
112 | - Params
113 | - UnitTesting
114 | - Coverage
115 | - StaticTypeCheck
116 | - BuildTheDocs
117 | - PublishToGitHubPages
118 | - PublishTestResults
119 | with:
120 | package: ${{ fromJson(needs.Params.outputs.params).artifacts.package }}
121 | remaining: |
122 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-ubuntu-3.7
123 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-ubuntu-3.8
124 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-ubuntu-3.9
125 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-ubuntu-3.10
126 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-windows-3.7
127 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-windows-3.8
128 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-windows-3.9
129 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-windows-3.10
130 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-msys2-3.9
131 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-macos-3.7
132 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-macos-3.8
133 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-macos-3.9
134 | ${{ fromJson(needs.Params.outputs.params).artifacts.unittesting }}-macos-3.10
135 | ${{ fromJson(needs.Params.outputs.params).artifacts.coverage }}
136 | ${{ fromJson(needs.Params.outputs.params).artifacts.typing }}
137 | ${{ fromJson(needs.Params.outputs.params).artifacts.doc }}
138 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python cache and object files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # Coverage.py
6 | .coverage
7 | .cov
8 | coverage.xml
9 |
10 | # setuptools
11 | /build/**/*.*
12 | /dist/**/*.*
13 | /*.egg-info
14 |
15 | # Dependencies
16 | !requirements.txt
17 |
18 | # Sphinx
19 | doc/_build/
20 | doc/pyTooling.TerminalUI/**/*.*
21 | !doc/pyTooling.TerminalUI/index.rst
22 |
23 | # BuildTheDocs
24 | doc/_theme/**/*.*
25 |
26 | # IntelliJ project files
27 | /.idea/workspace.xml
28 |
29 | # Git files
30 | !.git*
31 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | pyTooling.TerminalUI
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/markdown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/pyTooling.TerminalUI.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.trimTrailingWhitespace": false,
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | This is a local copy of the Apache License Version 2.0.
2 | The original can be obtained here: [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
3 |
4 | --------------------------------------------------------------------------------
5 |
6 | # Apache License
7 |
8 | Version 2.0, January 2004
9 |
10 | ## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
11 |
12 | ### 1. Definitions.
13 |
14 | *"License"* shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
15 |
16 | *"Licensor"* shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
17 |
18 | *"Legal Entity"* shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
19 |
20 | *"You"* (or *"Your"*) shall mean an individual or Legal Entity exercising permissions granted by this License.
21 |
22 | *"Source"* form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
23 |
24 | *"Object"* form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
25 |
26 | *"Work"* shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
27 |
28 | *"Derivative Works"* shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
29 |
30 | *"Contribution"* shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, *"submitted"* means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as *"Not a Contribution."*
31 |
32 | *"Contributor"* shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
33 |
34 | ### 2. Grant of Copyright License.
35 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
36 |
37 | ### 3. Grant of Patent License.
38 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
39 |
40 | ### 4. Redistribution.
41 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
42 |
43 | - You must give any other recipients of the Work or Derivative Works a copy of this License; and
44 | - You must cause any modified files to carry prominent notices stating that You changed the files; and
45 | - You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
46 | - If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
47 |
48 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
49 |
50 | ### 5. Submission of Contributions.
51 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
52 |
53 | ### 6. Trademarks.
54 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
55 |
56 | ### 7. Disclaimer of Warranty.
57 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
58 |
59 | ### 8. Limitation of Liability.
60 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
61 |
62 | ### 9. Accepting Warranty or Additional Liability.
63 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
64 |
65 |
66 | ## Appendix: How to apply the Apache License to your work
67 |
68 | To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
69 |
70 | Copyright [yyyy] [name of copyright owner]
71 |
72 | Licensed under the Apache License, Version 2.0 (the "License");
73 | you may not use this file except in compliance with the License.
74 | You may obtain a copy of the License at
75 |
76 | http://www.apache.org/licenses/LICENSE-2.0
77 |
78 | Unless required by applicable law or agreed to in writing, software
79 | distributed under the License is distributed on an "AS IS" BASIS,
80 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
81 | See the License for the specific language governing permissions and
82 | limitations under the License.
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://GitHub.com/pyTooling/pyTooling.TerminalUI)
2 | [](LICENSE.md)
3 | [](https://GitHub.com/pyTooling/pyTooling.TerminalUI/tags)
4 | [](https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases/latest)
5 | [](https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases)
6 | [](https://GitHub.com/pyTooling/pyTooling.TerminalUI/network/dependents)
7 | [](https://GitHub.com/pyTooling/pyTooling.TerminalUI/actions/workflows/Pipeline.yml)
8 | [](https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI)
9 | [](https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI)
10 | [](https://codecov.io/gh/pyTooling/pyTooling.TerminalUI)
11 | [](https://libraries.io/github/pyTooling/pyTooling.TerminalUI/sourcerank)
12 | [](https://pypi.org/project/pyTooling.TerminalUI/)
13 | 
14 | 
15 | [](https://libraries.io/github/pyTooling/pyTooling.TerminalUI)
16 | [](https://requires.io/github/pyTooling/pyTooling.TerminalUI/requirements/?branch=main)
17 | [](doc/Doc-License.rst)
18 | [](https://pyTooling.GitHub.io/pyTooling.TerminalUI)
19 |
20 | # pyTooling.TerminalUI
21 |
22 | A set of helpers to implement a text user interface (TUI) in a terminal.
23 |
24 | ## Features
25 | * Colored command line outputs based on colorama
26 | * Message classification in fatal, error, warning, normal, quiet, ...
27 | * Get information like terminal dimensions from underlying terminal window
28 |
29 |
30 | ## Simple Terminal Application
31 |
32 | This is a minimal terminal application example which inherits from `LineTerminal`.
33 |
34 | ```python
35 | from pyTooling.TerminalUI import LineTerminal
36 |
37 | class Application(LineTerminal):
38 | def __init__(self):
39 | super().__init__(verbose=True, debug=True, quiet=False)
40 |
41 | def run(self):
42 | self.WriteNormal("This is a simple application.")
43 | self.WriteWarning("This is a warning message.")
44 | self.WriteError("This is an error message.")
45 |
46 | # entry point
47 | if __name__ == "__main__":
48 | Application.versionCheck((3, 6, 0))
49 | app = Application()
50 | app.run()
51 | app.exit()
52 | ```
53 |
54 | ## Complex Terminal Application
55 |
56 | This example hands over the terminal instance to a submodule, which implements
57 | `ILineTerminal`, so the submodule can also use the terminal's writing methods.
58 |
59 | ```python
60 | from pathlib import Path
61 | from pyTooling.TerminalUI import LineTerminal, ILineTerminal
62 |
63 | class SubModule(ILineTerminal):
64 | def __init__(self, configFile: Path, terminal):
65 | super().__init__(terminal)
66 |
67 | if not configFile.exists():
68 | self.WriteError(f"Config file '{configFile}' not found.")
69 |
70 |
71 | class Application(LineTerminal):
72 | def __init__(self):
73 | super().__init__(verbose=True, debug=True, quiet=False)
74 |
75 | mod = SubModule(Path("config.yml"), self)
76 |
77 | def run(self):
78 | pass
79 |
80 | # entry point
81 | if __name__ == "__main__":
82 | app = Application()
83 | app.run()
84 | ```
85 |
86 |
87 | ## Contributors
88 |
89 | * [Patrick Lehmann](https://GitHub.com/Paebbels) (Maintainer)
90 | * [and more...](https://GitHub.com/pyTooling/pyTooling.TerminalUI/graphs/contributors)
91 |
92 |
93 | ## License
94 |
95 | This Python package (source code) licensed under [Apache License 2.0](LICENSE.md).
96 | The accompanying documentation is licensed under [Creative Commons - Attribution 4.0 (CC-BY 4.0)](doc/Doc-License.rst).
97 |
98 |
99 | -------------------------
100 |
101 | SPDX-License-Identifier: Apache-2.0
102 |
--------------------------------------------------------------------------------
/dist/requirements.txt:
--------------------------------------------------------------------------------
1 | wheel
2 | twine
3 |
--------------------------------------------------------------------------------
/doc/Dependencies.rst:
--------------------------------------------------------------------------------
1 | .. _dependency:
2 |
3 | Dependencies
4 | ############
5 |
6 | .. |img-TerminalUI-lib-status| image:: https://img.shields.io/librariesio/release/pypi/pyTooling.TerminalUI
7 | :alt: Libraries.io status for latest release
8 | :height: 22
9 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI
10 | .. |img-TerminalUI-req-status| image:: https://img.shields.io/requires/github/pyTooling/pyTooling.TerminalUI
11 | :alt: Requires.io
12 | :height: 22
13 | :target: https://requires.io/github/pyTooling/pyTooling.TerminalUI/requirements/?branch=main
14 |
15 | +------------------------------------------+------------------------------------------+
16 | | `Libraries.io `_ | `Requires.io `_ |
17 | +==========================================+==========================================+
18 | | |img-TerminalUI-lib-status| | |img-TerminalUI-req-status| |
19 | +------------------------------------------+------------------------------------------+
20 |
21 | .. _dependency-package:
22 |
23 | pyTooling.TerminalUI Package (Mandatory)
24 | ****************************************
25 |
26 | .. rubric:: Manually Installing Package Requirements
27 |
28 | Use the :file:`requirements.txt` file to install all dependencies via ``pip3`` or install the package directly from
29 | PyPI (see :ref:`installation`).
30 |
31 | .. code-block:: shell
32 |
33 | pip3 install -U -r requirements.txt
34 |
35 |
36 | .. rubric:: Dependency List
37 |
38 | +----------------------------------------------------------+-------------+-------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
39 | | **Package** | **Version** | **License** | **Dependencies** |
40 | +==========================================================+=============+===========================================================================================+=================================================================================================================================+
41 | | `colorama `__ | ≥0.4.5 | `BSD-3-Clause `__ | None |
42 | +----------------------------------------------------------+-------------+-------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
43 | | `pyTooling `__ | ≥2.1.0 | `Apache License, 2.0 `__ | *None* |
44 | +----------------------------------------------------------+-------------+-------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
45 |
46 |
47 |
48 | .. _dependency-testing:
49 |
50 | Unit Testing / Coverage / Type Checking (Optional)
51 | **************************************************
52 |
53 | Additional Python packages needed for testing, code coverage collection and static type checking. These packages are
54 | only needed for developers or on a CI server, thus sub-dependencies are not evaluated further.
55 |
56 |
57 | .. rubric:: Manually Installing Test Requirements
58 |
59 | Use the :file:`tests/requirements.txt` file to install all dependencies via ``pip3``. The file will recursively install
60 | the mandatory dependencies too.
61 |
62 | .. code-block:: shell
63 |
64 | pip3 install -U -r tests/requirements.txt
65 |
66 |
67 | .. rubric:: Dependency List
68 |
69 | +-----------------------------------------------------------+-------------+----------------------------------------------------------------------------------------+----------------------+
70 | | **Package** | **Version** | **License** | **Dependencies** |
71 | +===========================================================+=============+========================================================================================+======================+
72 | | `pytest `__ | ≥7.1.1 | `MIT `__ | *Not yet evaluated.* |
73 | +-----------------------------------------------------------+-------------+----------------------------------------------------------------------------------------+----------------------+
74 | | `pytest-cov `__ | ≥3.0.0 | `MIT `__ | *Not yet evaluated.* |
75 | +-----------------------------------------------------------+-------------+----------------------------------------------------------------------------------------+----------------------+
76 | | `Coverage `__ | ≥6.3 | `Apache License, 2.0 `__ | *Not yet evaluated.* |
77 | +-----------------------------------------------------------+-------------+----------------------------------------------------------------------------------------+----------------------+
78 | | `mypy `__ | ≥0.931 | `MIT `__ | *Not yet evaluated.* |
79 | +-----------------------------------------------------------+-------------+----------------------------------------------------------------------------------------+----------------------+
80 | | `lxml `__ | ≥4.8 | `BSD 3-Clause `__ | *Not yet evaluated.* |
81 | +-----------------------------------------------------------+-------------+----------------------------------------------------------------------------------------+----------------------+
82 |
83 |
84 | .. _dependency-documentation:
85 |
86 | Sphinx Documentation (Optional)
87 | *******************************
88 |
89 | Additional Python packages needed for documentation generation. These packages are only needed for developers or on a
90 | CI server, thus sub-dependencies are not evaluated further.
91 |
92 |
93 | .. rubric:: Manually Installing Documentation Requirements
94 |
95 | Use the :file:`doc/requirements.txt` file to install all dependencies via ``pip3``. The file will recursively install
96 | the mandatory dependencies too.
97 |
98 | .. code-block:: shell
99 |
100 | pip3 install -U -r doc/requirements.txt
101 |
102 |
103 | .. rubric:: Dependency List
104 |
105 | +-------------------------------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+----------------------+
106 | | **Package** | **Version** | **License** | **Dependencies** |
107 | +=================================================================================================+==============+==========================================================================================================+======================+
108 | | `Sphinx `__ | ≥4.5.0 | `BSD 3-Clause `__ | *Not yet evaluated.* |
109 | +-------------------------------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+----------------------+
110 | | `sphinx_btd_theme `__ | ≥0.5.2 | `MIT `__ | *Not yet evaluated.* |
111 | +-------------------------------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+----------------------+
112 | | !! `sphinx_fontawesome `__ | ≥0.0.6 | `GPL 2.0 `__ | *Not yet evaluated.* |
113 | +-------------------------------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+----------------------+
114 | | `sphinx_autodoc_typehints `__ | ≥1.18.1 | `MIT `__ | *Not yet evaluated.* |
115 | +-------------------------------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+----------------------+
116 |
117 |
118 | .. _dependency-packaging:
119 |
120 | Packaging (Optional)
121 | ********************
122 |
123 | Additional Python packages needed for installation package generation. These packages are only needed for developers or
124 | on a CI server, thus sub-dependencies are not evaluated further.
125 |
126 |
127 | .. rubric:: Manually Installing Packaging Requirements
128 |
129 | Use the :file:`build/requirements.txt` file to install all dependencies via ``pip3``. The file will recursively
130 | install the mandatory dependencies too.
131 |
132 | .. code-block:: shell
133 |
134 | pip3 install -U -r build/requirements.txt
135 |
136 |
137 | .. rubric:: Dependency List
138 |
139 | +----------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
140 | | **Package** | **Version** | **License** | **Dependencies** |
141 | +============================================================================+==============+==========================================================================================================+======================================================================================================================================================+
142 | | `pyTooling `__ | ≥2.1.0 | `Apache License, 2.0 `__ | *None* |
143 | +----------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
144 | | `wheel `__ | any | `MIT `__ | *Not yet evaluated.* |
145 | +----------------------------------------------------------------------------+--------------+----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
146 |
147 |
148 | .. _dependency-publishing:
149 |
150 | Publishing (CI-Server only)
151 | ***************************
152 |
153 | Additional Python packages needed for publishing the generated installation package to e.g, PyPI or any equivalent
154 | services. These packages are only needed for maintainers or on a CI server, thus sub-dependencies are not evaluated
155 | further.
156 |
157 |
158 | .. rubric:: Manually Installing Publishing Requirements
159 |
160 | Use the :file:`dist/requirements.txt` file to install all dependencies via ``pip3``. The file will recursively
161 | install the mandatory dependencies too.
162 |
163 | .. code-block:: shell
164 |
165 | pip3 install -U -r dist/requirements.txt
166 |
167 |
168 | .. rubric:: Dependency List
169 |
170 | +----------------------------------------------------------+--------------+-------------------------------------------------------------------------------------------+----------------------+
171 | | **Package** | **Version** | **License** | **Dependencies** |
172 | +==========================================================+==============+===========================================================================================+======================+
173 | | `wheel `__ | any | `MIT `__ | *Not yet evaluated.* |
174 | +----------------------------------------------------------+--------------+-------------------------------------------------------------------------------------------+----------------------+
175 | | `Twine `__ | any | `Apache License, 2.0 `__ | *Not yet evaluated.* |
176 | +----------------------------------------------------------+--------------+-------------------------------------------------------------------------------------------+----------------------+
177 |
--------------------------------------------------------------------------------
/doc/Doc-License.rst:
--------------------------------------------------------------------------------
1 | .. _DOCLICENSE:
2 |
3 | .. Note:: This is a local copy of the `Creative Commons - Attribution 4.0 International (CC BY 4.0) `__.
4 |
5 | .. Attention:: This **CC BY 4.0** license applies only to the **documentation** of this project.
6 |
7 |
8 | Creative Commons Attribution 4.0 International
9 | ##############################################
10 |
11 | Creative Commons Corporation (“Creative Commons”) is not a law firm and does not
12 | provide legal services or legal advice. Distribution of Creative Commons public
13 | licenses does not create a lawyer-client or other relationship. Creative Commons
14 | makes its licenses and related information available on an “as-is” basis.
15 | Creative Commons gives no warranties regarding its licenses, any material
16 | licensed under their terms and conditions, or any related information. Creative
17 | Commons disclaims all liability for damages resulting from their use to the
18 | fullest extent possible.
19 |
20 | .. topic:: Using Creative Commons Public Licenses
21 |
22 | Creative Commons public licenses provide a standard set of terms and conditions
23 | that creators and other rights holders may use to share original works of
24 | authorship and other material subject to copyright and certain other rights
25 | specified in the public license below. The following considerations are for
26 | informational purposes only, are not exhaustive, and do not form part of our
27 | licenses.
28 |
29 | * **Considerations for licensors:** Our public licenses are intended for use
30 | by those authorized to give the public permission to use material in ways
31 | otherwise restricted by copyright and certain other rights. Our licenses are
32 | irrevocable. Licensors should read and understand the terms and conditions
33 | of the license they choose before applying it. Licensors should also secure
34 | all rights necessary before applying our licenses so that the public can reuse
35 | the material as expected. Licensors should clearly mark any material not
36 | subject to the license. This includes other CC-licensed material, or material
37 | used under an exception or limitation to copyright.
38 | `More considerations for licensors `__.
39 |
40 | * **Considerations for the public:** By using one of our public licenses, a
41 | licensor grants the public permission to use the licensed material under
42 | specified terms and conditions. If the licensor’s permission is not necessary
43 | for any reason–for example, because of any applicable exception or limitation
44 | to copyright–then that use is not regulated by the license. Our licenses grant
45 | only permissions under copyright and certain other rights that a licensor has
46 | authority to grant. Use of the licensed material may still be restricted for
47 | other reasons, including because others have copyright or other rights in the
48 | material. A licensor may make special requests, such as asking that all
49 | changes be marked or described. Although not required by our licenses, you are
50 | encouraged to respect those requests where reasonable.
51 | `More considerations for the public `__.
52 |
53 | :xlarge:`Creative Commons Attribution 4.0 International Public License`
54 |
55 | By exercising the Licensed Rights (defined below), You accept and agree to be
56 | bound by the terms and conditions of this Creative Commons Attribution 4.0
57 | International Public License ("Public License"). To the extent this Public
58 | License may be interpreted as a contract, You are granted the Licensed Rights
59 | in consideration of Your acceptance of these terms and conditions, and the
60 | Licensor grants You such rights in consideration of benefits the Licensor
61 | receives from making the Licensed Material available under these terms and
62 | conditions.
63 |
64 | Section 1 – Definitions.
65 | ========================
66 |
67 | a. **Adapted Material** means material subject to Copyright and Similar
68 | Rights that is derived from or based upon the Licensed Material and in
69 | which the Licensed Material is translated, altered, arranged, transformed, or
70 | otherwise modified in a manner requiring permission under the Copyright and
71 | Similar Rights held by the Licensor. For purposes of this Public License,
72 | where the Licensed Material is a musical work, performance, or sound
73 | recording, Adapted Material is always produced where the Licensed Material
74 | is synched in timed relation with a moving image.
75 |
76 | b. **Adapter's License** means the license You apply to Your Copyright and
77 | Similar Rights in Your contributions to Adapted Material in accordance with
78 | the terms and conditions of this Public License.
79 |
80 | c. **Copyright and Similar Rights** means copyright and/or similar rights
81 | closely related to copyright including, without limitation, performance,
82 | broadcast, sound recording, and Sui Generis Database Rights, without regard
83 | to how the rights are labeled or categorized. For purposes of this Public
84 | License, the rights specified in Section 2(b)(1)-(2) are not Copyright and
85 | Similar Rights.
86 |
87 | d. **Effective Technological Measures** means those measures that, in the
88 | absence of proper authority, may not be circumvented under laws fulfilling
89 | obligations under Article 11 of the WIPO Copyright Treaty adopted on
90 | December 20, 1996, and/or similar international agreements.
91 |
92 | e. **Exceptions and Limitations** means fair use, fair dealing, and/or any
93 | other exception or limitation to Copyright and Similar Rights that applies to
94 | Your use of the Licensed Material.
95 |
96 | f. **Licensed Material** means the artistic or literary work, database, or
97 | other material to which the Licensor applied this Public License.
98 |
99 | g. **Licensed Rights** means the rights granted to You subject to the terms
100 | and conditions of this Public License, which are limited to all Copyright and
101 | Similar Rights that apply to Your use of the Licensed Material and that the
102 | Licensor has authority to license.
103 |
104 | h. **Licensor** means the individual(s) or entity(ies) granting rights under
105 | this Public License.
106 |
107 | i. **Share** means to provide material to the public by any means or process
108 | that requires permission under the Licensed Rights, such as reproduction,
109 | public display, public performance, distribution, dissemination,
110 | communication, or importation, and to make material available to the public
111 | including in ways that members of the public may access the material from a
112 | place and at a time individually chosen by them.
113 |
114 | j. **Sui Generis Database Rights** means rights other than copyright
115 | resulting from Directive 96/9/EC of the European Parliament and of the
116 | Council of 11 March 1996 on the legal protection of databases, as amended
117 | and/or succeeded, as well as other essentially equivalent rights anywhere
118 | in the world.
119 |
120 | k. **You** means the individual or entity exercising the Licensed Rights
121 | under this Public License. **Your** has a corresponding meaning.
122 |
123 | Section 2 – Scope.
124 | ==================
125 |
126 | a. **License grant.**
127 |
128 | 1. Subject to the terms and conditions of this Public License, the Licensor
129 | hereby grants You a worldwide, royalty-free, non-sublicensable,
130 | non-exclusive, irrevocable license to exercise the Licensed Rights in the
131 | Licensed Material to:
132 |
133 | A. reproduce and Share the Licensed Material, in whole or in part; and
134 |
135 | B. produce, reproduce, and Share Adapted Material.
136 |
137 | 2. :underline:`Exceptions and Limitations.` For the avoidance of doubt, where
138 | Exceptions and Limitations apply to Your use, this Public License does not
139 | apply, and You do not need to comply with its terms and conditions.
140 |
141 | 3. :underline:`Term.` The term of this Public License is specified in Section 6(a).
142 |
143 | 4. :underline:`Media and formats`; :underline:`technical modifications allowed.` The Licensor
144 | authorizes You to exercise the Licensed Rights in all media and formats
145 | whether now known or hereafter created, and to make technical
146 | modifications necessary to do so. The Licensor waives and/or agrees not to
147 | assert any right or authority to forbid You from making technical
148 | modifications necessary to exercise the Licensed Rights, including
149 | technical modifications necessary to circumvent Effective Technological
150 | Measures. For purposes of this Public License, simply making modifications
151 | authorized by this Section 2(a)(4) never produces Adapted Material.
152 |
153 | 5. :underline:`Downstream recipients.`
154 |
155 | A. :underline:`Offer from the Licensor – Licensed Material.` Every recipient of
156 | the Licensed Material automatically receives an offer from the
157 | Licensor to exercise the Licensed Rights under the terms and
158 | conditions of this Public License.
159 |
160 | B. :underline:`No downstream restrictions.` You may not offer or impose any
161 | additional or different terms or conditions on, or apply any Effective
162 | Technological Measures to, the Licensed Material if doing so restricts
163 | exercise of the Licensed Rights by any recipient of the Licensed
164 | Material.
165 |
166 | 6. :underline:`No endorsement.` Nothing in this Public License constitutes or may
167 | be construed as permission to assert or imply that You are, or that Your
168 | use of the Licensed Material is, connected with, or sponsored, endorsed,
169 | or granted official status by, the Licensor or others designated to
170 | receive attribution as provided in Section 3(a)(1)(A)(i).
171 |
172 | b. **Other rights.**
173 |
174 | 1. Moral rights, such as the right of integrity, are not licensed under this
175 | Public License, nor are publicity, privacy, and/or other similar
176 | personality rights; however, to the extent possible, the Licensor waives
177 | and/or agrees not to assert any such rights held by the Licensor to the
178 | limited extent necessary to allow You to exercise the Licensed Rights, but
179 | not otherwise.
180 |
181 | 2. Patent and trademark rights are not licensed under this Public License.
182 |
183 | 3. To the extent possible, the Licensor waives any right to collect royalties
184 | from You for the exercise of the Licensed Rights, whether directly or
185 | through a collecting society under any voluntary or waivable statutory or
186 | compulsory licensing scheme. In all other cases the Licensor expressly
187 | reserves any right to collect such royalties.
188 |
189 | Section 3 – License Conditions.
190 | ===============================
191 |
192 | Your exercise of the Licensed Rights is expressly made subject to the following conditions.
193 |
194 | a. **Attribution.**
195 |
196 | 1. If You Share the Licensed Material (including in modified form), You must:
197 |
198 | A. retain the following if it is supplied by the Licensor with the
199 | Licensed Material:
200 |
201 | i. identification of the creator(s) of the Licensed Material and any
202 | others designated to receive attribution, in any reasonable manner
203 | requested by the Licensor (including by pseudonym if designated);
204 |
205 | ii. a copyright notice;
206 |
207 | iii. a notice that refers to this Public License;
208 |
209 | iv. a notice that refers to the disclaimer of warranties;
210 |
211 | v. a URI or hyperlink to the Licensed Material to the extent reasonably
212 | practicable;
213 |
214 | B. indicate if You modified the Licensed Material and retain an
215 | indication of any previous modifications; and
216 |
217 | C. indicate the Licensed Material is licensed under this Public License,
218 | and include the text of, or the URI or hyperlink to, this Public
219 | License.
220 |
221 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
222 | based on the medium, means, and context in which You Share the Licensed
223 | Material. For example, it may be reasonable to satisfy the conditions by
224 | providing a URI or hyperlink to a resource that includes the required
225 | information.
226 |
227 | 3. If requested by the Licensor, You must remove any of the information
228 | required by Section 3(a)(1)(A) to the extent reasonably practicable.
229 |
230 | 4. If You Share Adapted Material You produce, the Adapter's License You apply
231 | must not prevent recipients of the Adapted Material from complying with
232 | this Public License.
233 |
234 | Section 4 – Sui Generis Database Rights.
235 | ========================================
236 |
237 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your
238 | use of the Licensed Material:
239 |
240 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
241 | reuse, reproduce, and Share all or a substantial portion of the contents of
242 | the database;
243 |
244 | b. if You include all or a substantial portion of the database contents in a
245 | database in which You have Sui Generis Database Rights, then the database
246 | in which You have Sui Generis Database Rights (but not its individual
247 | contents) is Adapted Material; and
248 |
249 | c. You must comply with the conditions in Section 3(a) if You Share all or a
250 | substantial portion of the contents of the database.
251 |
252 | For the avoidance of doubt, this Section 4 supplements and does not replace
253 | Your obligations under this Public License where the Licensed Rights include
254 | other Copyright and Similar Rights.
255 |
256 | Section 5 – Disclaimer of Warranties and Limitation of Liability.
257 | =================================================================
258 |
259 | a. **Unless otherwise separately undertaken by the Licensor, to the extent
260 | possible, the Licensor offers the Licensed Material as-is and as-available,
261 | and makes no representations or warranties of any kind concerning the
262 | Licensed Material, whether express, implied, statutory, or other. This
263 | includes, without limitation, warranties of title, merchantability,
264 | fitness for a particular purpose, non-infringement, absence of latent or
265 | other defects, accuracy, or the presence or absence of errors, whether or
266 | not known or discoverable. Where disclaimers of warranties are not allowed
267 | in full or in part, this disclaimer may not apply to You.**
268 |
269 | b. **To the extent possible, in no event will the Licensor be liable to You
270 | on any legal theory (including, without limitation, negligence) or
271 | otherwise for any direct, special, indirect, incidental, consequential,
272 | punitive, exemplary, or other losses, costs, expenses, or damages arising
273 | out of this Public License or use of the Licensed Material, even if the
274 | Licensor has been advised of the possibility of such losses, costs, expenses,
275 | or damages. Where a limitation of liability is not allowed in full or in
276 | part, this limitation may not apply to You.**
277 |
278 | c. The disclaimer of warranties and limitation of liability provided above
279 | shall be interpreted in a manner that, to the extent possible, most
280 | closely approximates an absolute disclaimer and waiver of all liability.
281 |
282 | Section 6 – Term and Termination.
283 | =================================
284 |
285 | a. This Public License applies for the term of the Copyright and Similar Rights
286 | licensed here. However, if You fail to comply with this Public License, then
287 | Your rights under this Public License terminate automatically.
288 |
289 | b. Where Your right to use the Licensed Material has terminated under
290 | Section 6(a), it reinstates:
291 |
292 | 1. automatically as of the date the violation is cured, provided it is cured
293 | within 30 days of Your discovery of the violation; or
294 |
295 | 2. upon express reinstatement by the Licensor.
296 |
297 | For the avoidance of doubt, this Section 6(b) does not affect any right the
298 | Licensor may have to seek remedies for Your violations of this Public License.
299 |
300 | c. For the avoidance of doubt, the Licensor may also offer the Licensed Material
301 | under separate terms or conditions or stop distributing the Licensed Material
302 | at any time; however, doing so will not terminate this Public License.
303 |
304 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
305 |
306 | Section 7 – Other Terms and Conditions.
307 | =======================================
308 |
309 | a. The Licensor shall not be bound by any additional or different terms or
310 | conditions communicated by You unless expressly agreed.
311 |
312 | b. Any arrangements, understandings, or agreements regarding the Licensed
313 | Material not stated herein are separate from and independent of the terms
314 | and conditions of this Public License.
315 |
316 | Section 8 – Interpretation.
317 | ===========================
318 |
319 | a. For the avoidance of doubt, this Public License does not, and shall not be
320 | interpreted to, reduce, limit, restrict, or impose conditions on any use of
321 | the Licensed Material that could lawfully be made without permission under
322 | this Public License.
323 |
324 | b. To the extent possible, if any provision of this Public License is deemed
325 | unenforceable, it shall be automatically reformed to the minimum extent
326 | necessary to make it enforceable. If the provision cannot be reformed, it
327 | shall be severed from this Public License without affecting the
328 | enforceability of the remaining terms and conditions.
329 |
330 | c. No term or condition of this Public License will be waived and no failure to
331 | comply consented to unless expressly agreed to by the Licensor.
332 |
333 | d. Nothing in this Public License constitutes or may be interpreted as a
334 | limitation upon, or waiver of, any privileges and immunities that apply to
335 | the Licensor or You, including from the legal processes of any jurisdiction
336 | or authority.
337 |
338 | ------------------
339 |
340 | Creative Commons is not a party to its public licenses. Notwithstanding,
341 | Creative Commons may elect to apply one of its public licenses to material it
342 | publishes and in those instances will be considered the “Licensor.” Except for
343 | the limited purpose of indicating that material is shared under a Creative
344 | Commons public license or as otherwise permitted by the Creative Commons
345 | policies published at `creativecommons.org/policies `__,
346 | Creative Commons does not authorize the use of the trademark “Creative Commons”
347 | or any other trademark or logo of Creative Commons without its prior written
348 | consent including, without limitation, in connection with any unauthorized
349 | modifications to any of its public licenses or any other arrangements,
350 | understandings, or agreements concerning use of licensed material. For the
351 | avoidance of doubt, this paragraph does not form part of the public licenses.
352 |
353 | Creative Commons may be contacted at `creativecommons.org `__
354 |
--------------------------------------------------------------------------------
/doc/ILineTerminal.rst:
--------------------------------------------------------------------------------
1 | ILineTerminal
2 | #############
3 |
4 | .. autoclass:: pyTooling.TerminalUI.ILineTerminal
5 | :members:
6 | :private-members:
7 |
--------------------------------------------------------------------------------
/doc/Installation.rst:
--------------------------------------------------------------------------------
1 | Installation/Updates
2 | ####################
3 |
4 | Using PIP
5 | *********
6 |
7 | Installation using PIP
8 | ======================
9 |
10 | .. code-block:: bash
11 |
12 | pip3 install pyTooling.TerminalUI
13 |
14 |
15 | Updating using PIP
16 | ==================
17 |
18 | .. code-block:: bash
19 |
20 | pip3 install -U pyTooling.TerminalUI
21 |
--------------------------------------------------------------------------------
/doc/License.rst:
--------------------------------------------------------------------------------
1 | .. Note:: This is a local copy of the `Apache License Version 2.0 `_.
2 |
3 | Apache License 2.0
4 | ##################
5 |
6 | Version 2.0, January 2004
7 |
8 | **TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION**
9 |
10 |
11 | 1. Definitions.
12 | ===============
13 | **"License"** shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
14 |
15 | **"Licensor"** shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
16 |
17 | **"Legal Entity"** shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that
18 | entity. For the purposes of this definition, **"control"** means (i) the power, direct or indirect, to cause the direction or management of such entity, whether
19 | by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
20 |
21 | **"You"** (or **"Your"**) shall mean an individual or Legal Entity exercising permissions granted by this License.
22 |
23 | **"Source"** form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and
24 | configuration files.
25 |
26 | **"Object"** form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object
27 | code, generated documentation, and conversions to other media types.
28 |
29 | **"Work"** shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is
30 | included in or attached to the work (an example is provided in the Appendix below).
31 |
32 | **"Derivative Works"** shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions,
33 | annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works
34 | shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
35 |
36 | **"Contribution"** shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative
37 | Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to
38 | submit on behalf of the copyright owner. For the purposes of this definition, **"submitted"** means any form of electronic, verbal, or written communication
39 | sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue
40 | tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is
41 | conspicuously marked or otherwise designated in writing by the copyright owner as **"Not a Contribution."**
42 |
43 | **"Contributor"** shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently
44 | incorporated within the Work.
45 |
46 | 2. Grant of Copyright License.
47 | ==============================
48 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
49 | irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such
50 | Derivative Works in Source or Object form.
51 |
52 | 3. Grant of Patent License.
53 | ===========================
54 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
55 | irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such
56 | license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of
57 | their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim
58 | or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then
59 | any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
60 |
61 | 4. Redistribution.
62 | ==================
63 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form,
64 | provided that You meet the following conditions:
65 |
66 | * You must give any other recipients of the Work or Derivative Works a copy of this License; and
67 | * You must cause any modified files to carry prominent notices stating that You changed the files; and
68 | * You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source
69 | form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
70 | * If the Work includes a **"NOTICE"** text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the
71 | attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the
72 | following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the
73 | Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE
74 | file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute,
75 | alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
76 |
77 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or
78 | distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise
79 | complies with the conditions stated in this License.
80 |
81 | 5. Submission of Contributions.
82 | ===============================
83 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and
84 | conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any
85 | separate license agreement you may have executed with Licensor regarding such Contributions.
86 |
87 | 6. Trademarks.
88 | ==============
89 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable
90 | and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
91 |
92 | 7. Disclaimer of Warranty.
93 | ==========================
94 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
95 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
96 | MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and
97 | assume any risks associated with Your exercise of permissions under this License.
98 |
99 | 8. Limitation of Liability.
100 | ===========================
101 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate
102 | and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or
103 | consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages
104 | for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been
105 | advised of the possibility of such damages.
106 |
107 | 9. Accepting Warranty or Additional Liability.
108 | ==============================================
109 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other
110 | liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole
111 | responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability
112 | incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
113 |
114 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------
115 |
116 | **Appendix: How to apply the Apache License to your work**
117 |
118 | To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying
119 | information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or
120 | class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
121 |
122 | .. code-block:: none
123 |
124 | Copyright [yyyy] [name of copyright owner]
125 |
126 | Licensed under the Apache License, Version 2.0 (the "License");
127 | you may not use this file except in compliance with the License.
128 | You may obtain a copy of the License at
129 |
130 | http://www.apache.org/licenses/LICENSE-2.0
131 |
132 | Unless required by applicable law or agreed to in writing, software
133 | distributed under the License is distributed on an "AS IS" BASIS,
134 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135 | See the License for the specific language governing permissions and
136 | limitations under the License.
137 |
--------------------------------------------------------------------------------
/doc/Line.rst:
--------------------------------------------------------------------------------
1 | Line
2 | ####
3 |
4 | ``Line`` represents a single line in a line-based terminal application. If a
5 | line is visible, depends on the :class:`~pyTooling.TerminalUI.Severity`-level of a
6 | ``Line`` object.
7 |
8 | .. autoclass:: pyTooling.TerminalUI.Line
9 | :show-inheritance:
10 | :members:
11 | :private-members:
12 |
--------------------------------------------------------------------------------
/doc/LineTerminal.rst:
--------------------------------------------------------------------------------
1 | LineTerminal
2 | ############
3 |
4 | .. inheritance-diagram:: pyTooling.TerminalUI.LineTerminal
5 | :parts: 1
6 |
7 | .. autoclass:: pyTooling.TerminalUI.LineTerminal
8 | :show-inheritance:
9 | :members:
10 | :private-members:
11 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/doc/Severity.rst:
--------------------------------------------------------------------------------
1 | Severity
2 | ########
3 |
4 | .. autoclass:: pyTooling.TerminalUI.Severity
5 | :show-inheritance:
6 | :members:
7 | :private-members:
8 |
--------------------------------------------------------------------------------
/doc/Terminal.rst:
--------------------------------------------------------------------------------
1 | Terminal
2 | ********
3 |
4 | .. autoclass:: pyTooling.TerminalUI.Terminal
5 | :show-inheritance:
6 | :members:
7 | :private-members:
8 |
--------------------------------------------------------------------------------
/doc/_extensions/DocumentMember.py:
--------------------------------------------------------------------------------
1 | # ==============================================================================
2 | # Authors: Patrick Lehmann
3 | #
4 | # Python Module:
5 | #
6 | # Description:
7 | # ------------------------------------
8 | # - TODO
9 | #
10 | # License:
11 | # ==============================================================================
12 | # Copyright 2007-2016 Patrick Lehmann - Dresden, Germany
13 | #
14 | # Licensed under the Apache License, Version 2.0 (the "License");
15 | # you may not use this file except in compliance with the License.
16 | # You may obtain a copy of the License at
17 | #
18 | # http://www.apache.org/licenses/LICENSE-2.0
19 | #
20 | # Unless required by applicable law or agreed to in writing, software
21 | # distributed under the License is distributed on an "AS IS" BASIS,
22 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 | # See the License for the specific language governing permissions and
24 | # limitations under the License.
25 | # ==============================================================================
26 | #
27 | from SphinxExtensions import DocumentMemberAttribute
28 |
29 |
30 | def skip_member_handler(app, what, name, obj, skip, options):
31 | # try:
32 | # print("skip_member_handler: ", obj)
33 | # except:
34 | # print("skip_member_handler: ERROR")
35 |
36 | try:
37 | attributes = DocumentMemberAttribute.GetAttributes(obj)
38 | if (len(attributes) > 0):
39 | # print("*#"*20)
40 | # try:
41 | # print("skip_member_handler: ", obj)
42 | # except:
43 | # print("skip_member_handler: ERROR")
44 |
45 | return not attributes[0].value
46 | except:
47 | pass
48 | return None
49 |
50 | def setup(app):
51 | app.connect('autodoc-skip-member', skip_member_handler)
52 |
--------------------------------------------------------------------------------
/doc/_extensions/autoapi/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Copyright (C) 2015 Carlos Jenkins
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | from __future__ import unicode_literals, absolute_import
19 | from __future__ import print_function, division
20 |
21 | from .apinode import __doc__, APINode # noqa
22 |
23 | __author__ = 'Carlos Jenkins'
24 | __email__ = 'carlos@jenkins.co.cr'
25 | __version__ = '1.3.1'
26 |
27 | __all__ = ['APINode']
28 |
--------------------------------------------------------------------------------
/doc/_extensions/autoapi/apinode.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Copyright (C) 2015 Carlos Jenkins
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | """
19 | Module that provides the module tree node :class:`APINode`.
20 |
21 | This class will load the module identified by ``name`` and recursively build a
22 | tree with all it's submodules and subpackages. In the process, each node
23 | analyze and fetch the public API of that module.
24 |
25 | ``name`` can be any node, like the root package, or any subpackage or submodule
26 | and a tree will be built from there. ``name`` must follow the standard
27 | "dot notation" for importing a module.
28 |
29 | This class will not assume any special naming, or perform any complex analysis
30 | to determine what must be in the public interface. This is because it is not
31 | only a difficult problem, but it involves analyzing deeply the namespace of the
32 | module which can be quite expensive.
33 |
34 | In general it is very difficult to determine in a module namespace what
35 | elements are private or public declared locally, private or public but declared
36 | in another module and brought into the module local namespace
37 | (``from x import y``), third party library, Python standard library, etc. At
38 | the end, any algorithm that tries to determine this will eventually fail to
39 | meet the requirements or expectations of the developer, leaving false positives
40 | or removing elements expected to be present in the public API.
41 |
42 | For example, a common scenario is that some modules, specially package entry
43 | points ``__init__.py``, can be setup to expose the public API of their sibling
44 | modules, possible causing several objects to be identified as part of the
45 | public API of both modules.
46 |
47 | Because of this the approach taken by this module follows the rule in PEP20
48 | "Explicit is better than implicit". In consequence, the node will consider
49 | elements as public if they are explicitly listed in the ``__api__`` or
50 | ``__all__`` variables. It is up to the developer to list the elements that must
51 | be published in the public API.
52 |
53 | ``__api__`` is a special variable introduced by this module, and it exists for
54 | situation were for whatever reason the developer don't want to list in the
55 | ``__all__`` variable an element that needs to be published in the public API.
56 |
57 | This class will extract all elements identified in ONE of those listings (not
58 | the union), with ``__api__`` having the precedence. If none of those variables
59 | exists in the module then it will be assumed that no public API exists for that
60 | module and no futher actions will be taken.
61 |
62 | If any of those variables exists this class will iterate all elements listed in
63 | them and will catalog them in four categories:
64 |
65 | - Functions.
66 | - Exceptions.
67 | - Classes.
68 | - Variables.
69 |
70 | Being Variables the default if it cannot be determined that an element belongs
71 | to any of other categories.
72 | """
73 |
74 | from __future__ import unicode_literals, absolute_import
75 | from __future__ import print_function, division
76 |
77 | from logging import getLogger
78 | from traceback import format_exc
79 | from importlib import import_module
80 | from pkgutil import iter_modules
81 | from inspect import isclass, isfunction
82 | from collections import OrderedDict
83 |
84 |
85 | log = getLogger(__name__)
86 |
87 |
88 | class APINode(object):
89 | """
90 | Tree node class for module instrospection.
91 |
92 | :param str name: Name of the module to build the tree from. It must follow
93 | the "dot notation" of the import mechanism.
94 | :param dict directory: Directory to store the index of all the modules.
95 | If None, the default, the root node will create one a pass it to the
96 | subnodes.
97 |
98 | **Attributes:**
99 |
100 | :var name: Name of the current module.
101 | :var subname: Last part of the name of this module. For example if name is
102 | ``my.module.another`` the subname will be ``another``.
103 | :var directory: Directory of the tree. This is a :py:class:`OrderedDict`
104 | that will register all modules name with it's associated node
105 | :class:`APINode`. All nodes of a tree share this index and thus
106 | the whole tree can be queried from any node.
107 | :var module: The loaded module.
108 | :var subnodes: A list of :class:`APINode` with all child submodules
109 | and subpackages.
110 | :var subnodes_failed: A list of submodules and subpackages names that
111 | failed to import.
112 |
113 | **Public API categories:**
114 |
115 | :var functions: A :py:class:`OrderedDict` of all functions found in the
116 | public API of the module.
117 | :var classes: A :py:class:`OrderedDict` of all classes found in the
118 | public API of the module.
119 | :var exceptions: A :py:class:`OrderedDict` of all exceptions found in the
120 | public API of the module.
121 | :var variables: A :py:class:`OrderedDict` of all other elements found in
122 | the public API of the module.
123 |
124 | In all categories the order on which the elements are listed is preserved.
125 | """
126 |
127 | def __init__(self, name, directory=None):
128 | self.module = import_module(name)
129 | self.name = name
130 | self.subname = name.split('.')[-1]
131 |
132 | self.functions = OrderedDict()
133 | self.classes = OrderedDict()
134 | self.exceptions = OrderedDict()
135 | self.variables = OrderedDict()
136 | self.api = OrderedDict((
137 | ('functions', self.functions),
138 | ('classes', self.classes),
139 | ('exceptions', self.exceptions),
140 | ('variables', self.variables),
141 | ))
142 |
143 | self.subnodes = []
144 | self.subnodes_failed = []
145 |
146 | self.directory = OrderedDict()
147 | if directory is not None:
148 | self.directory = directory
149 |
150 | self._relevant = None
151 |
152 | # Now that all node public attributes exists and module was imported
153 | # register itself in the directory
154 | self.directory[self.name] = self
155 |
156 | # Check if package and iterate over subnodes
157 | if hasattr(self.module, '__path__'):
158 | for _, subname, ispkg in iter_modules(
159 | self.module.__path__, self.module.__name__ + '.'):
160 | log.info('Recursing into {}'.format(subname))
161 |
162 | try:
163 | subnode = APINode(subname, self.directory)
164 | self.subnodes.append(subnode)
165 | except: # Overbroad exception handling on purpose
166 | log.error('Failed to import {}'.format(subname))
167 | log.debug(format_exc())
168 | self.subnodes_failed.append(subname)
169 |
170 | # Fetch all public objects
171 | public = OrderedDict()
172 | for public_key in ['__api__', '__all__']:
173 | if not hasattr(self.module, public_key):
174 | continue
175 |
176 | for obj_name in getattr(self.module, public_key):
177 | if not hasattr(self.module, obj_name):
178 | log.warning(
179 | 'Module {} doesn\'t have a element {}'.format(
180 | self.name, obj_name
181 | )
182 | )
183 | continue
184 | public[obj_name] = getattr(self.module, obj_name)
185 | break
186 |
187 | # Categorize objects
188 | for obj_name, obj in public.items():
189 | if isclass(obj):
190 | if issubclass(obj, Exception):
191 | self.exceptions[obj_name] = obj
192 | continue
193 | self.classes[obj_name] = obj
194 | continue
195 | if isfunction(obj):
196 | self.functions[obj_name] = obj
197 | continue
198 | self.variables[obj_name] = obj
199 |
200 | # Flag to mark if this branch is relevant
201 | # For self._relevant, None means undertermined
202 | if self.is_root():
203 | self.is_relevant()
204 |
205 | def has_public_api(self):
206 | """
207 | Check if this node has a public API.
208 |
209 | :rtype: bool
210 | :return: True if any category has at least one element.
211 | """
212 | return any(self.api.values())
213 |
214 | def is_leaf(self):
215 | """
216 | Check if the current node is a leaf in the tree.
217 |
218 | A leaf node not necessarily is a module, it can be a package without
219 | modules (just the entry point ``__init__.py``).
220 |
221 | :rtype: bool
222 | :return: True if no other subnodes exists for this node.
223 | """
224 | return not self.subnodes
225 |
226 | def is_root(self):
227 | """
228 | Check if the current node is the root node.
229 |
230 | :rtype: bool
231 | :return: True if the current node is the root node.
232 | """
233 | for key in self.directory.keys():
234 | return key == self.name
235 | raise Exception('Empty directory!')
236 |
237 | def is_relevant(self):
238 | """
239 | Check if this branch of the tree is relevant.
240 |
241 | A branch is relevant if the current node has a public API or if any of
242 | its subnodes is relevant (in order to reach relevant nodes).
243 |
244 | Relevancy is determined at initialization by the root node.
245 |
246 | :rtype: bool
247 | :return: True if the current node is relevant.
248 | """
249 | if self._relevant is not None:
250 | return self._relevant
251 |
252 | relevant = False
253 | if self.has_public_api() or \
254 | any(s.is_relevant() for s in self.subnodes):
255 | relevant = True
256 |
257 | self._relevant = relevant
258 |
259 | return self._relevant
260 |
261 | def depth(self):
262 | """
263 | Get the depth of the current node in the tree.
264 |
265 | :rtype: int
266 | :return: The depth of the node. For example, for node ``my.add.foo``
267 | the depth is 3.
268 | """
269 | return len(self.name.split('.'))
270 |
271 | def get_module(self, name):
272 | """
273 | Get a module node by it's name.
274 |
275 | This is just a helper that does lookup on the directory index.
276 |
277 | :rtype: :class:`APINode` or None
278 | :return: The module node identified by ``name`` in the tree. ``None``
279 | if the name doesn't exists.
280 | """
281 | return self.directory.get(name, None)
282 |
283 | def walk(self):
284 | """
285 | Traverse the tree top-down.
286 |
287 | :return: This method will yield tuples ``(node, [leaves])`` for each
288 | node in the tree.
289 | """
290 | if self.is_leaf():
291 | raise StopIteration()
292 |
293 | yield (self, [n for n in self.subnodes if n.is_leaf()])
294 |
295 | for subnode in [n for n in self.subnodes if not n.is_leaf()]:
296 | for step in subnode.walk():
297 | yield step
298 |
299 | def __iter__(self):
300 | return self.walk
301 |
302 | def tree(self, level=0, fullname=True):
303 | """
304 | Pretty print the subtree at the current node.
305 |
306 | For example, for the module ``confspec``:
307 |
308 | ::
309 |
310 | confspec
311 | confspec.manager [c]
312 | confspec.options [c]
313 | confspec.providers [c, v]
314 | confspec.providers.dict [c]
315 | confspec.providers.ini [c]
316 | confspec.providers.json [c]
317 | confspec.utils [f]
318 | confspec.validation [f]
319 |
320 | The tags at the right of the name shows what kind of elements are
321 | present in the public interfaces of those modules.
322 |
323 | :param int level: Indentation level.
324 | :param bool fullname: Plot the full name of the module or just it's
325 | subname.
326 | """
327 | name = [(' ' * level)]
328 | if fullname:
329 | name.append(self.name)
330 | else:
331 | name.append(self.subname)
332 |
333 | tags = []
334 | for tag, category in zip(['f', 'c', 'e', 'v'], self.api.values()):
335 | if category:
336 | tags.append(tag)
337 | if tags:
338 | name.append(' [{}]'.format(', '.join(tags)))
339 |
340 | output = [''.join(name)]
341 | for subnode in self.subnodes:
342 | output.append(subnode.tree(level=level + 1, fullname=fullname))
343 | return '\n'.join(output)
344 |
345 | def __str__(self):
346 | return self.tree()
347 |
348 | def __repr__(self):
349 | return self.name
350 |
351 |
352 | __all__ = ['APINode']
353 | __api__ = []
354 |
--------------------------------------------------------------------------------
/doc/_extensions/autoapi/sphinx.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Copyright (C) 2015 Carlos Jenkins
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | """
19 | Glue for Sphinx API.
20 | """
21 |
22 | from __future__ import unicode_literals, absolute_import
23 | from __future__ import print_function, division
24 |
25 | from inspect import getdoc
26 | from logging import getLogger
27 | from traceback import format_exc
28 | from os.path import join, dirname, abspath, exists
29 | from os import environ
30 |
31 | from jinja2.sandbox import SandboxedEnvironment
32 | from sphinx.util.osutil import ensuredir
33 | from sphinx.jinja2glue import BuiltinTemplateLoader
34 |
35 | from . import __version__
36 | from .apinode import APINode
37 |
38 |
39 | log = getLogger(__name__)
40 |
41 |
42 | def handle_exception(func):
43 | """
44 | Utility decorator to report all exceptions in module without making Sphinx
45 | to die.
46 | """
47 | def wrapper(app):
48 | try:
49 | func(app)
50 | except Exception:
51 | app.warn(
52 | 'Unhandled exception in autoapi module: \n{}'.format(
53 | format_exc()
54 | )
55 | )
56 |
57 | # Preserve docstring
58 | if hasattr(func, '__doc__'):
59 | wrapper.__doc__ = func.__doc__
60 |
61 | return wrapper
62 |
63 |
64 | def filter_summary(obj):
65 | """
66 | Jinja2 filter that allows to extract the documentation summary of an
67 | object.
68 | """
69 | try:
70 | doc = getdoc(obj)
71 | if doc is None:
72 | return 'Undocumented.'
73 |
74 | summary = doc.split('\n').pop(0)
75 | summary.replace('\\', '\\\\') # Escape backslash in RST
76 | return summary
77 | except:
78 | log.error(
79 | 'AutoApi failed to determine autosummary for obj: {}'.format(obj)
80 | )
81 | log.error(format_exc())
82 |
83 | return 'AutoApi: Unable to determine summary.'
84 |
85 |
86 | def get_template_env(app):
87 | """
88 | Get the template environment.
89 |
90 | .. note::
91 |
92 | Template should be loaded as a package_data using
93 | :py:function:`pkgutil.get_data`, but because we want the user to
94 | override the default template we need to hook it to the Sphinx loader,
95 | and thus a file system approach is required as it is implemented like
96 | that.
97 | """
98 | template_dir = [join(dirname(abspath(__file__)), 'templates')]
99 | template_loader = BuiltinTemplateLoader()
100 | template_loader.init(app.builder, dirs=template_dir)
101 | template_env = SandboxedEnvironment(loader=template_loader)
102 | template_env.filters['summary'] = filter_summary
103 | return template_env
104 |
105 |
106 | @handle_exception
107 | def builder_inited(app):
108 | """
109 | autoapi Sphinx extension hook for the ``builder-inited`` event.
110 |
111 | This hook will read the configuration value ``autoapi_modules`` and render
112 | the modules described in it.
113 |
114 | See http://sphinx-doc.org/extdev/appapi.html#event-builder-inited
115 | """
116 | # Get modules to build documentation for
117 | modules = app.config.autoapi_modules
118 | if not modules:
119 | return
120 |
121 | # Overwrite all files in an ReadTheDocs environment when the first builder runs (pickle)
122 | overrideDefault = True
123 | if (environ.get('READTHEDOCS') == "True"):
124 | #if (app.buildername != "pickle"):
125 | overrideDefault = False
126 |
127 | # Get template environment
128 | template_env = get_template_env(app)
129 |
130 | print("===============================")
131 | print("overrideDefault set to: {0!s}".format(overrideDefault))
132 | print("===============================")
133 |
134 | for module, overrides in modules.items():
135 |
136 | # Get options
137 | options = {
138 | 'prune': False,
139 | 'override': overrideDefault,
140 | 'template': 'module',
141 | 'output': module
142 | }
143 | if overrides:
144 | options.update(overrides)
145 |
146 | # Get template
147 | template = template_env.get_template(
148 | 'autoapi/{}.rst'.format(options['template'])
149 | )
150 |
151 | # Build API tree
152 | tree = APINode(module)
153 |
154 | # Gather nodes to document
155 | if options['prune']:
156 | nodes = [
157 | node for node in tree.directory.values()
158 | if node.is_relevant()
159 | ]
160 | else:
161 | nodes = tree.directory.values()
162 |
163 | if not nodes:
164 | continue
165 |
166 | # Define output directory
167 | out_dir = join(app.env.srcdir, options['output'])
168 | ensuredir(out_dir)
169 |
170 | # Iterate nodes and render them
171 | for node in nodes:
172 | out_file = join(out_dir, node.name + app.config.source_suffix[0])
173 |
174 | # Skip file if it override is off and it exists
175 | if not options['override'] and exists(out_file):
176 | continue
177 |
178 | # Consider only subnodes that are relevant if prune is enabled
179 | subnodes = node.subnodes
180 | if options['prune']:
181 | subnodes = [
182 | subnode for subnode in node.subnodes
183 | if subnode.is_relevant()
184 | ]
185 |
186 | # Write file
187 | with open(out_file, 'w') as fd:
188 | fd.write(
189 | template.render(
190 | node=node,
191 | subnodes=subnodes
192 | )
193 | )
194 |
195 |
196 | def setup(app):
197 | """
198 | autoapi Sphinx extension setup.
199 |
200 | See http://sphinx-doc.org/extdev/tutorial.html#the-setup-function
201 | """
202 | # autodoc is required
203 | app.setup_extension('sphinx.ext.autodoc')
204 | app.add_config_value('autoapi_modules', {}, True)
205 | app.connect(str('builder-inited'), builder_inited)
206 | return {'version': __version__}
207 |
208 |
209 | __all__ = ['builder_inited', 'setup']
210 |
--------------------------------------------------------------------------------
/doc/_static/.gitempty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyTooling/pyTooling.TerminalUI/6a01c78dcbc6ac9a51cf67a79d18b89484a2547b/doc/_static/.gitempty
--------------------------------------------------------------------------------
/doc/_templates/autoapi/module.rst:
--------------------------------------------------------------------------------
1 | .. # Template modified by Patrick Lehmann
2 | * removed automodule on top, because private members are activated for autodoc (no doubled documentation).
3 | * Made sections like 'submodules' bold text, but no headlines to reduce number of ToC levels.
4 |
5 | =={{ '=' * node.name|length }}==
6 | ``{{ node.name }}``
7 | =={{ '=' * node.name|length }}==
8 |
9 | .. py:module:: {{ node.name }}
10 |
11 | {##}
12 | {%- block modules -%}
13 | {%- if subnodes %}
14 |
15 | **Submodules**
16 |
17 |
18 | .. toctree::
19 | {% for item in subnodes %}
20 | {{ item.name }}
21 | {%- endfor %}
22 | {##}
23 | {%- endif -%}
24 | {%- endblock -%}
25 | {##}
26 | .. currentmodule:: {{ node.name }}
27 | {##}
28 | {%- block functions -%}
29 | {%- if node.functions %}
30 |
31 | **Functions**
32 |
33 | {% for item, obj in node.functions.items() -%}
34 | - :py:func:`{{ item }}`:
35 | {{ obj|summary }}
36 |
37 | {% endfor -%}
38 |
39 | {% for item in node.functions %}
40 | .. autofunction:: {{ item }}
41 | {##}
42 | {%- endfor -%}
43 | {%- endif -%}
44 | {%- endblock -%}
45 |
46 | {%- block classes -%}
47 | {%- if node.classes %}
48 |
49 | **Classes**
50 |
51 | {% for item, obj in node.classes.items() -%}
52 | - :py:class:`{{ item }}`:
53 | {{ obj|summary }}
54 |
55 | {% endfor -%}
56 |
57 | {% for item in node.classes %}
58 | .. autoclass:: {{ item }}
59 | :members:
60 |
61 | .. rubric:: Inheritance
62 | .. inheritance-diagram:: {{ item }}
63 | :parts: 1
64 | {##}
65 | {%- endfor -%}
66 | {%- endif -%}
67 | {%- endblock -%}
68 |
69 | {%- block exceptions -%}
70 | {%- if node.exceptions %}
71 |
72 | **Exceptions**
73 |
74 | {% for item, obj in node.exceptions.items() -%}
75 | - :py:exc:`{{ item }}`:
76 | {{ obj|summary }}
77 |
78 | {% endfor -%}
79 |
80 | {% for item in node.exceptions %}
81 | .. autoexception:: {{ item }}
82 |
83 | .. rubric:: Inheritance
84 | .. inheritance-diagram:: {{ item }}
85 | :parts: 1
86 | {##}
87 | {%- endfor -%}
88 | {%- endif -%}
89 | {%- endblock -%}
90 |
91 | {%- block variables -%}
92 | {%- if node.variables %}
93 |
94 | **Variables**
95 |
96 | {% for item, obj in node.variables.items() -%}
97 | - :py:data:`{{ item }}`
98 | {% endfor -%}
99 |
100 | {% for item, obj in node.variables.items() %}
101 | .. autodata:: {{ item }}
102 | :annotation:
103 |
104 | .. code-block:: text
105 |
106 | {{ obj|pprint|indent(6) }}
107 | {##}
108 | {%- endfor -%}
109 | {%- endif -%}
110 | {%- endblock -%}
111 |
--------------------------------------------------------------------------------
/doc/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | from json import loads
14 | from os.path import abspath
15 | from pathlib import Path
16 | from sys import path as sys_path
17 |
18 | from pyTooling.Packaging import extractVersionInformation
19 |
20 | sys_path.insert(0, abspath('.'))
21 | sys_path.insert(0, abspath('..'))
22 | sys_path.insert(0, abspath('../pyTooling.TerminalUI'))
23 | sys_path.insert(0, abspath('_extensions'))
24 | #sys_path.insert(0, os.path.abspath('_themes/sphinx_rtd_theme'))
25 |
26 |
27 | # ==============================================================================
28 | # Project information and versioning
29 | # ==============================================================================
30 | # The version info for the project you're documenting, acts as replacement for
31 | # |version| and |release|, also used in various other places throughout the
32 | # built documents.
33 | project = "pyTooling.TerminalUI"
34 |
35 | packageInformationFile = Path(f"../{project.replace('.', '/')}/__init__.py")
36 | versionInformation = extractVersionInformation(packageInformationFile)
37 |
38 | author = versionInformation.Author
39 | copyright = versionInformation.Copyright
40 | version = ".".join(versionInformation.Version.split(".")[:2]) # e.g. 2.3 The short X.Y version.
41 | release = versionInformation.Version
42 |
43 |
44 | # ==============================================================================
45 | # Miscellaneous settings
46 | # ==============================================================================
47 | # The master toctree document.
48 | master_doc = 'index'
49 |
50 | # Add any paths that contain templates here, relative to this directory.
51 | templates_path = ['_templates']
52 |
53 | # List of patterns, relative to source directory, that match files and
54 | # directories to ignore when looking for source files.
55 | # This pattern also affects html_static_path and html_extra_path.
56 | exclude_patterns = [
57 | "_build",
58 | "_themes",
59 | "Thumbs.db",
60 | ".DS_Store"
61 | ]
62 |
63 | # The name of the Pygments (syntax highlighting) style to use.
64 | pygments_style = 'stata-dark'
65 |
66 |
67 | # ==============================================================================
68 | # Restructured Text settings
69 | # ==============================================================================
70 | prologPath = "prolog.inc"
71 | try:
72 | with open(prologPath, "r") as prologFile:
73 | rst_prolog = prologFile.read()
74 | except Exception as ex:
75 | print(f"[ERROR:] While reading '{prologPath}'.")
76 | print(ex)
77 | rst_prolog = ""
78 |
79 |
80 | # ==============================================================================
81 | # Options for HTML output
82 | # ==============================================================================
83 | html_theme_options = {
84 | 'home_breadcrumbs': True,
85 | 'vcs_pageview_mode': 'blob',
86 | }
87 |
88 | html_context = {}
89 | ctx = Path(__file__).resolve().parent / 'context.json'
90 | if ctx.is_file():
91 | html_context.update(loads(ctx.open('r').read()))
92 |
93 | html_theme_path = ["."]
94 | html_theme = "_theme"
95 |
96 | # Add any paths that contain custom static files (such as style sheets) here,
97 | # relative to this directory. They are copied after the builtin static files,
98 | # so a file named "default.css" will overwrite the builtin "default.css".
99 | html_static_path = ['_static']
100 |
101 | # Output file base name for HTML help builder.
102 | htmlhelp_basename = 'pyToolingDoc'
103 |
104 | # If not None, a 'Last updated on:' timestamp is inserted at every page
105 | # bottom, using the given strftime format.
106 | # The empty string is equivalent to '%b %d, %Y'.
107 | html_last_updated_fmt = "%d.%m.%Y"
108 |
109 |
110 | # ==============================================================================
111 | # Options for LaTeX / PDF output
112 | # ==============================================================================
113 | from textwrap import dedent
114 |
115 | latex_elements = {
116 | # The paper size ('letterpaper' or 'a4paper').
117 | 'papersize': 'a4paper',
118 |
119 | # The font size ('10pt', '11pt' or '12pt').
120 | #'pointsize': '10pt',
121 |
122 | # Additional stuff for the LaTeX preamble.
123 | 'preamble': dedent(r"""
124 | % ================================================================================
125 | % User defined additional preamble code
126 | % ================================================================================
127 | % Add more Unicode characters for pdfLaTeX.
128 | % - Alternatively, compile with XeLaTeX or LuaLaTeX.
129 | % - https://GitHub.com/sphinx-doc/sphinx/issues/3511
130 | %
131 | \ifdefined\DeclareUnicodeCharacter
132 | \DeclareUnicodeCharacter{2265}{$\geq$}
133 | \DeclareUnicodeCharacter{21D2}{$\Rightarrow$}
134 | \fi
135 |
136 |
137 | % ================================================================================
138 | """),
139 |
140 | # Latex figure (float) alignment
141 | #'figure_align': 'htbp',
142 | }
143 |
144 | # Grouping the document tree into LaTeX files. List of tuples
145 | # (source start file, target name, title,
146 | # author, documentclass [howto, manual, or own class]).
147 | latex_documents = [
148 | ( master_doc,
149 | 'pyTooling.TerminalUI.tex',
150 | 'The pyTooling.TerminalUI Documentation',
151 | 'Patrick Lehmann',
152 | 'manual'
153 | ),
154 | ]
155 |
156 |
157 |
158 | # ==============================================================================
159 | # Extensions
160 | # ==============================================================================
161 | extensions = [
162 | # Standard Sphinx extensions
163 | "sphinx.ext.autodoc",
164 | 'sphinx.ext.extlinks',
165 | 'sphinx.ext.intersphinx',
166 | 'sphinx.ext.inheritance_diagram',
167 | 'sphinx.ext.todo',
168 | 'sphinx.ext.graphviz',
169 | 'sphinx.ext.mathjax',
170 | 'sphinx.ext.ifconfig',
171 | 'sphinx.ext.viewcode',
172 | # 'sphinx.ext.duration',
173 |
174 | # SphinxContrib extensions
175 | # 'sphinxcontrib.actdiag',
176 | 'sphinxcontrib.mermaid',
177 | # 'sphinxcontrib.seqdiag',
178 | # 'sphinxcontrib.textstyle',
179 | # 'sphinxcontrib.spelling',
180 | # 'changelog',
181 |
182 | # BuildTheDocs extensions
183 | # 'btd.sphinx.autoprogram',
184 | # 'btd.sphinx.graphviz',
185 | # 'btd.sphinx.inheritance_diagram',
186 |
187 | # Other extensions
188 | # 'DocumentMember',
189 | 'sphinx_fontawesome',
190 | 'sphinx_autodoc_typehints',
191 |
192 | # local extensions (patched)
193 | # 'autoapi.sphinx',
194 |
195 | # local extensions
196 | # 'DocumentMember'
197 | ]
198 |
199 | # ==============================================================================
200 | # Sphinx.Ext.InterSphinx
201 | # ==============================================================================
202 | intersphinx_mapping = {
203 | 'python': ('https://docs.python.org/3', None),
204 | 'pyTooling': ('http://pyTooling.GitHub.io/pyTooling', None),
205 | }
206 |
207 |
208 | # ==============================================================================
209 | # Sphinx.Ext.AutoDoc
210 | # ==============================================================================
211 | # see: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#configuration
212 | autodoc_member_order = "bysource" # alphabetical, groupwise, bysource
213 |
214 |
215 | # ==============================================================================
216 | # Sphinx.Ext.ExtLinks
217 | # ==============================================================================
218 | extlinks = {
219 | "gh": ("https://GitHub.com/%s", "gh:"),
220 | "ghissue": ('https://GitHub.com/pyTooling/pyTooling.TerminalUI/issues/%s', 'issue #'),
221 | "ghpull": ('https://GitHub.com/pyTooling/pyTooling.TerminalUI/pull/%s', 'pull request #'),
222 | "ghsrc": ('https://GitHub.com/pyTooling/pyTooling.TerminalUI/blob/main/pyTooling/%s?ts=2', None),
223 | # "ghtest": ('https://GitHub.com/pyTooling/pyTooling.TerminalUI/blob/main/test/%s?ts=2', None)
224 | }
225 |
226 |
227 | # ==============================================================================
228 | # Sphinx.Ext.Graphviz
229 | # ==============================================================================
230 | graphviz_output_format = "svg"
231 |
232 |
233 |
234 | # ==============================================================================
235 | # Sphinx.Ext.ToDo
236 | # ==============================================================================
237 | # If true, `todo` and `todoList` produce output, else they produce nothing.
238 | todo_include_todos = True
239 | todo_link_only = True
240 |
241 |
242 |
243 | # ==============================================================================
244 | # AutoAPI.Sphinx
245 | # ==============================================================================
246 | autoapi_modules = {
247 | 'pyTooling.TerminalUI': {'output': "pyTooling.TerminalUI", "override": True}
248 | }
249 |
--------------------------------------------------------------------------------
/doc/genindex.rst:
--------------------------------------------------------------------------------
1 | .. This file is a placeholder and will be replaced
2 |
3 | Index
4 | #####
5 |
--------------------------------------------------------------------------------
/doc/index.rst:
--------------------------------------------------------------------------------
1 | .. |img-TerminalUI-github| image:: https://img.shields.io/badge/pyTooling-pyTooling.TerminalUI-323131.svg?logo=github&longCache=true
2 | :alt: Sourcecode on GitHub
3 | :height: 22
4 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI
5 | .. |img-TerminalUI-codelicense| image:: https://img.shields.io/pypi/l/pyTooling.TerminalUI?logo=GitHub&label=code%20license
6 | :alt: Sourcecode License
7 | :height: 22
8 | .. |img-TerminalUI-tag| image:: https://img.shields.io/github/v/tag/pyTooling/pyTooling.TerminalUI?logo=GitHub&include_prereleases
9 | :alt: GitHub tag (latest SemVer incl. pre-release)
10 | :height: 22
11 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/tags
12 | .. |img-TerminalUI-release| image:: https://img.shields.io/github/v/release/pyTooling/pyTooling.TerminalUI?logo=GitHub&include_prereleases
13 | :alt: GitHub release (latest SemVer incl. including pre-releases
14 | :height: 22
15 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases/latest
16 | .. |img-TerminalUI-date| image:: https://img.shields.io/github/release-date/pyTooling/pyTooling.TerminalUI?logo=GitHub
17 | :alt: GitHub release date
18 | :height: 22
19 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases
20 | .. |img-TerminalUI-lib-dep| image:: https://img.shields.io/librariesio/dependents/pypi/pyTooling.TerminalUI?logo=librariesdotio
21 | :alt: Dependents (via libraries.io)
22 | :height: 22
23 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/network/dependents
24 | .. |img-TerminalUI-gha-pipeline| image:: https://img.shields.io/github/workflow/status/pyTooling/pyTooling.TerminalUI/Unit%20Testing,%20Coverage%20Collection,%20Package,%20Release,%20Documentation%20and%20Publish?label=Pipeline&logo=GitHub%20Actions&logoColor=FFFFFF
25 | :alt: GitHub Workflow - Build and Test Status
26 | :height: 22
27 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/actions/workflows/Pipeline.yml
28 | .. |img-TerminalUI-codacy-quality| image:: https://img.shields.io/codacy/grade/e8a1b6e33d564f82927235e17fb26e93?logo=Codacy
29 | :alt: Codacy - Quality
30 | :height: 22
31 | :target: https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI
32 | .. |img-TerminalUI-codacy-coverage| image:: https://img.shields.io/codacy/coverage/e8a1b6e33d564f82927235e17fb26e93?logo=Codacy
33 | :alt: Codacy - Line Coverage
34 | :height: 22
35 | :target: https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI
36 | .. |img-TerminalUI-codecov-coverage| image:: https://img.shields.io/codecov/c/github/pyTooling/pyTooling.TerminalUI?logo=Codecov
37 | :alt: Codecov - Branch Coverage
38 | :height: 22
39 | :target: https://codecov.io/gh/pyTooling/pyTooling.TerminalUI
40 | .. |img-TerminalUI-lib-rank| image:: https://img.shields.io/librariesio/sourcerank/pypi/pyTooling.TerminalUI?logo=librariesdotio
41 | :alt: Libraries.io SourceRank
42 | :height: 22
43 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI/sourcerank
44 | .. |img-TerminalUI-pypi-tag| image:: https://img.shields.io/pypi/v/pyTooling.TerminalUI?logo=PyPI&logoColor=FBE072
45 | :alt: PyPI - Tag
46 | :height: 22
47 | :target: https://pypi.org/project/pyTooling.TerminalUI/
48 | .. |img-TerminalUI-pypi-python| image:: https://img.shields.io/pypi/pyversions/pyTooling.TerminalUI?logo=PyPI&logoColor=FBE072
49 | :alt: PyPI - Python Version
50 | :height: 22
51 | .. |img-TerminalUI-pypi-status| image:: https://img.shields.io/pypi/status/pyTooling.TerminalUI?logo=PyPI&logoColor=FBE072
52 | :alt: PyPI - Status
53 | :height: 22
54 | .. |img-TerminalUI-lib-status| image:: https://img.shields.io/librariesio/release/pypi/pyTooling.TerminalUI?logo=librariesdotio
55 | :alt: Libraries.io status for latest release
56 | :height: 22
57 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI
58 | .. |img-TerminalUI-req-status| image:: https://img.shields.io/requires/github/pyTooling/pyTooling.TerminalUI
59 | :alt: Requires.io
60 | :height: 22
61 | :target: https://requires.io/github/pyTooling/pyTooling.TerminalUI/requirements/?branch=main
62 | .. |img-TerminalUI-doclicense| image:: https://img.shields.io/badge/doc%20license-CC--BY%204.0-green?logo=readthedocs
63 | :alt: Documentation License
64 | :height: 22
65 | :target: Doc-License.html
66 | .. |img-TerminalUI-doc| image:: https://img.shields.io/badge/doc-read%20now%20%E2%9E%9A-blueviolet?logo=readthedocs
67 | :alt: Documentation - Read Now!
68 | :height: 22
69 | :target: https://pyTooling.GitHub.io/pyTooling.TerminalUI
70 |
71 | |img-TerminalUI-github| |img-TerminalUI-codelicense| |img-TerminalUI-tag| |img-TerminalUI-release| |img-TerminalUI-date| |img-TerminalUI-lib-dep| |br|
72 | |img-TerminalUI-gha-pipeline| |img-TerminalUI-codacy-quality| |img-TerminalUI-codacy-coverage| |img-TerminalUI-codecov-coverage| |img-TerminalUI-lib-rank| |br|
73 | |img-TerminalUI-pypi-tag| |img-TerminalUI-pypi-python| |img-TerminalUI-pypi-status| |img-TerminalUI-lib-status| |img-TerminalUI-req-status| |br|
74 | |img-TerminalUI-doclicense| |img-TerminalUI-doc|
75 |
76 |
77 | pyTooling.TerminalUI Documentation
78 | ##################################
79 |
80 | A set of helpers to implement a text user interface (TUI) in a terminal.
81 |
82 | Introduction
83 | ************
84 |
85 | This package offers a :py:class:`pyTooling.TerminalUI.LineTerminal` implementation,
86 | derived from a basic :py:class:`pyTooling.TerminalUI.Terminal` class. It eases the
87 | creation of simple terminal/console applications. It includes colored outputs
88 | based on
89 |
90 | List of meta classes
91 | ********************
92 |
93 | * :py:class:`pyTooling.TerminalUI.Terminal`
94 | * :py:class:`pyTooling.TerminalUI.LineTerminal`
95 |
96 |
97 | Example
98 | *******
99 |
100 | .. code-block:: Python
101 |
102 | from pyTooling.TerminalUI import LineTerminal
103 |
104 | class Application(LineTerminal):
105 | def __init__(self):
106 | super().__init__(verbose=True, debug=True, quiet=False)
107 |
108 | def run(self):
109 | self.WriteQuiet("This is a quiet message.")
110 | self.WriteNormal("This is a normal message.")
111 | self.WriteInfo("This is a info message.")
112 | self.WriteDebug("This is a debug message.")
113 | self.WriteWarning("This is a warning message.")
114 | self.WriteError("This is an error message.")
115 | self.WriteFatal("This is a fatal message.")
116 |
117 | # entry point
118 | if __name__ == "__main__":
119 | Application.versionCheck((3,6,0))
120 | app = Application()
121 | app.run()
122 | app.exit()
123 |
124 |
125 |
126 | Contributors
127 | ************
128 |
129 | * `Patrick Lehmann `__ (Maintainer)
130 | * `and more... `__
131 |
132 |
133 |
134 | License
135 | *******
136 |
137 | .. only:: html
138 |
139 | This Python package (source code) is licensed under `Apache License 2.0 `__. |br|
140 | The accompanying documentation is licensed under `Creative Commons - Attribution 4.0 (CC-BY 4.0) `__.
141 |
142 | .. only:: latex
143 |
144 | This Python package (source code) is licensed under **Apache License 2.0**. |br|
145 | The accompanying documentation is licensed under **Creative Commons - Attribution 4.0 (CC-BY 4.0)**.
146 |
147 |
148 | ------------------------------------
149 |
150 | .. |docdate| date:: %b %d, %Y - %H:%M
151 |
152 | .. only:: html
153 |
154 | This document was generated on |docdate|.
155 |
156 | .. toctree::
157 | :caption: Overview
158 | :hidden:
159 |
160 | Installation
161 | Dependencies
162 |
163 |
164 | .. toctree::
165 | :caption: pyTooling.TerminalUI Classes
166 | :hidden:
167 |
168 | Terminal
169 | Severity
170 | Line
171 | ILineTerminal
172 | LineTerminal
173 |
174 |
175 | .. toctree::
176 | :caption: Appendix
177 | :hidden:
178 |
179 | Coverage Report ➚
180 | Static Type Check Report ➚
181 | License
182 | Doc-License
183 | genindex
184 | py-modindex
185 |
--------------------------------------------------------------------------------
/doc/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/doc/prolog.inc:
--------------------------------------------------------------------------------
1 | .. # Load pre-defined aliases and graphical characters like © from docutils
2 | # is used to denote the special path
3 | # \Lib\site-packages\docutils\parsers\rst\include
4 | .. include::
5 | .. include::
6 |
7 | .. # define a hard line break for HTML
8 | .. |br| raw:: html
9 |
10 |
11 |
12 | .. # define horizontal line for HTML
13 | .. |hr| raw:: html
14 |
15 |
16 |
17 | .. # define additional CSS based styles and ReST roles for HTML
18 | .. raw:: html
19 |
20 |
25 |
26 | .. role:: bolditalic
27 | :class: bolditalic
28 |
29 | .. role:: underline
30 | :class: underline
31 |
32 | .. role:: xlarge
33 | :class: xlarge
34 |
--------------------------------------------------------------------------------
/doc/py-modindex.rst:
--------------------------------------------------------------------------------
1 | .. This file is a placeholder and will be replaced
2 |
3 | Python Module Index
4 | ###################
5 |
--------------------------------------------------------------------------------
/doc/requirements.txt:
--------------------------------------------------------------------------------
1 | -r ../requirements.txt
2 |
3 | pyTooling>=2.1.0
4 |
5 | # Enforce latest version on ReadTheDocs
6 | sphinx>=5.0.2
7 |
8 | # Sphinx Extenstions
9 | #sphinx.ext.coverage
10 | #sphinxcontrib-actdiag>=0.8.5
11 | sphinxcontrib-mermaid>=0.7.1
12 | #sphinxcontrib-seqdiag>=0.8.5
13 | #sphinxcontrib-textstyle>=0.2.1
14 | #sphinxcontrib-spelling>=2.2.0
15 | autoapi
16 | sphinx_fontawesome>=0.0.6
17 | sphinx_autodoc_typehints>=1.18.1
18 | # changelog>=0.3.5
19 |
20 | # BuildTheDocs Extensions (mostly patched Sphinx extensions)
21 |
--------------------------------------------------------------------------------
/doc/shields.inc:
--------------------------------------------------------------------------------
1 | .. # Use http://b64.io/ to encode any image to base64. Then replace `/` with
2 | # `%2F` and `+` with `%2B` (or use http://meyerweb.com/eric/tools/dencoder/).
3 | # Beware that `?logo=data:image/png;base64,` must also be converted to
4 | # percent encoding so that the URL is properly parsed.
5 |
6 | .. # Sourcecode link to GitHub
7 | .. |SHIELD:svg:pyTooling-github| image:: https://img.shields.io/badge/pyTooling-pyTooling.TerminalUI-323131?logo=github&longCache=true
8 | :alt: Sourcecode on GitHub
9 | :height: 22
10 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI
11 | .. |SHIELD:png:pyTooling-github| image:: https://raster.shields.io/badge/pyTooling-pyTooling.TerminalUI-323131?logo=github&longCache=true
12 | :alt: Sourcecode on GitHub
13 | :height: 22
14 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI
15 |
16 | .. # Sourcecode license
17 | .. |SHIELD:svg:pyTooling-src-license| image:: https://img.shields.io/pypi/l/pyTooling.TerminalUI?logo=GitHub&label=code%20license
18 | :alt: Code license
19 | :height: 22
20 | :target: Code-License.html
21 | .. |SHIELD:png:pyTooling-src-license| image:: https://img.shields.io/pypi/l/pyTooling.TerminalUI?logo=GitHub&label=code%20license
22 | :alt: Code license
23 | :height: 22
24 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/blob/main/LICENSE.md
25 |
26 | .. # GitHub tag
27 | .. |SHIELD:svg:pyTooling-tag| image:: https://img.shields.io/github/v/tag/pyTooling/pyTooling.TerminalUI?logo=GitHub&include_prereleases
28 | :alt: GitHub tag (latest SemVer incl. pre-release
29 | :height: 22
30 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/tags
31 | .. |SHIELD:png:pyTooling-tag| image:: https://raster.shields.io/github/v/tag/pyTooling/pyTooling.TerminalUI?logo=GitHub&include_prereleases
32 | :alt: GitHub tag (latest SemVer incl. pre-release
33 | :height: 22
34 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/tags
35 |
36 | .. # GitHub release
37 | .. |SHIELD:svg:pyTooling-release| image:: https://img.shields.io/github/v/release/pyTooling/pyTooling.TerminalUI?logo=GitHub&include_prereleases
38 | :alt: GitHub release (latest SemVer incl. including pre-releases
39 | :height: 22
40 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases/latest
41 | .. |SHIELD:png:pyTooling-release| image:: https://raster.shields.io/github/v/release/pyTooling/pyTooling.TerminalUI?logo=GitHub&include_prereleases
42 | :alt: GitHub release (latest SemVer incl. including pre-releases
43 | :height: 22
44 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases/latest
45 |
46 | .. # GitHub release date
47 | .. |SHIELD:svg:pyTooling-date| image:: https://img.shields.io/github/release-date/pyTooling/pyTooling.TerminalUI?logo=GitHub
48 | :alt: GitHub release date
49 | :height: 22
50 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases
51 | .. |SHIELD:png:pyTooling-date| image:: https://raster.shields.io/github/release-date/pyTooling/pyTooling.TerminalUI?logo=GitHub
52 | :alt: GitHub release date
53 | :height: 22
54 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/releases
55 |
56 | .. # GitHub/Libraries dependent projects
57 | .. |SHIELD:svg:pyTooling-lib-dep| image:: https://img.shields.io/librariesio/dependent-repos/pypi/pyTooling.TerminalUI
58 | :alt: Dependent repos (via libraries.io)
59 | :height: 22
60 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/network/dependents
61 | .. |SHIELD:png:pyTooling-lib-dep| image:: https://raster.shields.io/librariesio/dependent-repos/pypi/pyTooling.TerminalUI
62 | :alt: Dependent repos (via libraries.io)
63 | :height: 22
64 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/network/dependents
65 |
66 | .. # GHA test and coverage
67 | .. |SHIELD:svg:pyTooling-gha-test| image:: https://img.shields.io/github/workflow/status/pyTooling/pyTooling.TerminalUI/Unit%20Testing,%20Coverage%20Collection,%20Package,%20Release,%20Documentation%20and%20Publish?label=Build%20and%20Test&logo=GitHub%20Actions&logoColor=FFFFFF
68 | :alt: GitHub Workflow - Build and Test Status
69 | :height: 22
70 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/actions?query=workflow%3A%22Unit%20Testing,%20Coverage%20Collection,%20Package,%20Release,%20Documentation%20and%20Publish%22
71 | .. |SHIELD:png:pyTooling-gha-test| image:: https://img.shields.io/github/workflow/status/pyTooling/pyTooling.TerminalUI/Unit%20Testing,%20Coverage%20Collection,%20Package,%20Release,%20Documentation%20and%20Publish?label=Build%20and%20Test&logo=GitHub%20Actions&logoColor=FFFFFF
72 | :alt: GitHub Workflow - Build and Test Status
73 | :height: 22
74 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/actions?query=workflow%3A%22Unit%20Testing,%20Coverage%20Collection,%20Package,%20Release,%20Documentation%20and%20Publish%22
75 |
76 | .. # Codacy - quality
77 | .. |SHIELD:svg:pyTooling-codacy-quality| image:: https://img.shields.io/codacy/grade/08ef744c0b70490289712b02a7a4cebe?logo=codacy
78 | :alt: Codacy - Quality
79 | :height: 22
80 | :target: https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI
81 | .. |SHIELD:png:pyTooling-codacy-quality| image:: https://raster.shields.io/codacy/grade/08ef744c0b70490289712b02a7a4cebe?logo=codacy
82 | :alt: Codacy - Quality
83 | :height: 22
84 | :target: https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI
85 |
86 | .. # Codacy - coverage
87 | .. |SHIELD:svg:pyTooling-codacy-coverage| image:: https://img.shields.io/codacy/coverage/08ef744c0b70490289712b02a7a4cebe?logo=codacy
88 | :alt: Codacy - Line Coverage
89 | :height: 22
90 | :target: https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI
91 | .. |SHIELD:png:pyTooling-codacy-coverage| image:: https://raster.shields.io/codacy/coverage/08ef744c0b70490289712b02a7a4cebe?logo=codacy
92 | :alt: Codacy - Line Coverage
93 | :height: 22
94 | :target: https://www.codacy.com/gh/pyTooling/pyTooling.TerminalUI
95 |
96 | .. # Codecov - coverage
97 | .. |SHIELD:svg:pyTooling-codecov-coverage| image:: https://img.shields.io/codecov/c/github/pyTooling/pyTooling.TerminalUI
98 | :alt: Codecov - Branch Coverage
99 | :height: 22
100 | :target: https://codecov.io/gh/pyTooling/pyTooling.TerminalUI
101 | .. |SHIELD:png:pyTooling-codecov-coverage| image:: https://raster.shields.io/codecov/c/github/pyTooling/pyTooling.TerminalUI
102 | :alt: Codecov - Branch Coverage
103 | :height: 22
104 | :target: https://codecov.io/gh/pyTooling/pyTooling.TerminalUI
105 |
106 | .. # Libraries - source rank
107 | .. |SHIELD:svg:pyTooling-lib-rank| image:: https://img.shields.io/librariesio/sourcerank/pypi/pyTooling.TerminalUI
108 | :alt: Libraries.io SourceRank
109 | :height: 22
110 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI/sourcerank
111 | .. |SHIELD:png:pyTooling-lib-rank| image:: https://raster.shields.io/librariesio/sourcerank/pypi/pyTooling.TerminalUI
112 | :alt: Libraries.io SourceRank
113 | :height: 22
114 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI/sourcerank
115 |
116 | .. # PyPI tag
117 | .. |SHIELD:svg:pyTooling-pypi-tag| image:: https://img.shields.io/pypi/v/pyTooling.TerminalUI?logo=PyPI
118 | :alt: PyPI - Tag
119 | :height: 22
120 | :target: https://pypi.org/project/pyTooling.TerminalUI/
121 | .. |SHIELD:png:pyTooling-pypi-tag| image:: https://raster.shields.io/pypi/v/pyTooling.TerminalUI?logo=PyPI
122 | :alt: PyPI - Tag
123 | :height: 22
124 | :target: https://pypi.org/project/pyTooling.TerminalUI/
125 |
126 | .. # PyPI project status
127 | .. |SHIELD:svg:pyTooling-pypi-status| image:: https://img.shields.io/pypi/status/pyTooling.TerminalUI?logo=PyPI
128 | :alt: PyPI - Status
129 | :height: 22
130 | .. |SHIELD:png:pyTooling-pypi-status| image:: https://raster.shields.io/pypi/status/pyTooling.TerminalUI?logo=PyPI
131 | :alt: PyPI - Status
132 | :height: 22
133 |
134 | .. # PyPI Python versions
135 | .. |SHIELD:svg:pyTooling-pypi-python| image:: https://img.shields.io/pypi/pyversions/pyTooling.TerminalUI?logo=PyPI
136 | :alt: PyPI - Python Version
137 | :height: 22
138 | .. |SHIELD:png:pyTooling-pypi-python| image:: https://raster.shields.io/pypi/pyversions/pyTooling.TerminalUI?logo=PyPI
139 | :alt: PyPI - Python Version
140 | :height: 22
141 |
142 | .. # Libraries - status
143 | .. |SHIELD:svg:pyTooling-lib-status| image:: https://img.shields.io/librariesio/release/pypi/pyTooling.TerminalUI
144 | :alt: Libraries.io status for latest release
145 | :height: 22
146 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI
147 | .. |SHIELD:png:pyTooling-lib-status| image:: https://raster.shields.io/librariesio/release/pypi/pyTooling.TerminalUI
148 | :alt: Libraries.io status for latest release
149 | :height: 22
150 | :target: https://libraries.io/github/pyTooling/pyTooling.TerminalUI
151 |
152 | .. # Requires - status
153 | .. |SHIELD:svg:pyTooling-req-status| image:: https://img.shields.io/requires/github/pyTooling/pyTooling.TerminalUI
154 | :alt: Requires.io
155 | :height: 22
156 | :target: https://requires.io/github/pyTooling/pyTooling.TerminalUI/requirements/?branch=main
157 | .. |SHIELD:png:pyTooling-req-status| image:: https://raster.shields.io/requires/github/pyTooling/pyTooling.TerminalUI
158 | :alt: Requires.io
159 | :height: 22
160 | :target: https://requires.io/github/pyTooling/pyTooling.TerminalUI/requirements/?branch=main
161 |
162 | .. # Documentation license
163 | .. |SHIELD:svg:pyTooling-doc-license| image:: https://img.shields.io/badge/doc%20license-CC--BY%204.0-green
164 | :alt: Documentation License
165 | :height: 22
166 | :target: Doc-License.html
167 | .. |SHIELD:png:pyTooling-doc-license| image:: https://img.shields.io/badge/doc%20license-CC--BY%204.0-green
168 | :alt: Documentation License
169 | :height: 22
170 | :target: https://GitHub.com/pyTooling/pyTooling.TerminalUI/blob/main/doc/Doc-License.rst
171 |
172 | .. # GHPages - read now
173 | .. |SHIELD:svg:pyTooling-ghp-doc| image:: https://img.shields.io/badge/doc-read%20now%20%E2%9E%9A-blueviolet
174 | :alt: Documentation - Read Now!
175 | :height: 22
176 | :target: https://pyTooling.GitHub.io/pyTooling.TerminalUI/
177 | .. |SHIELD:png:pyTooling-ghp-doc| image:: https://img.shields.io/badge/doc-read%20now%20%E2%9E%9A-blueviolet
178 | :alt: Documentation - Read Now!
179 | :height: 22
180 | :target: https://pyTooling.GitHub.io/pyTooling.TerminalUI/
181 |
--------------------------------------------------------------------------------
/pyTooling/TerminalUI/__init__.py:
--------------------------------------------------------------------------------
1 | # ==================================================================================================================== #
2 | # _____ _ _ _____ _ _ _ _ ___ #
3 | # _ __ _ |_ _|__ ___ | (_)_ __ __ _|_ _|__ _ __ _ __ ___ (_)_ __ __ _| | | | |_ _| #
4 | # | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` | | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | | | | || | #
5 | # | |_) | |_| || | (_) | (_) | | | | | | (_| |_| | __/ | | | | | | | | | | | (_| | | |_| || | #
6 | # | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)_|\___|_| |_| |_| |_|_|_| |_|\__,_|_|\___/|___| #
7 | # |_| |___/ |___/ #
8 | # ==================================================================================================================== #
9 | # Authors: #
10 | # Patrick Lehmann #
11 | # #
12 | # License: #
13 | # ==================================================================================================================== #
14 | # Copyright 2017-2022 Patrick Lehmann - Bötzingen, Germany #
15 | # #
16 | # Licensed under the Apache License, Version 2.0 (the "License"); #
17 | # you may not use this file except in compliance with the License. #
18 | # You may obtain a copy of the License at #
19 | # #
20 | # http://www.apache.org/licenses/LICENSE-2.0 #
21 | # #
22 | # Unless required by applicable law or agreed to in writing, software #
23 | # distributed under the License is distributed on an "AS IS" BASIS, #
24 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
25 | # See the License for the specific language governing permissions and #
26 | # limitations under the License. #
27 | # #
28 | # SPDX-License-Identifier: Apache-2.0 #
29 | # ==================================================================================================================== #
30 | #
31 | """A set of helpers to implement a text user interface (TUI) in a terminal."""
32 | __author__ = "Patrick Lehmann"
33 | __email__ = "Paebbels@gmail.com"
34 | __copyright__ = "2007-2022, Patrick Lehmann"
35 | __license__ = "Apache License, Version 2.0"
36 | __version__ = "1.5.9"
37 | __keywords__ = ["terminal", "shell", "text user interface", "TUI", "console", "message logging"]
38 |
39 | from enum import Enum, unique
40 | from platform import system as platform_system
41 | from typing import NoReturn, Tuple, Any
42 |
43 | from pyTooling.Decorators import export
44 | from pyTooling.MetaClasses import ExtendedType
45 |
46 |
47 | @export
48 | class Terminal:
49 | FATAL_EXIT_CODE = 255
50 |
51 | try:
52 | from colorama import Fore as Foreground
53 | Foreground = {
54 | "RED": Foreground.LIGHTRED_EX,
55 | "DARK_RED": Foreground.RED,
56 | "GREEN": Foreground.LIGHTGREEN_EX,
57 | "DARK_GREEN": Foreground.GREEN,
58 | "YELLOW": Foreground.LIGHTYELLOW_EX,
59 | "DARK_YELLOW": Foreground.YELLOW,
60 | "MAGENTA": Foreground.LIGHTMAGENTA_EX,
61 | "BLUE": Foreground.LIGHTBLUE_EX,
62 | "DARK_BLUE": Foreground.BLUE,
63 | "CYAN": Foreground.LIGHTCYAN_EX,
64 | "DARK_CYAN": Foreground.CYAN,
65 | "GRAY": Foreground.WHITE,
66 | "DARK_GRAY": Foreground.LIGHTBLACK_EX,
67 | "WHITE": Foreground.LIGHTWHITE_EX,
68 | "NOCOLOR": Foreground.RESET,
69 |
70 | "HEADLINE": Foreground.LIGHTMAGENTA_EX,
71 | "ERROR": Foreground.LIGHTRED_EX,
72 | "WARNING": Foreground.LIGHTYELLOW_EX
73 | } #: Terminal colors
74 | except:
75 | Foreground = {
76 | "RED": "",
77 | "DARK_RED": "",
78 | "GREEN": "",
79 | "DARK_GREEN": "",
80 | "YELLOW": "",
81 | "DARK_YELLOW": "",
82 | "MAGENTA": "",
83 | "BLUE": "",
84 | "DARK_BLUE": "",
85 | "CYAN": "",
86 | "DARK_CYAN": "",
87 | "GRAY": "",
88 | "DARK_GRAY": "",
89 | "WHITE": "",
90 | "NOCOLOR": "",
91 |
92 | "HEADLINE": "",
93 | "ERROR": "",
94 | "WARNING": ""
95 | } #: Terminal colors
96 |
97 | _width : int = None #: Terminal width in characters
98 | _height : int = None #: Terminal height in characters
99 |
100 | def __init__(self):
101 | """
102 | Initialize a terminal.
103 |
104 | If the Python package `colorama `_ [#f_colorama]_ is available, then initialize it for colored outputs.
105 |
106 | .. [#f_colorama] Colorama on Github: https://GitHub.com/tartley/colorama
107 | """
108 |
109 | self.initColors()
110 | (self._width, self._height) = self.GetTerminalSize()
111 |
112 | @classmethod
113 | def initColors(cls) -> None:
114 | """Initialize the terminal for color support by colorama."""
115 | try:
116 | from colorama import init
117 |
118 | init()#strip=False)
119 | except:
120 | pass
121 |
122 | @classmethod
123 | def deinitColors(cls) -> None:
124 | """Uninitialize the terminal for color support by colorama."""
125 | try:
126 | from colorama import deinit
127 |
128 | deinit()
129 | except:
130 | pass
131 |
132 | @classmethod
133 | def fatalExit(cls, returnCode:int =0) -> NoReturn:
134 | """Exit the terminal application by uninitializing color support and returning a fatal exit code."""
135 | cls.exit(cls.FATAL_EXIT_CODE if returnCode == 0 else returnCode)
136 |
137 | @classmethod
138 | def exit(cls, returnCode:int =0) -> NoReturn:
139 | """Exit the terminal application by uninitializing color support and returning an exit code."""
140 | cls.deinitColors()
141 | exit(returnCode)
142 |
143 | @classmethod
144 | def versionCheck(cls, version) -> None:
145 | """Check if the used Python interpreter fulfills the minimum version requirements."""
146 |
147 | from sys import version_info
148 |
149 | if (version_info < version):
150 | cls.initColors()
151 |
152 | print("{RED}ERROR:{NOCOLOR} Used Python interpreter ({major}.{minor}.{micro}-{level}) is to old.".format(
153 | major=version_info.major,
154 | minor=version_info.minor,
155 | micro=version_info.micro,
156 | level=version_info.releaselevel,
157 | **cls.Foreground
158 | ))
159 | print(f" Minimal required Python version is {version[0]}.{version[1]}.{version[2]}")
160 |
161 | cls.exit(1)
162 |
163 | @classmethod
164 | def printException(cls, ex) -> NoReturn:
165 | """Prints an exception of type :exc:`Exception`."""
166 | from traceback import print_tb, walk_tb
167 |
168 | cls.initColors()
169 |
170 | print("{RED}FATAL: An unknown or unhandled exception reached the topmost exception handler!{NOCOLOR}".format(**cls.Foreground))
171 | print(" {YELLOW}Exception type:{NOCOLOR} {typename}".format(typename=ex.__class__.__name__, **cls.Foreground))
172 | print(" {YELLOW}Exception message:{NOCOLOR} {message!s}".format(message=ex, **cls.Foreground))
173 | frame, sourceLine = [x for x in walk_tb(ex.__traceback__)][-1]
174 | filename = frame.f_code.co_filename
175 | funcName = frame.f_code.co_name
176 | print(" {YELLOW}Caused in:{NOCOLOR} {function} in file '{filename}' at line {line}".format(
177 | function=funcName,
178 | filename=filename,
179 | line=sourceLine,
180 | **cls.Foreground
181 | ))
182 | if (ex.__cause__ is not None):
183 | print(" {DARK_YELLOW}Caused by type:{NOCOLOR} {typename}".format(typename=ex.__cause__.__class__.__name__, **cls.Foreground))
184 | print(" {DARK_YELLOW}Caused by message:{NOCOLOR} {message!s}".format(message=ex.__cause__, **cls.Foreground))
185 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
186 | print_tb(ex.__traceback__)
187 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
188 | print(("{RED}Please report this bug at GitHub: https://GitHub.com/pyTooling/pyTooling.TerminalUI/issues{NOCOLOR}").format(**cls.Foreground))
189 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
190 |
191 | cls.exit(1)
192 |
193 | @classmethod
194 | def printNotImplementedError(cls, ex) -> NoReturn:
195 | """Prints a not-implemented exception of type :exc:`NotImplementedError`."""
196 | from traceback import walk_tb
197 |
198 | cls.initColors()
199 |
200 | frame, _ = [x for x in walk_tb(ex.__traceback__)][-1]
201 | filename = frame.f_code.co_filename
202 | funcName = frame.f_code.co_name
203 | print("{RED}NOT IMPLEMENTED:{NOCOLOR} {function} in file '{filename}': {message!s}".format(
204 | function=funcName,
205 | filename=filename,
206 | message=ex,
207 | **cls.Foreground
208 | ))
209 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
210 | print(("{RED}Please report this bug at GitHub: https://GitHub.com/pyTooling/pyTooling.TerminalUI/issues{NOCOLOR}").format(**cls.Foreground))
211 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
212 |
213 | cls.exit(1)
214 |
215 | @classmethod
216 | def printExceptionBase(cls, ex) -> NoReturn:
217 | cls.initColors()
218 |
219 | print("{RED}FATAL: A known but unhandled exception reached the topmost exception handler!{NOCOLOR}".format(**cls.Foreground))
220 | print("{RED}ERROR:{NOCOLOR} {message}".format(message=ex.message, **cls.Foreground))
221 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
222 | print(("{RED}Please report this bug at GitHub: https://GitHub.com/pyTooling/pyTooling.TerminalUI/issues{NOCOLOR}").format(**cls.Foreground))
223 | print(("{RED}" + ("-" * 80) + "{NOCOLOR}").format(**cls.Foreground))
224 |
225 | cls.exit(1)
226 |
227 | @property
228 | def Width(self) -> int:
229 | """Returns the current terminal window's width."""
230 | return self._width
231 |
232 | @property
233 | def Height(self) -> int:
234 | """Returns the current terminal window's height."""
235 | return self._height
236 |
237 | @staticmethod
238 | def GetTerminalSize() -> Tuple[int, int]:
239 | """Returns the terminal size as tuple (width, height) for Windows, Mac OS (Darwin), Linux, cygwin (Windows), MinGW32/64 (Windows)."""
240 | size = None
241 |
242 | platform = platform_system()
243 | if (platform == "Windows"):
244 | size = Terminal.__GetTerminalSizeOnWindows()
245 | elif ((platform in ["Linux", "Darwin"]) or
246 | platform.startswith("CYGWIN") or
247 | platform.startswith("MINGW32") or
248 | platform.startswith("MINGW64")):
249 | size = Terminal.__GetTerminalSizeOnLinux()
250 |
251 | if (size is None):
252 | size = (80, 25) # default size
253 | return size
254 |
255 | @staticmethod
256 | def __GetTerminalSizeOnWindows() -> Tuple[int, int]:
257 | """Returns the current terminal window's size for Windows."""
258 | try:
259 | from ctypes import windll, create_string_buffer
260 | from struct import unpack as struct_unpack
261 |
262 | hStdError = windll.kernel32.GetStdHandle(-12) # stderr handle = -12
263 | stringBuffer = create_string_buffer(22)
264 | result = windll.kernel32.GetConsoleScreenBufferInfo(hStdError, stringBuffer)
265 | if result:
266 | (bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx, maxy) = struct_unpack("hhhhHhhhhhh", stringBuffer.raw)
267 | width = right - left + 1
268 | height = bottom - top + 1
269 | return (width, height)
270 | except:
271 | pass
272 |
273 | return Terminal.__GetTerminalSizeWithTPut()
274 |
275 | @staticmethod
276 | def __GetTerminalSizeWithTPut() -> Tuple[int, int]:
277 | from shlex import split as shlex_split
278 | from subprocess import check_output
279 |
280 | try:
281 | width = int(check_output(shlex_split('tput cols')))
282 | height = int(check_output(shlex_split('tput lines')))
283 | return (width, height)
284 | except:
285 | pass
286 |
287 | @staticmethod
288 | def __GetTerminalSizeOnLinux() -> Tuple[int, int]:
289 | """Returns the current terminal window's size for Linux."""
290 | import os
291 |
292 | def ioctl_GWINSZ(fd):
293 | """GetWindowSize of file descriptor."""
294 | try:
295 | from fcntl import ioctl as fcntl_ioctl
296 | from struct import unpack as struct_unpack
297 | from termios import TIOCGWINSZ
298 |
299 | return struct_unpack('hh', fcntl_ioctl(fd, TIOCGWINSZ, '1234'))
300 | except:
301 | pass
302 |
303 | # STDIN STDOUT STDERR
304 | cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
305 | if not cr:
306 | try:
307 |
308 | fd = os.open(os.ctermid(), os.O_RDONLY)
309 | cr = ioctl_GWINSZ(fd)
310 | os.close(fd)
311 | except:
312 | pass
313 | if not cr:
314 | try:
315 | cr = (os.environ['LINES'], os.environ['COLUMNS'])
316 | except:
317 | return None
318 | return (int(cr[1]), int(cr[0]))
319 |
320 |
321 | @export
322 | @unique
323 | class Severity(Enum):
324 | """Logging message severity levels."""
325 |
326 | Fatal = 30 #: Fatal messages
327 | Error = 25 #: Error messages
328 | Quiet = 20 #: Always visible messages, even in quiet mode.
329 | Warning = 15 #: Warning messages
330 | Info = 10 #: Informative messages
331 | DryRun = 5 #: Messages visible in a dry-run
332 | Normal = 4 #: Normal messages
333 | Verbose = 2 #: Verbose messages
334 | Debug = 1 #: Debug messages
335 | All = 0 #: All messages
336 |
337 | def __hash__(self):
338 | return hash(self.name)
339 |
340 | def __eq__(self, other: Any):
341 | if isinstance(other, Severity):
342 | return self.value == other.value
343 | else:
344 | raise TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.")
345 |
346 | def __ne__(self, other: Any):
347 | if isinstance(other, Severity):
348 | return self.value != other.value
349 | else:
350 | raise TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by != operator.")
351 |
352 | def __lt__(self, other: Any):
353 | if isinstance(other, Severity):
354 | return self.value < other.value
355 | else:
356 | raise TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by < operator.")
357 |
358 | def __le__(self, other: Any):
359 | if isinstance(other, Severity):
360 | return self.value <= other.value
361 | else:
362 | raise TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by <= operator.")
363 |
364 | def __gt__(self, other: Any):
365 | if isinstance(other, Severity):
366 | return self.value > other.value
367 | else:
368 | raise TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by > operator.")
369 |
370 | def __ge__(self, other: Any):
371 | if isinstance(other, Severity):
372 | return self.value >= other.value
373 | else:
374 | raise TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by >= operator.")
375 |
376 |
377 | @export
378 | class Line:
379 | """Represents a single line message with a severity and indentation level."""
380 |
381 | _LOG_MESSAGE_FORMAT__ = {
382 | Severity.Fatal: "FATAL: {message}",
383 | Severity.Error: "ERROR: {message}",
384 | Severity.Warning: "WARNING: {message}",
385 | Severity.Info: "INFO: {message}",
386 | Severity.Quiet: "{message}",
387 | Severity.Normal: "{message}",
388 | Severity.Verbose: "VERBOSE: {message}",
389 | Severity.Debug: "DEBUG: {message}",
390 | Severity.DryRun: "DRYRUN: {message}"
391 | } #: Terminal messages formatting rules
392 |
393 | def __init__(self, message, severity=Severity.Normal, indent=0, appendLinebreak=True):
394 | """Constructor for a new ``Line`` object."""
395 | self._severity = severity
396 | self._message = message
397 | self._indent = indent
398 | self.AppendLinebreak = appendLinebreak
399 |
400 |
401 | @property
402 | def Severity(self) -> Severity:
403 | """Return the line's severity level."""
404 | return self._severity
405 |
406 | @property
407 | def Indent(self) -> int:
408 | """Return the line's indentation level."""
409 | return self._indent
410 |
411 | @property
412 | def Message(self) -> str:
413 | """Return the indented line."""
414 | return (" " * self._indent) + self._message
415 |
416 | def IndentBy(self, indent) -> None:
417 | """Increase a line's indentation level."""
418 | self._indent += indent
419 |
420 | def __str__(self) -> str:
421 | """Returns a formatted version of a ``Line`` objects as a string."""
422 | return self._LOG_MESSAGE_FORMAT__[self._severity].format(message=self._message)
423 |
424 |
425 | @export
426 | class ILineTerminal:
427 | """A mixin class (interface) to provide class-local terminal writing methods."""
428 |
429 | _terminal = None
430 |
431 | def __init__(self, terminal=None):
432 | """MixIn initializer."""
433 | self._terminal = terminal
434 |
435 | # FIXME: Alter methods if a terminal is present or set dummy methods
436 |
437 | @property
438 | def Terminal(self) -> Terminal:
439 | """Return the local terminal instance."""
440 | return self._terminal
441 |
442 | def WriteLine(self, line : Line, condition=True):
443 | """Write an entry to the local terminal."""
444 | if ((self._terminal is not None) and condition):
445 | return self._terminal.WriteLine(line)
446 | return False
447 |
448 | # def _TryWriteLine(self, *args, condition=True, **kwargs):
449 | # if ((self._terminal is not None) and condition):
450 | # return self._terminal.TryWrite(*args, **kwargs)
451 | # return False
452 |
453 | def WriteFatal(self, *args, condition=True, **kwargs):
454 | """Write a fatal message if ``condition`` is true."""
455 | if ((self._terminal is not None) and condition):
456 | return self._terminal.WriteFatal(*args, **kwargs)
457 | return False
458 |
459 | def WriteError(self, *args, condition=True, **kwargs):
460 | """Write an error message if ``condition`` is true."""
461 | if ((self._terminal is not None) and condition):
462 | return self._terminal.WriteError(*args, **kwargs)
463 | return False
464 |
465 | def WriteWarning(self, *args, condition=True, **kwargs):
466 | """Write a warning message if ``condition`` is true."""
467 | if ((self._terminal is not None) and condition):
468 | return self._terminal.WriteWarning(*args, **kwargs)
469 | return False
470 |
471 | def WriteInfo(self, *args, condition=True, **kwargs):
472 | """Write a info message if ``condition`` is true."""
473 | if ((self._terminal is not None) and condition):
474 | return self._terminal.WriteInfo(*args, **kwargs)
475 | return False
476 |
477 | def WriteQuiet(self, *args, condition=True, **kwargs):
478 | """Write a message even in quiet mode if ``condition`` is true."""
479 | if ((self._terminal is not None) and condition):
480 | return self._terminal.WriteQuiet(*args, **kwargs)
481 | return False
482 |
483 | def WriteNormal(self, *args, condition=True, **kwargs):
484 | """Write a *normal* message if ``condition`` is true."""
485 | if ((self._terminal is not None) and condition):
486 | return self._terminal.WriteNormal(*args, **kwargs)
487 | return False
488 |
489 | def WriteVerbose(self, *args, condition=True, **kwargs):
490 | """Write a verbose message if ``condition`` is true."""
491 | if ((self._terminal is not None) and condition):
492 | return self._terminal.WriteVerbose(*args, **kwargs)
493 | return False
494 |
495 | def WriteDebug(self, *args, condition=True, **kwargs):
496 | """Write a debug message if ``condition`` is true."""
497 | if ((self._terminal is not None) and condition):
498 | return self._terminal.WriteDebug(*args, **kwargs)
499 | return False
500 |
501 | def WriteDryRun(self, *args, condition=True, **kwargs):
502 | """Write a dry-run message if ``condition`` is true."""
503 | if ((self._terminal is not None) and condition):
504 | return self._terminal.WriteDryRun(*args, **kwargs)
505 | return False
506 |
507 |
508 | @export
509 | class LineTerminal(Terminal, ILineTerminal, metaclass=ExtendedType, singleton=True):
510 | def __init__(self, verbose=False, debug=False, quiet=False, writeToStdOut=True):
511 | """Initializer of a line based terminal interface."""
512 | Terminal.__init__(self)
513 | ILineTerminal.__init__(self, self)
514 |
515 | self._verbose = True if debug else verbose
516 | self._debug = debug
517 | self._quiet = quiet
518 |
519 | if quiet:
520 | self._WriteLevel = Severity.Quiet
521 | elif debug:
522 | self._WriteLevel = Severity.Debug
523 | elif verbose:
524 | self._WriteLevel = Severity.Verbose
525 | else:
526 | self._WriteLevel = Severity.Normal
527 |
528 | self._writeToStdOut = writeToStdOut
529 | self._lines = []
530 | self._baseIndent = 0
531 |
532 | self._errorCounter = 0
533 | self._warningCounter = 0
534 |
535 | @property
536 | def Verbose(self) -> bool:
537 | """Returns true, if verbose messages are enabled."""
538 | return self._verbose
539 |
540 | @property
541 | def Debug(self) -> bool:
542 | """Returns true, if debug messages are enabled."""
543 | return self._debug
544 |
545 | @property
546 | def Quiet(self) -> bool:
547 | """Returns true, if quiet mode is enabled."""
548 | return self._quiet
549 |
550 | @property
551 | def LogLevel(self) -> Severity:
552 | """Return the current minimal severity level for writing."""
553 | return self._WriteLevel
554 | @LogLevel.setter
555 | def LogLevel(self, value: Severity) -> None:
556 | """Set the minimal severity level for writing."""
557 | self._WriteLevel = value
558 |
559 | @property
560 | def BaseIndent(self) -> int:
561 | return self._baseIndent
562 | @BaseIndent.setter
563 | def BaseIndent(self, value: int) -> None:
564 | self._baseIndent = value
565 |
566 | _LOG_MESSAGE_FORMAT__ = {
567 | Severity.Fatal: "{DARK_RED}[FATAL] {message}{NOCOLOR}",
568 | Severity.Error: "{RED}[ERROR] {message}{NOCOLOR}",
569 | Severity.Quiet: "{WHITE}{message}{NOCOLOR}",
570 | Severity.Warning: "{YELLOW}[WARNING]{message}{NOCOLOR}",
571 | Severity.Info: "{WHITE}{message}{NOCOLOR}",
572 | Severity.DryRun: "{DARK_CYAN}[DRY] {message}{NOCOLOR}",
573 | Severity.Normal: "{WHITE}{message}{NOCOLOR}",
574 | Severity.Verbose: "{GRAY}{message}{NOCOLOR}",
575 | Severity.Debug: "{DARK_GRAY}{message}{NOCOLOR}"
576 | } #: Message formatting rules.
577 |
578 | def ExitOnPreviousErrors(self) -> None:
579 | """Exit application if errors have been printed."""
580 | if self._errorCounter > 0:
581 | self.WriteFatal("Too many errors in previous steps.")
582 | self.fatalExit()
583 |
584 | def ExitOnPreviousWarnings(self) -> None:
585 | """Exit application if warnings have been printed."""
586 | if self._warningCounter > 0:
587 | self.WriteError("Too many warnings in previous steps.")
588 | self.exit()
589 |
590 | def WriteLine(self, line : Line):
591 | """Print a formatted line to the underlying terminal/console offered by the operating system."""
592 | if (line.Severity >= self._WriteLevel):
593 | self._lines.append(line)
594 | if self._writeToStdOut:
595 | print(self._LOG_MESSAGE_FORMAT__[line.Severity].format(message=line.Message, **self.Foreground), end="\n" if line.AppendLinebreak else "")
596 | return True
597 | else:
598 | return False
599 |
600 | def TryWriteLine(self, line) -> bool:
601 | return (line.Severity >= self._WriteLevel)
602 |
603 | def WriteFatal(self, message, indent=0, appendLinebreak=True, immediateExit=True):
604 | ret = self.WriteLine(Line(message, Severity.Fatal, self._baseIndent + indent, appendLinebreak))
605 | if immediateExit:
606 | self.fatalExit()
607 | return ret
608 |
609 | def WriteError(self, message, indent=0, appendLinebreak=True):
610 | self._errorCounter += 1
611 | return self.WriteLine(Line(message, Severity.Error, self._baseIndent + indent, appendLinebreak))
612 |
613 | def WriteWarning(self, message, indent=0, appendLinebreak=True):
614 | self._warningCounter += 1
615 | return self.WriteLine(Line(message, Severity.Warning, self._baseIndent + indent, appendLinebreak))
616 |
617 | def WriteInfo(self, message, indent=0, appendLinebreak=True):
618 | return self.WriteLine(Line(message, Severity.Info, self._baseIndent + indent, appendLinebreak))
619 |
620 | def WriteQuiet(self, message, indent=0, appendLinebreak=True):
621 | return self.WriteLine(Line(message, Severity.Quiet, self._baseIndent + indent, appendLinebreak))
622 |
623 | def WriteNormal(self, message, indent=0, appendLinebreak=True):
624 | return self.WriteLine(Line(message, Severity.Normal, self._baseIndent + indent, appendLinebreak))
625 |
626 | def WriteVerbose(self, message, indent=1, appendLinebreak=True):
627 | return self.WriteLine(Line(message, Severity.Verbose, self._baseIndent + indent, appendLinebreak))
628 |
629 | def WriteDebug(self, message, indent=2, appendLinebreak=True):
630 | return self.WriteLine(Line(message, Severity.Debug, self._baseIndent + indent, appendLinebreak))
631 |
632 | def WriteDryRun(self, message, indent=2, appendLinebreak=True):
633 | return self.WriteLine(Line(message, Severity.DryRun, self._baseIndent + indent, appendLinebreak))
634 |
--------------------------------------------------------------------------------
/pyTooling/TerminalUI/py.typed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyTooling/pyTooling.TerminalUI/6a01c78dcbc6ac9a51cf67a79d18b89484a2547b/pyTooling/TerminalUI/py.typed
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = [
3 | "pyTooling >= 2.1.0",
4 | "setuptools >= 60.9.3",
5 | "wheel >= 0.37.1"
6 | ]
7 | build-backend = "setuptools.build_meta"
8 |
9 | [tool.black]
10 | line-length = 120
11 |
12 | [tool.pytest.ini_options]
13 | # Don't set 'python_classes = *' otherwise, pytest doesn't search for classes
14 | # derived from unittest.Testcase
15 | python_files = "*"
16 | python_functions = "test_*"
17 |
18 | [tool.coverage.run]
19 | branch = true
20 | omit = [
21 | "*site-packages*",
22 | "setup.py"
23 | ]
24 |
25 | [tool.coverage.report]
26 | skip_covered = true
27 | skip_empty = true
28 | exclude_lines = [
29 | "raise NotImplementedError"
30 | ]
31 |
32 | [tool.coverage.html]
33 | directory = "report/coverage/html"
34 |
35 | [tool.coverage.xml]
36 | output = "report/coverage/coverage.xml"
37 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | colorama>=0.4.5
2 |
3 | pyTooling>=2.1.0
4 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # _____ _ _ _____ _ _ _ _ ___
3 | # _ __ _ |_ _|__ ___ | (_)_ __ __ _|_ _|__ _ __ _ __ ___ (_)_ __ __ _| | | | |_ _|
4 | # | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` | | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | | | | || |
5 | # | |_) | |_| || | (_) | (_) | | | | | | (_| |_| | __/ | | | | | | | | | | | (_| | | |_| || |
6 | # | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)_|\___|_| |_| |_| |_|_|_| |_|\__,_|_|\___/|___|
7 | # |_| |___/ |___/
8 | # =============================================================================
9 | # Authors: Patrick Lehmann
10 | #
11 | # Package installer: A set of helpers to implement a text user interface (TUI) in a terminal.
12 | #
13 | # License:
14 | # ============================================================================
15 | # Copyright 2017-2022 Patrick Lehmann - Bötzingen, Germany
16 | #
17 | # Licensed under the Apache License, Version 2.0 (the "License");
18 | # you may not use this file except in compliance with the License.
19 | # You may obtain a copy of the License at
20 | #
21 | # http://www.apache.org/licenses/LICENSE-2.0
22 | #
23 | # Unless required by applicable law or agreed to in writing, software
24 | # distributed under the License is distributed on an "AS IS" BASIS,
25 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 | # See the License for the specific language governing permissions and
27 | # limitations under the License.
28 | #
29 | # SPDX-License-Identifier: Apache-2.0
30 | # ============================================================================
31 | #
32 | from pathlib import Path
33 | from pyTooling.Packaging import DescribePythonPackageHostedOnGitHub
34 |
35 | gitHubNamespace = "pyTooling"
36 | packageName = "pyTooling.TerminalUI"
37 | packageDirectory = packageName.replace(".", "/")
38 | packageInformationFile = Path(f"{packageDirectory}/__init__.py")
39 |
40 | DescribePythonPackageHostedOnGitHub(
41 | packageName=packageName,
42 | description="A set of helpers to implement a text user interface (TUI) in a terminal.",
43 | gitHubNamespace=gitHubNamespace,
44 | sourceFileWithVersion=packageInformationFile,
45 | dataFiles={
46 | packageName: ["py.typed"]
47 | }
48 | )
49 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # _____ _ _ _ _ ___
3 | # _ __ _ |_ _|__ _ __ _ __ ___ (_)_ __ __ _| | | | |_ _|
4 | # | '_ \| | | || |/ _ \ '__| '_ ` _ \| | '_ \ / _` | | | | || |
5 | # | |_) | |_| || | __/ | | | | | | | | | | | (_| | | |_| || |
6 | # | .__/ \__, ||_|\___|_| |_| |_| |_|_|_| |_|\__,_|_|\___/|___|
7 | # |_| |___/
8 | # =============================================================================
9 | # Authors: Patrick Lehmann
10 | #
11 | # Python unittest: Helper functions for unittests
12 | #
13 | # Description:
14 | # ------------------------------------
15 | # TODO
16 | #
17 | # License:
18 | # ============================================================================
19 | # Copyright 2017-2022 Patrick Lehmann - Bötzingen, Germany
20 | # Copyright 2007-2016 Patrick Lehmann - Dresden, Germany
21 | #
22 | # Licensed under the Apache License, Version 2.0 (the "License");
23 | # you may not use this file except in compliance with the License.
24 | # You may obtain a copy of the License at
25 | #
26 | # http://www.apache.org/licenses/LICENSE-2.0
27 | #
28 | # Unless required by applicable law or agreed to in writing, software
29 | # distributed under the License is distributed on an "AS IS" BASIS,
30 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 | # See the License for the specific language governing permissions and
32 | # limitations under the License.
33 | #
34 | # SPDX-License-Identifier: Apache-2.0
35 | # ============================================================================
36 | #
37 | """
38 | Module containing test code written for `pyTest `__.
39 |
40 | :copyright: Copyright 2007-2022 Patrick Lehmann - Bötzingen, Germany
41 | :license: Apache License, Version 2.0
42 | """
43 |
--------------------------------------------------------------------------------
/tests/requirements.txt:
--------------------------------------------------------------------------------
1 | -r ../requirements.txt
2 |
3 | # Coverage collection
4 | Coverage>=6.3
5 |
6 | # Test Runner
7 | pytest>=7.1.2
8 | pytest-cov>=3.0.0
9 |
10 | # Static Type Checking
11 | mypy>=0.931
12 | lxml>=4.9
13 |
--------------------------------------------------------------------------------
/tests/unit/TerminalUI.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # _____ _ _ _ _ ___
3 | # _ __ _ |_ _|__ _ __ _ __ ___ (_)_ __ __ _| | | | |_ _|
4 | # | '_ \| | | || |/ _ \ '__| '_ ` _ \| | '_ \ / _` | | | | || |
5 | # | |_) | |_| || | __/ | | | | | | | | | | | (_| | | |_| || |
6 | # | .__/ \__, ||_|\___|_| |_| |_| |_|_|_| |_|\__,_|_|\___/|___|
7 | # |_| |___/
8 | # =============================================================================
9 | # Authors: Patrick Lehmann
10 | #
11 | # Python unittest: Testing the pyTooling.TerminalUI module
12 | #
13 | # License:
14 | # ============================================================================
15 | # Copyright 2017-2022 Patrick Lehmann - Bötzingen, Germany
16 | # Copyright 2007-2016 Patrick Lehmann - Dresden, Germany
17 | #
18 | # Licensed under the Apache License, Version 2.0 (the "License");
19 | # you may not use this file except in compliance with the License.
20 | # You may obtain a copy of the License at
21 | #
22 | # http://www.apache.org/licenses/LICENSE-2.0
23 | #
24 | # Unless required by applicable law or agreed to in writing, software
25 | # distributed under the License is distributed on an "AS IS" BASIS,
26 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27 | # See the License for the specific language governing permissions and
28 | # limitations under the License.
29 | #
30 | # SPDX-License-Identifier: Apache-2.0
31 | # ============================================================================
32 | #
33 | """
34 | pyTooling.TerminalUI
35 | ####################
36 |
37 | :copyright: Copyright 2007-2022 Patrick Lehmann - Bötzingen, Germany
38 | :license: Apache License, Version 2.0
39 | """
40 | from unittest import TestCase
41 |
42 | from pyTooling.TerminalUI import LineTerminal
43 |
44 |
45 | if __name__ == "__main__": # pragma: no cover
46 | print("ERROR: you called a testcase declaration file as an executable module.")
47 | print("Use: 'python -m unitest '")
48 | exit(1)
49 |
50 |
51 | class Application(LineTerminal):
52 | def __init__(self):
53 | super().__init__(verbose=True, debug=True, quiet=False)
54 |
55 | LineTerminal.FATAL_EXIT_CODE = 0
56 |
57 |
58 | class Terminal(TestCase):
59 | app : Application
60 |
61 | def setUp(self) -> None:
62 | self.app = Application()
63 |
64 | def test_Version(self) -> None:
65 | Application.versionCheck((3, 6, 0))
66 |
67 | def test_Write(self) -> None:
68 | self.app.WriteQuiet("This is a quiet message.")
69 | self.app.WriteNormal("This is a normal message.")
70 | self.app.WriteInfo("This is a info message.")
71 | self.app.WriteDebug("This is a debug message.")
72 | self.app.WriteWarning("This is a warning message.")
73 | self.app.WriteError("This is an error message.")
74 | self.app.WriteFatal("This is a fatal message.", immediateExit=False)
75 |
--------------------------------------------------------------------------------
/tests/unit/__init__.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # _____ _ _ _ _ ___
3 | # _ __ _ |_ _|__ _ __ _ __ ___ (_)_ __ __ _| | | | |_ _|
4 | # | '_ \| | | || |/ _ \ '__| '_ ` _ \| | '_ \ / _` | | | | || |
5 | # | |_) | |_| || | __/ | | | | | | | | | | | (_| | | |_| || |
6 | # | .__/ \__, ||_|\___|_| |_| |_| |_|_|_| |_|\__,_|_|\___/|___|
7 | # |_| |___/
8 | # =============================================================================
9 | # Authors: Patrick Lehmann
10 | #
11 | # Python unittest: Helper functions for unittests
12 | #
13 | # License:
14 | # ============================================================================
15 | # Copyright 2017-2022 Patrick Lehmann - Bötzingen, Germany
16 | # Copyright 2007-2016 Patrick Lehmann - Dresden, Germany
17 | #
18 | # Licensed under the Apache License, Version 2.0 (the "License");
19 | # you may not use this file except in compliance with the License.
20 | # You may obtain a copy of the License at
21 | #
22 | # http://www.apache.org/licenses/LICENSE-2.0
23 | #
24 | # Unless required by applicable law or agreed to in writing, software
25 | # distributed under the License is distributed on an "AS IS" BASIS,
26 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27 | # See the License for the specific language governing permissions and
28 | # limitations under the License.
29 | #
30 | # SPDX-License-Identifier: Apache-2.0
31 | # ============================================================================
32 | #
33 | """
34 | pyTooling.TerminalUI
35 | ####################
36 |
37 | :copyright: Copyright 2007-2022 Patrick Lehmann - Bötzingen, Germany
38 | :license: Apache License, Version 2.0
39 | """
40 |
--------------------------------------------------------------------------------