Skip to content

Commit 1c83d73

Browse files
committed
[jnifti] jnifti reading nii.gz and writign nii.gz for nifti-1/2, add compression apis
1 parent 8ed1719 commit 1c83d73

File tree

8 files changed

+263
-62
lines changed

8 files changed

+263
-62
lines changed

.github/check-pypi-upload.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
PYPKG_BUILD_VERSION=$(awk -F"-" '{ print $2 }' <<< $(ls dist/ | head -1))
3+
PYPKG_VERSIONS_STRING=$(pip index versions jdata | grep versions:)
4+
PYPKG_VERSIONS_STRING=${PYPKG_VERSIONS_STRING#*:}
5+
UPLOAD_TO_PYPI=1
6+
while IFS=', ' read -ra PYPKG_VERSIONS_ARRAY; do
7+
for VERSION in "${PYPKG_VERSIONS_ARRAY[@]}"; do
8+
if [ "$PYPKG_BUILD_VERSION" = "$VERSION" ]; then
9+
UPLOAD_TO_PYPI=0
10+
fi
11+
done;
12+
done <<< "$PYPKG_VERSIONS_STRING"
13+
if [ "$UPLOAD_TO_PYPI" = 1 ]; then
14+
echo "Wheel version wasn't found on PyPi.";
15+
else
16+
echo "Wheel was found on PyPi.";
17+
fi
18+
echo "perform_pypi_upload=$UPLOAD_TO_PYPI" >> $GITHUB_OUTPUT

.github/workflows/run_test.yml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Test JData
33
on: [push]
44

55
jobs:
6-
build:
6+
test:
77
runs-on: ubuntu-22.04
88
strategy:
99
matrix:
@@ -35,3 +35,30 @@ jobs:
3535
pip install bjdata lz4 blosc2
3636
cp -a test/benchcodecs.py .
3737
python -m benchcodecs
38+
39+
deploy:
40+
runs-on: ubuntu-22.04
41+
needs: test
42+
steps:
43+
- name: Checkout repo
44+
uses: actions/checkout@v3
45+
with:
46+
submodules: 'recursive'
47+
- name: Install build
48+
run: python3 -m pip install --upgrade build
49+
- name: Build wheel
50+
run: |
51+
python3 -m build
52+
- name: Check If the Build Version Exists on PyPI
53+
id: perform_pypi_upload_check
54+
shell: bash
55+
run: |
56+
$GITHUB_WORKSPACE/.github/check-pypi-upload.sh
57+
- name: Upload packages to PyPI
58+
uses: pypa/gh-action-pypi-publish@release/v1
59+
if: ${{ github.actor == 'fangq' && steps.perform_pypi_upload_check.outputs.perform_pypi_upload == 1 && github.event_name != 'pull_request'}}
60+
with:
61+
password: ${{ secrets.PYPI_API_TOKEN }}
62+
verify_metadata: false
63+
verbose: true
64+
skip_existing: true

Makefile

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ test:
1111
build:
1212
$(PY) -m build
1313

14-
report:
15-
@echo '====== all imported functions ======'
16-
@grep '^\s*[a-z]*,' jdata/__init__.py | sed -e 's/^\s*//g' -e 's/,//g' | sort | uniq -c
17-
@echo '====== all tested functions ======'
18-
@grep 'def\s*test' test/run_test.py | sed -e 's/\s*def test_//g' -e 's/(self)://g' -e 's/_.*//g' | sort | uniq -c
1914

2015
.DEFAULT_GOAL=all
21-
.PHONY: all pretty test report
16+
.PHONY: all pretty test

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# JData for Python - lightweight and serializable data annotations for Python
44

5-
- Copyright: (C) Qianqian Fang (2019-2024) <q.fang at neu.edu>
5+
- Copyright: (C) Qianqian Fang (2019-2025) <q.fang at neu.edu>
66
- License: Apache License, Version 2.0
77
- Version: 0.6.0
88
- URL: https://github.com/NeuroJSON/pyjdata
@@ -65,23 +65,23 @@ are no longer supported.
6565
One can also install this module from the source code. To do this, you first
6666
check out a copy of the latest code from Github by
6767
```
68-
git clone https://github.com/NeuroJSON/pyjdata.git
69-
cd pyjdata
68+
git clone https://github.com/NeuroJSON/pyjdata.git
69+
cd pyjdata
7070
```
7171
then install the module to your local user folder by
7272
```
73-
python3 setup.py install --user
73+
python3 setup.py install --user
7474
```
7575
or, if you prefer, install to the system folder for all users by
7676
```
77-
sudo python3 setup.py install
77+
sudo python3 setup.py install
7878
```
7979
Please replace `python` by `python3` if you want to install it for Python 3.x instead of 2.x.
8080

8181
Instead of installing the module, you can also import the jdata module directly from
8282
your local copy by cd the root folder of the unzipped pyjdata package, and run
8383
```
84-
import jdata as jd
84+
import jdata as jd
8585
```
8686

8787
## How to use

jdata/__init__.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,22 @@
4949
jdlink,
5050
jext,
5151
)
52-
from .jdata import encode, decode, jdtype, jsonfilter
52+
from .jdata import (
53+
encode,
54+
decode,
55+
jdtype,
56+
jsonfilter,
57+
zlibencode,
58+
zlibdecode,
59+
gzipencode,
60+
gzipdecode,
61+
lzmaencode,
62+
lzmadecode,
63+
lz4encode,
64+
lz4decode,
65+
base64encode,
66+
base64decode,
67+
)
5368
from .jpath import jsonpath
5469
from .jnifti import (
5570
nii2jnii,
@@ -102,6 +117,16 @@
102117
"niiformat",
103118
"loadh5",
104119
"saveh5",
120+
"zlibencode",
121+
"zlibdecode",
122+
"gzipencode",
123+
"gzipdecode",
124+
"lzmaencode",
125+
"lzmadecode",
126+
"lz4encode",
127+
"lz4decode",
128+
"base64encode",
129+
"base64decode",
105130
]
106131
__license__ = """Apache license 2.0, Copyright (c) 2019-2024 Qianqian Fang"""
107132

