pyOpenSourceProjects 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/.github/workflows/build.yml +2 -2
  2. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/PKG-INFO +9 -7
  3. pyopensourceprojects-0.4.0/README.md +17 -0
  4. pyopensourceprojects-0.4.0/osprojects/__init__.py +1 -0
  5. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/osprojects/check_project.py +23 -18
  6. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/osprojects/checkos.py +14 -11
  7. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/osprojects/editor.py +7 -11
  8. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/osprojects/github_api.py +20 -35
  9. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/osprojects/osproject.py +22 -58
  10. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/pyproject.toml +4 -3
  11. pyopensourceprojects-0.4.0/scripts/blackisort +15 -0
  12. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/tests/basetest.py +8 -21
  13. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/tests/test_github.py +6 -15
  14. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/tests/test_github_api.py +5 -11
  15. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/tests/test_osproject.py +30 -23
  16. pyopensourceprojects-0.3.0/README.md +0 -15
  17. pyopensourceprojects-0.3.0/osprojects/__init__.py +0 -1
  18. pyopensourceprojects-0.3.0/scripts/blackisort +0 -7
  19. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/.github/workflows/upload-to-pypi.yml +0 -0
  20. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/.gitignore +0 -0
  21. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/.project +0 -0
  22. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/.pydevproject +0 -0
  23. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/LICENSE +0 -0
  24. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/mkdocs.yml +0 -0
  25. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/scripts/doc +0 -0
  26. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/scripts/install +0 -0
  27. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/scripts/installAndTest +0 -0
  28. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/scripts/release +0 -0
  29. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/scripts/test +0 -0
  30. {pyopensourceprojects-0.3.0 → pyopensourceprojects-0.4.0}/tests/__init__.py +0 -0
@@ -20,8 +20,8 @@ jobs:
20
20
  matrix:
21
21
  #os: [ubuntu-latest, macos-latest, windows-latest]
22
22
  os: [ubuntu-latest]
23
- #python-version: [ '3.9', '3.10', '3.11', '3.12' ]
24
- python-version: ["3.10"]
23
+ #python-version: [ '3.11', '3.12', '3.13' ]
24
+ python-version: ["3.12"]
25
25
 
26
26
  steps:
27
27
  - uses: actions/checkout@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyOpenSourceProjects
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Dynamic: Summary
5
5
  Project-URL: Home, https://github.com/WolfgangFahl/pyOpenSourceProjects
6
6
  Project-URL: Documentation, http://wiki.bitplan.com/index.php/pyOpenSourceProjects
@@ -10,14 +10,14 @@ Maintainer-email: Wolfgang Fahl <wf@bitplan.com>
10
10
  License-Expression: Apache-2.0
11
11
  License-File: LICENSE
12
12
  Classifier: Programming Language :: Python
13
- Classifier: Programming Language :: Python :: 3.10
14
13
  Classifier: Programming Language :: Python :: 3.11
15
14
  Classifier: Programming Language :: Python :: 3.12
16
15
  Classifier: Programming Language :: Python :: 3.13
17
- Requires-Python: >=3.10
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: beautifulsoup4>=4.14.2
18
18
  Requires-Dist: gitpython
19
19
  Requires-Dist: packaging>=24.1
20
- Requires-Dist: py-3rdparty-mediawiki>=0.17.0
20
+ Requires-Dist: py-3rdparty-mediawiki>=0.18.1
21
21
  Requires-Dist: pylodstorage>=0.17.0
22
22
  Requires-Dist: python-dateutil>=2.8.2
23
23
  Requires-Dist: requests
@@ -26,13 +26,15 @@ Provides-Extra: test
26
26
  Description-Content-Type: text/markdown
27
27
 
28
28
  # pyOpenSourceProjects
29
+
29
30
  Helper Library to organize open source Projects
30
31
 
31
32
  | | |
32
33
  | :--- | :--- |
