pyformatters-json 0.5.9__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.
@@ -0,0 +1,9 @@
1
+ # ignore .git and .cache folders
2
+ .git
3
+ .cache
4
+ .pytest_cache
5
+ models
6
+ tests
7
+ log
8
+ **/__pycache__
9
+ *.pyc
@@ -0,0 +1,17 @@
1
+ /.idea/
2
+ /.vscode/
3
+ /dist/
4
+ dist
5
+ .git
6
+ .cache
7
+ **/.pytest_cache
8
+ models
9
+ log
10
+ **/__pycache__/
11
+ *.pyc
12
+ **/test-reports
13
+ **/.passwd-pypi
14
+ **/.env
15
+ **/results.xml
16
+ .groovylintrc.json
17
+ .emailNotif
@@ -0,0 +1 @@
1
+ pymultirole38
@@ -0,0 +1,19 @@
1
+ FROM python:3.8-slim-bookworm
2
+ # Install prerequisites
3
+ RUN apt-get update -y && \
4
+ apt-get install -y \
5
+ patch \
6
+ gcc && \
7
+ apt-get install -y --no-install-recommends \
8
+ g++ \
9
+ git && \
10
+ # Final upgrade + clean
11
+ apt-get update -y && \
12
+ apt-get clean all -y
13
+
14
+ # Enable Installing packages as root
15
+ ENV FLIT_ROOT_INSTALL=1
16
+
17
+ # Add pyproject.toml + README.md for flit install
18
+ ADD pyproject.toml pyproject.toml
19
+ ADD README.md README.md
@@ -0,0 +1,422 @@
1
+ #!groovy
2
+ // to test groovy snippets online:
3
+ // https://www.jdoodle.com/execute-groovy-online
4
+
5
+ pipeline {
6
+
7
+ agent none
8
+
9
+ triggers {
10
+ upstream(upstreamProjects: 'pymultirole_plugins/' + BRANCH_NAME.replaceAll('/', '%2F'),\
11
+ threshold: hudson.model.Result.SUCCESS)
12
+ }
13
+
14
+ // variables declared in environment block can not be changed in any steps/stages
15
+ environment {
16
+ PATH_HOME = '/home/jenkins'
17
+ TEST_REPORT_DIR = '/root/test-reports'
18
+ PYTHONPYCACHEPREFIX = '/tmp/.pytest_cache'
19
+ PYTHONDONTWRITEBYTECODE = '1'
20
+ JENKINS_UIDGID = '1004:1004'
21
+
22
+ MAJOR_VERSION = '0'
23
+ MINOR_VERSION = '5'
24
+ }
25
+
26
+ stages {
27
+ stage('Catch build termination') {
28
+ agent {
29
+ node {
30
+ label 'built-in'
31
+ customWorkspace "${PATH_HOME}/${JOB_NAME}"
32
+ }
33
+ }
34
+ stages {
35
+ stage('Analyse build cause') {
36
+ steps {
37
+ script {
38
+ analyseBuildCause()
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ stage('Generate new version') {
46
+ when {
47
+ environment name: 'SKIP_JOB', value: '0'
48
+ }
49
+
50
+ agent {
51
+ node {
52
+ label 'built-in'
53
+ customWorkspace "${PATH_HOME}/${JOB_NAME}"
54
+ }
55
+ }
56
+
57
+ stages {
58
+ stage('Add credentials') {
59
+ steps {
60
+ script {
61
+ // Add password file for flit publishing
62
+ sh "cp ${PATH_HOME}/.passwd-pypi .env"
63
+ }
64
+ }
65
+ }
66
+
67
+ stage('Commit new version') {
68
+ steps {
69
+ script {
70
+ println("attempt to publish ${JOB_NAME} with version: ${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_ID}")
71
+
72
+ // push updates of file __init__.py
73
+ withCredentials([gitUsernamePassword(credentialsId: 'bitbucket-user', gitToolName: 'git-tool')]) {
74
+ sh 'git pull'
75
+ sh "echo '\"\"\"Sherpa Json formatter\"\"\"' > pyformatters_json/__init__.py"
76
+ sh "echo '__version__ = \"${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_ID}\"' >> pyformatters_json/__init__.py"
77
+ sh 'git commit pyformatters_json/__init__.py -m "[Jenkins CI] Commit on version files" || echo "No changes to commit"'
78
+ sh 'git push'
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ stage('Build, test and publish') {
87
+ when {
88
+ beforeAgent true
89
+ environment name: 'SKIP_JOB', value: '0'
90
+ }
91
+
92
+ agent {
93
+ // dockerfile agent
94
+ // Mounted volume for Junit reports
95
+ // - docker: /root/test-reports
96
+ // - host : /tmp/_${JOB_NAME}/test-reports
97
+ dockerfile {
98
+ label 'built-in'
99
+ customWorkspace "${PATH_HOME}/${JOB_NAME}"
100
+ filename 'Dockerfile'
101
+ args "-u root --privileged -v /tmp/_${JOB_NAME}/test-reports:${TEST_REPORT_DIR}"
102
+ }
103
+ }
104
+
105
+ stages {
106
+ stage('Install flit & flake8') {
107
+ steps {
108
+ sh 'python -m pip install pip==22.0.3'
109
+ sh 'pip install --no-cache-dir flit==3.2.0 flake8==3.9.2 flakehell'
110
+ sh 'flit install'
111
+ }
112
+ }
113
+
114
+ stage('Lint python code') {
115
+ steps {
116
+ sh 'flakehell lint'
117
+ }
118
+ }
119
+
120
+ stage('Test with pytest') {
121
+ steps {
122
+ // purge python cache from any previous run
123
+ sh "rm -rf ${PYTHONPYCACHEPREFIX}"
124
+ // remove any previous results.xml file
125
+ sh "rm -f ${TEST_REPORT_DIR}/results.xml"
126
+ sh "pytest --verbose -o cache_dir=${PYTHONPYCACHEPREFIX} --junit-xml ${TEST_REPORT_DIR}/results.xml"
127
+ // purge python cache
128
+ sh "rm -rf ${PYTHONPYCACHEPREFIX}"
129
+ }
130
+ }
131
+
132
+ stage('Publish on PyPI') {
133
+ environment {
134
+ FLIT_USERNAME = getUserName '.env'
135
+ FLIT_PASSWORD = getUserPass '.env'
136
+ }
137
+ steps {
138
+ // remove any previous folder dist
139
+ sh 'rm -rf dist'
140
+ // create (as root) folder dist
141
+ sh 'mkdir dist'
142
+ // pull recent updates of file __init__.py
143
+ withCredentials([gitUsernamePassword(credentialsId: 'bitbucket-user', gitToolName: 'git-tool')]) {
144
+ sh 'git config --global pull.rebase false'
145
+ sh "git config --global --add safe.directory ${WORKSPACE}"
146
+ sh 'git pull'
147
+ }
148
+ // put back owner of .git folder
149
+ sh "chown -R ${JENKINS_UIDGID} ${WORKSPACE}/.git"
150
+ // put back owner of pulled file
151
+ sh "chown ${JENKINS_UIDGID} pyformatters_json/__init__.py"
152
+ // get git status
153
+ sh 'git status'
154
+ // publish on PyPI
155
+ sh '''
156
+ export COMMIT_VERSION=$( cat pyformatters_json/__init__.py|grep version|cut -d '"' -f2|tr -s '[:blank:]' )
157
+ export BUILD_VERSION="${MAJOR_VERSION}"."${MINOR_VERSION}"."${BUILD_ID}"
158
+ if [ "${COMMIT_VERSION}" = "${BUILD_VERSION}" ] ; then flit publish ; fi
159
+ '''
160
+ // remove current folder dist
161
+ sh 'rm -rf dist'
162
+ // remove current folder .hypothesis
163
+ sh 'rm -rf .hypothesis'
164
+ // remove current folder .tox
165
+ sh 'rm -rf .tox'
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ post {
173
+ // only triggered when blue or green sign
174
+ success {
175
+ // node is specified here to get an agent
176
+ node('built-in') {
177
+ // keep using customWorkspace to store Junit report
178
+ ws("${PATH_HOME}/${JOB_NAME}") {
179
+ script {
180
+ try {
181
+ sh 'rm -f results.xml'
182
+ sh "cp /tmp/_${JOB_NAME}/test-reports/results.xml results.xml"
183
+ } catch (Exception e) {
184
+ println 'Exception occurred: ' + e.toString()
185
+ }
186
+ try {
187
+ junit 'results.xml'
188
+ } catch (Exception e) {
189
+ println 'Exception occurred: ' + e.toString()
190
+ }
191
+ if (sendEmailNotif("${PATH_HOME}/${JOB_NAME}", "${BUILD_NUMBER}")) {
192
+ println 'sending Success Build notification'
193
+ def CUSTOM_SUBJECT = '[CI - Jenkinzz SUCCESS] ' + CUSTOM_SUBJECT
194
+ emailext(
195
+ mimeType: 'text/html',
196
+ subject: CUSTOM_SUBJECT,
197
+ body: '${DEFAULT_CONTENT}',
198
+ replyTo: '${DEFAULT_REPLYTO}',
199
+ to: '${ADMIN_RECIPIENTS}' + ';' + CUSTOM_RECIPIENTS
200
+ )
201
+ switchEmailNotif(false, BUILD_NUMBER)
202
+ } else {
203
+ println 'preventing Success Build notification'
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ // triggered when red sign
210
+ failure {
211
+ // node is specified here to get an agent
212
+ node('built-in') {
213
+ // keep using customWorkspace to store Junit report
214
+ ws("${PATH_HOME}/${JOB_NAME}") {
215
+ script {
216
+ try {
217
+ sh 'rm -f results.xml'
218
+ sh "cp /tmp/_${JOB_NAME}/test-reports/results.xml results.xml"
219
+ } catch (Exception e) {
220
+ println 'Exception occurred: ' + e.toString()
221
+ }
222
+ try {
223
+ junit 'results.xml'
224
+ } catch (Exception e) {
225
+ println 'Exception occurred: ' + e.toString()
226
+ }
227
+ println 'sending Failure Build notification'
228
+ def CUSTOM_SUBJECT = '[CI - Jenkinzz FAILURE] ' + CUSTOM_SUBJECT
229
+ emailext(
230
+ mimeType: 'text/html',
231
+ subject: CUSTOM_SUBJECT,
232
+ body: '${DEFAULT_CONTENT}',
233
+ replyTo: '${DEFAULT_REPLYTO}',
234
+ to: '${ADMIN_RECIPIENTS}' + ';' + CUSTOM_RECIPIENTS
235
+ )
236
+ }
237
+ }
238
+ }
239
+ }
240
+ // triggered when black sign
241
+ aborted {
242
+ println 'post-declarative message: abort job'
243
+ }
244
+ // trigger every-works
245
+ //always {
246
+ //}
247
+ }
248
+ }
249
+
250
+ // return FLIT_USERNAME from given file
251
+ def getUserName(path) {
252
+ def USERNAME = sh(
253
+ script: "grep FLIT_USERNAME ${path}|cut -d '=' -f2",
254
+ returnStdout: true
255
+ ).trim()
256
+ return USERNAME
257
+ }
258
+
259
+ // return FLIT_PASSWORD from given file
260
+ def getUserPass(path) {
261
+ def USERPASS = sh(
262
+ script: "grep FLIT_PASSWORD ${path}|cut -d '=' -f2",
263
+ returnStdout: true
264
+ ).trim()
265
+ return USERPASS
266
+ }
267
+
268
+ // create/remove emailNotif file to trigger email notification
269
+ def switchEmailNotif(toggle, build) {
270
+ if (toggle) {
271
+ sh 'echo ' + build + ' > .emailNotif'
272
+ } else {
273
+ if (build == BUILD_NUMBER) {
274
+ sh 'rm -f .emailNotif'
275
+ }
276
+ }
277
+ }
278
+
279
+ // return true if emailNotif file present
280
+ boolean sendEmailNotif(path, build) {
281
+ def emailNotif = sh(
282
+ script: "find ${path} -name '.emailNotif'|wc -l",
283
+ returnStdout: true
284
+ ).trim()
285
+ def emailContent = ''
286
+ if (emailNotif == '1') {
287
+ emailContent = sh(
288
+ script: "cat ${path}/.emailNotif",
289
+ returnStdout: true
290
+ ).trim()
291
+ }
292
+ return (emailContent == build)
293
+ }
294
+
295
+ def analyseBuildCause() {
296
+ String[] upstreamProjects = ['pymultirole_plugins']
297
+ boolean upstreamRunning = false
298
+ String jobName
299
+ // iterate over upstreamProjects
300
+ for (upstream_project in upstreamProjects) {
301
+ Jenkins.instance.getItemByFullName(upstream_project).items.each { repository ->
302
+ boolean isRunning = false
303
+ //repository.parent.name: project
304
+ //repository.name: branch
305
+ if ( repository.name == BRANCH_NAME ) {
306
+ // iterate over all jobs of current repository
307
+ repository.allJobs.each { job ->
308
+ // iterate over all builds of current job
309
+ job.builds.each { build ->
310
+ // determine if a build is running or not
311
+ if ( build.result == (null) ) {
312
+ jobName = build.parent.parent.name
313
+ isRunning = true
314
+ }
315
+ }
316
+ if ( isRunning ) {
317
+ upstreamRunning = true
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+
324
+ // Catch if build has been triggered by CI Commit
325
+ // returnStatus = true when string not found -> Team commit
326
+ // returnStatus = false when string is found -> CI commit
327
+ boolean lastCommitIsTeam = sh(
328
+ script: 'git log -1 | grep "\\[Jenkins CI\\]"',
329
+ returnStatus: true
330
+ )
331
+
332
+ // Skip build when upstream detected
333
+ if (upstreamRunning) {
334
+ println 'Skipping build because upstream job detected (' + jobName + ')'
335
+ env.SKIP_JOB = '1'
336
+ switchEmailNotif(false, 0)
337
+ currentBuild.result = 'NOT_BUILT'
338
+ }
339
+
340
+ // Catch if build has been triggered by User
341
+ boolean isStartedByUser = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause) != null
342
+ if (isStartedByUser && !upstreamRunning) {
343
+ env.SKIP_JOB = '0'
344
+ env.CUSTOM_SUBJECT = JOB_NAME + ' - Manual Build #' + BUILD_NUMBER
345
+ env.CUSTOM_RECIPIENTS = emailextrecipients([[$class: 'RequesterRecipientProvider']])
346
+ switchEmailNotif(true, BUILD_NUMBER)
347
+ println 'Job started by User, proceeding'
348
+ }
349
+
350
+ // Catch if build has been triggered by Upstream
351
+ boolean isStartedByUpstream = currentBuild.rawBuild.getCause(hudson.model.Cause$UpstreamCause) != null
352
+ if (isStartedByUpstream && !upstreamRunning) {
353
+ int changeSetCount = 0
354
+ int ciSkipCount = 0
355
+ String upstreamFullJobName = ''
356
+ for (Run upstreamBuild : currentBuild.upstreamBuilds) {
357
+ upstreamFullJobName = upstreamBuild.rawBuild.fullDisplayName
358
+ if (upstreamBuild.changeSets != null) {
359
+ def changeLogSets = upstreamBuild.changeSets
360
+ for (int i = 0; i < changeLogSets.size(); i++) {
361
+ changeSetCount++
362
+ def entries = changeLogSets[i].items
363
+ for (int j = 0; j < entries.length; j++) {
364
+ def entry = entries[j]
365
+ if (entry.msg.contains('[Jenkins CI]')) {
366
+ ciSkipCount++
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ if (changeSetCount > 0 && changeSetCount == ciSkipCount) {
373
+ env.SKIP_JOB = '1'
374
+ switchEmailNotif(false, 0)
375
+ println 'Job started by Upstream [' + upstreamFullJobName + '], with CI commit, skipping'
376
+ currentBuild.result = 'NOT_BUILT'
377
+ } else {
378
+ env.SKIP_JOB = '0'
379
+ env.CUSTOM_SUBJECT = JOB_NAME + ' - Upstream Build #' + BUILD_NUMBER
380
+ env.CUSTOM_RECIPIENTS = emailextrecipients([[$class:'UpstreamComitterRecipientProvider']])
381
+ switchEmailNotif(true, BUILD_NUMBER)
382
+ println 'Job started by Upstream [' + upstreamFullJobName + '], proceeding'
383
+ }
384
+ }
385
+
386
+ // Catch if build has been triggered by User Commit
387
+ boolean isStartedByCommit = currentBuild.rawBuild.getCause(jenkins.branch.BranchEventCause) != null
388
+ if (isStartedByCommit && lastCommitIsTeam && !upstreamRunning) {
389
+ env.SKIP_JOB = '0'
390
+ env.CUSTOM_SUBJECT = JOB_NAME + ' - SCM Build #' + BUILD_NUMBER
391
+ env.CUSTOM_RECIPIENTS = emailextrecipients([[$class: 'DevelopersRecipientProvider'], [$class:'CulpritsRecipientProvider']])
392
+ switchEmailNotif(true, BUILD_NUMBER)
393
+ println 'Job started by User Commit, proceeding'
394
+ }
395
+
396
+ // Catch if build has been triggered by cron
397
+ boolean isStartedByCron = currentBuild.rawBuild.getCause(hudson.triggers.TimerTrigger$TimerTriggerCause) != null
398
+ if (isStartedByCron && lastCommitIsTeam && !upstreamRunning) {
399
+ env.SKIP_JOB = '0'
400
+ env.CUSTOM_SUBJECT = JOB_NAME + ' - CRON Build #' + BUILD_NUMBER
401
+ env.CUSTOM_RECIPIENTS = emailextrecipients([[$class: 'DevelopersRecipientProvider'], [$class:'CulpritsRecipientProvider']])
402
+ switchEmailNotif(true, BUILD_NUMBER)
403
+ println 'Job started by Cron, proceeding'
404
+ }
405
+
406
+ // Catch if build has been triggered by branch discovery
407
+ boolean isStartedByBranchDiscovery = currentBuild.rawBuild.getCause(jenkins.branch.BranchIndexingCause) != null
408
+ if (isStartedByBranchDiscovery && lastCommitIsTeam && !upstreamRunning) {
409
+ env.SKIP_JOB = '0'
410
+ env.CUSTOM_SUBJECT = JOB_NAME + ' - BranchDiscovery Build #' + BUILD_NUMBER
411
+ env.CUSTOM_RECIPIENTS = emailextrecipients([[$class: 'DevelopersRecipientProvider'], [$class:'CulpritsRecipientProvider']])
412
+ switchEmailNotif(true, BUILD_NUMBER)
413
+ println 'Job started by Branch Discovery, proceeding'
414
+ }
415
+
416
+ if (!lastCommitIsTeam && !upstreamRunning && !isStartedByUser && !isStartedByUpstream) {
417
+ println 'Skipping build because last commit has been done by CI'
418
+ env.SKIP_JOB = '1'
419
+ switchEmailNotif(false, 0)
420
+ //currentBuild.result = 'NOT_BUILT'
421
+ }
422
+ }
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyformatters-json
3
+ Version: 0.5.9
4
+ Summary: Sherpa Json formatter
5
+ Home-page: https://kairntech.com/
6
+ Author: Olivier Terrier
7
+ Author-email: olivier.terrier@kairntech.com
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ Classifier: Intended Audience :: Information Technology
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Topic :: Internet
16
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Classifier: Topic :: Software Development
20
+ Classifier: Typing :: Typed
21
+ Classifier: Development Status :: 4 - Beta
22
+ Classifier: Environment :: Web Environment
23
+ Classifier: Framework :: AsyncIO
24
+ Classifier: Intended Audience :: Developers
25
+ Classifier: Programming Language :: Python :: 3 :: Only
26
+ Classifier: Programming Language :: Python :: 3.8
27
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
28
+ Classifier: Topic :: Internet :: WWW/HTTP
29
+ Requires-Dist: pymultirole_plugins>=0.5.0,<0.6.0
30
+ Requires-Dist: pytest
31
+
32
+ ## Requirements
33
+
34
+ - Python 3.8+
35
+ - Flit to put Python packages and modules on PyPI
36
+ - Pydantic for the data parts.
37
+
38
+ ## Installation
39
+ ```
40
+ pip install flit
41
+ pip install pyconverters-plugins
42
+ ```
43
+
44
+ ## Publish the Python Package to PyPI
45
+ - Increment the version of your package in the `__init__.py` file:
46
+ ```
47
+ """An amazing package!"""
48
+
49
+ __version__ = 'x.y.z'
50
+ ```
51
+ - Publish
52
+ ```
53
+ flit publish
54
+ ```
55
+
@@ -0,0 +1,23 @@
1
+ ## Requirements
2
+
3
+ - Python 3.8+
4
+ - Flit to put Python packages and modules on PyPI
5
+ - Pydantic for the data parts.
6
+
7
+ ## Installation
8
+ ```
9
+ pip install flit
10
+ pip install pyconverters-plugins
11
+ ```
12
+
13
+ ## Publish the Python Package to PyPI
14
+ - Increment the version of your package in the `__init__.py` file:
15
+ ```
16
+ """An amazing package!"""
17
+
18
+ __version__ = 'x.y.z'
19
+ ```
20
+ - Publish
21
+ ```
22
+ flit publish
23
+ ```
@@ -0,0 +1 @@
1
+ {"dependencies": [{"name": "annotated-doc", "version": "0.0.4", "vulns": []}, {"name": "annotated-types", "version": "0.7.0", "vulns": []}, {"name": "anyio", "version": "4.12.1", "vulns": []}, {"name": "arrow", "version": "1.4.0", "vulns": []}, {"name": "attrs", "version": "25.4.0", "vulns": []}, {"name": "boolean-py", "version": "5.0", "vulns": []}, {"name": "cachecontrol", "version": "0.14.4", "vulns": []}, {"name": "certifi", "version": "2026.2.25", "vulns": []}, {"name": "chardet", "version": "5.2.0", "vulns": []}, {"name": "charset-normalizer", "version": "3.4.5", "vulns": []}, {"name": "cyclonedx-bom", "version": "7.2.2", "vulns": []}, {"name": "cyclonedx-python-lib", "version": "11.7.0", "vulns": []}, {"name": "defusedxml", "version": "0.7.1", "vulns": []}, {"name": "et-xmlfile", "version": "2.0.0", "vulns": []}, {"name": "fastapi", "version": "0.135.1", "vulns": []}, {"name": "filelock", "version": "3.25.0", "vulns": []}, {"name": "fqdn", "version": "1.5.1", "vulns": []}, {"name": "idna", "version": "3.11", "vulns": []}, {"name": "iniconfig", "version": "2.3.0", "vulns": []}, {"name": "isoduration", "version": "20.11.0", "vulns": []}, {"name": "jsonpointer", "version": "3.0.0", "vulns": []}, {"name": "jsonschema", "version": "4.26.0", "vulns": []}, {"name": "jsonschema-specifications", "version": "2025.9.1", "vulns": []}, {"name": "lark", "version": "1.3.1", "vulns": []}, {"name": "license-expression", "version": "30.4.4", "vulns": []}, {"name": "lxml", "version": "6.0.2", "vulns": []}, {"name": "markdown-it-py", "version": "4.0.0", "vulns": []}, {"name": "mdurl", "version": "0.1.2", "vulns": []}, {"name": "msgpack", "version": "1.1.2", "vulns": []}, {"name": "numpy", "version": "2.4.2", "vulns": []}, {"name": "openpyxl", "version": "3.1.5", "vulns": []}, {"name": "packageurl-python", "version": "0.17.6", "vulns": []}, {"name": "packaging", "version": "26.0", "vulns": []}, {"name": "pandas", "version": "3.0.1", "vulns": []}, {"name": "pip", "version": "26.0.1", "vulns": []}, {"name": "pip-api", "version": "0.0.34", "vulns": []}, {"name": "pip-audit", "version": "2.10.0", "vulns": []}, {"name": "pip-requirements-parser", "version": "32.0.1", "vulns": []}, {"name": "platformdirs", "version": "4.9.4", "vulns": []}, {"name": "pluggy", "version": "1.6.0", "vulns": []}, {"name": "py-serializable", "version": "2.1.0", "vulns": []}, {"name": "pydantic", "version": "2.12.5", "vulns": []}, {"name": "pydantic-core", "version": "2.41.5", "vulns": []}, {"name": "pyformatters-json", "version": "0.6.5", "vulns": []}, {"name": "pygments", "version": "2.19.2", "vulns": []}, {"name": "pymultirole-plugins", "version": "0.6.21", "vulns": []}, {"name": "pyparsing", "version": "3.3.2", "vulns": []}, {"name": "pytest", "version": "9.0.2", "vulns": []}, {"name": "python-dateutil", "version": "2.9.0.post0", "vulns": []}, {"name": "python-singleton-metaclasses", "version": "0.2.1", "vulns": []}, {"name": "referencing", "version": "0.37.0", "vulns": []}, {"name": "requests", "version": "2.32.5", "vulns": []}, {"name": "rfc3339-validator", "version": "0.1.4", "vulns": []}, {"name": "rfc3986-validator", "version": "0.1.1", "vulns": []}, {"name": "rfc3987-syntax", "version": "1.1.0", "vulns": []}, {"name": "rich", "version": "14.3.3", "vulns": []}, {"name": "rpds-py", "version": "0.30.0", "vulns": []}, {"name": "six", "version": "1.17.0", "vulns": []}, {"name": "sortedcontainers", "version": "2.4.0", "vulns": []}, {"name": "starlette", "version": "0.52.1", "vulns": []}, {"name": "tomli", "version": "2.4.0", "vulns": []}, {"name": "tomli-w", "version": "1.2.0", "vulns": []}, {"name": "typing-extensions", "version": "4.15.0", "vulns": []}, {"name": "typing-inspection", "version": "0.4.2", "vulns": []}, {"name": "tzdata", "version": "2025.3", "vulns": []}, {"name": "uri-template", "version": "1.3.0", "vulns": []}, {"name": "urllib3", "version": "2.6.3", "vulns": []}, {"name": "webcolors", "version": "25.10.0", "vulns": []}], "fixes": []}
@@ -0,0 +1,41 @@
1
+ import re
2
+ import sys
3
+ from pathlib import Path
4
+
5
+
6
+ def main(argv):
7
+ part = argv[0].lower() if len(argv) > 0 else "minor"
8
+ Jenkinsfile = Path("./Jenkinsfile")
9
+ pyprojectfile = Path("./pyproject.toml")
10
+ with Jenkinsfile.open("r", encoding="utf-8") as fin:
11
+ data = fin.read()
12
+ for line in data.split(fin.newlines):
13
+ if "MAJOR_VERSION" in line:
14
+ result = re.search(r'MAJOR_VERSION\s*=\s*"([0-9]+)"', line)
15
+ if result:
16
+ major = int(result.group(1))
17
+ if part == "major":
18
+ to_replace = result.group(0)
19
+ by_replace = f"MAJOR_VERSION = \"{major + 1}\""
20
+ if "MINOR_VERSION" in line:
21
+ result = re.search(r'MINOR_VERSION\s*=\s*"([0-9]+)"', line)
22
+ if result:
23
+ minor = int(result.group(1))
24
+ if part == "minor":
25
+ to_replace = result.group(0)
26
+ by_replace = f"MINOR_VERSION = \"{minor + 1}\""
27
+ data = data.replace(to_replace, by_replace)
28
+ with Jenkinsfile.open("wt") as fout:
29
+ fout.write(data)
30
+
31
+ depend_string = f"{major}.{minor}.0,<{major}.{minor + 1}.0"
32
+ new_depend_string = f"{major}.{minor + 1}.0,<{major}.{minor + 2}.0"
33
+ with pyprojectfile.open("r", encoding="utf-8") as fin:
34
+ data = fin.read()
35
+ data = data.replace(depend_string, new_depend_string)
36
+ with pyprojectfile.open("wt") as fout:
37
+ fout.write(data)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ main(sys.argv[1:])
@@ -0,0 +1,2 @@
1
+ """Sherpa Json formatter"""
2
+ __version__ = "0.5.9"
@@ -0,0 +1,47 @@
1
+ import json
2
+ from typing import Type
3
+
4
+ from pydantic import BaseModel
5
+ from pymultirole_plugins.v1.formatter import FormatterBase, FormatterParameters
6
+ from pymultirole_plugins.v1.schema import Document
7
+ from starlette.responses import Response, JSONResponse
8
+
9
+
10
+ class JsonParameters(FormatterParameters):
11
+ pass
12
+
13
+
14
+ class JsonFormatter(FormatterBase):
15
+ """Json formatter.
16
+ """
17
+
18
+ def format(self, document: Document, parameters: FormatterParameters) \
19
+ -> Response:
20
+ """Parse the altTexts of the document and return a json response.
21
+
22
+ :param document: An annotated document.
23
+ :param options: options of the parser.
24
+ :returns: Response.
25
+ """
26
+ parameters: JsonParameters = parameters
27
+ try:
28
+ alts = []
29
+ if document.altTexts:
30
+ altTexts = document.altTexts
31
+ alts = {altText.name: altText.text for altText in altTexts}
32
+ anames = list(alts.keys())
33
+ for aname in anames:
34
+ atext = alts[aname]
35
+ result = None
36
+ try:
37
+ result = json.loads(atext)
38
+ alts[aname] = result
39
+ except json.JSONDecodeError:
40
+ del alts[aname]
41
+ return JSONResponse(alts)
42
+ except BaseException as err:
43
+ raise err
44
+
45
+ @classmethod
46
+ def get_model(cls) -> Type[BaseModel]:
47
+ return JsonParameters
@@ -0,0 +1,68 @@
1
+ [build-system]
2
+ requires = ["flit_core >=2,<4"]
3
+ build-backend = "flit_core.buildapi"
4
+
5
+ [tool.flit.metadata]
6
+ module = "pyformatters_json"
7
+ author = "Olivier Terrier"
8
+ author-email = "olivier.terrier@kairntech.com"
9
+ home-page = "https://kairntech.com/"
10
+ classifiers = [
11
+ "Intended Audience :: Information Technology",
12
+ "Intended Audience :: System Administrators",
13
+ "Operating System :: OS Independent",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python",
16
+ "Topic :: Internet",
17
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
18
+ "Topic :: Software Development :: Libraries :: Python Modules",
19
+ "Topic :: Software Development :: Libraries",
20
+ "Topic :: Software Development",
21
+ "Typing :: Typed",
22
+ "Development Status :: 4 - Beta",
23
+ "Environment :: Web Environment",
24
+ "Framework :: AsyncIO",
25
+ "Intended Audience :: Developers",
26
+ "Programming Language :: Python :: 3 :: Only",
27
+ "Programming Language :: Python :: 3.8",
28
+ "Topic :: Internet :: WWW/HTTP :: HTTP Servers",
29
+ "Topic :: Internet :: WWW/HTTP",
30
+ ]
31
+ requires = [
32
+ "pymultirole_plugins>=0.5.0,<0.6.0",
33
+ "pytest"
34
+ ]
35
+ dist-name = "pyformatters-json"
36
+ description-file = "README.md"
37
+ requires-python = ">=3.8"
38
+
39
+ [tool.flit.entrypoints."pyformatters.plugins"]
40
+ json = "pyformatters_json.json_formatter:JsonFormatter"
41
+
42
+ [tool.flakehell]
43
+ exclude = ["README.md"]
44
+ format = "colored"
45
+ #format = "junit-xml"
46
+ max_line_length = 120
47
+ show_source = true
48
+ #whitelist = "../../allowlist.txt"
49
+ extended_default_ignore = []
50
+
51
+ [tool.flakehell.plugins]
52
+ flake8-bandit = ["+*", "-S322"]
53
+ flake8-bugbear = ["+*"]
54
+ flake8-builtins = ["+*", "-A003"]
55
+ flake8-comprehensions = ["+*"]
56
+ #flake8-darglint = ["+*"]
57
+ flake8-docstrings = ["+*"]
58
+ flake8-eradicate = ["+*"]
59
+ flake8-isort = ["+*"]
60
+ flake8-mutable = ["+*"]
61
+ flake8-pytest-style = ["+*"]
62
+ flake8-spellcheck = ["+*"]
63
+ mccabe = ["+*"]
64
+ pep8-naming = ["+*"]
65
+ pycodestyle = ["+*"]
66
+ pyflakes = ["+*"]
67
+ pylint = ["+*"]
68
+
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env python
2
+ # setup.py generated by flit for tools that don't yet use PEP 517
3
+
4
+ from distutils.core import setup
5
+
6
+ packages = \
7
+ ['pyformatters_json']
8
+
9
+ package_data = \
10
+ {'': ['*']}
11
+
12
+ install_requires = \
13
+ ['pymultirole_plugins>=0.5.0,<0.6.0', 'pytest']
14
+
15
+ entry_points = \
16
+ {'pyformatters.plugins': ['json = '
17
+ 'pyformatters_json.json_formatter:JsonFormatter']}
18
+
19
+ setup(name='pyformatters-json',
20
+ version='0.5.9',
21
+ description='Sherpa Json formatter',
22
+ author='Olivier Terrier',
23
+ author_email='olivier.terrier@kairntech.com',
24
+ url='https://kairntech.com/',
25
+ packages=packages,
26
+ package_data=package_data,
27
+ install_requires=install_requires,
28
+ entry_points=entry_points,
29
+ python_requires='>=3.8',
30
+ )
File without changes
@@ -0,0 +1,29 @@
1
+ {
2
+ "text": "![img-0.png](img-0.png)\n\nJO: Cizeron et Fournier Beaudry hypnotisent Milan et s'offrent l'or olympique",
3
+ "identifier": "cizeronfournier.docx",
4
+ "title": "cizeronfournier.docx",
5
+ "metadata": {
6
+ "original": "cizeronfournier.docx",
7
+ "mime-type": "text/markdown",
8
+ "language": "fr"
9
+ },
10
+ "altTexts": [
11
+ {
12
+ "name": "img-0.png",
13
+ "text": "{\n \"description\": \"Gabriella Papadakis et Guillaume Cizeron, patineurs artistiques, posent sur la glace, m\u00e9dailles d'or autour du cou, apr\u00e8s leur victoire olympique. Ils tiennent ensemble un drapeau fran\u00e7ais d\u00e9ploy\u00e9 au-dessus de leurs t\u00eates et saluent le public. Les deux athl\u00e8tes portent des tenues de patinage assorties de couleur bleu-gris. L'ambiance est festive et la glace occupe l'arri\u00e8re-plan.\",\n \"persons\": [\n {\n \"name\": \"Gabriella Papadakis\",\n \"role\": \"athl\u00e8te\",\n \"clothing\": \"robe de patinage bleu-gris sans manches\",\n \"position\": \"gauche, au centre de l'image\"\n },\n {\n \"name\": \"Guillaume Cizeron\",\n \"role\": \"athl\u00e8te\",\n \"clothing\": \"haut \u00e0 manches longues bleu-gris et pantalon assorti\",\n \"position\": \"droite, au centre de l'image\"\n }\n ],\n \"nbpersons\": 2,\n \"objects\": [\n {\n \"name\": \"drapeau fran\u00e7ais\",\n \"material\": \"tissu\",\n \"color\": \"bleu, blanc, rouge\"\n },\n {\n \"name\": \"m\u00e9dailles d'or\",\n \"material\": \"m\u00e9tal\",\n \"color\": \"or\"\n }\n ],\n \"animals\": [],\n \"scene\": {\n \"location\": \"Milan\",\n \"setting\": \"indoor\",\n \"event\": \"Jeux Olympiques, patinage artistique\"\n },\n \"camera\": {\n \"angle\": \"l\u00e9g\u00e8rement en plong\u00e9e\",\n \"framing\": \"plan moyen\"\n },\n \"crowd\": false,\n \"interaction\": \"Les deux athl\u00e8tes se tiennent c\u00f4te \u00e0 c\u00f4te, tenant ensemble un drapeau et saluant.\",\n \"light\": \"\u00e9clairage artificiel de patinoire\",\n \"colors\": [\"bleu\", \"blanc\", \"rouge\", \"gris\"],\n \"visible_text\": []\n}"
14
+ }
15
+ ],
16
+ "sentences": [
17
+ {
18
+ "start": 0,
19
+ "end": 102,
20
+ "metadata": {
21
+ "original": "cizeronfournier.docx",
22
+ "mime-type": "text/markdown",
23
+ "language": "fr"
24
+ }
25
+ }
26
+ ],
27
+ "annotations": [],
28
+ "categories": []
29
+ }
@@ -0,0 +1,22 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ from pymultirole_plugins.v1.schema import Document
5
+ from starlette.responses import Response
6
+
7
+ from pyformatters_json.json_formatter import JsonFormatter, JsonParameters
8
+
9
+
10
+ def test_json():
11
+ testdir = Path(__file__).parent
12
+ source = Path(testdir, 'data/afp_cv-document-cizeronfournier.docx.gpt-4.1.json')
13
+ with source.open("r") as fin:
14
+ jdoc = json.load(fin)
15
+ doc = Document(**jdoc)
16
+ formatter = JsonFormatter()
17
+ options = JsonParameters()
18
+ resp: Response = formatter.format(doc, options)
19
+ assert resp.status_code == 200
20
+ assert resp.media_type == "application/json"
21
+ json_resp = json.loads(resp.body)
22
+ assert "Guillaume Cizeron" in json_resp['img-0.png']['description']