pyformatjson 0.2.5__tar.gz → 0.2.6__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.
- pyformatjson-0.2.6/.github/workflows/docs.yml +73 -0
- pyformatjson-0.2.6/.github/workflows/publish.yml +24 -0
- pyformatjson-0.2.6/.github/workflows/release.yml +46 -0
- pyformatjson-0.2.6/.gitignore +180 -0
- pyformatjson-0.2.6/CODE_OF_CONDUCT.md +83 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/PKG-INFO +22 -13
- pyformatjson-0.2.6/docs/api-manual/index.md +1 -0
- pyformatjson-0.2.6/docs/index.md +1 -0
- pyformatjson-0.2.6/docs/requirements.txt +7 -0
- pyformatjson-0.2.6/docs/users-guide/bug-report.md +1 -0
- pyformatjson-0.2.6/docs/users-guide/installation.md +13 -0
- pyformatjson-0.2.6/docs/users-guide/pull-request.md +1 -0
- pyformatjson-0.2.6/mkdocs.yml +148 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/core/_base.py +3 -3
- pyformatjson-0.2.6/pyformatjson/tools/__init__.py +0 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/tools/generate_dict.py +83 -40
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/tools/write_dict.py +1 -1
- pyformatjson-0.2.6/pyformatjson.sublime-project +24 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyproject.toml +56 -18
- pyformatjson-0.2.6/scripts/generate_docs.py +134 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/LICENSE +0 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/README.md +0 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/__init__.py +0 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/core/__init__.py +0 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/core/update_json.py +0 -0
- {pyformatjson-0.2.5 → pyformatjson-0.2.6}/pyformatjson/main.py +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Deploy Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v5
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v6
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
|
|
20
|
+
- name: Cache pip
|
|
21
|
+
uses: actions/cache@v4
|
|
22
|
+
with:
|
|
23
|
+
path: ~/.cache/pip
|
|
24
|
+
key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }}
|
|
25
|
+
restore-keys: |
|
|
26
|
+
${{ runner.os }}-pip-
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: |
|
|
30
|
+
pip install -r docs/requirements.txt
|
|
31
|
+
|
|
32
|
+
- name: Generate API docs
|
|
33
|
+
run: python scripts/generate_docs.py
|
|
34
|
+
|
|
35
|
+
- name: Build documentation (strict)
|
|
36
|
+
run: mkdocs build --strict
|
|
37
|
+
|
|
38
|
+
deploy:
|
|
39
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
needs: test
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v5
|
|
44
|
+
with:
|
|
45
|
+
token: ${{ secrets.PAT_TOKEN }}
|
|
46
|
+
|
|
47
|
+
- name: Set up Python
|
|
48
|
+
uses: actions/setup-python@v6
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.12"
|
|
51
|
+
|
|
52
|
+
- name: Cache pip
|
|
53
|
+
uses: actions/cache@v4
|
|
54
|
+
with:
|
|
55
|
+
path: ~/.cache/pip
|
|
56
|
+
key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }}
|
|
57
|
+
restore-keys: |
|
|
58
|
+
${{ runner.os }}-pip-
|
|
59
|
+
|
|
60
|
+
- name: Install dependencies
|
|
61
|
+
run: |
|
|
62
|
+
pip install -r docs/requirements.txt
|
|
63
|
+
|
|
64
|
+
- name: Generate API docs
|
|
65
|
+
run: python scripts/generate_docs.py
|
|
66
|
+
|
|
67
|
+
- name: Configure Git
|
|
68
|
+
run: |
|
|
69
|
+
git config user.name "GitHub Actions"
|
|
70
|
+
git config user.email "actions@github.com"
|
|
71
|
+
|
|
72
|
+
- name: Deploy to GitHub Pages
|
|
73
|
+
run: mkdocs gh-deploy --force --remote-branch gh-pages
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- name: Checkout
|
|
13
|
+
uses: actions/checkout@v5
|
|
14
|
+
|
|
15
|
+
- name: Install uv
|
|
16
|
+
uses: astral-sh/setup-uv@v6
|
|
17
|
+
|
|
18
|
+
- name: Build package
|
|
19
|
+
run: uv build
|
|
20
|
+
|
|
21
|
+
- name: Publish to PyPI
|
|
22
|
+
env:
|
|
23
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
24
|
+
run: uv publish
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v5
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
token: ${{ secrets.PAT_TOKEN }}
|
|
18
|
+
ref: main
|
|
19
|
+
|
|
20
|
+
- name: Setup Node.js
|
|
21
|
+
uses: actions/setup-node@v6
|
|
22
|
+
with:
|
|
23
|
+
node-version: "24"
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm install -g conventional-changelog conventional-changelog-angular
|
|
27
|
+
|
|
28
|
+
- name: Generate changelog
|
|
29
|
+
# run: conventional-changelog -p angular -i CHANGELOG.md -s -r 0
|
|
30
|
+
run: conventional-changelog -p angular -i CHANGELOG.md -s -r 2
|
|
31
|
+
|
|
32
|
+
# - name: Commit changelog
|
|
33
|
+
# run: |
|
|
34
|
+
# git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
35
|
+
# git config --local user.name "github-actions[bot]"
|
|
36
|
+
# git add CHANGELOG.md
|
|
37
|
+
# git commit -m "docs: update changelog for ${{ github.ref_name }}" || exit 0
|
|
38
|
+
# git push
|
|
39
|
+
|
|
40
|
+
- name: Create GitHub Release
|
|
41
|
+
uses: softprops/action-gh-release@v2
|
|
42
|
+
with:
|
|
43
|
+
body_path: CHANGELOG.md
|
|
44
|
+
# generate_release_notes: true
|
|
45
|
+
env:
|
|
46
|
+
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Common ignored files and folders
|
|
2
|
+
# Ignored files
|
|
3
|
+
.DS_Store
|
|
4
|
+
poetry.lock
|
|
5
|
+
uv.lock
|
|
6
|
+
|
|
7
|
+
*.sublime-workspace
|
|
8
|
+
*.code-workspace
|
|
9
|
+
|
|
10
|
+
# Ignored folders
|
|
11
|
+
node_modules/
|
|
12
|
+
.virtual_documents/
|
|
13
|
+
.ruff_cache
|
|
14
|
+
.idea/
|
|
15
|
+
.vscode/
|
|
16
|
+
tests_temp/
|
|
17
|
+
|
|
18
|
+
# Special for this project
|
|
19
|
+
|
|
20
|
+
# From https://github.com/github/gitignore/blob/main/Python.gitignore
|
|
21
|
+
# Byte-compiled / optimized / DLL files
|
|
22
|
+
__pycache__/
|
|
23
|
+
*.py[cod]
|
|
24
|
+
*$py.class
|
|
25
|
+
|
|
26
|
+
# C extensions
|
|
27
|
+
*.so
|
|
28
|
+
|
|
29
|
+
# Distribution / packaging
|
|
30
|
+
.Python
|
|
31
|
+
build/
|
|
32
|
+
develop-eggs/
|
|
33
|
+
dist/
|
|
34
|
+
downloads/
|
|
35
|
+
eggs/
|
|
36
|
+
.eggs/
|
|
37
|
+
lib/
|
|
38
|
+
lib64/
|
|
39
|
+
parts/
|
|
40
|
+
sdist/
|
|
41
|
+
var/
|
|
42
|
+
wheels/
|
|
43
|
+
share/python-wheels/
|
|
44
|
+
*.egg-info/
|
|
45
|
+
.installed.cfg
|
|
46
|
+
*.egg
|
|
47
|
+
MANIFEST
|
|
48
|
+
|
|
49
|
+
# PyInstaller
|
|
50
|
+
# Usually these files are written by a python script from a template
|
|
51
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
52
|
+
*.manifest
|
|
53
|
+
*.spec
|
|
54
|
+
|
|
55
|
+
# Installer logs
|
|
56
|
+
pip-log.txt
|
|
57
|
+
pip-delete-this-directory.txt
|
|
58
|
+
|
|
59
|
+
# Unit test / coverage reports
|
|
60
|
+
htmlcov/
|
|
61
|
+
.tox/
|
|
62
|
+
.nox/
|
|
63
|
+
.coverage
|
|
64
|
+
.coverage.*
|
|
65
|
+
.cache
|
|
66
|
+
nosetests.xml
|
|
67
|
+
coverage.xml
|
|
68
|
+
*.cover
|
|
69
|
+
*.py,cover
|
|
70
|
+
.hypothesis/
|
|
71
|
+
.pytest_cache/
|
|
72
|
+
cover/
|
|
73
|
+
|
|
74
|
+
# Translations
|
|
75
|
+
*.mo
|
|
76
|
+
*.pot
|
|
77
|
+
|
|
78
|
+
# Django stuff:
|
|
79
|
+
*.log
|
|
80
|
+
local_settings.py
|
|
81
|
+
db.sqlite3
|
|
82
|
+
db.sqlite3-journal
|
|
83
|
+
|
|
84
|
+
# Flask stuff:
|
|
85
|
+
instance/
|
|
86
|
+
.webassets-cache
|
|
87
|
+
|
|
88
|
+
# Scrapy stuff:
|
|
89
|
+
.scrapy
|
|
90
|
+
|
|
91
|
+
# Sphinx documentation
|
|
92
|
+
docs/_build/
|
|
93
|
+
|
|
94
|
+
# PyBuilder
|
|
95
|
+
.pybuilder/
|
|
96
|
+
target/
|
|
97
|
+
|
|
98
|
+
# Jupyter Notebook
|
|
99
|
+
.ipynb_checkpoints
|
|
100
|
+
|
|
101
|
+
# IPython
|
|
102
|
+
profile_default/
|
|
103
|
+
ipython_config.py
|
|
104
|
+
|
|
105
|
+
# pyenv
|
|
106
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
107
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
108
|
+
# .python-version
|
|
109
|
+
|
|
110
|
+
# pipenv
|
|
111
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
112
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
113
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
114
|
+
# install all needed dependencies.
|
|
115
|
+
#Pipfile.lock
|
|
116
|
+
|
|
117
|
+
# poetry
|
|
118
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
119
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
120
|
+
# commonly ignored for libraries.
|
|
121
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
122
|
+
#poetry.lock
|
|
123
|
+
|
|
124
|
+
# pdm
|
|
125
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
126
|
+
#pdm.lock
|
|
127
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
128
|
+
# in version control.
|
|
129
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
130
|
+
.pdm.toml
|
|
131
|
+
|
|
132
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
133
|
+
__pypackages__/
|
|
134
|
+
|
|
135
|
+
# Celery stuff
|
|
136
|
+
celerybeat-schedule
|
|
137
|
+
celerybeat.pid
|
|
138
|
+
|
|
139
|
+
# SageMath parsed files
|
|
140
|
+
*.sage.py
|
|
141
|
+
|
|
142
|
+
# Environments
|
|
143
|
+
.env
|
|
144
|
+
.venv
|
|
145
|
+
env/
|
|
146
|
+
venv/
|
|
147
|
+
ENV/
|
|
148
|
+
env.bak/
|
|
149
|
+
venv.bak/
|
|
150
|
+
|
|
151
|
+
# Spyder project settings
|
|
152
|
+
.spyderproject
|
|
153
|
+
.spyproject
|
|
154
|
+
|
|
155
|
+
# Rope project settings
|
|
156
|
+
.ropeproject
|
|
157
|
+
|
|
158
|
+
# mkdocs documentation
|
|
159
|
+
/site
|
|
160
|
+
|
|
161
|
+
# mypy
|
|
162
|
+
.mypy_cache/
|
|
163
|
+
.dmypy.json
|
|
164
|
+
dmypy.json
|
|
165
|
+
|
|
166
|
+
# Pyre type checker
|
|
167
|
+
.pyre/
|
|
168
|
+
|
|
169
|
+
# pytype static type analyzer
|
|
170
|
+
.pytype/
|
|
171
|
+
|
|
172
|
+
# Cython debug symbols
|
|
173
|
+
cython_debug/
|
|
174
|
+
|
|
175
|
+
# PyCharm
|
|
176
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
177
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
178
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
179
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
180
|
+
#.idea/
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
6
|
+
|
|
7
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
|
8
|
+
|
|
9
|
+
## Our Standards
|
|
10
|
+
|
|
11
|
+
Examples of behavior that contributes to a positive environment for our community include:
|
|
12
|
+
|
|
13
|
+
* Demonstrating empathy and kindness toward other people
|
|
14
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
15
|
+
* Giving and gracefully accepting constructive feedback
|
|
16
|
+
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
|
17
|
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
|
18
|
+
|
|
19
|
+
Examples of unacceptable behavior include:
|
|
20
|
+
|
|
21
|
+
* The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
22
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
23
|
+
* Public or private harassment
|
|
24
|
+
* Publishing others' private information, such as a physical or email address, without their explicit permission
|
|
25
|
+
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
26
|
+
|
|
27
|
+
## Enforcement Responsibilities
|
|
28
|
+
|
|
29
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
|
30
|
+
|
|
31
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
32
|
+
|
|
33
|
+
## Scope
|
|
34
|
+
|
|
35
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
|
36
|
+
|
|
37
|
+
## Enforcement
|
|
38
|
+
|
|
39
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [INSERT CONTACT METHOD]. All complaints will be reviewed and investigated promptly and fairly.
|
|
40
|
+
|
|
41
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
|
42
|
+
|
|
43
|
+
## Enforcement Guidelines
|
|
44
|
+
|
|
45
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
|
46
|
+
|
|
47
|
+
### 1. Correction
|
|
48
|
+
|
|
49
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
|
50
|
+
|
|
51
|
+
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
|
52
|
+
|
|
53
|
+
### 2. Warning
|
|
54
|
+
|
|
55
|
+
**Community Impact**: A violation through a single incident or series of actions.
|
|
56
|
+
|
|
57
|
+
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
|
58
|
+
|
|
59
|
+
### 3. Temporary Ban
|
|
60
|
+
|
|
61
|
+
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
|
62
|
+
|
|
63
|
+
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
|
64
|
+
|
|
65
|
+
### 4. Permanent Ban
|
|
66
|
+
|
|
67
|
+
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
|
68
|
+
|
|
69
|
+
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
|
70
|
+
|
|
71
|
+
## Attribution
|
|
72
|
+
|
|
73
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
|
|
74
|
+
|
|
75
|
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
|
76
|
+
|
|
77
|
+
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
|
|
78
|
+
|
|
79
|
+
[homepage]: https://www.contributor-covenant.org
|
|
80
|
+
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
|
81
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
|
82
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
|
83
|
+
[translations]: https://www.contributor-covenant.org/translations
|
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyformatjson
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: pyformatjson
|
|
5
|
-
|
|
5
|
+
Project-URL: Homepage, https://github.com/Easy-PhD/pyformatjson
|
|
6
|
+
Project-URL: Repository, https://github.com/Easy-PhD/pyformatjson
|
|
7
|
+
Project-URL: Documentation, https://Easy-PhD.github.io/pyformatjson
|
|
8
|
+
Project-URL: Source, https://github.com/Easy-PhD/pyformatjson
|
|
9
|
+
Project-URL: Issues, https://github.com/Easy-PhD/pyformatjson/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/Easy-PhD/pyformatjson/releases
|
|
11
|
+
Author-email: NextAI <nextartifintell@gmail.com>
|
|
12
|
+
Maintainer-email: NextAI <nextartifintell@gmail.com>
|
|
13
|
+
License-Expression: GPL-3.0-or-later
|
|
6
14
|
License-File: LICENSE
|
|
7
|
-
Keywords: Python
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Maintainer: NextAI
|
|
11
|
-
Maintainer-email: nextartifintell@gmail.com
|
|
12
|
-
Requires-Python: >=3.12
|
|
13
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
15
|
+
Keywords: JSON,Python
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
14
18
|
Classifier: Programming Language :: Python :: 3
|
|
15
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
21
|
Classifier: Programming Language :: Python :: 3.14
|
|
18
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
Requires-Python: >=3.12
|
|
24
|
+
Requires-Dist: beautifulsoup4>=4.14.2
|
|
25
|
+
Requires-Dist: func-timeout>=4.3.5
|
|
26
|
+
Requires-Dist: lxml>=6.0.2
|
|
27
|
+
Requires-Dist: playwright>=1.55.0
|
|
28
|
+
Requires-Dist: psutil>=7.1.2
|
|
29
|
+
Requires-Dist: pyadvtools>=0.3.8
|
|
30
|
+
Requires-Dist: requests>=2.32.5
|
|
31
|
+
Requires-Dist: selenium>=4.38.0
|
|
22
32
|
Description-Content-Type: text/markdown
|
|
23
33
|
|
|
24
34
|
# PyFormatJson
|
|
@@ -28,4 +38,3 @@ Description-Content-Type: text/markdown
|
|
|
28
38
|