33
- | **GitHub** | [![Github Actions Build](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml/badge.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml) [![GitHub issues](https://img.shields.io/github/issues/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues/?q=is%3Aissue+is%3Aclosed) |
34
- | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/pyOpenSourceProjects.svg)](https://pypi.python.org/pypi/pyOpenSourceProjects/) [![License](https://img.shields.io/github/license/WolfgangFahl/pyOpenSourceProjects.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) |
35
- | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://WolfgangFahl.github.io/pyOpenSourceProjects/) |
34
+ | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/pyOpenSourceProjects.svg)](https://pypi.python.org/pypi/pyOpenSourceProjects/) [![License](https://img.shields.io/github/license/WolfgangFahl/pyOpenSourceProjects.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) [![format](https://img.shields.io/pypi/format/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) [![downloads](https://img.shields.io/pypi/dd/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) |
35
+ | **GitHub** | [![Github Actions Build](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml/badge.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml) [![Release](https://img.shields.io/github/v/release/WolfgangFahl/pyOpenSourceProjects)](https://github.com/WolfgangFahl/pyOpenSourceProjects/releases) [![Contributors](https://img.shields.io/github/contributors/WolfgangFahl/pyOpenSourceProjects)](https://github.com/WolfgangFahl/pyOpenSourceProjects/graphs/contributors) [![Last Commit](https://img.shields.io/github/last-commit/WolfgangFahl/pyOpenSourceProjects)](https://github.com/WolfgangFahl/pyOpenSourceProjects/commits/) [![GitHub issues](https://img.shields.io/github/issues/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues/?q=is%3Aissue+is%3Aclosed) |
36
+ | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) |
37
+ | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://WolfgangFahl.github.io/pyOpenSourceProjects/) [![formatter-docformatter](https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg)](https://github.com/PyCQA/docformatter) [![style-google](https://img.shields.io/badge/%20style-google-3666d6.svg)](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |
36
38
 
37
39
  ## Documentation
38
40
  [Wiki](https://wiki.bitplan.com/index.php/PyOpenSourceProjects)
@@ -0,0 +1,17 @@
1
+ # pyOpenSourceProjects
2
+
3
+ Helper Library to organize open source Projects
4
+
5
+ | | |
6
+ | :--- | :--- |
7
+ | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/pyOpenSourceProjects.svg)](https://pypi.python.org/pypi/pyOpenSourceProjects/) [![License](https://img.shields.io/github/license/WolfgangFahl/pyOpenSourceProjects.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) [![format](https://img.shields.io/pypi/format/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) [![downloads](https://img.shields.io/pypi/dd/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) |
8
+ | **GitHub** | [![Github Actions Build](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml/badge.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml) [![Release](https://img.shields.io/github/v/release/WolfgangFahl/pyOpenSourceProjects)](https://github.com/WolfgangFahl/pyOpenSourceProjects/releases) [![Contributors](https://img.shields.io/github/contributors/WolfgangFahl/pyOpenSourceProjects)](https://github.com/WolfgangFahl/pyOpenSourceProjects/graphs/contributors) [![Last Commit](https://img.shields.io/github/last-commit/WolfgangFahl/pyOpenSourceProjects)](https://github.com/WolfgangFahl/pyOpenSourceProjects/commits/) [![GitHub issues](https://img.shields.io/github/issues/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues/?q=is%3Aissue+is%3Aclosed) |
9
+ | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) |
10
+ | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://WolfgangFahl.github.io/pyOpenSourceProjects/) [![formatter-docformatter](https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg)](https://github.com/PyCQA/docformatter) [![style-google](https://img.shields.io/badge/%20style-google-3666d6.svg)](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |
11
+
12
+ ## Documentation
13
+ [Wiki](https://wiki.bitplan.com/index.php/PyOpenSourceProjects)
14
+
15
+ ### Authors
16
+ * [Tim Holzheim](https://www.semantic-mediawiki.org/wiki/Tim_Holzheim)
17
+ * [Wolfgang Fahl](http://www.bitplan.com/Wolfgang_Fahl)
@@ -0,0 +1 @@
1
+ __version__ = "0.4.0"
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2024-08-28
1
+ """Created on 2024-08-28.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -13,10 +12,9 @@ from git import Repo
13
12
  from git.exc import InvalidGitRepositoryError, NoSuchPathError
14
13
  from packaging import version
15
14
 
16
- from osprojects.github_api import GitHubAction
17
-
18
15
  # original at ngwidgets - use redundant local copy ...
19
16
  from osprojects.editor import Editor
17
+ from osprojects.github_api import GitHubAction
20
18
 
21
19
 
22
20
  @dataclass
@@ -42,9 +40,7 @@ class Check:
42
40
 
43
41
 
44
42
  class CheckProject:
45
- """
46
- Checker for an individual open source project
47
- """
43
+ """Checker for an individual open source project."""
48
44
 
49
45
  def __init__(self, parent, project, args):
50
46
  self.parent = parent
@@ -101,14 +97,28 @@ class CheckProject:
101
97
  self.checks.append(path_exists)
102
98
  return path_exists
103
99
 
100
+ def generate_badge_markdown(self) -> str:
101
+ """Generate README.md badge table markup."""
102
+ project_name = self.project_name
103
+ owner = self.project.owner
104
+ project_id = self.project.project_id
105
+
106
+ markup= f"""| | |
107
+ | :--- | :--- |
108
+ | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/{project_name}.svg)](https://pypi.python.org/pypi/{project_name}/) [![License](https://img.shields.io/github/license/{owner}/{project_id}.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/{project_name})](https://pypi.org/project/{project_name}/) [![format](https://img.shields.io/pypi/format/{project_name})](https://pypi.org/project/{project_name}/) [![downloads](https://img.shields.io/pypi/dd/{project_name})](https://pypi.org/project/{project_name}/) |
109
+ | **GitHub** | [![Github Actions Build](https://github.com/{owner}/{project_id}/actions/workflows/build.yml/badge.svg)](https://github.com/{owner}/{project_id}/actions/workflows/build.yml) [![Release](https://img.shields.io/github/v/release/{owner}/{project_id})](https://github.com/{owner}/{project_id}/releases) [![Contributors](https://img.shields.io/github/contributors/{owner}/{project_id})](https://github.com/{owner}/{project_id}/graphs/contributors) [![Last Commit](https://img.shields.io/github/last-commit/{owner}/{project_id})](https://github.com/{owner}/{project_id}/commits/) [![GitHub issues](https://img.shields.io/github/issues/{owner}/{project_id}.svg)](https://github.com/{owner}/{project_id}/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/{owner}/{project_id}.svg)](https://github.com/{owner}/{project_id}/issues/?q=is%3Aissue+is%3Aclosed) |
110
+ | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) |
111
+ | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://{owner}.github.io/{project_id}/) [![formatter-docformatter](https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg)](https://github.com/PyCQA/docformatter) [![style-google](https://img.shields.io/badge/%20style-google-3666d6.svg)](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |"""
112
+ return markup
113
+
114
+
115
+
104
116
  def check_local(self) -> Check:
105
117
  local = Check.file_exists(self.project_path)
106
118
  return local
107
119
 
108
120
  def check_github_workflows(self):
109
- """
110
- check the github workflow files
111
- """
121
+ """Check the github workflow files."""
112
122
  workflows_path = os.path.join(self.project_path, ".github", "workflows")
113
123
  workflows_exist = self.add_path_check(workflows_path)
114
124
 
@@ -231,9 +241,7 @@ class CheckProject:
231
241
  )
232
242
 
233
243
  def check_pyproject_toml(self) -> bool:
234
- """
235
- pyproject.toml
236
- """
244
+ """pyproject.toml."""
237
245
  toml_path = os.path.join(self.project_path, "pyproject.toml")
238
246
  toml_exists = self.add_path_check(toml_path)
239
247
  if toml_exists.ok:
@@ -274,8 +282,7 @@ class CheckProject:
274
282
  return toml_exists.ok
275
283
 
276
284
  def check_git(self) -> bool:
277
- """
278
- Check git repository information using GitHub class
285
+ """Check git repository information using GitHub class.
279
286
 
280
287
  Returns:
281
288
  bool: True if git owner matches project owner and the repo is not a fork
@@ -335,9 +342,7 @@ class CheckProject:
335
342
  return owner_match and not is_fork
336
343
 
337
344
  def check(self, title: str):
338
- """
339
- Check the given project and print results
340
- """
345
+ """Check the given project and print results."""
341
346
  self.check_local()
342
347
  self.check_git()
343
348
  if self.check_pyproject_toml():
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python
2
- """
3
- Created on 2024-07-30
2
+ """Created on 2024-07-30.
4
3
 
5
4
  @author: wf
6
5
  """
@@ -15,9 +14,7 @@ from osprojects.osproject import OsProjects
15
14
 
16
15
 
17
16
  class CheckOS:
18
- """
19
- checker for a set of open source projects
20
- """
17
+ """Checker for a set of open source projects."""
21
18
 
22
19
  def __init__(
23
20
  self, args: Namespace, osprojects: OsProjects, max_python_version_minor=12
@@ -67,9 +64,8 @@ class CheckOS:
67
64
  self.osprojects.filter_projects(local_only=True)
68
65
 
69
66
  def check_projects(self):
70
- """
71
- Select, filter, and check all projects based on the provided arguments.
72
- """
67
+ """Select, filter, and check all projects based on the provided
68
+ arguments."""
73
69
  self.select_projects()
74
70
  self.filter_projects()
75
71
 
@@ -78,6 +74,9 @@ class CheckOS:
78
74
  ):
79
75
  checker = CheckProject(self, project, self.args)
80
76
  checker.check(f"{i:3}:")
77
+ if self.args.badges:
78
+ print(checker.generate_badge_markdown())
79
+
81
80
 
82
81
  def handle_exception(self, ex: Exception):
83
82
  CheckOS.show_exception(ex, self.args.debug)
@@ -91,9 +90,7 @@ class CheckOS:
91
90
 
92
91
 
93
92
  def main(_argv=None):
94
- """
95
- main command line entry point
96
- """
93
+ """Main command line entry point."""
97
94
  parser = argparse.ArgumentParser(description="Check open source projects")
98
95
  parser.add_argument(
99
96
  "-d",
@@ -101,6 +98,12 @@ def main(_argv=None):
101
98
  action="store_true",
102
99
  help="add debug output",
103
100
  )
101
+ parser.add_argument(
102
+ "-b",
103
+ "--badges",
104
+ action="store_true",
105
+ help="create and output standard README.md badges markup",
106
+ )
104
107
  parser.add_argument(
105
108
  "-e",
106
109
  "--editor",
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2022-11-27
1
+ """Created on 2022-11-27.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -15,10 +14,10 @@ from bs4 import BeautifulSoup
15
14
 
16
15
 
17
16
  class Editor:
18
- """
19
- helper class to open the system defined editor
17
+ """Helper class to open the system defined editor.
20
18
 
21
- see https://stackoverflow.com/questions/1442841/lauch-default-editor-like-webbrowser-module
19
+ see
20
+ https://stackoverflow.com/questions/1442841/lauch-default-editor-like-webbrowser-module
22
21
  """
23
22
 
24
23
  @classmethod
@@ -32,8 +31,7 @@ class Editor:
32
31
 
33
32
  @classmethod
34
33
  def extract_text(cls, html_text: str) -> str:
35
- """
36
- extract the text from the given html_text
34
+ """Extract the text from the given html_text.
37
35
 
38
36
  Args:
39
37
  html_text(str): the input for the html text
@@ -65,8 +63,7 @@ class Editor:
65
63
  extract_text: bool = True,
66
64
  default_editor_cmd: str = "/usr/local/bin/atom",
67
65
  ) -> str:
68
- """
69
- open an editor for the given file_source
66
+ """Open an editor for the given file_source.
70
67
 
71
68
  Args:
72
69
  file_source(str): the path to the file
@@ -104,8 +101,7 @@ class Editor:
104
101
 
105
102
  @classmethod
106
103
  def open_tmp_text(cls, text: str, file_name: str = None) -> str:
107
- """
108
- open an editor for the given text in a newly created temporary file
104
+ """Open an editor for the given text in a newly created temporary file.
109
105
 
110
106
  Args:
111
107
  text(str): the text to write to a temporary file and then open
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2024-08-27
1
+ """Created on 2024-08-27.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -25,17 +24,13 @@ class GitHubApi:
25
24
 
26
25
  @classmethod
27
26
  def get_instance(cls) -> "GitHubApi":
28
- """
29
- singleton access
30
- """
27
+ """Singleton access."""
31
28
  if cls.githubapi_instance is None:
32
29
  cls.githubapi_instance = cls()
33
30
  return cls.githubapi_instance
34
31
 
35
32
  def __init__(self):
36
- """
37
- constructor
38
- """
33
+ """constructor."""
39
34
  home_dir = os.path.expanduser("~")
40
35
  self.base_dir = os.path.join(home_dir, ".github")
41
36
  os.makedirs(self.base_dir, exist_ok=True)
@@ -50,9 +45,8 @@ class GitHubApi:
50
45
  self.api_url = "https://api.github.com"
51
46
 
52
47
  def load_access_token(self) -> str:
53
- """
54
- if $HOME/.github/access_token.json exists read the token from there
55
- """
48
+ """If $HOME/.github/access_token.json exists read the token from
49
+ there."""
56
50
  # Specify the path to the access token file
57
51
  token_file_path = os.path.join(self.base_dir, "access_token.json")
58
52
 
@@ -66,8 +60,7 @@ class GitHubApi:
66
60
  return None
67
61
 
68
62
  def get_response(self, title: str, url: str, params={}, allow_redirects=True):
69
- """
70
- Get response from GitHub API or Google Docs API
63
+ """Get response from GitHub API or Google Docs API.
71
64
 
72
65
  Args:
73
66
  title (str): Description of the request
@@ -95,8 +88,8 @@ class GitHubApi:
95
88
  return response
96
89
 
97
90
  def repos_for_owner(self, owner: str, cache_expiry: int = 300) -> list[dict]:
98
- """
99
- Retrieve all repositories for the given owner, using cache if available and valid, or via API otherwise.
91
+ """Retrieve all repositories for the given owner, using cache if
92
+ available and valid, or via API otherwise.
100
93
 
101
94
  This method first checks if the repository data is available in the cache. If not, it fetches the
102
95
  data from the GitHub API and caches it for future use.
@@ -129,8 +122,7 @@ class GitHubApi:
129
122
  def repos_for_owner_from_cache(
130
123
  self, owner: str
131
124
  ) -> tuple[str, list[dict] | None, float | None]:
132
- """
133
- Retrieve repositories for the given owner from the cache.
125
+ """Retrieve repositories for the given owner from the cache.
134
126
 
135
127
  Args:
136
128
  owner (str): The username of the owner whose repositories are being retrieved.
@@ -154,8 +146,8 @@ class GitHubApi:
154
146
  return cache_file, cache_content, cache_age
155
147
 
156
148
  def repos_for_owner_via_api(self, owner: str) -> list[dict]:
157
- """
158
- Retrieve all repositories for the given owner directly from the GitHub API.
149
+ """Retrieve all repositories for the given owner directly from the
150
+ GitHub API.
159
151
 
160
152
  Args:
161
153
  owner (str): The username of the owner whose repositories are being retrieved.
@@ -187,8 +179,7 @@ class GitHubApi:
187
179
 
188
180
  @dataclass
189
181
  class GitHubRepo:
190
- """
191
- Represents a GitHub Repository
182
+ """Represents a GitHub Repository.
192
183
 
193
184
  Attributes:
194
185
  owner (str): The owner of the repository.
@@ -203,8 +194,7 @@ class GitHubRepo:
203
194
 
204
195
  @classmethod
205
196
  def from_url(cls, url: str) -> (str, str):
206
- """
207
- Resolve project url to owner and project name
197
+ """Resolve project url to owner and project name.
208
198
 
209
199
  Returns:
210
200
  (owner, project)
@@ -257,8 +247,8 @@ class GitHubRepo:
257
247
 
258
248
  @dataclass
259
249
  class GitHubAction:
260
- """
261
- Represents a GitHub Action with its identifying information and log content.
250
+ """Represents a GitHub Action with its identifying information and log
251
+ content.
262
252
 
263
253
  Attributes:
264
254
  repo (GitHubRepo): The repository associated with this action.
@@ -287,8 +277,8 @@ class GitHubAction:
287
277
 
288
278
  @classmethod
289
279
  def from_url(cls, url: str) -> "GitHubAction":
290
- """
291
- Create a GitHubAction instance from a GitHub Actions URL and fetch its logs.
280
+ """Create a GitHubAction instance from a GitHub Actions URL and fetch
281
+ its logs.
292
282
 
293
283
  Args:
294
284
  url (str): The GitHub Actions URL.
@@ -313,8 +303,7 @@ class GitHubAction:
313
303
 
314
304
  @classmethod
315
305
  def get_latest_workflow_run(cls, project):
316
- """
317
- Get the latest GitHub Actions workflow run for a given project.
306
+ """Get the latest GitHub Actions workflow run for a given project.
318
307
 
319
308
  Args:
320
309
  project (OsProject): The project to check for the latest workflow run.
@@ -331,9 +320,7 @@ class GitHubAction:
331
320
  return run
332
321
 
333
322
  def fetch_logs(self):
334
- """
335
- Fetch the logs for this GitHub Action.
336
- """
323
+ """Fetch the logs for this GitHub Action."""
337
324
  if self.log_content is None:
338
325
  api_url = f"https://api.github.com/repos/{self.repo.owner}/{self.repo.project_id}/actions/jobs/{self.job_id}/logs"
339
326
  log_response = self.repo.github.get_response(
@@ -344,9 +331,7 @@ class GitHubAction:
344
331
  self.save_logs()
345
332
 
346
333
  def save_logs(self):
347
- """
348
- Save the log content to a local file.
349
- """
334
+ """Save the log content to a local file."""
350
335
  if self.log_content is None:
351
336
  raise ValueError("No log content to save. Make sure to fetch logs first.")
352
337
  with open(self.log_file, "w", encoding="utf-8") as f:
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2022-01-24
1
+ """Created on 2022-01-24.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -21,9 +20,7 @@ from osprojects.github_api import GitHubApi, GitHubRepo
21
20
 
22
21
 
23
22
  class Ticket(object):
24
- """
25
- a Ticket
26
- """
23
+ """A Ticket."""
27
24
 
28
25
  @staticmethod
29
26
  def getSamples():
@@ -46,18 +43,14 @@ class Ticket(object):
46
43
 
47
44
  @classmethod
48
45
  def init_from_dict(cls, **records):
49
- """
50
- inits Ticket from given args
51
- """
46
+ """Inits Ticket from given args."""
52
47
  issue = Ticket()
53
48
  for k, v in records.items():
54
49
  setattr(issue, k, v)
55
50
  return issue
56
51
 
57
52
  def toWikiMarkup(self) -> str:
58
- """
59
- Returns Ticket in wiki markup
60
- """
53
+ """Returns Ticket in wiki markup."""
61
54
  return f"""# {{{{Ticket
62
55
  |number={self.number}
63
56
  |title={self.title}
@@ -69,9 +62,7 @@ class Ticket(object):
69
62
 
70
63
 
71
64
  class Commit(object):
72
- """
73
- a commit
74
- """
65
+ """A commit."""
75
66
 
76
67
  @staticmethod
77
68
  def getSamples():
@@ -89,9 +80,7 @@ class Commit(object):
89
80
  return samples
90
81
 
91
82
  def toWikiMarkup(self):
92
- """
93
- Returns Commit as wiki markup
94
- """
83
+ """Returns Commit as wiki markup."""
95
84
  params = [
96
85
  f"{attr}={getattr(self, attr, '')}" for attr in self.getSamples()[0].keys()
97
86
  ]
@@ -100,14 +89,10 @@ class Commit(object):
100
89
 
101
90
 
102
91
  class OsProjects:
103
- """
104
- a set of open source projects
105
- """
92
+ """A set of open source projects."""
106
93
 
107
94
  def __init__(self):
108
- """
109
- constructor
110
- """
95
+ """constructor."""
111
96
  self.projects = {}
112
97
  self.projects_by_url = {}
113
98
  self.local_projects = {}
@@ -124,8 +109,7 @@ class OsProjects:
124
109
  self.selected_projects[project.projectUrl()] = project
125
110
 
126
111
  def select_projects(self, owners=None, project_id=None, local_only=False):
127
- """
128
- Select projects based on given criteria.
112
+ """Select projects based on given criteria.
129
113
 
130
114
  Args:
131
115
  owners (Optional[list[str]]): The owners of the projects to select.
@@ -169,8 +153,7 @@ class OsProjects:
169
153
  return self.selected_projects
170
154
 
171
155
  def filter_projects(self, language=None, local_only=False):
172
- """
173
- Filter the selected projects based on language and locality.
156
+ """Filter the selected projects based on language and locality.
174
157
 
175
158
  Args:
176
159
  language (str, optional): The programming language to filter by.
@@ -197,9 +180,7 @@ class OsProjects:
197
180
  return self.selected_projects
198
181
 
199
182
  def add_projects_of_owner(self, owner: str, cache_expiry: int = 300):
200
- """
201
- add the projects of the given owner
202
- """
183
+ """Add the projects of the given owner."""
203
184
  if not owner in self.projects:
204
185
  self.projects[owner] = {}
205
186
  repo_infos = self.github.repos_for_owner(owner, cache_expiry)
@@ -222,8 +203,7 @@ class OsProjects:
222
203
 
223
204
  @classmethod
224
205
  def get_project_url_from_git_config(cls, project_path: str) -> Optional[str]:
225
- """
226
- Get the project URL from the git config file.
206
+ """Get the project URL from the git config file.
227
207
 
228
208
  Args:
229
209
  project_path (str): The path to the project directory.
@@ -248,8 +228,7 @@ class OsProjects:
248
228
 
249
229
  @classmethod
250
230
  def from_folder(cls, folder_path: str, with_progress: bool = False) -> "OsProjects":
251
- """
252
- Collect all github projects from the given folders.
231
+ """Collect all github projects from the given folders.
253
232
 
254
233
  Args:
255
234
  folder_path (str): The path to the folder containing projects.
@@ -285,8 +264,7 @@ class OsProjects:
285
264
  def github_repos_of_folder(
286
265
  cls, folder_path: str
287
266
  ) -> Tuple[Set[str], Dict[str, GitHubRepo]]:
288
- """
289
- Collect GitHub repositories from a given folder.
267
+ """Collect GitHub repositories from a given folder.
290
268
 
291
269
  Args:
292
270
  folder_path (str): The path to the folder to search for repositories.
@@ -316,9 +294,7 @@ class OsProjects:
316
294
 
317
295
 
318
296
  class OsProject:
319
- """
320
- a GitHub based opens source project
321
- """
297
+ """A GitHub based opens source project."""
322
298
 
323
299
  def __init__(self, owner: str = None, project_id: str = None):
324
300
  self.repo_info = None # might be fetched
@@ -328,9 +304,7 @@ class OsProject:
328
304
 
329
305
  @classmethod
330
306
  def fromUrl(cls, url: str) -> "OsProject":
331
- """
332
- Init OsProject from given url
333
- """
307
+ """Init OsProject from given url."""
334
308
  if "github.com" in url:
335
309
  os_project = cls()
336
310
  os_project.repo = GitHubRepo.from_url(url)
@@ -340,12 +314,10 @@ class OsProject:
340
314
 
341
315
  @classmethod
342
316
  def fromRepo(cls):
343
- """
344
- Init OsProject from repo in current working directory
345
- """
317
+ """Init OsProject from repo in current working directory."""
346
318
  url = subprocess.check_output(["git", "config", "--get", "remote.origin.url"])
347
319
  url = url.decode().strip("\n")
348
- repo= cls.fromUrl(url)
320
+ repo = cls.fromUrl(url)
349
321
  return repo
350
322
 
351
323
  def getIssues(self, limit: int = None, **params) -> List[Ticket]:
@@ -402,9 +374,7 @@ class OsProject:
402
374
  return tickets_dict
403
375
 
404
376
  def getComments(self, issue_number: int) -> List[dict]:
405
- """
406
- Fetch all comments for a specific issue number from GitHub.
407
- """
377
+ """Fetch all comments for a specific issue number from GitHub."""
408
378
  comments_url = self.commentUrl(issue_number)
409
379
  response = self.get_response("fetch comments", comments_url)
410
380
  return response.json()
@@ -416,9 +386,7 @@ class OsProject:
416
386
  return f"{self.projectUrl()}/commit/{commit_id}"
417
387
 
418
388
  def commentUrl(self, issue_number: int):
419
- """
420
- Construct the URL for accessing comments of a specific issue.
421
- """
389
+ """Construct the URL for accessing comments of a specific issue."""
422
390
  return f"{self.repo.github.api_url}/repos/{self.repo.owner}/{self.repo.project_id}/issues/{issue_number}/comments"
423
391
 
424
392
  @property
@@ -530,9 +498,7 @@ class OsProject:
530
498
 
531
499
 
532
500
  def gitlog2wiki(_argv=None):
533
- """
534
- cmdline interface to get gitlog entries in wiki markup
535
- """
501
+ """Cmdline interface to get gitlog entries in wiki markup."""
536
502
  parser = argparse.ArgumentParser(description="gitlog2wiki")
537
503
  if _argv:
538
504
  _args = parser.parse_args(args=_argv)
@@ -543,9 +509,7 @@ def gitlog2wiki(_argv=None):
543
509
 
544
510
 
545
511
  def main(_argv=None):
546
- """
547
- main command line entry point
548
- """
512
+ """Main command line entry point."""
549
513
  parser = argparse.ArgumentParser(description="Issue2ticket")
550
514
  parser.add_argument("-o", "--owner", help="project owner")
551
515
  parser.add_argument("-p", "--project", help="name of the project")
@@ -15,13 +15,15 @@ readme = "README.md"
15
15
  license = "Apache-2.0"
16
16
 
17
17
  dependencies = [
18
+ # https://pypi.org/project/beautifulsoup4/
19
+ "beautifulsoup4>=4.14.2",
18
20
  # https://pypi.org/project/GitPython/
19
21
  "gitpython",
20
22
  # https://pypi.org/project/requests/
21
23
  "requests",
22
24
  "pyLodStorage>=0.17.0",
23
25
  # https://pypi.org/project/py-3rdparty-mediawiki/
24
- 'py-3rdparty-mediawiki>=0.17.0',
26
+ 'py-3rdparty-mediawiki>=0.18.1',
25
27
  # https://pypi.org/project/python-dateutil/
26
28
  "python-dateutil>=2.8.2",
27
29
  # https://github.com/pypa/packaging
@@ -29,11 +31,10 @@ dependencies = [
29
31
  # https://pypi.org/project/tqdm/
30
32
  "tqdm>=4.66.5"
31
33
  ]
32
- requires-python = ">=3.10"
34
+ requires-python = ">=3.11"
33
35
 
34
36
  classifiers = [
35
37
  "Programming Language :: Python",
36
- "Programming Language :: Python :: 3.10",
37
38
  "Programming Language :: Python :: 3.11",
38
39
  "Programming Language :: Python :: 3.12",
39
40
  "Programming Language :: Python :: 3.13"
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ # WF 2024-01-10
3
+ package=osprojects
4
+
5
+ # Sort imports
6
+ isort tests/*.py
7
+ isort $package/*.py
8
+
9
+ # Format code
10
+ black tests/*.py
11
+ black $package/*.py
12
+
13
+ # Format docstrings
14
+ docformatter --in-place tests/*.py
15
+ docformatter --in-place $package/*.py
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2021-08-19
1
+ """Created on 2021-08-19.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -15,14 +14,10 @@ from unittest import TestCase
15
14
 
16
15
 
17
16
  class BaseTest(TestCase):
18
- """
19
- base test case
20
- """
17
+ """Base test case."""
21
18
 
22
19
  def setUp(self, debug=False, profile=True):
23
- """
24
- setUp test environment
25
- """
20
+ """SetUp test environment."""
26
21
  TestCase.setUp(self)
27
22
  self.debug = debug
28
23
  self.profile = profile
@@ -35,9 +30,7 @@ class BaseTest(TestCase):
35
30
 
36
31
  @staticmethod
37
32
  def inPublicCI():
38
- """
39
- are we running in a public Continuous Integration Environment?
40
- """
33
+ """Are we running in a public Continuous Integration Environment?"""
41
34
  publicCI = getpass.getuser() in ["travis", "runner"]
42
35
  jenkins = "JENKINS_HOME" in os.environ
43
36
  return publicCI or jenkins
@@ -71,8 +64,7 @@ class BaseTest(TestCase):
71
64
 
72
65
  @staticmethod
73
66
  def captureOutput(fn: Callable, *args, **kwargs) -> str:
74
- """
75
- Captures stdout put of the given function
67
+ """Captures stdout put of the given function.
76
68
 
77
69
  Args:
78
70
  fn(callable): function to call
@@ -93,13 +85,10 @@ if __name__ == "__main__":
93
85
 
94
86
 
95
87
  class Profiler:
96
- """
97
- simple profiler
98
- """
88
+ """Simple profiler."""
99
89
 
100
90
  def __init__(self, msg, profile=True):
101
- """
102
- construct me with the given msg and profile active flag
91
+ """Construct me with the given msg and profile active flag.
103
92
 
104
93
  Args:
105
94
  msg(str): the message to show if profiling is active
@@ -112,9 +101,7 @@ class Profiler:
112
101
  print(f"Starting {msg} ...")
113
102
 
114
103
  def time(self, extraMsg=""):
115
- """
116
- time the action and print if profile is active
117
- """
104
+ """Time the action and print if profile is active."""
118
105
  elapsed = time.time() - self.starttime
119
106
  if self.profile:
120
107
  print(f"{self.msg}{extraMsg} took {elapsed:5.1f} s")
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2024-08-27
1
+ """Created on 2024-08-27.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -12,17 +11,13 @@ from tests.basetest import BaseTest
12
11
 
13
12
 
14
13
  class TestGitHub(BaseTest):
15
- """
16
- tests GitHub class
17
- """
14
+ """Tests GitHub class."""
18
15
 
19
16
  def setUp(self, debug=True, profile=True):
20
17
  BaseTest.setUp(self, debug=debug, profile=profile)
21
18
 
22
19
  def test_GitHubRepo_from_url(self):
23
- """
24
- tests the creating GitHubRepos from the project url
25
- """
20
+ """Tests the creating GitHubRepos from the project url."""
26
21
  urlCases = [
27
22
  {
28
23
  "owner": "WolfgangFahl",
@@ -49,9 +44,7 @@ class TestGitHub(BaseTest):
49
44
  self.assertEqual(expectedProject, github_repo.project_id)
50
45
 
51
46
  def testOsProjects(self):
52
- """
53
- tests the list_projects_as_os_projects method
54
- """
47
+ """Tests the list_projects_as_os_projects method."""
55
48
  owner = "WolfgangFahl"
56
49
  project_id = "pyOpenSourceProjects"
57
50
  osprojects = OsProjects.from_owners([owner])
@@ -105,9 +98,7 @@ class TestGitHub(BaseTest):
105
98
  "Tests querying wikidata which is often blocked on public CI",
106
99
  )
107
100
  def test_projects_from_folder(self):
108
- """
109
- test projects from a specific folder
110
- """
101
+ """Test projects from a specific folder."""
111
102
  debug = self.debug
112
103
  # debug=True
113
104
  home_dir = os.path.expanduser("~")
@@ -117,4 +108,4 @@ class TestGitHub(BaseTest):
117
108
  if debug:
118
109
  print(f"found {count} local projects")
119
110
  self.assertTrue(count > 30)
120
- pass
111
+ pass
@@ -1,5 +1,4 @@
1
- """
2
- Created on 2024-08-27
1
+ """Created on 2024-08-27.
3
2
 
4
3
  @author: wf
5
4
  """
@@ -12,18 +11,15 @@ from tests.basetest import BaseTest
12
11
 
13
12
 
14
13
  class TestGitHubApi(BaseTest):
15
- """
16
- test the GithHubApi functionalities
17
- """
14
+ """Test the GithHubApi functionalities."""
18
15
 
19
16
  def setUp(self, debug=False, profile=True):
20
17
  BaseTest.setUp(self, debug=debug, profile=profile)
21
18
  self.github = GitHubApi.get_instance()
22
19
 
23
20
  def test_repos_for_owner(self):
24
- """
25
- Test the repos_for_owner method for two owners, with caching in between.
26
- """
21
+ """Test the repos_for_owner method for two owners, with caching in
22
+ between."""
27
23
  owners = ["WolfgangFahl", "BITPlan"]
28
24
  cache_expiry = 300 # 5 minutes
29
25
 
@@ -45,9 +41,7 @@ class TestGitHubApi(BaseTest):
45
41
 
46
42
  @unittest.skipIf(BaseTest.inPublicCI(), "missing admin rights in public CI")
47
43
  def test_github_action_from_url(self):
48
- """
49
- Test creating GitHubAction instances from URLs.
50
- """
44
+ """Test creating GitHubAction instances from URLs."""
51
45
  test_cases = [
52
46
  (
53
47
  "single_failure",
@@ -1,22 +1,22 @@
1
- """
2
- Created on 2022-01-24
1
+ """Created on 2022-01-24.
3
2
 
4
3
  @author: wf
5
4
  """
6
5
 
6
+ from argparse import Namespace
7
+
8
+ from osprojects.check_project import CheckProject
7
9
  from osprojects.osproject import Commit, OsProject, Ticket, gitlog2wiki, main
10
+
8
11
  from tests.basetest import BaseTest
9
12
 
10
13
 
11
14
  class TestOsProject(BaseTest):
12
- """
13
- test the OsProject concepts
14
- """
15
+ """Test the OsProject concepts."""
15
16
 
16
17
  def testOsProject(self):
17
- """
18
- tests if the projects details, commits and issues/tickets are correctly queried
19
- """
18
+ """Tests if the projects details, commits and issues/tickets are
19
+ correctly queried."""
20
20
  osProject = OsProject(owner="WolfgangFahl", project_id="pyOpenSourceProjects")
21
21
  tickets = osProject.getAllTickets()
22
22
  sampleTicket = self.getSampleById(Ticket, "number", 2)
@@ -33,10 +33,25 @@ class TestOsProject(BaseTest):
33
33
  self.assertEqual(ticket2.project, sampleTicket.project)
34
34
  pass
35
35
 
36
+ def testBadgeMarkdown(self):
37
+ """Tests badge markdown generation."""
38
+ osProject = OsProject(owner="WolfgangFahl", project_id="pyOpenSourceProjects")
39
+
40
+ args = Namespace(badges=True, debug=False, editor=False)
41
+ checker = CheckProject(parent=None, project=osProject, args=args)
42
+ checker.project_name = "pyOpenSourceProjects"
43
+
44
+ markup = checker.generate_badge_markdown()
45
+
46
+ self.assertIn("| **PyPi** |", markup)
47
+ self.assertIn("| **GitHub** |", markup)
48
+ self.assertIn("| **Code** |", markup)
49
+ self.assertIn("| **Docs** |", markup)
50
+ self.assertIn("[![PyPI Status]", markup)
51
+ self.assertIn("WolfgangFahl/pyOpenSourceProjects", markup)
52
+
36
53
  def testGetCommits(self):
37
- """
38
- tests extraction of commits for a repository
39
- """
54
+ """Tests extraction of commits for a repository."""
40
55
  if self.inPublicCI():
41
56
  return
42
57
  osProject = OsProject(owner="WolfgangFahl", project_id="pyOpenSourceProjects")
@@ -46,9 +61,7 @@ class TestOsProject(BaseTest):
46
61
  self.assertDictEqual(expectedCommit.__dict__, commits[0].__dict__)
47
62
 
48
63
  def testCmdLine(self):
49
- """
50
- tests cmdline of osproject
51
- """
64
+ """Tests cmdline of osproject."""
52
65
  testParams = [
53
66
  ["-o", "WolfgangFahl", "-p", "pyOpenSourceProjects"],
54
67
  ["--repo"],
@@ -59,9 +72,7 @@ class TestOsProject(BaseTest):
59
72
  self.assertIn("{{Ticket", output)
60
73
 
61
74
  def testGitlog2IssueCmdline(self):
62
- """
63
- tests gitlog2issue
64
- """
75
+ """Tests gitlog2issue."""
65
76
  if self.inPublicCI():
66
77
  return
67
78
  commit = self.getSampleById(Commit, "hash", "106254f")
@@ -72,14 +83,10 @@ class TestOsProject(BaseTest):
72
83
 
73
84
 
74
85
  class TestCommit(BaseTest):
75
- """
76
- Tests Commit class
77
- """
86
+ """Tests Commit class."""
78
87
 
79
88
  def testToWikiMarkup(self):
80
- """
81
- tests toWikiMarkup
82
- """
89
+ """Tests toWikiMarkup."""
83
90
  commit = self.getSampleById(Commit, "hash", "106254f")
84
91
  expectedMarkup = "{{commit|host=https://github.com/WolfgangFahl/pyOpenSourceProjects|path=|project=pyOpenSourceProjects|subject=Initial commit|name=GitHub|date=2022-01-24 07:02:55+01:00|hash=106254f|storemode=subobject|viewmode=line}}"
85
92
  self.assertEqual(expectedMarkup, commit.toWikiMarkup())
@@ -1,15 +0,0 @@
1
- # pyOpenSourceProjects
2
- Helper Library to organize open source Projects
3
-
4
- | | |
5
- | :--- | :--- |
6
- | **GitHub** | [![Github Actions Build](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml/badge.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/actions/workflows/build.yml) [![GitHub issues](https://img.shields.io/github/issues/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/WolfgangFahl/pyOpenSourceProjects.svg)](https://github.com/WolfgangFahl/pyOpenSourceProjects/issues/?q=is%3Aissue+is%3Aclosed) |
7
- | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/pyOpenSourceProjects.svg)](https://pypi.python.org/pypi/pyOpenSourceProjects/) [![License](https://img.shields.io/github/license/WolfgangFahl/pyOpenSourceProjects.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/pyOpenSourceProjects)](https://pypi.org/project/pyOpenSourceProjects/) |
8
- | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://WolfgangFahl.github.io/pyOpenSourceProjects/) |
9
-
10
- ## Documentation
11
- [Wiki](https://wiki.bitplan.com/index.php/PyOpenSourceProjects)
12
-
13
- ### Authors
14
- * [Tim Holzheim](https://www.semantic-mediawiki.org/wiki/Tim_Holzheim)
15
- * [Wolfgang Fahl](http://www.bitplan.com/Wolfgang_Fahl)
@@ -1 +0,0 @@
1
- __version__ = "0.3.0"
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
- # WF 2024-01-10
3
- package=osprojects
4
- isort tests/*.py
5
- black tests/*.py
6
- isort $package/*.py
7
- black $package/*.py