github-dependents-info 3.2.1__tar.gz → 4.1.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.
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/PKG-INFO +65 -33
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/README.md +58 -27
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/github_dependents_info/__main__.py +4 -2
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/github_dependents_info/gh_dependents_info.py +145 -56
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/pyproject.toml +20 -19
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/LICENSE +0 -0
- {github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/github_dependents_info/__init__.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-dependents-info
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: Collect information about dependencies between a github repo and other repositories. Results available in JSON, markdown and badges.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Keywords: github,dependent,used-by,repository,stats,dependencies,using
|
|
8
8
|
Author: nvuillam
|
|
9
9
|
Author-email: nicolas.vuillamy@gmail.com
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.11,<4.0
|
|
11
11
|
Classifier: Development Status :: 3 - Alpha
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
@@ -15,12 +15,13 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
17
|
Requires-Dist: beautifulsoup4 (==4.15.0)
|
|
18
|
-
Requires-Dist: click (>=8.
|
|
18
|
+
Requires-Dist: click (>=8.5,<8.6)
|
|
19
19
|
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
20
|
-
Requires-Dist: idna (>=3.
|
|
21
|
-
Requires-Dist: pandas (>=
|
|
20
|
+
Requires-Dist: idna (>=3.20)
|
|
21
|
+
Requires-Dist: pandas (>=3.1,<3.2)
|
|
22
22
|
Requires-Dist: rich (>=15,<15.1)
|
|
23
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: soupsieve (>=2.8.4)
|
|
24
|
+
Requires-Dist: typer (>=0.27.1,<0.28)
|
|
24
25
|
Project-URL: Homepage, https://github.com/nvuillam/github-dependents-info
|
|
25
26
|
Project-URL: Repository, https://github.com/nvuillam/github-dependents-info
|
|
26
27
|
Description-Content-Type: text/markdown
|
|
@@ -37,7 +38,7 @@ Description-Content-Type: text/markdown
|
|
|
37
38
|
[](https://github.com/nvuillam/github-dependents-info/pulls?utf8=%E2%9C%93&q=is%3Apr%20author%3Aapp%2Fdependabot)
|
|
38
39
|
|
|
39
40
|
[](https://github.com/nvuillam/github-dependents-info/graphs/contributors/)<!-- gh-dependents-info-used-by-start -->
|
|
40
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->
|
|
41
42
|
[](https://github.com/sponsors/nvuillam)
|
|
42
43
|
[](https://github.com/nvuillam/github-dependents-info/actions/workflows/mega-linter.yml)
|
|
43
44
|
[](https://github.com/nvuillam/github-dependents-info/blob/master/LICENSE)
|
|
@@ -62,8 +63,7 @@ This package uses GitHub HTML to collect dependents information and can:
|
|
|
62
63
|
- Generate summary markdown file
|
|
63
64
|
- Optionally add an AI-generated usage summary (via `litellm`) when an LLM API key is present
|
|
64
65
|
- Update existing markdown by inserting **Used by** badge within tags
|
|
65
|
-
-
|
|
66
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->`
|
|
66
|
+
- <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code>
|
|
67
67
|
- Handle multiple repositories packages
|
|
68
68
|
- Filter results using minimum stars or by repository owner
|
|
69
69
|
- Keep huge ecosystems manageable with pagination controls (`--max-scraped-pages`, `--pagination/--no-pagination`, `--page-size`)
|
|
@@ -268,31 +268,30 @@ _________________
|
|
|
268
268
|
| Parameter | Type | Description |
|
|
269
269
|
|-----------|--------|----------------------------------------------|
|
|
270
270
|
| --repo | String | Repository. Example: `oxsecurity/megalinter` |
|
|
271
|
-
| -b<br/> --badgemarkdownfile
|
|
272
|
-
|
|
273
|
-
| -
|
|
274
|
-
| -
|
|
275
|
-
| -
|
|
276
|
-
| -
|
|
277
|
-
| -
|
|
278
|
-
| -
|
|
279
|
-
| -
|
|
280
|
-
|
|
|
281
|
-
| --
|
|
282
|
-
| --
|
|
283
|
-
| --llm-
|
|
284
|
-
| --llm-
|
|
285
|
-
| --llm-max-
|
|
286
|
-
| --llm-
|
|
287
|
-
| --
|
|
288
|
-
|
|
|
289
|
-
| --verbose | Boolean | _(optional)_ Verbose output |
|
|
271
|
+
| -b<br/> --badgemarkdownfile | String | _(optional)_ Path to markdown file where to insert/update **Used by** badge <br/> (must contain tags <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code>) |
|
|
272
|
+
| -s<br/> --sort | String | _(optional)_ Sort order: name (default) or stars |
|
|
273
|
+
| -x<br/> --minstars | String | _(optional)_ If set, filters repositories to keep only those with more than X stars |
|
|
274
|
+
| -m<br/> --markdownfile | String | _(optional)_ Output markdown file file |
|
|
275
|
+
| -d<br/> --docurl | String | _(optional)_ Hyperlink to use when clicking on badge markdown file badge. (Default: link to markdown file) |
|
|
276
|
+
| -p<br/> --mergepackages | String | _(optional)_ In case of multiple packages, merge their stats in a single one in markdown and json output |
|
|
277
|
+
| -j<br/> --json | String | _(optional)_ Output in json format |
|
|
278
|
+
| -u<br/> --owner | String | _(optional)_ If set, filters repositories to keep only those owned by the specified user/organization |
|
|
279
|
+
| -n<br/> --max-scraped-pages | Integer | _(optional)_ Maximum number of GitHub pages to scrape per package (0 uses all available pages) |
|
|
280
|
+
| --pagination<br/> --no-pagination | Boolean | _(optional)_ Enable (default) or disable pagination when writing markdown output |
|
|
281
|
+
| --page-size | Integer | _(optional)_ Number of repositories per markdown page when pagination is enabled (default: 500) |
|
|
282
|
+
| --llm-summary<br/> --no-llm-summary | Boolean | _(optional)_ Generate an AI usage summary in markdown output when an LLM API key is present (default: enabled) |
|
|
283
|
+
| --llm-model | String | _(optional)_ LiteLLM model to use for the summary. If not set, a lightweight model is selected based on the detected API key provider |
|
|
284
|
+
| --llm-max-repos | Integer | _(optional)_ Max dependent repos included in the summary prompt payload (default: 500) |
|
|
285
|
+
| --llm-max-words | Integer | _(optional)_ Max words for the generated summary (default: 300) |
|
|
286
|
+
| --llm-timeout | Float | _(optional)_ Timeout (seconds) for the summary LLM call (default: 120) |
|
|
287
|
+
| -v<br/> --version | Boolean | _(optional)_ Displays version of github-dependents-info |
|
|
288
|
+
| --verbose | Boolean | _(optional)_ Verbose output |
|
|
290
289
|
|
|
291
290
|
Badge tags example (the tool replaces everything between the markers):
|
|
292
291
|
|
|
293
292
|
```markdown
|
|
294
293
|
<!-- gh-dependents-info-used-by-start -->
|
|
295
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->
|
|
296
295
|
```
|
|
297
296
|
|
|
298
297
|
_________________
|
|
@@ -306,8 +305,7 @@ _________________
|
|
|
306
305
|
|
|
307
306
|
github-dependents-info --repo nvuillam/npm-groovy-lint --json
|
|
308
307
|
|
|
309
|
-
- Insert/Update **Used by** markdown badge within an existing markdown file containing tags
|
|
310
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->`
|
|
308
|
+
- Insert/Update **Used by** markdown badge within an existing markdown file containing tags <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code>
|
|
311
309
|
|
|
312
310
|
github-dependents-info --repo nvuillam/npm-groovy-lint --badgemarkdownfile ./README.md
|
|
313
311
|
|
|
@@ -367,6 +365,7 @@ If an LLM API key is detected in the environment (for example `OPENAI_API_KEY`),
|
|
|
367
365
|
- Override model with `--llm-model` (or env var `GITHUB_DEPENDENTS_INFO_LLM_MODEL` / `LITELLM_MODEL`)
|
|
368
366
|
- Adjust max summary length with `--llm-max-words` (or env var `GITHUB_DEPENDENTS_INFO_LLM_MAX_WORDS`)
|
|
369
367
|
- The summary is cached in `--csvdirectory` (file `llm_summary_<repo>.json`) and reused on subsequent runs
|
|
368
|
+
- A previously generated summary is never lost: if a new summary can not be generated (no API key anymore, no credit left, rate limit, timeout...), the summary found in the cache or in the existing `--markdownfile` is reused
|
|
370
369
|
|
|
371
370
|
|
|
372
371
|
## Use as GitHub Action
|
|
@@ -379,8 +378,7 @@ Create a file **.github/workflows/github-dependents-info.yml** in your repositor
|
|
|
379
378
|
|
|
380
379
|
If will generate a new Pull Request (or replace the pending one) every time the usage stats will have changed :)
|
|
381
380
|
|
|
382
|
-
Don't forget to add tags
|
|
383
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->` in your **README.md**, at the end of another badge line if you want github-dependents-info to replace its content automatically.
|
|
381
|
+
Don't forget to add tags <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code> in your **README.md**, at the end of another badge line if you want github-dependents-info to replace its content automatically.
|
|
384
382
|
|
|
385
383
|
```yaml
|
|
386
384
|
# GitHub Dependents Info workflow
|
|
@@ -431,6 +429,9 @@ jobs:
|
|
|
431
429
|
# badgemarkdownfile: README.md
|
|
432
430
|
# sort: stars
|
|
433
431
|
# minstars: "0"
|
|
432
|
+
# pagination: "true" # set to "false" to write a single markdown file
|
|
433
|
+
# page-size: "500" # number of repositories per markdown page
|
|
434
|
+
# max-scraped-pages: "0" # max pages to scrape per package (0 = no limit)
|
|
434
435
|
# llm-summary: "true" # set to "false" to disable AI usage summary
|
|
435
436
|
# llm-model: "" # optional: override LiteLLM model (example: gpt-4o-mini, gemini-3-flash-preview)
|
|
436
437
|
# llm-max-repos: "500" # optional: cap repos sent to the summary prompt
|
|
@@ -467,6 +468,37 @@ jobs:
|
|
|
467
468
|
STEPS_CPR_OUTPUTS_PULL_REQUEST_URL: ${{ steps.cpr.outputs.pull-request-url }}
|
|
468
469
|
```
|
|
469
470
|
|
|
471
|
+
### GitHub Action inputs
|
|
472
|
+
|
|
473
|
+
Action inputs are named after the CLI options, without the leading `--`. Boolean CLI flags such as `--no-pagination` become inputs with a `"true"` / `"false"` value.
|
|
474
|
+
|
|
475
|
+
| Input | Description | CLI equivalent | Default |
|
|
476
|
+
|----------------------|--------------------------------------------------------------------------------|--------------------------------------|------------------------------------|
|
|
477
|
+
| `repo` | Owner and name of the repository (required) | `--repo` | _(required)_ |
|
|
478
|
+
| `outputrepo` | Owner and name of the output repository, if different from `repo` | `--outputrepo` | `""` |
|
|
479
|
+
| `markdownfile` | Path of the output markdown file | `--markdownfile` | `"docs/github-dependents-info.md"` |
|
|
480
|
+
| `badgemarkdownfile` | File where badges are replaced (between the `gh-dependents-info-used-by` tags) | `--badgemarkdownfile` | `"README.md"` |
|
|
481
|
+
| `docurl` | Custom URL for the badges hyperlink | `--docurl` | `""` |
|
|
482
|
+
| `markdownbadgecolor` | Color of the generated badges | `--markdownbadgecolor` | `"informational"` |
|
|
483
|
+
| `sort` | Sort criteria: `stars` or `name` | `--sort` | `"stars"` |
|
|
484
|
+
| `minstars` | Minimum number of stars to appear in the results | `--minstars` | `"0"` |
|
|
485
|
+
| `timedelay` | Delay in seconds between GitHub requests | `--timedelay` | `"0.1"` |
|
|
486
|
+
| `csvdirectory` | Directory where CSV progress files are written | `--csvdirectory` | `""` |
|
|
487
|
+
| `mergepackages` | `true` to merge multiple packages into a single result | `--mergepackages` | `"false"` |
|
|
488
|
+
| `json` | `true` to emit JSON output | `--json` | `"false"` |
|
|
489
|
+
| `verbose` | `true` to enable verbose logging | `--verbose` | `"false"` |
|
|
490
|
+
| `overwrite` | `true` to overwrite existing CSV progress files | `--overwrite` | `"false"` |
|
|
491
|
+
| `owner` | Filter dependent repositories by owner | `--owner` | `""` |
|
|
492
|
+
| `max-scraped-pages` | Max pages to scrape per package (`0` = no limit) | `--max-scraped-pages` | `"0"` |
|
|
493
|
+
| `pagination` | `false` to write a single markdown file instead of multiple pages | `--pagination` / `--no-pagination` | `"true"` |
|
|
494
|
+
| `no-pagination` | `true` to disable pagination (same as `pagination: "false"`) | `--no-pagination` | `"false"` |
|
|
495
|
+
| `page-size` | Number of repositories per markdown page when pagination is enabled | `--page-size` | `"500"` |
|
|
496
|
+
| `llm-summary` | `false` to disable the AI usage summary | `--llm-summary` / `--no-llm-summary` | `"true"` |
|
|
497
|
+
| `llm-model` | LiteLLM model for the AI usage summary | `--llm-model` | `""` |
|
|
498
|
+
| `llm-max-repos` | Max dependent repos included in the summary prompt | `--llm-max-repos` | `"500"` |
|
|
499
|
+
| `llm-max-words` | Max words for the generated summary | `--llm-max-words` | `"250"` |
|
|
500
|
+
| `llm-timeout` | Timeout (seconds) for the summary LLM call | `--llm-timeout` | `"120"` |
|
|
501
|
+
|
|
470
502
|
_________________
|
|
471
503
|
## 🛡 License
|
|
472
504
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://github.com/nvuillam/github-dependents-info/pulls?utf8=%E2%9C%93&q=is%3Apr%20author%3Aapp%2Fdependabot)
|
|
11
11
|
|
|
12
12
|
[](https://github.com/nvuillam/github-dependents-info/graphs/contributors/)<!-- gh-dependents-info-used-by-start -->
|
|
13
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->
|
|
14
14
|
[](https://github.com/sponsors/nvuillam)
|
|
15
15
|
[](https://github.com/nvuillam/github-dependents-info/actions/workflows/mega-linter.yml)
|
|
16
16
|
[](https://github.com/nvuillam/github-dependents-info/blob/master/LICENSE)
|
|
@@ -35,8 +35,7 @@ This package uses GitHub HTML to collect dependents information and can:
|
|
|
35
35
|
- Generate summary markdown file
|
|
36
36
|
- Optionally add an AI-generated usage summary (via `litellm`) when an LLM API key is present
|
|
37
37
|
- Update existing markdown by inserting **Used by** badge within tags
|
|
38
|
-
-
|
|
39
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->`
|
|
38
|
+
- <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code>
|
|
40
39
|
- Handle multiple repositories packages
|
|
41
40
|
- Filter results using minimum stars or by repository owner
|
|
42
41
|
- Keep huge ecosystems manageable with pagination controls (`--max-scraped-pages`, `--pagination/--no-pagination`, `--page-size`)
|
|
@@ -241,31 +240,30 @@ _________________
|
|
|
241
240
|
| Parameter | Type | Description |
|
|
242
241
|
|-----------|--------|----------------------------------------------|
|
|
243
242
|
| --repo | String | Repository. Example: `oxsecurity/megalinter` |
|
|
244
|
-
| -b<br/> --badgemarkdownfile
|
|
245
|
-
|
|
246
|
-
| -
|
|
247
|
-
| -
|
|
248
|
-
| -
|
|
249
|
-
| -
|
|
250
|
-
| -
|
|
251
|
-
| -
|
|
252
|
-
| -
|
|
253
|
-
|
|
|
254
|
-
| --
|
|
255
|
-
| --
|
|
256
|
-
| --llm-
|
|
257
|
-
| --llm-
|
|
258
|
-
| --llm-max-
|
|
259
|
-
| --llm-
|
|
260
|
-
| --
|
|
261
|
-
|
|
|
262
|
-
| --verbose | Boolean | _(optional)_ Verbose output |
|
|
243
|
+
| -b<br/> --badgemarkdownfile | String | _(optional)_ Path to markdown file where to insert/update **Used by** badge <br/> (must contain tags <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code>) |
|
|
244
|
+
| -s<br/> --sort | String | _(optional)_ Sort order: name (default) or stars |
|
|
245
|
+
| -x<br/> --minstars | String | _(optional)_ If set, filters repositories to keep only those with more than X stars |
|
|
246
|
+
| -m<br/> --markdownfile | String | _(optional)_ Output markdown file file |
|
|
247
|
+
| -d<br/> --docurl | String | _(optional)_ Hyperlink to use when clicking on badge markdown file badge. (Default: link to markdown file) |
|
|
248
|
+
| -p<br/> --mergepackages | String | _(optional)_ In case of multiple packages, merge their stats in a single one in markdown and json output |
|
|
249
|
+
| -j<br/> --json | String | _(optional)_ Output in json format |
|
|
250
|
+
| -u<br/> --owner | String | _(optional)_ If set, filters repositories to keep only those owned by the specified user/organization |
|
|
251
|
+
| -n<br/> --max-scraped-pages | Integer | _(optional)_ Maximum number of GitHub pages to scrape per package (0 uses all available pages) |
|
|
252
|
+
| --pagination<br/> --no-pagination | Boolean | _(optional)_ Enable (default) or disable pagination when writing markdown output |
|
|
253
|
+
| --page-size | Integer | _(optional)_ Number of repositories per markdown page when pagination is enabled (default: 500) |
|
|
254
|
+
| --llm-summary<br/> --no-llm-summary | Boolean | _(optional)_ Generate an AI usage summary in markdown output when an LLM API key is present (default: enabled) |
|
|
255
|
+
| --llm-model | String | _(optional)_ LiteLLM model to use for the summary. If not set, a lightweight model is selected based on the detected API key provider |
|
|
256
|
+
| --llm-max-repos | Integer | _(optional)_ Max dependent repos included in the summary prompt payload (default: 500) |
|
|
257
|
+
| --llm-max-words | Integer | _(optional)_ Max words for the generated summary (default: 300) |
|
|
258
|
+
| --llm-timeout | Float | _(optional)_ Timeout (seconds) for the summary LLM call (default: 120) |
|
|
259
|
+
| -v<br/> --version | Boolean | _(optional)_ Displays version of github-dependents-info |
|
|
260
|
+
| --verbose | Boolean | _(optional)_ Verbose output |
|
|
263
261
|
|
|
264
262
|
Badge tags example (the tool replaces everything between the markers):
|
|
265
263
|
|
|
266
264
|
```markdown
|
|
267
265
|
<!-- gh-dependents-info-used-by-start -->
|
|
268
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->
|
|
269
267
|
```
|
|
270
268
|
|
|
271
269
|
_________________
|
|
@@ -279,8 +277,7 @@ _________________
|
|
|
279
277
|
|
|
280
278
|
github-dependents-info --repo nvuillam/npm-groovy-lint --json
|
|
281
279
|
|
|
282
|
-
- Insert/Update **Used by** markdown badge within an existing markdown file containing tags
|
|
283
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->`
|
|
280
|
+
- Insert/Update **Used by** markdown badge within an existing markdown file containing tags <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code>
|
|
284
281
|
|
|
285
282
|
github-dependents-info --repo nvuillam/npm-groovy-lint --badgemarkdownfile ./README.md
|
|
286
283
|
|
|
@@ -340,6 +337,7 @@ If an LLM API key is detected in the environment (for example `OPENAI_API_KEY`),
|
|
|
340
337
|
- Override model with `--llm-model` (or env var `GITHUB_DEPENDENTS_INFO_LLM_MODEL` / `LITELLM_MODEL`)
|
|
341
338
|
- Adjust max summary length with `--llm-max-words` (or env var `GITHUB_DEPENDENTS_INFO_LLM_MAX_WORDS`)
|
|
342
339
|
- The summary is cached in `--csvdirectory` (file `llm_summary_<repo>.json`) and reused on subsequent runs
|
|
340
|
+
- A previously generated summary is never lost: if a new summary can not be generated (no API key anymore, no credit left, rate limit, timeout...), the summary found in the cache or in the existing `--markdownfile` is reused
|
|
343
341
|
|
|
344
342
|
|
|
345
343
|
## Use as GitHub Action
|
|
@@ -352,8 +350,7 @@ Create a file **.github/workflows/github-dependents-info.yml** in your repositor
|
|
|
352
350
|
|
|
353
351
|
If will generate a new Pull Request (or replace the pending one) every time the usage stats will have changed :)
|
|
354
352
|
|
|
355
|
-
Don't forget to add tags
|
|
356
|
-
[](https://github.com/nvuillam/github-dependents-info/blob/main/docs/github-dependents-info.md)<!-- gh-dependents-info-used-by-end -->` in your **README.md**, at the end of another badge line if you want github-dependents-info to replace its content automatically.
|
|
353
|
+
Don't forget to add tags <code><!-- gh-dependents-info-used-by-start --></code> and <code><!-- gh-dependents-info-used-by-end --></code> in your **README.md**, at the end of another badge line if you want github-dependents-info to replace its content automatically.
|
|
357
354
|
|
|
358
355
|
```yaml
|
|
359
356
|
# GitHub Dependents Info workflow
|
|
@@ -404,6 +401,9 @@ jobs:
|
|
|
404
401
|
# badgemarkdownfile: README.md
|
|
405
402
|
# sort: stars
|
|
406
403
|
# minstars: "0"
|
|
404
|
+
# pagination: "true" # set to "false" to write a single markdown file
|
|
405
|
+
# page-size: "500" # number of repositories per markdown page
|
|
406
|
+
# max-scraped-pages: "0" # max pages to scrape per package (0 = no limit)
|
|
407
407
|
# llm-summary: "true" # set to "false" to disable AI usage summary
|
|
408
408
|
# llm-model: "" # optional: override LiteLLM model (example: gpt-4o-mini, gemini-3-flash-preview)
|
|
409
409
|
# llm-max-repos: "500" # optional: cap repos sent to the summary prompt
|
|
@@ -440,6 +440,37 @@ jobs:
|
|
|
440
440
|
STEPS_CPR_OUTPUTS_PULL_REQUEST_URL: ${{ steps.cpr.outputs.pull-request-url }}
|
|
441
441
|
```
|
|
442
442
|
|
|
443
|
+
### GitHub Action inputs
|
|
444
|
+
|
|
445
|
+
Action inputs are named after the CLI options, without the leading `--`. Boolean CLI flags such as `--no-pagination` become inputs with a `"true"` / `"false"` value.
|
|
446
|
+
|
|
447
|
+
| Input | Description | CLI equivalent | Default |
|
|
448
|
+
|----------------------|--------------------------------------------------------------------------------|--------------------------------------|------------------------------------|
|
|
449
|
+
| `repo` | Owner and name of the repository (required) | `--repo` | _(required)_ |
|
|
450
|
+
| `outputrepo` | Owner and name of the output repository, if different from `repo` | `--outputrepo` | `""` |
|
|
451
|
+
| `markdownfile` | Path of the output markdown file | `--markdownfile` | `"docs/github-dependents-info.md"` |
|
|
452
|
+
| `badgemarkdownfile` | File where badges are replaced (between the `gh-dependents-info-used-by` tags) | `--badgemarkdownfile` | `"README.md"` |
|
|
453
|
+
| `docurl` | Custom URL for the badges hyperlink | `--docurl` | `""` |
|
|
454
|
+
| `markdownbadgecolor` | Color of the generated badges | `--markdownbadgecolor` | `"informational"` |
|
|
455
|
+
| `sort` | Sort criteria: `stars` or `name` | `--sort` | `"stars"` |
|
|
456
|
+
| `minstars` | Minimum number of stars to appear in the results | `--minstars` | `"0"` |
|
|
457
|
+
| `timedelay` | Delay in seconds between GitHub requests | `--timedelay` | `"0.1"` |
|
|
458
|
+
| `csvdirectory` | Directory where CSV progress files are written | `--csvdirectory` | `""` |
|
|
459
|
+
| `mergepackages` | `true` to merge multiple packages into a single result | `--mergepackages` | `"false"` |
|
|
460
|
+
| `json` | `true` to emit JSON output | `--json` | `"false"` |
|
|
461
|
+
| `verbose` | `true` to enable verbose logging | `--verbose` | `"false"` |
|
|
462
|
+
| `overwrite` | `true` to overwrite existing CSV progress files | `--overwrite` | `"false"` |
|
|
463
|
+
| `owner` | Filter dependent repositories by owner | `--owner` | `""` |
|
|
464
|
+
| `max-scraped-pages` | Max pages to scrape per package (`0` = no limit) | `--max-scraped-pages` | `"0"` |
|
|
465
|
+
| `pagination` | `false` to write a single markdown file instead of multiple pages | `--pagination` / `--no-pagination` | `"true"` |
|
|
466
|
+
| `no-pagination` | `true` to disable pagination (same as `pagination: "false"`) | `--no-pagination` | `"false"` |
|
|
467
|
+
| `page-size` | Number of repositories per markdown page when pagination is enabled | `--page-size` | `"500"` |
|
|
468
|
+
| `llm-summary` | `false` to disable the AI usage summary | `--llm-summary` / `--no-llm-summary` | `"true"` |
|
|
469
|
+
| `llm-model` | LiteLLM model for the AI usage summary | `--llm-model` | `""` |
|
|
470
|
+
| `llm-max-repos` | Max dependent repos included in the summary prompt | `--llm-max-repos` | `"500"` |
|
|
471
|
+
| `llm-max-words` | Max words for the generated summary | `--llm-max-words` | `"250"` |
|
|
472
|
+
| `llm-timeout` | Timeout (seconds) for the summary LLM call | `--llm-timeout` | `"120"` |
|
|
473
|
+
|
|
443
474
|
_________________
|
|
444
475
|
## 🛡 License
|
|
445
476
|
|
{github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/github_dependents_info/__main__.py
RENAMED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
from typing import Annotated
|
|
3
2
|
|
|
3
|
+
import logging
|
|
4
|
+
|
|
4
5
|
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
5
8
|
from github_dependents_info import version
|
|
6
9
|
from github_dependents_info.gh_dependents_info import GithubDependentsInfo
|
|
7
|
-
from rich.console import Console
|
|
8
10
|
|
|
9
11
|
app = typer.Typer(
|
|
10
12
|
name="github-dependents-info",
|
|
@@ -13,35 +13,40 @@ import numpy as np
|
|
|
13
13
|
import pandas as pd
|
|
14
14
|
from bs4 import BeautifulSoup
|
|
15
15
|
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# Markers surrounding the AI summary in generated markdown, so a previous summary
|
|
19
|
+
# can be found again and reused when a new one can not be generated.
|
|
20
|
+
LLM_SUMMARY_START_MARKER = "<!-- gh-dependents-info-summary-start -->"
|
|
21
|
+
LLM_SUMMARY_END_MARKER = "<!-- gh-dependents-info-summary-end -->"
|
|
22
|
+
|
|
16
23
|
|
|
17
24
|
class GithubDependentsInfo:
|
|
18
25
|
def __init__(self, repo, **options) -> None:
|
|
19
26
|
self.repo = repo
|
|
20
|
-
self.outputrepo =
|
|
27
|
+
self.outputrepo = options.get("outputrepo", self.repo)
|
|
21
28
|
if self.outputrepo is None or self.outputrepo == "" or len(self.outputrepo) < 4:
|
|
22
29
|
self.outputrepo = self.repo
|
|
23
30
|
self.url_init = f"https://github.com/{self.repo}/network/dependents"
|
|
24
31
|
self.url_starts_with = f"/{self.repo}/network/dependents" + "?package_id="
|
|
25
|
-
self.sort_key = "
|
|
26
|
-
self.min_stars =
|
|
27
|
-
self.json_output =
|
|
28
|
-
self.merge_packages =
|
|
29
|
-
self.doc_url = options
|
|
30
|
-
self.markdown_file = options
|
|
31
|
-
self.badge_color = options
|
|
32
|
-
self.debug =
|
|
33
|
-
self.overwrite_progress = (
|
|
34
|
-
True if "overwrite_progress" in options and options["overwrite_progress"] is True else False
|
|
35
|
-
)
|
|
32
|
+
self.sort_key = options.get("sort_key", "name")
|
|
33
|
+
self.min_stars = options.get("min_stars", None)
|
|
34
|
+
self.json_output = options.get("json_output") is True
|
|
35
|
+
self.merge_packages = options.get("merge_packages") is True
|
|
36
|
+
self.doc_url = options.get("doc_url", None)
|
|
37
|
+
self.markdown_file = options.get("markdown_file", None)
|
|
38
|
+
self.badge_color = options.get("badge_color", "informational")
|
|
39
|
+
self.debug = options.get("debug") is True
|
|
40
|
+
self.overwrite_progress = options.get("overwrite_progress") is True
|
|
36
41
|
self.csv_directory = (
|
|
37
42
|
Path(options["csv_directory"])
|
|
38
43
|
if ("csv_directory" in options and options["csv_directory"] is not None)
|
|
39
44
|
else None
|
|
40
45
|
)
|
|
41
|
-
self.owner = options
|
|
42
|
-
self.max_scraped_pages = options
|
|
46
|
+
self.owner = options.get("owner", None)
|
|
47
|
+
self.max_scraped_pages = options.get("max_scraped_pages", 0)
|
|
43
48
|
self.max_concurrent_requests = options.get("max_concurrent_requests", 10)
|
|
44
|
-
self.pagination =
|
|
49
|
+
self.pagination = options.get("pagination", True)
|
|
45
50
|
self.page_size = options.get("page_size", 500)
|
|
46
51
|
self.total_sum = 0
|
|
47
52
|
self.total_public_sum = 0
|
|
@@ -51,7 +56,7 @@ class GithubDependentsInfo:
|
|
|
51
56
|
self.all_public_dependent_repos = []
|
|
52
57
|
self.badges = {}
|
|
53
58
|
self.result = {}
|
|
54
|
-
self.time_delay = options
|
|
59
|
+
self.time_delay = options.get("time_delay", 0.1)
|
|
55
60
|
self.http_retry_attempts = options.get("http_retry_attempts", 5)
|
|
56
61
|
self.http_retry_initial_delay = options.get("http_retry_initial_delay", max(self.time_delay, 1.0))
|
|
57
62
|
self.http_retry_backoff = options.get("http_retry_backoff", 2.0)
|
|
@@ -66,12 +71,13 @@ class GithubDependentsInfo:
|
|
|
66
71
|
self.llm_model = (
|
|
67
72
|
options.get("llm_model") or os.getenv("GITHUB_DEPENDENTS_INFO_LLM_MODEL") or os.getenv("LITELLM_MODEL")
|
|
68
73
|
)
|
|
69
|
-
self.llm_max_repos = int(options.get("llm_max_repos", os.getenv("GITHUB_DEPENDENTS_INFO_LLM_MAX_REPOS", 500)))
|
|
70
|
-
self.llm_max_words = int(options.get("llm_max_words", os.getenv("GITHUB_DEPENDENTS_INFO_LLM_MAX_WORDS", 300)))
|
|
71
|
-
self.llm_timeout = float(options.get("llm_timeout", os.getenv("GITHUB_DEPENDENTS_INFO_LLM_TIMEOUT", 120)))
|
|
74
|
+
self.llm_max_repos = int(options.get("llm_max_repos", os.getenv("GITHUB_DEPENDENTS_INFO_LLM_MAX_REPOS", "500")))
|
|
75
|
+
self.llm_max_words = int(options.get("llm_max_words", os.getenv("GITHUB_DEPENDENTS_INFO_LLM_MAX_WORDS", "300")))
|
|
76
|
+
self.llm_timeout = float(options.get("llm_timeout", os.getenv("GITHUB_DEPENDENTS_INFO_LLM_TIMEOUT", "120")))
|
|
72
77
|
self.llm_model_used: str | None = None
|
|
73
78
|
self.llm_summary: str | None = None
|
|
74
79
|
self.llm_summary_error: str | None = None
|
|
80
|
+
self.llm_summary_reused: bool = False
|
|
75
81
|
|
|
76
82
|
def collect(self):
|
|
77
83
|
"""Main entry point - synchronous wrapper for async collection."""
|
|
@@ -95,13 +101,13 @@ class GithubDependentsInfo:
|
|
|
95
101
|
if self.owner:
|
|
96
102
|
url += "&owner=" + self.owner
|
|
97
103
|
if self.debug is True:
|
|
98
|
-
|
|
104
|
+
logger.info("Package " + package["name"] + ": browsing " + url + " ...")
|
|
99
105
|
else:
|
|
100
106
|
url = self.url_init
|
|
101
107
|
if self.owner:
|
|
102
108
|
url += "?owner=" + self.owner
|
|
103
109
|
if self.debug is True:
|
|
104
|
-
|
|
110
|
+
logger.info("Package " + self.repo + ": browsing " + url + " ...")
|
|
105
111
|
package["url"] = url
|
|
106
112
|
package["public_dependent_stars"] = 0
|
|
107
113
|
|
|
@@ -115,7 +121,7 @@ class GithubDependentsInfo:
|
|
|
115
121
|
result = sorted(result, key=lambda d: d[self.sort_key])
|
|
116
122
|
if self.debug is True:
|
|
117
123
|
for r in result:
|
|
118
|
-
|
|
124
|
+
logger.info(r)
|
|
119
125
|
|
|
120
126
|
# Build package stats
|
|
121
127
|
total_public_dependents = len(result)
|
|
@@ -151,8 +157,8 @@ class GithubDependentsInfo:
|
|
|
151
157
|
|
|
152
158
|
# Output
|
|
153
159
|
if self.debug is True:
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
logger.info("Total for package: " + str(total_public_dependents))
|
|
161
|
+
logger.info("")
|
|
156
162
|
# Save crawl progress
|
|
157
163
|
self.save_progress(package) # only saves if csv_directory is provided
|
|
158
164
|
|
|
@@ -225,10 +231,73 @@ class GithubDependentsInfo:
|
|
|
225
231
|
if summary:
|
|
226
232
|
self.llm_summary = summary
|
|
227
233
|
return True
|
|
228
|
-
except Exception as exc:
|
|
229
|
-
|
|
234
|
+
except Exception as exc: # noqa: BLE001 - a corrupted cache must never break the run
|
|
235
|
+
logger.warning("Failed to load cached LLM summary: %s", exc)
|
|
230
236
|
return False
|
|
231
237
|
|
|
238
|
+
def _extract_summary_from_markdown_content(self, content: str) -> str | None:
|
|
239
|
+
"""Extract a summary previously written by github-dependents-info in a markdown content."""
|
|
240
|
+
marked = re.search(
|
|
241
|
+
re.escape(LLM_SUMMARY_START_MARKER) + "(.*?)" + re.escape(LLM_SUMMARY_END_MARKER),
|
|
242
|
+
content,
|
|
243
|
+
re.DOTALL,
|
|
244
|
+
)
|
|
245
|
+
if marked is not None:
|
|
246
|
+
block = marked.group(1)
|
|
247
|
+
else:
|
|
248
|
+
# Markdown generated before summary markers existed: fallback on the "## Summary" section
|
|
249
|
+
heading = re.search(r"^##\s+Summary\s*$", content, re.MULTILINE)
|
|
250
|
+
if heading is None:
|
|
251
|
+
return None
|
|
252
|
+
block = content[heading.end() :]
|
|
253
|
+
block = re.sub(r"^\s*##\s+Summary\s*$", "", block, count=1, flags=re.MULTILINE)
|
|
254
|
+
# Keep only the summary text: stop at the next heading, badge, table or footer
|
|
255
|
+
summary_lines: list[str] = []
|
|
256
|
+
for line in block.splitlines():
|
|
257
|
+
stripped = line.strip()
|
|
258
|
+
if stripped.startswith(("#", "[![", "|", "_Generated using [")):
|
|
259
|
+
break
|
|
260
|
+
summary_lines.append(line)
|
|
261
|
+
return "\n".join(summary_lines).strip() or None
|
|
262
|
+
|
|
263
|
+
def _load_previous_markdown_summary(self) -> str | None:
|
|
264
|
+
"""Read the summary generated by a previous run in the output markdown file."""
|
|
265
|
+
if not self.markdown_file:
|
|
266
|
+
return None
|
|
267
|
+
try:
|
|
268
|
+
if not os.path.isfile(self.markdown_file):
|
|
269
|
+
return None
|
|
270
|
+
with open(self.markdown_file, encoding="utf-8") as f:
|
|
271
|
+
content = f.read()
|
|
272
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
273
|
+
logger.warning("Failed to read previous summary from %s: %s", self.markdown_file, exc)
|
|
274
|
+
return None
|
|
275
|
+
return self._extract_summary_from_markdown_content(content)
|
|
276
|
+
|
|
277
|
+
def reuse_previous_llm_summary(self, reason: str) -> bool:
|
|
278
|
+
"""Reuse the summary of a previous run when a new one can not be generated.
|
|
279
|
+
|
|
280
|
+
This avoids losing an existing summary when the LLM call is impossible
|
|
281
|
+
(no API key anymore, no credit left, rate limit, timeout...).
|
|
282
|
+
"""
|
|
283
|
+
if self.llm_summary:
|
|
284
|
+
return True
|
|
285
|
+
if self.load_llm_summary():
|
|
286
|
+
self.llm_summary_reused = True
|
|
287
|
+
else:
|
|
288
|
+
previous_summary = self._load_previous_markdown_summary()
|
|
289
|
+
if not previous_summary:
|
|
290
|
+
return False
|
|
291
|
+
self.llm_summary = previous_summary
|
|
292
|
+
self.llm_summary_reused = True
|
|
293
|
+
# Keep it in the progress directory so next runs can find it faster
|
|
294
|
+
self.save_llm_summary()
|
|
295
|
+
logger.warning(
|
|
296
|
+
"Unable to generate a new AI summary (%s): reusing the summary generated by a previous run",
|
|
297
|
+
reason,
|
|
298
|
+
)
|
|
299
|
+
return True
|
|
300
|
+
|
|
232
301
|
def save_llm_summary(self) -> None:
|
|
233
302
|
"""Persist LLM summary into progress directory if enabled."""
|
|
234
303
|
cache_path = self._llm_summary_cache_path()
|
|
@@ -245,9 +314,9 @@ class GithubDependentsInfo:
|
|
|
245
314
|
}
|
|
246
315
|
with open(cache_path, "w", encoding="utf-8") as f:
|
|
247
316
|
json.dump(payload, f, indent=2)
|
|
248
|
-
except Exception as exc:
|
|
317
|
+
except Exception as exc: # noqa: BLE001 - caching is best effort
|
|
249
318
|
if self.debug:
|
|
250
|
-
|
|
319
|
+
logger.warning("Failed to save cached LLM summary: %s", exc)
|
|
251
320
|
|
|
252
321
|
def _prepare_llm_summary_payload(self) -> dict:
|
|
253
322
|
"""Prepare a compact data payload for the LLM prompt."""
|
|
@@ -295,6 +364,7 @@ class GithubDependentsInfo:
|
|
|
295
364
|
|
|
296
365
|
provider_info = self._detect_llm_provider()
|
|
297
366
|
if provider_info is None:
|
|
367
|
+
self.reuse_previous_llm_summary("no LLM API key found in environment variables")
|
|
298
368
|
return
|
|
299
369
|
|
|
300
370
|
# Default model if none was provided
|
|
@@ -346,9 +416,13 @@ class GithubDependentsInfo:
|
|
|
346
416
|
if content:
|
|
347
417
|
self.llm_summary = str(content).strip()
|
|
348
418
|
self.save_llm_summary()
|
|
349
|
-
|
|
419
|
+
else:
|
|
420
|
+
self.llm_summary_error = "LLM returned an empty summary"
|
|
421
|
+
self.reuse_previous_llm_summary(self.llm_summary_error)
|
|
422
|
+
except Exception as exc: # noqa: BLE001 - any provider error must not break the run
|
|
350
423
|
self.llm_summary_error = str(exc)
|
|
351
|
-
|
|
424
|
+
logger.warning("Failed to generate LLM summary: %s", exc)
|
|
425
|
+
self.reuse_previous_llm_summary(str(exc))
|
|
352
426
|
finally:
|
|
353
427
|
# LiteLLM can keep async clients around. Ensure they're closed before
|
|
354
428
|
# asyncio.run() tears down the event loop to avoid:
|
|
@@ -375,9 +449,9 @@ class GithubDependentsInfo:
|
|
|
375
449
|
result = close_fn()
|
|
376
450
|
if inspect.isawaitable(result):
|
|
377
451
|
await result
|
|
378
|
-
except Exception as exc:
|
|
452
|
+
except Exception as exc: # noqa: BLE001 - cleanup is best effort
|
|
379
453
|
if self.debug:
|
|
380
|
-
|
|
454
|
+
logger.debug("LiteLLM async client cleanup skipped: %s", exc)
|
|
381
455
|
|
|
382
456
|
def _extract_owner_repo(self, dependent_row):
|
|
383
457
|
repo_anchor = dependent_row.find("a", {"data-hovercard-type": "repository"})
|
|
@@ -426,7 +500,7 @@ class GithubDependentsInfo:
|
|
|
426
500
|
if "{{" in package_name:
|
|
427
501
|
continue
|
|
428
502
|
if self.debug is True:
|
|
429
|
-
|
|
503
|
+
logger.info(package_name)
|
|
430
504
|
self.packages += [{"id": package_id, "name": package_name}]
|
|
431
505
|
if len(self.packages) == 0:
|
|
432
506
|
self.packages = [{"id": None, "name": self.repo}]
|
|
@@ -452,7 +526,10 @@ class GithubDependentsInfo:
|
|
|
452
526
|
sources_all_df.set_index("name", inplace=True)
|
|
453
527
|
source_df = pd.json_normalize(source_info).set_index("name", drop=True)
|
|
454
528
|
for column in source_df.columns:
|
|
455
|
-
|
|
529
|
+
# pandas >= 3 infers text columns as StringDtype rather than object, so a
|
|
530
|
+
# `dtype == object` test misses them and writing text into a numeric column
|
|
531
|
+
# raises instead of upcasting. Widen the target column for any non-numeric value.
|
|
532
|
+
if column in sources_all_df.columns and not pd.api.types.is_numeric_dtype(source_df[column]):
|
|
456
533
|
sources_all_df[column] = sources_all_df[column].astype("object")
|
|
457
534
|
sources_all_df.loc[source_df.index, column] = source_df[column]
|
|
458
535
|
sources_all_df.reset_index(inplace=True, drop=False)
|
|
@@ -567,9 +644,26 @@ class GithubDependentsInfo:
|
|
|
567
644
|
"""Build the standard footer for markdown files."""
|
|
568
645
|
return [
|
|
569
646
|
"",
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
647
|
+
(
|
|
648
|
+
"_Generated using [github-dependents-info]"
|
|
649
|
+
"(https://github.com/nvuillam/github-dependents-info), "
|
|
650
|
+
"by [Nicolas Vuillamy](https://github.com/nvuillam)_"
|
|
651
|
+
),
|
|
652
|
+
]
|
|
653
|
+
|
|
654
|
+
def _append_llm_summary(self, md_lines: list) -> None:
|
|
655
|
+
"""Append the AI summary section, surrounded by markers so it can be reused by later runs."""
|
|
656
|
+
if not self.llm_summary:
|
|
657
|
+
return
|
|
658
|
+
md_lines += [
|
|
659
|
+
LLM_SUMMARY_START_MARKER,
|
|
660
|
+
"",
|
|
661
|
+
"## Summary",
|
|
662
|
+
"",
|
|
663
|
+
self.llm_summary.strip(),
|
|
664
|
+
"",
|
|
665
|
+
LLM_SUMMARY_END_MARKER,
|
|
666
|
+
"",
|
|
573
667
|
]
|
|
574
668
|
|
|
575
669
|
def _append_summary_table(self, md_lines: list) -> None:
|
|
@@ -606,8 +700,7 @@ class GithubDependentsInfo:
|
|
|
606
700
|
self._append_summary_table(md_lines)
|
|
607
701
|
|
|
608
702
|
# Optional LLM summary
|
|
609
|
-
|
|
610
|
-
md_lines += ["## Summary", "", self.llm_summary.strip(), ""]
|
|
703
|
+
self._append_llm_summary(md_lines)
|
|
611
704
|
|
|
612
705
|
# Single dependents list
|
|
613
706
|
if self.merge_packages is True:
|
|
@@ -702,8 +795,7 @@ class GithubDependentsInfo:
|
|
|
702
795
|
self._append_summary_table(md_lines)
|
|
703
796
|
|
|
704
797
|
# Optional LLM summary (only on first page)
|
|
705
|
-
|
|
706
|
-
md_lines += ["## Summary", "", self.llm_summary.strip(), ""]
|
|
798
|
+
self._append_llm_summary(md_lines)
|
|
707
799
|
|
|
708
800
|
# Calculate start and end indices for this page
|
|
709
801
|
start_idx = (page_num - 1) * self.page_size
|
|
@@ -840,12 +932,9 @@ class GithubDependentsInfo:
|
|
|
840
932
|
md_lines += [f"|{image_md} [{repo_label}](https://github.com/{repo_label}) | {repo_stars} |"]
|
|
841
933
|
|
|
842
934
|
def build_badge(self, label, nb, **options):
|
|
843
|
-
|
|
844
|
-
url = options["url"]
|
|
845
|
-
else:
|
|
846
|
-
url = f"https://github.com/{self.repo}/network/dependents"
|
|
935
|
+
url = options.get("url", f"https://github.com/{self.repo}/network/dependents")
|
|
847
936
|
return (
|
|
848
|
-
f"[]({url})"
|
|
850
939
|
)
|
|
851
940
|
|
|
@@ -890,7 +979,7 @@ class GithubDependentsInfo:
|
|
|
890
979
|
raise
|
|
891
980
|
delay = self._compute_retry_delay(attempt, response=exc.response)
|
|
892
981
|
if self.debug:
|
|
893
|
-
|
|
982
|
+
logger.warning(
|
|
894
983
|
"HTTP %s while fetching %s (attempt %s/%s). Retrying in %.1fs",
|
|
895
984
|
status_code,
|
|
896
985
|
url,
|
|
@@ -905,7 +994,7 @@ class GithubDependentsInfo:
|
|
|
905
994
|
raise
|
|
906
995
|
delay = self._compute_retry_delay(attempt)
|
|
907
996
|
if self.debug:
|
|
908
|
-
|
|
997
|
+
logger.warning(
|
|
909
998
|
"Request error while fetching %s (attempt %s/%s): %s. Retrying in %.1fs",
|
|
910
999
|
url,
|
|
911
1000
|
attempt,
|
|
@@ -952,12 +1041,12 @@ class GithubDependentsInfo:
|
|
|
952
1041
|
# Check if we've reached the max pages limit
|
|
953
1042
|
if self.max_scraped_pages > 0 and page_number >= self.max_scraped_pages:
|
|
954
1043
|
if self.debug is True:
|
|
955
|
-
|
|
1044
|
+
logger.info(f" - reached max scraped pages limit ({self.max_scraped_pages})")
|
|
956
1045
|
break
|
|
957
1046
|
next_link = u["href"]
|
|
958
1047
|
page_number += 1
|
|
959
1048
|
if self.debug is True:
|
|
960
|
-
|
|
1049
|
+
logger.info(f" - discovered page {page_number}")
|
|
961
1050
|
break
|
|
962
1051
|
|
|
963
1052
|
if next_link is None:
|
|
@@ -970,13 +1059,13 @@ class GithubDependentsInfo:
|
|
|
970
1059
|
current_soup = BeautifulSoup(current_content, "html.parser")
|
|
971
1060
|
except (httpx.RequestError, httpx.TimeoutException) as e:
|
|
972
1061
|
if self.debug:
|
|
973
|
-
|
|
1062
|
+
logger.warning(f"Failed to fetch page during discovery: {e}")
|
|
974
1063
|
break
|
|
975
1064
|
|
|
976
1065
|
# Fetch additional pages in parallel if any
|
|
977
1066
|
if urls_to_fetch:
|
|
978
1067
|
if self.debug:
|
|
979
|
-
|
|
1068
|
+
logger.info(f" - fetching {len(urls_to_fetch)} additional pages in parallel...")
|
|
980
1069
|
tasks = [self.fetch_page(client, page_url, semaphore) for page_url in urls_to_fetch]
|
|
981
1070
|
additional_pages = await asyncio.gather(*tasks, return_exceptions=True)
|
|
982
1071
|
pages_content += additional_pages
|
|
@@ -987,7 +1076,7 @@ class GithubDependentsInfo:
|
|
|
987
1076
|
for page_content in pages_content:
|
|
988
1077
|
if isinstance(page_content, Exception):
|
|
989
1078
|
if self.debug:
|
|
990
|
-
|
|
1079
|
+
logger.warning(f"Failed to fetch page: {page_content}")
|
|
991
1080
|
continue
|
|
992
1081
|
|
|
993
1082
|
soup = BeautifulSoup(page_content, "html.parser")
|
|
@@ -997,7 +1086,7 @@ class GithubDependentsInfo:
|
|
|
997
1086
|
owner_repo = self._extract_owner_repo(t)
|
|
998
1087
|
if owner_repo is None:
|
|
999
1088
|
if self.debug:
|
|
1000
|
-
|
|
1089
|
+
logger.warning("Skipping dependent row without repository link")
|
|
1001
1090
|
continue
|
|
1002
1091
|
owner_name, repo_name = owner_repo
|
|
1003
1092
|
star_svg = t.find("svg", {"class": "octicon-star"})
|
|
@@ -1068,6 +1157,6 @@ class GithubDependentsInfo:
|
|
|
1068
1157
|
number_as_string = number_as_string.replace(",", "").replace(" ", "")
|
|
1069
1158
|
try:
|
|
1070
1159
|
return int(number_as_string)
|
|
1071
|
-
except
|
|
1072
|
-
|
|
1160
|
+
except (ValueError, TypeError):
|
|
1161
|
+
logger.warning(f'WARNING: Unable to get integer from "{number_as_string}"')
|
|
1073
1162
|
return 0
|
|
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "github-dependents-info"
|
|
8
|
-
version = "
|
|
8
|
+
version = "4.1.0"
|
|
9
9
|
description = "Collect information about dependencies between a github repo and other repositories. Results available in JSON, markdown and badges."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = "MIT"
|
|
@@ -13,7 +13,7 @@ license-files = ["LICENSE"]
|
|
|
13
13
|
authors = [
|
|
14
14
|
{name = "nvuillam", email = "nicolas.vuillamy@gmail.com"},
|
|
15
15
|
]
|
|
16
|
-
requires-python = ">=3.
|
|
16
|
+
requires-python = ">=3.11,<4.0"
|
|
17
17
|
|
|
18
18
|
# Keywords description https://python-poetry.org/docs/pyproject/#keywords
|
|
19
19
|
keywords = ["github", "dependent", "used-by", "repository", "stats", "dependencies", "using"]
|
|
@@ -37,41 +37,42 @@ Repository = "https://github.com/nvuillam/github-dependents-info"
|
|
|
37
37
|
"github-dependents-info" = "github_dependents_info.__main__:app"
|
|
38
38
|
|
|
39
39
|
[tool.poetry.dependencies]
|
|
40
|
-
python = ">=3.
|
|
40
|
+
python = ">=3.11,<4.0"
|
|
41
41
|
|
|
42
|
-
click = ">=8.
|
|
43
|
-
typer = ">=0.
|
|
42
|
+
click = ">=8.5,<8.6"
|
|
43
|
+
typer = ">=0.27.1,<0.28"
|
|
44
44
|
rich = ">=15,<15.1"
|
|
45
45
|
beautifulsoup4 = "4.15.0"
|
|
46
|
-
pandas = ">=
|
|
46
|
+
pandas = ">=3.1,<3.2"
|
|
47
47
|
httpx = "^0.28.1"
|
|
48
|
-
idna = ">=3.
|
|
48
|
+
idna = ">=3.20"
|
|
49
|
+
soupsieve = ">=2.8.4" # security floor (CVE-2026-49476, CVE-2026-49477), pulled by beautifulsoup4
|
|
49
50
|
|
|
50
51
|
[tool.poetry.group.dev.dependencies]
|
|
51
52
|
bandit = "^1.7.5"
|
|
52
53
|
black = ">=26.3.1"
|
|
53
54
|
darglint = "^1.8.1"
|
|
54
|
-
isort = {extras = ["colors"], version = "^
|
|
55
|
+
isort = {extras = ["colors"], version = "^9.0.0"}
|
|
55
56
|
mypy = "^2.0"
|
|
56
57
|
mypy-extensions = "^1.0.0"
|
|
57
58
|
pre-commit = "^4.0.0"
|
|
58
59
|
pydocstyle = "^6.3.0"
|
|
59
60
|
pylint = "^4.0.0"
|
|
60
|
-
pytest = "^9.
|
|
61
|
+
pytest = "^9.1.1"
|
|
61
62
|
pyupgrade = "^3.4.0"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
cryptography = ">=48.0.0"
|
|
63
|
+
coverage = "^7.16.1"
|
|
64
|
+
anybadge = "^1.16.0" # replaces coverage-badge, which imports pkg_resources (removed in setuptools 82)
|
|
65
|
+
cryptography = ">=50.0.0"
|
|
66
66
|
pytest-html = "^4.1.1"
|
|
67
67
|
pytest-cov = "^7.0.0"
|
|
68
|
-
marshmallow = ">=4.3,<4.4"
|
|
69
|
-
authlib = ">=1.
|
|
68
|
+
marshmallow = ">=4.3.1,<4.4"
|
|
69
|
+
authlib = ">=1.8.0"
|
|
70
70
|
requests = ">=2.34.2"
|
|
71
|
-
urllib3 = ">=2.
|
|
72
|
-
filelock = ">=
|
|
73
|
-
virtualenv = ">=21.
|
|
74
|
-
nltk = ">=3.
|
|
71
|
+
urllib3 = ">=2.8.0"
|
|
72
|
+
filelock = ">=4.0.1"
|
|
73
|
+
virtualenv = ">=21.9.0"
|
|
74
|
+
nltk = ">=3.10.0"
|
|
75
|
+
setuptools = ">=83.0.0"
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
[[tool.poetry.source]]
|
|
File without changes
|
{github_dependents_info-3.2.1 → github_dependents_info-4.1.0}/github_dependents_info/__init__.py
RENAMED
|
File without changes
|