|
|
29
39
|
[](https://pypi.org/project/pyformatjson/)
|
|
30
40
|
[](http://commitizen.github.io/cz-cli/)
|
|
31
|
-
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# API Reference
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# pyformatjson
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Bug Report
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Pull Request
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Project information
|
|
2
|
+
site_name: pyformatjson Documentation
|
|
3
|
+
site_url: https://Easy-PhD.github.com/pyformatjson
|
|
4
|
+
site_author: NextAI
|
|
5
|
+
site_description: >-
|
|
6
|
+
pyformatjson
|
|
7
|
+
|
|
8
|
+
# Repository
|
|
9
|
+
repo_url: https://github.com/Easy-PhD/pyformatjson
|
|
10
|
+
repo_name: Easy-PhD/pyformatjson
|
|
11
|
+
|
|
12
|
+
# Copyright
|
|
13
|
+
copyright: Copyright © 2025 - 2025 NextAI
|
|
14
|
+
|
|
15
|
+
# Configuration
|
|
16
|
+
theme:
|
|
17
|
+
name: material
|
|
18
|
+
features:
|
|
19
|
+
- announce.dismiss
|
|
20
|
+
# - content.action.edit
|
|
21
|
+
# - content.action.view
|
|
22
|
+
- content.code.annotate
|
|
23
|
+
- content.code.copy
|
|
24
|
+
# - content.code.select
|
|
25
|
+
# - content.footnote.tooltips
|
|
26
|
+
# - content.tabs.link
|
|
27
|
+
- content.tooltips
|
|
28
|
+
# - header.autohide
|
|
29
|
+
# - navigation.expand
|
|
30
|
+
- navigation.footer
|
|
31
|
+
- navigation.indexes
|
|
32
|
+
# - navigation.instant
|
|
33
|
+
# - navigation.instant.prefetch
|
|
34
|
+
# - navigation.instant.progress
|
|
35
|
+
# - navigation.prune
|
|
36
|
+
- navigation.sections
|
|
37
|
+
- navigation.tabs
|
|
38
|
+
# - navigation.tabs.sticky
|
|
39
|
+
- navigation.top
|
|
40
|
+
- navigation.tracking
|
|
41
|
+
- search.highlight
|
|
42
|
+
- search.share
|
|
43
|
+
- search.suggest
|
|
44
|
+
- toc.follow
|
|
45
|
+
# - toc.integrate
|
|
46
|
+
palette:
|
|
47
|
+
- scheme: default
|
|
48
|
+
primary: teal
|
|
49
|
+
accent: purple
|
|
50
|
+
toggle:
|
|
51
|
+
icon: material/brightness-7
|
|
52
|
+
name: Switch to dark mode
|
|
53
|
+
- scheme: slate
|
|
54
|
+
primary: teal
|
|
55
|
+
accent: purple
|
|
56
|
+
toggle:
|
|
57
|
+
icon: material/brightness-4
|
|
58
|
+
name: Switch to light mode
|
|
59
|
+
|
|
60
|
+
plugins:
|
|
61
|
+
- search:
|
|
62
|
+
lang: en
|
|
63
|
+
separator: '[\s\u200b\-_,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
|
|
64
|
+
- autorefs
|
|
65
|
+
- mkdocstrings:
|
|
66
|
+
default_handler: python
|
|
67
|
+
handlers:
|
|
68
|
+
python:
|
|
69
|
+
paths: [.]
|
|
70
|
+
options:
|
|
71
|
+
docstring_style: google
|
|
72
|
+
show_root_heading: true
|
|
73
|
+
show_source: true
|
|
74
|
+
show_category_heading: true
|
|
75
|
+
separate_signature: true
|
|
76
|
+
merge_init_into_class: true
|
|
77
|
+
- minify:
|
|
78
|
+
minify_html: true
|
|
79
|
+
|
|
80
|
+
# Extensions
|
|
81
|
+
markdown_extensions:
|
|
82
|
+
- abbr
|
|
83
|
+
- admonition
|
|
84
|
+
- attr_list
|
|
85
|
+
- def_list
|
|
86
|
+
- footnotes
|
|
87
|
+
- md_in_html
|
|
88
|
+
- toc:
|
|
89
|
+
permalink: true
|
|
90
|
+
- pymdownx.arithmatex:
|
|
91
|
+
generic: true
|
|
92
|
+
- pymdownx.betterem:
|
|
93
|
+
smart_enable: all
|
|
94
|
+
- pymdownx.caret
|
|
95
|
+
- pymdownx.details
|
|
96
|
+
- pymdownx.emoji:
|
|
97
|
+
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
|
98
|
+
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
|
99
|
+
- pymdownx.highlight:
|
|
100
|
+
anchor_linenums: true
|
|
101
|
+
line_spans: __span
|
|
102
|
+
pygments_lang_class: true
|
|
103
|
+
- pymdownx.inlinehilite
|
|
104
|
+
- pymdownx.keys
|
|
105
|
+
- pymdownx.magiclink:
|
|
106
|
+
normalize_issue_symbols: true
|
|
107
|
+
repo_url_shorthand: true
|
|
108
|
+
user: squidfunk
|
|
109
|
+
repo: mkdocs-material
|
|
110
|
+
- pymdownx.mark
|
|
111
|
+
- pymdownx.smartsymbols
|
|
112
|
+
- pymdownx.snippets:
|
|
113
|
+
auto_append:
|
|
114
|
+
- includes/mkdocs.md
|
|
115
|
+
- pymdownx.superfences:
|
|
116
|
+
custom_fences:
|
|
117
|
+
- name: mermaid
|
|
118
|
+
class: mermaid
|
|
119
|
+
format: !!python/name:pymdownx.superfences.fence_code_format
|
|
120
|
+
- pymdownx.tabbed:
|
|
121
|
+
alternate_style: true
|
|
122
|
+
combine_header_slug: true
|
|
123
|
+
slugify: !!python/object/apply:pymdownx.slugs.slugify
|
|
124
|
+
kwds:
|
|
125
|
+
case: lower
|
|
126
|
+
- pymdownx.tasklist:
|
|
127
|
+
custom_checkbox: true
|
|
128
|
+
- pymdownx.tilde
|
|
129
|
+
|
|
130
|
+
extra_javascript:
|
|
131
|
+
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
|
|
132
|
+
|
|
133
|
+
nav:
|
|
134
|
+
- Home: index.md
|
|
135
|
+
|
|
136
|
+
- Getting Started:
|
|
137
|
+
- Installation: users-guide/installation.md
|
|
138
|
+
|
|
139
|
+
- Auto API:
|
|
140
|
+
- Auto API: api-auto.md
|
|
141
|
+
|
|
142
|
+
- Manual API:
|
|
143
|
+
- Manual API: api-manual/index.md
|
|
144
|
+
|
|
145
|
+
- Community:
|
|
146
|
+
- Contributing:
|
|
147
|
+
- Reporting a bug: users-guide/bug-report.md
|
|
148
|
+
- Making a pull request: users-guide/pull-request.md
|
|
@@ -172,7 +172,7 @@ class IterateSortDict:
|
|
|
172
172
|
"""
|
|
173
173
|
self.reverse = reverse
|
|
174
174
|
|
|
175
|
-
def dict_update(self, old):
|
|
175
|
+
def dict_update(self, old: dict) -> dict:
|
|
176
176
|
"""Update and sort a dictionary recursively.
|
|
177
177
|
|
|
178
178
|
This method sorts the dictionary keys and recursively processes
|
|
@@ -188,7 +188,7 @@ class IterateSortDict:
|
|
|
188
188
|
old = self.dict_sort(old)
|
|
189
189
|
return old
|
|
190
190
|
|
|
191
|
-
def dict_sort_iteration(self, old: dict):
|
|
191
|
+
def dict_sort_iteration(self, old: dict) -> dict:
|
|
192
192
|
"""Recursively sort nested dictionaries.
|
|
193
193
|
|
|
194
194
|
This method iterates through the dictionary and recursively sorts
|
|
@@ -205,7 +205,7 @@ class IterateSortDict:
|
|
|
205
205
|
old[key] = self.dict_update(old[key])
|
|
206
206
|
return old
|
|
207
207
|
|
|
208
|
-
def dict_sort(self, old: dict):
|
|
208
|
+
def dict_sort(self, old: dict) -> dict:
|
|
209
209
|
"""Sort dictionary keys using natural sorting.
|
|
210
210
|
|
|
211
211
|
This method sorts the top-level keys of the dictionary using
|
|
File without changes
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def conference_journal_header():
|
|
7
|
+
def conference_journal_header() -> tuple[list[str], list[str]]:
|
|
7
8
|
"""Generate markdown table headers for conferences and journals.
|
|
8
9
|
|
|
9
10
|
This function creates the appropriate markdown table headers for displaying
|
|
@@ -82,7 +83,7 @@ class GenerateDataDict:
|
|
|
82
83
|
self.path_spidered_cj = path_spidered_conferences_or_journals
|
|
83
84
|
self.for_vue = for_vue
|
|
84
85
|
|
|
85
|
-
def generate(self):
|
|
86
|
+
def generate(self) -> tuple[dict, dict, dict]:
|
|
86
87
|
"""Generate publisher metadata and keyword-based publication information.
|
|
87
88
|
|
|
88
89
|
This method processes the JSON data to create three main dictionaries:
|
|
@@ -161,7 +162,7 @@ class GenerateDataDict:
|
|
|
161
162
|
|
|
162
163
|
return publisher_meta_dict, publisher_abbr_meta_dict, keyword_abbr_meta_dict
|
|
163
164
|
|
|
164
|
-
def conference_or_journal(self, publisher_url: str, abbr: str, abbr_dict: dict):
|
|
165
|
+
def conference_or_journal(self, publisher_url: str, abbr: str, abbr_dict: dict) -> tuple[dict[str, Any], list[str]]:
|
|
165
166
|
"""Process conference or journal data and generate formatted information.
|
|
166
167
|
|
|
167
168
|
This method processes individual conference or journal data, validates
|
|
@@ -214,7 +215,7 @@ class GenerateDataDict:
|
|
|
214
215
|
|
|
215
216
|
return {"txt_abouts": abouts, "txt_remarks": remarks, "row_inf": row_inf}, keywords
|
|
216
217
|
|
|
217
|
-
def _validate_name_lengths(self, abbr_dict: dict):
|
|
218
|
+
def _validate_name_lengths(self, abbr_dict: dict) -> None:
|
|
218
219
|
"""Validate that full and abbreviated names arrays have equal length.
|
|
219
220
|
|
|
220
221
|
This method ensures that the full names and abbreviated names arrays
|
|
@@ -231,7 +232,9 @@ class GenerateDataDict:
|
|
|
231
232
|
if len(full_names) != len(abbr_names):
|
|
232
233
|
raise ValueError(f"Length mismatch: {len(full_names)} {full_names} vs {len(abbr_names)} abbreviated names")
|
|
233
234
|
|
|
234
|
-
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
def _extract_full_abbr_names(self, abbr_dict: dict) -> tuple[str, str]:
|
|
235
238
|
"""Extract full and abbreviated names from dictionary.
|
|
236
239
|
|
|
237
240
|
This method extracts the appropriate full and abbreviated names based on
|
|
@@ -248,11 +251,11 @@ class GenerateDataDict:
|
|
|
248
251
|
abbr_name = abbr_dict.get("names_abbr", [""])[0]
|
|
249
252
|
return full_name, abbr_name
|
|
250
253
|
|
|
251
|
-
def _extract_homepage_url(self, abbr_dict: dict):
|
|
254
|
+
def _extract_homepage_url(self, abbr_dict: dict[str, Any]) -> str:
|
|
252
255
|
"""Extract and clean homepage URL.
|
|
253
256
|
|
|
254
257
|
Args:
|
|
255
|
-
abbr_dict (dict): Dictionary containing publication data.
|
|
258
|
+
abbr_dict (dict[str, Any]): Dictionary containing publication data.
|
|
256
259
|
|
|
257
260
|
Returns:
|
|
258
261
|
str: The first valid homepage URL, or empty string if none found.
|
|
@@ -260,11 +263,11 @@ class GenerateDataDict:
|
|
|
260
263
|
urls = [u.strip() for u in abbr_dict.get("urls_homepage", []) if u.strip()]
|
|
261
264
|
return urls[0] if urls else ""
|
|
262
265
|
|
|
263
|
-
def _format_period_with_dblp(self, abbr_dict: dict):
|
|
266
|
+
def _format_period_with_dblp(self, abbr_dict: dict[str, Any]) -> str:
|
|
264
267
|
"""Format publication period with DBLP link if available.
|
|
265
268
|
|
|
266
269
|
Args:
|
|
267
|
-
abbr_dict (dict): Dictionary containing publication data.
|
|
270
|
+
abbr_dict (dict[str, Any]): Dictionary containing publication data.
|
|
268
271
|
|
|
269
272
|
Returns:
|
|
270
273
|
str: Formatted period string with optional DBLP link.
|
|
@@ -283,11 +286,11 @@ class GenerateDataDict:
|
|
|
283
286
|
|
|
284
287
|
return period
|
|
285
288
|
|
|
286
|
-
def _extract_text_content(self, abbr_dict: dict, key: str):
|
|
289
|
+
def _extract_text_content(self, abbr_dict: dict[str, Any], key: str):
|
|
287
290
|
"""Extract and clean text content from dictionary.
|
|
288
291
|
|
|
289
292
|
Args:
|
|
290
|
-
abbr_dict (dict): Dictionary containing publication data.
|
|
293
|
+
abbr_dict (dict[str, Any]): Dictionary containing publication data.
|
|
291
294
|
key (str): Key to extract text content from.
|
|
292
295
|
|
|
293
296
|
Returns:
|
|
@@ -295,11 +298,11 @@ class GenerateDataDict:
|
|
|
295
298
|
"""
|
|
296
299
|
return [text for text in abbr_dict.get(key, []) if text.strip()]
|
|
297
300
|
|
|
298
|
-
def _extract_first_url(self, abbr_dict: dict, key: str):
|
|
301
|
+
def _extract_first_url(self, abbr_dict: dict[str, Any], key: str):
|
|
299
302
|
"""Extract first URL from a list in dictionary.
|
|
300
303
|
|
|
301
304
|
Args:
|
|
302
|
-
abbr_dict (dict): Dictionary containing publication data.
|
|
305
|
+
abbr_dict (dict[str, Any]): Dictionary containing publication data.
|
|
303
306
|
key (str): Key to extract URLs from.
|
|
304
307
|
|
|
305
308
|
Returns:
|
|
@@ -308,11 +311,11 @@ class GenerateDataDict:
|
|
|
308
311
|
urls = [url.strip() for url in abbr_dict.get(key, []) if url.strip()]
|
|
309
312
|
return urls[0].split(",")[0] if urls else ""
|
|
310
313
|
|
|
311
|
-
def _process_keywords(self, abbr_dict: dict):
|
|
314
|
+
def _process_keywords(self, abbr_dict: dict[str, Any]):
|
|
312
315
|
"""Process keywords and convert to Google search URLs.
|
|
313
316
|
|
|
314
317
|
Args:
|
|
315
|
-
abbr_dict (dict): Dictionary containing publication data.
|
|
318
|
+
abbr_dict (dict[str, Any]): Dictionary containing publication data.
|
|
316
319
|
|
|
317
320
|
Returns:
|
|
318
321
|
tuple: A tuple containing (keywords, keywords_url) where keywords
|
|
@@ -350,11 +353,11 @@ class GenerateDataDict:
|
|
|
350
353
|
|
|
351
354
|
return all_keywords, keywords_url
|
|
352
355
|
|
|
353
|
-
def _format_top_score(self, abbr_dict: dict):
|
|
356
|
+
def _format_top_score(self, abbr_dict: dict[str, Any]):
|
|
354
357
|
"""Format top score with optional early access link.
|
|
355
358
|
|
|
356
359
|
Args:
|
|
357
|
-
abbr_dict (dict): Dictionary containing publication data.
|
|
360
|
+
abbr_dict (dict[str, Any]): Dictionary containing publication data.
|
|
358
361
|
|
|
359
362
|
Returns:
|
|
360
363
|
str: Formatted top score with optional early access link.
|
|
@@ -376,7 +379,17 @@ class GenerateDataDict:
|
|
|
376
379
|
return f"[{text}]({url})" if url else text
|
|
377
380
|
|
|
378
381
|
def _generate_table_row(
|
|
379
|
-
self,
|
|
382
|
+
self,
|
|
383
|
+
publisher_url: str,
|
|
384
|
+
full_name: str,
|
|
385
|
+
abbr_name: str,
|
|
386
|
+
url_home: str,
|
|
387
|
+
url_about: str,
|
|
388
|
+
period: str,
|
|
389
|
+
top: str,
|
|
390
|
+
keywords: list[str],
|
|
391
|
+
abbr: str,
|
|
392
|
+
abbr_dict: dict[str, Any],
|
|
380
393
|
):
|
|
381
394
|
"""Generate appropriate table row based on publication type."""
|
|
382
395
|
if self.cj == "conferences":
|
|
@@ -390,7 +403,17 @@ class GenerateDataDict:
|
|
|
390
403
|
|
|
391
404
|
# Conferences
|
|
392
405
|
def _generate_for_conference(
|
|
393
|
-
self,
|
|
406
|
+
self,
|
|
407
|
+
publisher_url: str,
|
|
408
|
+
full_name: str,
|
|
409
|
+
abbr_name: str,
|
|
410
|
+
url_home: str,
|
|
411
|
+
url_about: str,
|
|
412
|
+
period: str,
|
|
413
|
+
top: str,
|
|
414
|
+
keywords: list[str],
|
|
415
|
+
abbr: str,
|
|
416
|
+
abbr_dict: dict[str, Any],
|
|
394
417
|
):
|
|
395
418
|
"""Generate a markdown table row for conference information.
|
|
396
419
|
|
|
@@ -441,7 +464,7 @@ class GenerateDataDict:
|
|
|
441
464
|
keywords,
|
|
442
465
|
)
|
|
443
466
|
|
|
444
|
-
def _process_conference_dates(self, abbr_dict):
|
|
467
|
+
def _process_conference_dates(self, abbr_dict: dict[str, Any]):
|
|
445
468
|
"""Parse and return conference dates."""
|
|
446
469
|
# Parse abstract due date
|
|
447
470
|
abstract_due = None
|
|
@@ -458,7 +481,7 @@ class GenerateDataDict:
|
|
|
458
481
|
|
|
459
482
|
return abstract_due, start_date, today
|
|
460
483
|
|
|
461
|
-
def _format_date_indicators(self, abstract_due, start_date, today):
|
|
484
|
+
def _format_date_indicators(self, abstract_due, start_date, today) -> tuple[str, str]:
|
|
462
485
|
"""Format date indicators for display."""
|
|
463
486
|
abstract_indicator, start_indicator = "", ""
|
|
464
487
|
|
|
@@ -479,22 +502,22 @@ class GenerateDataDict:
|
|
|
479
502
|
|
|
480
503
|
def _build_conference_row(
|
|
481
504
|
self,
|
|
482
|
-
publisher_url,
|
|
483
|
-
full_name,
|
|
484
|
-
abbr_name,
|
|
485
|
-
url_home,
|
|
486
|
-
url_about,
|
|
487
|
-
archive_display,
|
|
488
|
-
period,
|
|
489
|
-
top,
|
|
490
|
-
abbr_dict,
|
|
505
|
+
publisher_url: str,
|
|
506
|
+
full_name: str,
|
|
507
|
+
abbr_name: str,
|
|
508
|
+
url_home: str,
|
|
509
|
+
url_about: str,
|
|
510
|
+
archive_display: str,
|
|
511
|
+
period: str,
|
|
512
|
+
top: str,
|
|
513
|
+
abbr_dict: dict[str, Any],
|
|
491
514
|
abstract_due,
|
|
492
|
-
abstract_indicator,
|
|
515
|
+
abstract_indicator: str,
|
|
493
516
|
start_date,
|
|
494
|
-
start_indicator,
|
|
495
|
-
year_url,
|
|
496
|
-
keywords,
|
|
497
|
-
):
|
|
517
|
+
start_indicator: str,
|
|
518
|
+
year_url: str,
|
|
519
|
+
keywords: list[str],
|
|
520
|
+
) -> str:
|
|
498
521
|
"""Construct conference table row string."""
|
|
499
522
|
# Format date strings
|
|
500
523
|
abstract_date_str = abstract_due.strftime("%d/%m/%Y") if abstract_due else ""
|
|
@@ -522,8 +545,18 @@ class GenerateDataDict:
|
|
|
522
545
|
|
|
523
546
|
# Journals
|
|
524
547
|
def _generate_for_journal(
|
|
525
|
-
self,
|
|
526
|
-
|
|
548
|
+
self,
|
|
549
|
+
publisher_url: str,
|
|
550
|
+
full_name: str,
|
|
551
|
+
abbr_name: str,
|
|
552
|
+
url_home: str,
|
|
553
|
+
url_about: str,
|
|
554
|
+
period: str,
|
|
555
|
+
top: str,
|
|
556
|
+
keywords: list[str],
|
|
557
|
+
abbr: str,
|
|
558
|
+
abbr_dict: dict[str, Any],
|
|
559
|
+
) -> str:
|
|
527
560
|
r"""Generate a markdown table row for journal information.
|
|
528
561
|
|
|
529
562
|
Args:
|
|
@@ -551,8 +584,18 @@ class GenerateDataDict:
|
|
|
551
584
|
)
|
|
552
585
|
|
|
553
586
|
def _build_journal_row(
|
|
554
|
-
self,
|
|
555
|
-
|
|
587
|
+
self,
|
|
588
|
+
publisher_url: str,
|
|
589
|
+
full_name: str,
|
|
590
|
+
abbr_name: str,
|
|
591
|
+
url_home: str,
|
|
592
|
+
url_about: str,
|
|
593
|
+
issues_display: str,
|
|
594
|
+
period: str,
|
|
595
|
+
top: str,
|
|
596
|
+
abbr_dict: dict[str, Any],
|
|
597
|
+
keywords: list[str],
|
|
598
|
+
) -> str:
|
|
556
599
|
"""Construct journal table row string."""
|
|
557
600
|
return (
|
|
558
601
|
f"|{publisher_url}|"
|
|
@@ -569,7 +612,7 @@ class GenerateDataDict:
|
|
|
569
612
|
)
|
|
570
613
|
|
|
571
614
|
# Mermaid data
|
|
572
|
-
def generate_mermaid_data(self, publisher: str, abbr: str, inproceedings_or_article: str):
|
|
615
|
+
def generate_mermaid_data(self, publisher: str, abbr: str, inproceedings_or_article: str) -> list[str]:
|
|
573
616
|
"""Generate Mermaid diagram data from spidered README files.
|
|
574
617
|
|
|
575
618
|
This method reads spidered data from README files and generates
|
|
@@ -15,7 +15,7 @@ def create_safe_filename(text: str) -> str:
|
|
|
15
15
|
return safe_text if safe_text else "unnamed"
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def conference_journal_informations():
|
|
18
|
+
def conference_journal_informations() -> tuple[list[str], list[str]]:
|
|
19
19
|
"""Generate informational content for conferences and journals.
|
|
20
20
|
|
|
21
21
|
This function provides additional informational content that can be
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"build_systems": [
|
|
3
|
+
{
|
|
4
|
+
"file_patterns": ["*.py"],
|
|
5
|
+
"selector": "source.python",
|
|
6
|
+
"working_dir": "${project_path}",
|
|
7
|
+
"name": "Python3 Virtual Env",
|
|
8
|
+
"target": "terminus_exec",
|
|
9
|
+
"cancel": "terminus_cancel_build",
|
|
10
|
+
"shell_cmd": "\".venv/bin/python3\" -u \"$file\"",
|
|
11
|
+
"env": {
|
|
12
|
+
"PYTHONIOENCODING": "utf-8",
|
|
13
|
+
"PYTHONPATH": ".",
|
|
14
|
+
},
|
|
15
|
+
"file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
"settings": {},
|
|
19
|
+
"folders": [
|
|
20
|
+
{
|
|
21
|
+
"path": ".",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
}
|
|
@@ -1,24 +1,62 @@
|
|
|
1
|
-
[
|
|
1
|
+
[project]
|
|
2
2
|
name = "pyformatjson"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.6"
|
|
4
4
|
description = "pyformatjson"
|
|
5
5
|
license = "GPL-3.0-or-later"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
license-files = ["LICENSE"]
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "NextAI", email = "nextartifintell@gmail.com"},
|
|
9
|
+
]
|
|
10
|
+
maintainers = [
|
|
11
|
+
{name = "NextAI", email = "nextartifintell@gmail.com"},
|
|
12
|
+
]
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
keywords = ["Python", "JSON"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Programming Language :: Python",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
23
|
+
]
|
|
24
|
+
requires-python = ">=3.12"
|
|
25
|
+
dependencies = [
|
|
26
|
+
"beautifulsoup4>=4.14.2",
|
|
27
|
+
"func-timeout>=4.3.5",
|
|
28
|
+
"lxml>=6.0.2",
|
|
29
|
+
"playwright>=1.55.0",
|
|
30
|
+
"psutil>=7.1.2",
|
|
31
|
+
"pyadvtools>=0.3.8",
|
|
32
|
+
"requests>=2.32.5",
|
|
33
|
+
"selenium>=4.38.0",
|
|
34
|
+
]
|
|
14
35
|
|
|
15
|
-
[
|
|
16
|
-
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/Easy-PhD/pyformatjson"
|
|
38
|
+
Repository = "https://github.com/Easy-PhD/pyformatjson"
|
|
39
|
+
Documentation = "https://Easy-PhD.github.io/pyformatjson"
|
|
40
|
+
Source = "https://github.com/Easy-PhD/pyformatjson"
|
|
41
|
+
Issues = "https://github.com/Easy-PhD/pyformatjson/issues"
|
|
42
|
+
Changelog = "https://github.com/Easy-PhD/pyformatjson/releases"
|
|
17
43
|
|
|
18
|
-
[
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
[dependency-groups]
|
|
45
|
+
dev = [
|
|
46
|
+
"pytest>=8.4.2",
|
|
47
|
+
"pytest-cov>=7.0.0",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
docs = [
|
|
51
|
+
"ruff>=0.14.3",
|
|
52
|
+
"mkdocs>=1.6.1",
|
|
53
|
+
"mkdocs-autorefs>=1.4.3",
|
|
54
|
+
"mkdocs-material>=9.6.21",
|
|
55
|
+
"mkdocs-material-extensions>=1.3.1",
|
|
56
|
+
"mkdocs-minify-plugin>=0.8.0",
|
|
57
|
+
"mkdocs-redirects>=1.2.2",
|
|
58
|
+
"mkdocstrings[python]>=0.30.1",
|
|
59
|
+
]
|
|
22
60
|
|
|
23
61
|
[tool.pyright]
|
|
24
62
|
venvPath = "."
|
|
@@ -91,5 +129,5 @@ include_trailing_comma = true
|
|
|
91
129
|
[tool.pytest]
|
|
92
130
|
|
|
93
131
|
[build-system]
|
|
94
|
-
requires = ["
|
|
95
|
-
build-backend = "
|
|
132
|
+
requires = ["hatchling"]
|
|
133
|
+
build-backend = "hatchling.build"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DocGenerator:
|
|
8
|
+
"""Documentation generator class."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, package_name: str, source_dir: str, docs_dir: str = "docs"):
|
|
11
|
+
self.package_name = package_name
|
|
12
|
+
self.source_dir = Path(source_dir)
|
|
13
|
+
self.docs_dir = Path(docs_dir)
|
|
14
|
+
self.api_dir = self.docs_dir / "api-auto"
|
|
15
|
+
|
|
16
|
+
# Create necessary directories
|
|
17
|
+
self.api_dir.mkdir(parents=True, exist_ok=True)
|
|
18
|
+
|
|
19
|
+
def discover_modules(self) -> list[Path]:
|
|
20
|
+
modules = []
|
|
21
|
+
|
|
22
|
+
for py_file in self.source_dir.rglob("*.py"):
|
|
23
|
+
# Skip __pycache__ directories and test files
|
|
24
|
+
if "__pycache__" in str(py_file) or "test" in str(py_file).lower():
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
# Skip empty files and __init__.py files (handled separately)
|
|
28
|
+
if py_file.name == "__init__.py":
|
|
29
|
+
continue
|
|
30
|
+
|
|
31
|
+
modules.append(py_file)
|
|
32
|
+
|
|
33
|
+
return modules
|
|
34
|
+
|
|
35
|
+
def get_module_info(self, module_path: Path) -> dict[str, Any]:
|
|
36
|
+
# Calculate relative import path
|
|
37
|
+
relative_path = module_path.relative_to(self.source_dir)
|
|
38
|
+
module_name = str(relative_path).replace("/", ".").replace("\\", ".").replace(".py", "")
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
"path": module_path,
|
|
42
|
+
"name": module_name,
|
|
43
|
+
"import_path": f"{self.package_name}.{module_name}",
|
|
44
|
+
"doc_path": self.api_dir / f"{module_name}.md"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
def generate_module_doc(self, module_info: dict[str, Any]) -> str:
|
|
48
|
+
module_name = module_info["name"]
|
|
49
|
+
import_path = module_info["import_path"]
|
|
50
|
+
|
|
51
|
+
content = [
|
|
52
|
+
f"# {module_name}",
|
|
53
|
+
"",
|
|
54
|
+
f"::: {import_path}",
|
|
55
|
+
" options:",
|
|
56
|
+
" show_root_heading: false",
|
|
57
|
+
" show_submodules: true",
|
|
58
|
+
" heading_level: 2",
|
|
59
|
+
" show_source: true",
|
|
60
|
+
" show_category_heading: true",
|
|
61
|
+
""
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
return "\n".join(content)
|
|
65
|
+
|
|
66
|
+
def generate_api_index(self) -> str:
|
|
67
|
+
modules = self.discover_modules()
|
|
68
|
+
module_infos = [self.get_module_info(module) for module in modules]
|
|
69
|
+
|
|
70
|
+
content = [
|
|
71
|
+
"# API Reference",
|
|
72
|
+
"",
|
|
73
|
+
f"This is the complete API reference documentation for the {self.package_name} library.",
|
|
74
|
+
"",
|
|
75
|
+
"## Module List",
|
|
76
|
+
""
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
# Group modules by directory
|
|
80
|
+
modules_by_dir = {}
|
|
81
|
+
for info in module_infos:
|
|
82
|
+
dir_path = str(Path(info["name"]).parent)
|
|
83
|
+
if dir_path == ".":
|
|
84
|
+
dir_path = "Root Modules"
|
|
85
|
+
if dir_path not in modules_by_dir:
|
|
86
|
+
modules_by_dir[dir_path] = []
|
|
87
|
+
modules_by_dir[dir_path].append(info)
|
|
88
|
+
|
|
89
|
+
# Generate directory structure
|
|
90
|
+
for dir_name in sorted(modules_by_dir.keys()):
|
|
91
|
+
content.append(f"### {dir_name}")
|
|
92
|
+
content.append("")
|
|
93
|
+
|
|
94
|
+
for info in sorted(modules_by_dir[dir_name], key=lambda x: x["name"]):
|
|
95
|
+
module_name = info["name"]
|
|
96
|
+
doc_file = f"api-auto/{module_name}.md"
|
|
97
|
+
content.append(f"- [{module_name}]({doc_file})")
|
|
98
|
+
|
|
99
|
+
content.append("")
|
|
100
|
+
|
|
101
|
+
return "\n".join(content)
|
|
102
|
+
|
|
103
|
+
def write_file(self, filepath: Path, content: str) -> None:
|
|
104
|
+
# Ensure directory exists
|
|
105
|
+
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
|
|
107
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
108
|
+
f.write(content)
|
|
109
|
+
|
|
110
|
+
print(f"✓ Generated documentation: {filepath}")
|
|
111
|
+
|
|
112
|
+
def generate_all(self) -> None:
|
|
113
|
+
"""Generate all documentation."""
|
|
114
|
+
print("Starting API documentation generation...")
|
|
115
|
+
|
|
116
|
+
# Generate documentation for individual modules
|
|
117
|
+
modules = self.discover_modules()
|
|
118
|
+
print(f"Found {len(modules)} modules")
|
|
119
|
+
|
|
120
|
+
for module_path in modules:
|
|
121
|
+
module_info = self.get_module_info(module_path)
|
|
122
|
+
doc_content = self.generate_module_doc(module_info)
|
|
123
|
+
self.write_file(module_info["doc_path"], doc_content)
|
|
124
|
+
|
|
125
|
+
# Generate API index
|
|
126
|
+
api_index_content = self.generate_api_index()
|
|
127
|
+
self.write_file(self.docs_dir / "api-auto.md", api_index_content)
|
|
128
|
+
|
|
129
|
+
print("Documentation generation completed!")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
generator = DocGenerator("pyformatjson", "pyformatjson")
|
|
134
|
+
generator.generate_all()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|