Skip to content

Commit 59030cb

Browse files
authored
Merge pull request #9 from smartfile/python3
Python 3
2 parents 652c422 + d37e6b0 commit 59030cb

12 files changed

Lines changed: 121 additions & 81 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ venv
44

55
build
66
libarchive/__libarchive.so
7+
libarchive/_libarchive_wrap.o
78
python_libarchive.egg-info

.travis.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
language: python
2-
python:
3-
- "2.7"
4-
env:
5-
- DJANGO=1.3
6-
- DJANGO=1.4
2+
jobs:
3+
include:
4+
- python: "2.7"
5+
env: PYVER=2.7
6+
- python: "3.6"
7+
env: PYVER=3.6
78
before_install:
89
- sudo apt-get update -qq
910
- sudo apt-get install -qq libarchive-dev
11+
- pyenv shell $(python -c 'import platform; print(platform.python_version())')
1012
install:
11-
- pip install .
13+
- make build
1214
script:
1315
- make test
1416
notifications:

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
build:
2+
make -C libarchive
3+
14
test:
25
python tests.py
36

@@ -11,3 +14,6 @@ install:
1114
publish:
1215
python setup.py register
1316
python setup.py sdist upload
17+
18+
clean:
19+
make -C libarchive clean

docs/conf.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
master_doc = 'index'
4141

4242
# General information about the project.
43-
project = u'python-libarchive'
44-
copyright = u'2012, Ben Timby'
43+
project = 'python-libarchive'
44+
copyright = '2012, Ben Timby'
4545

4646
# The version info for the project you're documenting, acts as replacement for
4747
# |version| and |release|, also used in various other places throughout the
@@ -178,8 +178,8 @@
178178
# Grouping the document tree into LaTeX files. List of tuples
179179
# (source start file, target name, title, author, documentclass [howto/manual]).
180180
latex_documents = [
181-
('index', 'python-libarchive.tex', u'python-libarchive Documentation',
182-
u'Ben Timby', 'manual'),
181+
('index', 'python-libarchive.tex', 'python-libarchive Documentation',
182+
'Ben Timby', 'manual'),
183183
]
184184

185185
# The name of an image file (relative to this directory) to place at the top of
@@ -211,6 +211,6 @@
211211
# One entry per manual page. List of tuples
212212
# (source start file, name, description, authors, manual section).
213213
man_pages = [
214-
('index', 'python-libarchive', u'python-libarchive Documentation',
215-
[u'Ben Timby'], 1)
214+
('index', 'python-libarchive', 'python-libarchive Documentation',
215+
['Ben Timby'], 1)
216216
]

libarchive/Makefile

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
CFLAGS = -g
22
INCLUDE = -I/usr/include -I.
3-
LIBS = -L/usr/local/lib -l:libarchive.so.13.1.2
3+
LIBS = -larchive
44

5-
#if PYTHON_VERSION
6-
PYVER = $(PYTHON_VERSION)
7-
#else
8-
PYVER = 2.7
9-
#endif
5+
PYVER ?= 2.7
106

117
all: __libarchive.so
128

libarchive/__init__.py

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@
3030
import warnings
3131

3232
from libarchive import _libarchive
33-
try:
34-
from cStringIO import StringIO
35-
except ImportError:
36-
from StringIO import StringIO
33+
from io import StringIO
34+
35+
PY3 = sys.version_info[0] == 3
3736

3837
# Suggested block size for libarchive. Libarchive may adjust it.
3938
BLOCK_SIZE = 10240
@@ -134,7 +133,7 @@ def is_archive_name(filename, formats=None):
134133
This function will return the name of the most likely archive format, None if the file is
135134
unlikely to be an archive.'''
136135
if formats is None:
137-
formats = FORMAT_EXTENSIONS.values()
136+
formats = list(FORMAT_EXTENSIONS.values())
138137
format, filter = guess_format(filename)
139138
if format in formats:
140139
return format
@@ -153,8 +152,8 @@ def is_archive(f, formats=(None, ), filters=(None, )):
153152
154153
This function will return True if the file can be opened as an archive using the given
155154
format(s)/filter(s).'''
156-
if isinstance(f, basestring):
157-
f = file(f, 'r')
155+
if isinstance(f, str):
156+
f = open(f, 'r')
158157
a = _libarchive.archive_read_new()
159158
for format in formats:
160159
format = get_func(format, FORMATS, 0)
@@ -175,6 +174,7 @@ def is_archive(f, formats=(None, ), filters=(None, )):
175174
finally:
176175
_libarchive.archive_read_close(a)
177176
_libarchive.archive_read_free(a)
177+
f.close()
178178