jdata/jdata.py

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,22 @@
55
Copyright (c) 2019-2024 Qianqian Fang <q.fang at neu.edu>
66
"""
77

8-
__all__ = ["encode", "decode", "jdtype", "jsonfilter"]
8+
__all__ = [
9+
"encode",
10+
"decode",
11+
"jdtype",
12+
"jsonfilter",
13+
"zlibencode",
14+
"zlibdecode",
15+
"gzipencode",
16+
"gzipdecode",
17+
"lzmaencode",
18+
"lzmadecode",
19+
"lz4encode",
20+
"lz4decode",
21+
"base64encode",
22+
"base64decode",
23+
]
924

1025
##====================================================================================
1126
## dependent libraries
@@ -67,7 +82,7 @@
6782
##====================================================================================
6883

6984

70-
def encode(d, opt={}):
85+
def encode(d, opt={}, **kwargs):
7186
"""@brief Encoding a Python data structure to portable JData-annotated dict constructs
7287
7388
This function converts complex data types (usually not JSON-serializable) into
@@ -82,6 +97,7 @@ def encode(d, opt={}):
8297
"""
8398

8499
opt.setdefault("inplace", False)
100+
opt.update(kwargs)
85101

86102
if "compression" in opt:
87103
if opt["compression"] == "lzma":
@@ -166,6 +182,7 @@ def encode(d, opt={}):
166182
elif opt["compression"] == "gzip":
167183
gzipper = zlib.compressobj(wbits=(zlib.MAX_WBITS | 16))
168184
newobj["_ArrayZipData_"] = gzipper.compress(newobj["_ArrayZipData_"])
185+
newobj["_ArrayZipData_"] += gzipper.flush()
169186
elif opt["compression"] == "lzma":
170187
try:
171188
newobj["_ArrayZipData_"] = lzma.compress(
@@ -224,7 +241,7 @@ def encode(d, opt={}):
224241
##====================================================================================
225242

226243

227-
def decode(d, opt={}):
244+
def decode(d, opt={}, **kwargs):
228245
"""@brief Decoding a JData-annotated dict construct into native Python data
229246
230247
This function converts portable JData-annotated dict/list constructs back to native Python
@@ -237,6 +254,7 @@ def decode(d, opt={}):
237254

