Skip to content

Commit 7d77a76

Browse files
authored
Merge pull request #56 from cfv-project/ci-py3.12-py3.12
Add support for Python 3.12/3.13
2 parents c968dfe + cdb009a commit 7d77a76

File tree

10 files changed

+82
-64
lines changed

10 files changed

+82
-64
lines changed

.github/workflows/ci-python3-dependencies.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
const latestPythonMinorVersion = pythonVersions[0].split('.').slice(0, 2).join('.')
3434
3535
// Check if new Python minor version exists
36-
if (latestPythonMinorVersion === '3.12') {
36+
if (latestPythonMinorVersion === '3.13') {
3737
return
3838
}
3939

.github/workflows/ci-python3-freebsd.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ jobs:
6464
pip list
6565
6666
# Check syntax by compiling code
67-
python -m compileall -f .
67+
python -W error -bb -m compileall -f .
6868
6969
# Run unit tests
70-
su runner -c 'python -bb test/test.py --unit --exit-early'
70+
su runner -c 'python -W error -bb test/test.py --unit --exit-early'
7171
7272
# Run integration tests (internal)
73-
su runner -c 'ulimit -n; ulimit -n 4096; python -bb test/test.py -i --exit-early'
73+
su runner -c 'ulimit -n; ulimit -n 4096; python -W error -bb test/test.py -i --exit-early'
7474
7575
# Run integration tests (external process)
7676
su runner -c 'ulimit -n; ulimit -n 4096; test/test.py -e --exit-early'

.github/workflows/ci-python3.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
strategy:
2424
matrix:
2525
os: [ ubuntu-24.04, ubuntu-22.04, ubuntu-20.04 ]
26-
python-version: [ '3.6', '3.7', '3.8', '3.9', '3.10', '3.11' ]
26+
python-version: [ '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]
2727
# Exclude unsupported OS/Python version combinations
2828
exclude:
2929
- os: ubuntu-22.04
@@ -58,16 +58,16 @@ jobs:
5858
pip list
5959
6060
- name: Check syntax by compiling code
61-
run: python -m compileall -f .
61+
run: python -W error -bb -m compileall -f .
6262

6363
- name: Run unit tests
64-
run: python -bb test/test.py --unit --exit-early
64+
run: python -W error -bb test/test.py --unit --exit-early
6565

6666
- name: Run integration tests (internal)
6767
run: |
6868
ulimit -n
6969
ulimit -n 4096
70-
python -bb test/test.py -i --exit-early
70+
python -W error -bb test/test.py -i --exit-early
7171
7272
- name: Run integration tests (external process)
7373
run: |

Changelog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
* WARNING: This is a development snapshot, not a stable release.
33
* Drop support for Python 3.5.
44
* Python 3.6 is now the minimum supported version.
5+
* Add support for Python 3.12 (Thanks to Louis Sautier).
6+
* Add support for Python 3.13.
7+
* Correctly close files in various situations.
58

69
2022-10-30 - v3.0.0:
710
* Tested platforms: Linux and FreeBSD. If there is interest in supporting more platforms (e.g. OSX and Windows), please get in contact with the project.

lib/cfv/common.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
__version__ = '3.0.1.dev0'
3030
__homepage__ = 'https://github.com/cfv-project/cfv'
3131

32+
import contextlib
3233
import copy
3334
import errno
3435
import getopt
@@ -466,8 +467,6 @@ def test_chksumfile(self, file, filename):
466467
cache.set_verified(filename)
467468
try:
468469
cf_stats = stats.make_sub_stats()
469-
if not file:
470-
file = fileutil.open_read(filename, config)
471470
self.do_test_chksumfile(file)
472471
cf_stats.sub_stats_end(stats)
473472
view.ev_test_cf_done(filename, cf_stats)
@@ -1532,8 +1531,8 @@ def getimagedimensions(filename):
15321531
return '0', '0'
15331532
try:
15341533
from PIL import Image
1535-
im1 = Image.open(filename)
1536-
return list(map(str, im1.size))
1534+
with Image.open(filename) as im1:
1535+
return list(map(str, im1.size))
15371536
except (ImportError, IOError):
15381537
return '0', '0'
15391538

@@ -1694,26 +1693,33 @@ def visit_dir(name, st=None, noisy=1):
16941693

16951694

16961695
def test(filename, typename, restrict_typename='auto'):
1697-
if typename != 'auto':
1698-
cf = cftypes.get_handler(typename)()
1699-
cf.test_chksumfile(None, filename)
1700-
return
1696+
class UnexpectedHandlerException(Exception):
1697+
pass
17011698

1702-
try:
1703-
file = fileutil.open_read(filename, config)
1699+
def get_cf_handler(file, typename, restrict_typename):
1700+
if typename != 'auto':
1701+
return cftypes.get_handler(typename)()
17041702
cftype = cftypes.auto_chksumfile_match(file)
17051703
if restrict_typename != 'auto' and cftypes.get_handler(restrict_typename) != cftype:
1706-
return
1704+
raise UnexpectedHandlerException()
17071705
if cftype:
1708-
cf = cftype()
1706+
return cftype()
1707+
1708+
try:
1709+
with contextlib.closing(fileutil.open_read(filename, config)) as file:
1710+
cf = get_cf_handler(file, typename, restrict_typename)
1711+
if not cf:
1712+
view.ev_test_cf_unrecognized(filename, file._decode_errs)
1713+
stats.cferror += 1
1714+
return
1715+
17091716
cf.test_chksumfile(file, filename)
1710-
return
1717+
except UnexpectedHandlerException:
1718+
return
17111719
except EnvironmentError as a:
17121720
stats.cferror += 1
17131721
view.ev_cf_enverror(filename, a)
17141722
return -1
1715-
view.ev_test_cf_unrecognized(filename, file._decode_errs)
1716-
stats.cferror += 1
17171723

17181724

17191725
def make(cftype, ifilename, testfiles):

lib/cfv/fileutil.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def _done_peeking(self, raw):
104104
self.readline = self._readline
105105
self.read = fileobj.read
106106
self.seek = fileobj.seek
107+
self.close = fileobj.close
107108

108109
def seek(self, *args):
109110
self._done_peeking(raw=1)
@@ -117,6 +118,9 @@ def read(self, *args):
117118
self._done_peeking(raw=1)
118119
return self.read(*args)
119120

121+
def close(self):
122+
self.fileobj.close()
123+
120124

121125
def PeekFileNonseekable(fileobj, filename, encoding):
122126
return PeekFile(BytesIO(fileobj.read()), filename, encoding)

lib/cfv/hash.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,27 +45,31 @@ def finish(m, s):
4545
if callback:
4646
callback(s)
4747

48-
if f == sys.stdin.buffer or _nommap or callback:
49-
return finish(hasher(), 0)
50-
else:
51-
s = os.path.getsize(filename)
52-
try:
53-
if s > _MAX_MMAP:
54-
# Work around python 2.[56] problem with md5 of large mmap objects
55-
raise OverflowError
56-
m = hasher(dommap(f.fileno(), s))
57-
except OverflowError:
58-
# mmap size is limited by C's int type, which even on 64 bit
59-
# arches is often 32 bits, so we can't use sys.maxint
60-
# either. If we get the error, just assume 32 bits.
61-
mmapsize = min(s, _FALLBACK_MMAP)
62-
m = hasher(dommap(f.fileno(), mmapsize))
63-
f.seek(mmapsize)
64-
# unfortunatly, python's mmap module doesn't support the
65-
# offset parameter, so we just have to do the rest of the
66-
# file the old fashioned way.
67-
return finish(m, mmapsize)
68-
return m.digest(), s
48+
try:
49+
if f == sys.stdin.buffer or _nommap or callback:
50+
return finish(hasher(), 0)
51+
else:
52+
s = os.path.getsize(filename)
53+
try:
54+
if s > _MAX_MMAP:
55+
# Work around python 2.[56] problem with md5 of large mmap objects
56+
raise OverflowError
57+
m = hasher(dommap(f.fileno(), s))
58+
except OverflowError:
59+
# mmap size is limited by C's int type, which even on 64 bit
60+
# arches is often 32 bits, so we can't use sys.maxint
61+
# either. If we get the error, just assume 32 bits.
62+
mmapsize = min(s, _FALLBACK_MMAP)
63+
m = hasher(dommap(f.fileno(), mmapsize))
64+
f.seek(mmapsize)
65+
# unfortunatly, python's mmap module doesn't support the
66+
# offset parameter, so we just have to do the rest of the
67+
# file the old fashioned way.
68+
return finish(m, mmapsize)
69+
return m.digest(), s
70+
finally:
71+
if filename != '':
72+
f.close()
6973

7074

7175
def getfilechecksumgeneric(algo):

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ def _get_version(path):
4848
'Programming Language :: Python :: 3.9',
4949
'Programming Language :: Python :: 3.10',
5050
'Programming Language :: Python :: 3.11',
51+
'Programming Language :: Python :: 3.12',
52+
'Programming Language :: Python :: 3.13',
5153
],
5254
keywords='cfv checksum verify sfv csv crc bsdmd5 md5sum sha1sum sha224sum sha256sum sha384sum sha512sum torrent par par2',
5355
project_urls={

test/cfvtest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def all_unittests_suite():
242242
assert modules_to_test
243243
alltests = unittest.TestSuite()
244244
for module in map(my_import, modules_to_test):
245-
alltests.addTest(unittest.findTestCases(module))
245+
alltests.addTest(unittest.defaultTestLoader.loadTestsFromModule(module))
246246

247247
import cfv.common
248248
libdir = os.path.split(cfv.common.__file__)[0]

test/test.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,7 @@ def test_encoding2():
13541354
raw_fnok += 1
13551355
flag_ok_raw = True
13561356
try:
1357-
open(os.path.join(d, fn), 'rb')
1357+
open(os.path.join(d, fn), 'rb').close()
13581358
except (EnvironmentError, UnicodeError):
13591359
files_fnerrs += 1
13601360
else:
@@ -1394,14 +1394,13 @@ def test_encoding2():
13941394
def largefile2GB_test():
13951395
# hope you have sparse file support ;)
13961396
fn = os.path.join('bigfile2', 'bigfile')
1397-
f = open(fn, 'wb')
13981397
try:
1399-
f.write(b'hi')
1400-
f.seek(2 ** 30)
1401-
f.write(b'foo')
1402-
f.seek(2 ** 31)
1403-
f.write(b'bar')
1404-
f.close()
1398+
with open(fn, 'wb') as f:
1399+
f.write(b'hi')
1400+
f.seek(2 ** 30)
1401+
f.write(b'foo')
1402+
f.seek(2 ** 31)
1403+
f.write(b'bar')
14051404
test_generic(cfvcmd + ' -v -T -p %s' % 'bigfile2', rcurry(cfv_all_test, ok=6))
14061405
finally:
14071406
os.unlink(fn)
@@ -1410,16 +1409,15 @@ def largefile2GB_test():
14101409
def largefile4GB_test():
14111410
# hope you have sparse file support ;)
14121411
fn = os.path.join('bigfile', 'bigfile')
1413-
f = open(fn, 'wb')
14141412
try:
1415-
f.write(b'hi')
1416-
f.seek(2 ** 30)
1417-
f.write(b'foo')
1418-
f.seek(2 ** 31)
1419-
f.write(b'bar')
1420-
f.seek(2 ** 32)
1421-
f.write(b'baz')
1422-
f.close()
1413+
with open(fn, 'wb') as f:
1414+
f.write(b'hi')
1415+
f.seek(2 ** 30)
1416+
f.write(b'foo')
1417+
f.seek(2 ** 31)
1418+
f.write(b'bar')
1419+
f.seek(2 ** 32)
1420+
f.write(b'baz')
14231421
test_generic(cfvcmd + ' -v -T -p %s' % 'bigfile', rcurry(cfv_all_test, ok=10))
14241422
finally:
14251423
os.unlink(fn)
@@ -1766,7 +1764,7 @@ def sfvverify(f):
17661764
else:
17671765
if t == 'par':
17681766
try:
1769-
open('data1'.encode('utf-16le').decode('utf-16be'), 'rb')
1767+
open('data1'.encode('utf-16le').decode('utf-16be'), 'rb').close()
17701768
except UnicodeError:
17711769
nf = 0
17721770
err = 4
@@ -1778,7 +1776,7 @@ def sfvverify(f):
17781776
test_generic(cfvcmd + ' --encoding=cp500 -i -T -f test.' + t, rcurry(cfv_all_test, cferror=4))
17791777
else:
17801778
try:
1781-
open(b'data1'.decode('cp500'), 'rb')
1779+
open(b'data1'.decode('cp500'), 'rb').close()
17821780
except UnicodeError:
17831781
nf = 0
17841782
err = 4
@@ -1890,3 +1888,4 @@ def copytree(src, dst, ignore=None):
18901888
sys.exit(failed)
18911889
finally:
18921890
shutil.rmtree(tmpdatapath)
1891+
logfile.close()

0 commit comments

Comments
 (0)