179179

180180
class EntryReadStream(object):
@@ -271,7 +271,7 @@ def write(self, data):
271271
if self.buffer:
272272
self.buffer.write(data)
273273
else:
274-
_libarchive.archive_write_data_from_str(self.archive._a, data)
274+
_libarchive.archive_write_data_from_str(self.archive._a, data.encode('utf-8'))
275275
self.bytes += len(data)
276276

277277
def close(self):
@@ -280,7 +280,7 @@ def close(self):
280280
if self.buffer:
281281
self.entry.size = self.buffer.tell()
282282
self.entry.to_archive(self.archive)
283-
_libarchive.archive_write_data_from_str(self.archive._a, self.buffer.getvalue())
283+
_libarchive.archive_write_data_from_str(self.archive._a, self.buffer.getvalue().encode('utf-8'))
284284
_libarchive.archive_write_finish_entry(self.archive._a)
285285

286286
# Call archive.close() with _defer True to let it know we have been
@@ -312,8 +312,13 @@ def from_archive(cls, archive, encoding=ENCODING):
312312
call_and_check(_libarchive.archive_read_next_header2, archive._a, archive._a, e)
313313
mode = _libarchive.archive_entry_filetype(e)
314314
mode |= _libarchive.archive_entry_perm(e)
315-
entry = cls(
315+
if PY3:
316+
pathname=_libarchive.archive_entry_pathname(e)
317+
else:
316318
pathname=_libarchive.archive_entry_pathname(e).decode(encoding),
319+
320+
entry = cls(
321+
pathname=pathname,
317322
size=_libarchive.archive_entry_size(e),
318323
mtime=_libarchive.archive_entry_mtime(e),
319324
mode=mode,
@@ -330,7 +335,7 @@ def from_file(cls, f, entry=None, encoding=ENCODING):
330335
if entry is None:
331336
entry = cls(encoding=encoding)
332337
if entry.pathname is None:
333-
if isinstance(f, basestring):
338+
if isinstance(f, str):
334339
st = os.stat(f)
335340
entry.pathname = f
336341
entry.size = st.st_size
@@ -353,7 +358,10 @@ def to_archive(self, archive):
353358
'''Creates an archive header and writes it to the given archive.'''
354359
e = _libarchive.archive_entry_new()
355360
try:
356-
_libarchive.archive_entry_set_pathname(e, self.pathname.encode(self.encoding))
361+
if PY3:
362+
_libarchive.archive_entry_set_pathname(e, self.pathname)
363+
else:
364+
_libarchive.archive_entry_set_pathname(e, self.pathname.encode(self.encoding))
357365
_libarchive.archive_entry_set_filetype(e, stat.S_IFMT(self.mode))
358366
_libarchive.archive_entry_set_perm(e, stat.S_IMODE(self.mode))
359367
_libarchive.archive_entry_set_size(e, self.size)
@@ -390,9 +398,9 @@ def __init__(self, f, mode='r', format=None, filter=None, entry_class=Entry, enc
390398
self._stream = None
391399
self.encoding = encoding
392400
self.blocksize = blocksize
393-
if isinstance(f, basestring):
401+
if isinstance(f, str):
394402
self.filename = f
395-
f = file(f, mode)
403+
f = open(f, mode)
396404
# Only close it if we opened it...
397405
self._defer_close = True
398406
elif hasattr(f, 'fileno'):
@@ -520,11 +528,11 @@ def read(self, size):
520528
def readpath(self, f):
521529
'''Write current archive entry contents to file. f can be a file-like object or
522530
a path.'''
523-
if isinstance(f, basestring):
531+
if isinstance(f, str):
524532
basedir = os.path.basename(f)
525533
if not os.path.exists(basedir):
526534
os.makedirs(basedir)
527-
f = file(f, 'w')
535+
f = open(f, 'w')
528536
return _libarchive.archive_read_data_into_fd(self._a, f.fileno())
529537

530538
def readstream(self, size):
@@ -534,23 +542,26 @@ def readstream(self, size):
534542

535543
def write(self, member, data=None):
536544
'''Writes a string buffer to the archive as the given entry.'''
537-
if isinstance(member, basestring):
545+
if isinstance(member, str):
538546
member = self.entry_class(pathname=member, encoding=self.encoding)
539547
if data:
540548
member.size = len(data)
541549
member.to_archive(self)
542-
550+
543551
if data:
544-
_libarchive.archive_write_data_from_str(self._a, data)
552+
if PY3:
553+
result = _libarchive.archive_write_data_from_str(self._a, data.encode('utf8'))
554+
else:
555+
result = _libarchive.archive_write_data_from_str(self._a, data)
545556
_libarchive.archive_write_finish_entry(self._a)
546557

547558
def writepath(self, f, pathname=None, folder=False):
548559
'''Writes a file to the archive. f can be a file-like object or a path. Uses
549560
write() to do the actual writing.'''
550561
member = self.entry_class.from_file(f, encoding=self.encoding)
551-
if isinstance(f, basestring):
562+
if isinstance(f, str):
552563
if os.path.isfile(f):
553-
f = file(f, 'r')
564+
f = open(f, 'r')
554565
if pathname:
555566
member.pathname = pathname
556567
if folder and not member.isdir():
@@ -587,8 +598,8 @@ def __init__(self, f, **kwargs):
587598
self._stream = None
588599
# Convert file to open file. We need this to reopen the archive.
589600
mode = kwargs.setdefault('mode', 'r')
590-
if isinstance(f, basestring):
591-
f = file(f, mode)
601+
if isinstance(f, str):
602+
f = open(f, mode)
592603
super(SeekableArchive, self).__init__(f, **kwargs)
593604
self.entries = []
594605
self.eof = False
@@ -614,7 +625,11 @@ def reopen(self):
614625
def getentry(self, pathname):
615626
'''Take a name or entry object and returns an entry object.'''
616627
for entry in self:
617-
if entry.pathname == pathname:
628+
if PY3:
629+
entry_pathname = entry.pathname
630+
if not PY3:
631+
entry_pathname = entry.pathname[0]
632+
if entry_pathname == pathname:
618633
return entry
619634
raise KeyError(pathname)
620635

libarchive/_libarchive.i

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ extern const char *archive_error_string(struct archive *);
360360
%inline %{
361361
PyObject *archive_read_data_into_str(struct archive *archive, int len) {
362362
PyObject *str = NULL;
363-
if (!(str = PyString_FromStringAndSize(NULL, len))) {
363+
if (!(str = PyUnicode_FromStringAndSize(NULL, len))) {
364364
PyErr_SetString(PyExc_MemoryError, "could not allocate string.");
365365
return NULL;
366366
}

libarchive/_libarchive_wrap.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
739739
#define PyString_Size(str) PyBytes_Size(str)
740740
#define PyString_InternFromString(key) PyUnicode_InternFromString(key)
741741
#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE
742-
#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x)
742+
#define PyString_AS_STRING(x) PyBytes_AsString(x)
743743
#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x)
744744

745745
#endif
@@ -3342,10 +3342,17 @@ SWIG_AsVal_unsigned_SS_short (PyObject * obj, unsigned short *val)
33423342

33433343
PyObject *archive_read_data_into_str(struct archive *archive, int len) {
33443344
PyObject *str = NULL;
3345-
if (!(str = PyString_FromStringAndSize(NULL, len))) {
3345+
#if PY_VERSION_HEX >= 0x03000000
3346+
if (!(str = PyBytes_FromStringAndSize(NULL, len))) {
33463347
PyErr_SetString(PyExc_MemoryError, "could not allocate string.");
33473348
return NULL;
33483349
}
3350+
#else
3351+
if (!(str = PyString_FromStringAndSize(NULL, len))) {
3352+
PyErr_SetString(PyExc_MemoryError, "could not allocate string.");
3353+
return NULL;
3354+
}
3355+
#endif
33493356
if (len != archive_read_data(archive, PyString_AS_STRING(str), len)) {
33503357
PyErr_SetString(PyExc_RuntimeError, "could not read requested data.");
33513358
return NULL;

libarchive/tar.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ def getmembers(self):
7676
def getnames(self):
7777
return list(self.iterpaths)
7878

79-
def next(self):
79+
def __next__(self):
8080
raise NotImplementedError
8181
pass # TODO: how to do this?
8282

8383
def extract(self, member, path=None):
8484
if path is None:
8585
path = os.getcwd()
86-
if isinstance(member, basestring):
86+
if isinstance(member, str):
8787
f = os.path.join(path, member)
8888
else:
8989
f = os.path.join(path, member.pathname)

libarchive/zip.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def get_file_size(self):
2323
return self.size
2424

2525
def set_file_size(self, value):
26-
assert isinstance(value, (int, long)), 'Please provide size as int or long.'
26+
assert isinstance(value, int), 'Please provide size as int or long.'
2727
self.size = value
2828

2929
file_size = property(get_file_size, set_file_size)

0 commit comments

Comments
 (0)