238255
opt.setdefault("inplace", False)
239256
opt.setdefault("maxlinklevel", 0)
257+
opt.update(kwargs)
240258

241259
if (
242260
(isinstance(d, str) or type(d) == "unicode")
@@ -461,3 +479,112 @@ def decodelist(d0, opt={}):
461479

462480

463481
# -------------------------------------------------------------------------------------
482+
483+
484+
def zlibencode(buf):
485+
return zlib.compress(buf)
486+
487+
488+
# -------------------------------------------------------------------------------------
489+
490+
491+
def gzipencode(buf):
492+
gzipper = zlib.compressobj(wbits=(zlib.MAX_WBITS | 16))
493+
newbuf = gzipper.compress(buf)
494+
newbuf += gzipper.flush()
495+
return newbuf
496+
497+
498+
# -------------------------------------------------------------------------------------
499+
500+
501+
def lzmaencode(buf):
502+
try:
503+
try:
504+
import lzma
505+
except ImportError:
506+
from backports import lzma
507+
except Exception:
508+
raise Exception(
509+
"JData",
510+
'you must install "lzma" module to compress with this format',
511+
)
512+
return lzma.compress(buf, lzma.FORMAT_ALONE)
513+
514+
515+
# -------------------------------------------------------------------------------------
516+
517+
518+
def lz4encode(buf):
519+
try:
520+
import lz4.frame
521+
except ImportError:
522+
raise Exception(
523+
"JData",
524+
'you must install "lz4" module to compress with this format',
525+
)
526+
return lz4.compress(buf.tobytes(), lzma.FORMAT_ALONE)
527+
528+
529+
# -------------------------------------------------------------------------------------
530+
531+
532+
def base64encode(buf):
533+
return base64.b64encode(buf)
534+
535+
536+
# -------------------------------------------------------------------------------------
537+
538+
539+
def zlibdecode(buf):
540+
return zlib.decompress(buf)
541+
542+
543+
# -------------------------------------------------------------------------------------
544+
545+
546+
def gzipdecode(buf):
547+
return zlib.decompress(bytes(buf), zlib.MAX_WBITS | 32)
548+
549+
550+
# -------------------------------------------------------------------------------------
551+
552+
553+
def lzmadecode(buf):
554+
try:
555+
try:
556+
import lzma
557+
except ImportError:
558+
from backports import lzma
559+
except Exception:
560+
raise Exception(
561+
"JData",
562+
'you must install "lzma" module to compress with this format',
563+
)
564+
newbuf = bytearray(buf) # set length to -1 (unknown) if EOF appears
565+
newbuf[5:13] = b"\xff\xff\xff\xff\xff\xff\xff\xff"
566+
return lzma.decompress(newbuf, lzma.FORMAT_ALONE)
567+
568+
569+
# -------------------------------------------------------------------------------------
570+
571+
572+
def lz4decode(buf):
573+
try:
574+
import lz4.frame
575+
except ImportError:
576+
raise Exception(
577+
"JData",
578+
'you must install "lz4" module to compress with this format',
579+
)
580+
return lz4.frame.decompress(bytes(buf))
581+
582+
583+
# -------------------------------------------------------------------------------------
584+
585+
586+
def base64decode(buf):
587+
return base64.b64decode(buf)
588+
589+
590+
# -------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)