Skip to content

Commit e282e18

Browse files
authored
Merge pull request #29 from ankostis/appveyor
Enable Appveyor CI on Windows
2 parents 65989da + be5d426 commit e282e18

File tree

9 files changed

+425
-358
lines changed

9 files changed

+425
-358
lines changed

Diff for: .appveyor.yml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# CI on Windows via appveyor
2+
environment:
3+
4+
matrix:
5+
## MINGW
6+
#
7+
- PYTHON: "C:\\Python27"
8+
PYTHON_VERSION: "2.7"
9+
- PYTHON: "C:\\Python34-x64"
10+
PYTHON_VERSION: "3.4"
11+
- PYTHON: "C:\\Python35-x64"
12+
PYTHON_VERSION: "3.5"
13+
- PYTHON: "C:\\Miniconda35-x64"
14+
PYTHON_VERSION: "3.5"
15+
IS_CONDA: "yes"
16+
17+
install:
18+
- set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
19+
20+
## Print configuration for debugging.
21+
#
22+
- |
23+
echo %PATH%
24+
uname -a
25+
where python pip pip2 pip3 pip34
26+
python --version
27+
python -c "import struct; print(struct.calcsize('P') * 8)"
28+
29+
- IF "%IS_CONDA%"=="yes" (
30+
conda info -a &
31+
conda install --yes --quiet pip
32+
)
33+
- pip install nose wheel coveralls
34+
35+
## For commits performed with the default user.
36+
- |
37+
git config --global user.email "[email protected]"
38+
git config --global user.name "Travis Runner"
39+
40+
- pip install -e .
41+
42+
build: false
43+
44+
test_script:
45+
- IF "%PYTHON_VERSION%"=="3.5" (
46+
nosetests -v --with-coverage
47+
) ELSE (
48+
nosetests -v
49+
)

Diff for: README.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Although memory maps have many advantages, they represent a very limited system
99
## Overview
1010

1111
[![Build Status](https://travis-ci.org/gitpython-developers/smmap.svg?branch=master)](https://travis-ci.org/gitpython-developers/smmap)
12+
[![Build status](https://ci.appveyor.com/api/projects/status/h8rl7thsr42oc0pf?svg=true&passingText=windows%20OK&failingText=windows%20failed)](https://ci.appveyor.com/project/Byron/smmap)
1213
[![Coverage Status](https://coveralls.io/repos/gitpython-developers/smmap/badge.png)](https://coveralls.io/r/gitpython-developers/smmap)
1314
[![Issue Stats](http://www.issuestats.com/github/gitpython-developers/smmap/badge/pr)](http://www.issuestats.com/github/gitpython-developers/smmap)
1415
[![Issue Stats](http://www.issuestats.com/github/gitpython-developers/smmap/badge/issue)](http://www.issuestats.com/github/gitpython-developers/smmap)
@@ -44,15 +45,15 @@ The package was tested on all of the previously mentioned configurations.
4445
[![Documentation Status](https://readthedocs.org/projects/smmap/badge/?version=latest)](https://readthedocs.org/projects/smmap/?badge=latest)
4546

4647
Its easiest to install smmap using the [pip](http://www.pip-installer.org/en/latest) program:
47-
48+
4849
```bash
4950
$ pip install smmap
5051
```
51-
52+
5253
As the command will install smmap in your respective python distribution, you will most likely need root permissions to authorize the required changes.
5354

5455
If you have downloaded the source archive, the package can be installed by running the `setup.py` script:
55-
56+
5657
```bash
5758
$ python setup.py install
5859
```
@@ -68,17 +69,17 @@ The project is home on github at https://github.com/gitpython-developers/smmap .
6869
The latest source can be cloned from github as well:
6970

7071
* git://github.com/gitpython-developers/smmap.git
71-
72-
72+
73+
7374
For support, please use the git-python mailing list:
7475

7576
* http://groups.google.com/group/git-python
76-
77+
7778

7879
Issues can be filed on github:
7980

8081
* https://github.com/gitpython-developers/smmap/issues
81-
82+
8283

8384
## License Information
8485

Diff for: smmap/buf.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ def __init__(self, cursor=None, offset=0, size=sys.maxsize, flags=0):
4747
def __del__(self):
4848
self.end_access()
4949

50+
def __enter__(self):
51+
return self
52+
53+
def __exit__(self, exc_type, exc_value, traceback):
54+
self.end_access()
55+
5056
def __len__(self):
5157
return self._size
5258

@@ -83,15 +89,15 @@ def __getslice__(self, i, j):
8389
# in the previous iteration of this code
8490
pyvers = sys.version_info[:2]
8591
if (3, 0) <= pyvers <= (3, 3):
86-
# Memory view cannot be joined below python 3.4 ...
92+
# Memory view cannot be joined below python 3.4 ...
8793
out = bytes()
8894
while l:
8995
c.use_region(ofs, l)
9096
assert c.is_valid()
9197
d = c.buffer()[:l]
9298
ofs += len(d)
9399
l -= len(d)
94-
# This is slower than the join ... but what can we do ...
100+
# This is slower than the join ... but what can we do ...
95101
out += d
96102
del(d)
97103
# END while there are bytes to read
@@ -104,7 +110,7 @@ def __getslice__(self, i, j):
104110
d = c.buffer()[:l]
105111
ofs += len(d)
106112
l -= len(d)
107-
# Make sure we don't keep references, as c.use_region() might attempt to free resources, but
113+
# Make sure we don't keep references, as c.use_region() might attempt to free resources, but
108114
# can't unless we use pure bytes
109115
if hasattr(d, 'tobytes'):
110116
d = d.tobytes()

Diff for: smmap/mman.py

+6
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ def __init__(self, manager=None, regions=None):
4646
def __del__(self):
4747
self._destroy()
4848

49+
def __enter__(self):
50+
return self
51+
52+
def __exit__(self, exc_type, exc_value, traceback):
53+
self._destroy()
54+
4955
def _destroy(self):
5056
"""Destruction code to decrement counters"""
5157
self.unuse_region()

Diff for: smmap/test/lib.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ def __init__(self, size, prefix=''):
2121
self._path = tempfile.mktemp(prefix=prefix)
2222
self._size = size
2323

24-
fp = open(self._path, "wb")
25-
fp.seek(size - 1)
26-
fp.write(b'1')
27-
fp.close()
24+
with open(self._path, "wb") as fp:
25+
fp.seek(size - 1)
26+
fp.write(b'1')
2827

2928
assert os.path.getsize(self.path) == size
3029

@@ -35,6 +34,12 @@ def __del__(self):
3534
pass
3635
# END exception handling
3736

37+
def __enter__(self):
38+
return self
39+
40+
def __exit__(self, exc_type, exc_value, traceback):
41+
self.__del__()
42+
3843
@property
3944
def path(self):
4045
return self._path

Diff for: smmap/test/test_buf.py

+101-101
Original file line numberDiff line numberDiff line change
@@ -25,104 +25,104 @@
2525
class TestBuf(TestBase):
2626

2727
def test_basics(self):
28-
fc = FileCreator(self.k_window_test_size, "buffer_test")
29-
30-
# invalid paths fail upon construction
31-
c = man_optimal.make_cursor(fc.path)
32-
self.assertRaises(ValueError, SlidingWindowMapBuffer, type(c)()) # invalid cursor
33-
self.assertRaises(ValueError, SlidingWindowMapBuffer, c, fc.size) # offset too large
34-
35-
buf = SlidingWindowMapBuffer() # can create uninitailized buffers
36-
assert buf.cursor() is None
37-
38-
# can call end access any time
39-
buf.end_access()
40-
buf.end_access()
41-
assert len(buf) == 0
42-
43-
# begin access can revive it, if the offset is suitable
44-
offset = 100
45-
assert buf.begin_access(c, fc.size) == False
46-
assert buf.begin_access(c, offset) == True
47-
assert len(buf) == fc.size - offset
48-
assert buf.cursor().is_valid()
49-
50-
# empty begin access keeps it valid on the same path, but alters the offset
51-
assert buf.begin_access() == True
52-
assert len(buf) == fc.size
53-
assert buf.cursor().is_valid()
54-
55-
# simple access
56-
with open(fc.path, 'rb') as fp:
57-
data = fp.read()
58-
assert data[offset] == buf[0]
59-
assert data[offset:offset * 2] == buf[0:offset]
60-
61-
# negative indices, partial slices
62-
assert buf[-1] == buf[len(buf) - 1]
63-
assert buf[-10:] == buf[len(buf) - 10:len(buf)]
64-
65-
# end access makes its cursor invalid
66-
buf.end_access()
67-
assert not buf.cursor().is_valid()
68-
assert buf.cursor().is_associated() # but it remains associated
69-
70-
# an empty begin access fixes it up again
71-
assert buf.begin_access() == True and buf.cursor().is_valid()
72-
del(buf) # ends access automatically
73-
del(c)
74-
75-
assert man_optimal.num_file_handles() == 1
76-
77-
# PERFORMANCE
78-
# blast away with random access and a full mapping - we don't want to
79-
# exaggerate the manager's overhead, but measure the buffer overhead
80-
# We do it once with an optimal setting, and with a worse manager which
81-
# will produce small mappings only !
82-
max_num_accesses = 100
83-
fd = os.open(fc.path, os.O_RDONLY)
84-
for item in (fc.path, fd):
85-
for manager, man_id in ((man_optimal, 'optimal'),
86-
(man_worst_case, 'worst case'),
87-
(static_man, 'static optimal')):
88-
buf = SlidingWindowMapBuffer(manager.make_cursor(item))
89-
assert manager.num_file_handles() == 1
90-
for access_mode in range(2): # single, multi
91-
num_accesses_left = max_num_accesses
92-
num_bytes = 0
93-
fsize = fc.size
94-
95-
st = time()
96-
buf.begin_access()
97-
while num_accesses_left:
98-
num_accesses_left -= 1
99-
if access_mode: # multi
100-
ofs_start = randint(0, fsize)
101-
ofs_end = randint(ofs_start, fsize)
102-
d = buf[ofs_start:ofs_end]
103-
assert len(d) == ofs_end - ofs_start
104-
assert d == data[ofs_start:ofs_end]
105-
num_bytes += len(d)
106-
del d
107-
else:
108-
pos = randint(0, fsize)
109-
assert buf[pos] == data[pos]
110-
num_bytes += 1
111-
# END handle mode
112-
# END handle num accesses
113-
114-
buf.end_access()
115-
assert manager.num_file_handles()
116-
assert manager.collect()
117-
assert manager.num_file_handles() == 0
118-
elapsed = max(time() - st, 0.001) # prevent zero division errors on windows
119-
mb = float(1000 * 1000)
120-
mode_str = (access_mode and "slice") or "single byte"
121-
print("%s: Made %i random %s accesses to buffer created from %s reading a total of %f mb in %f s (%f mb/s)"
122-
% (man_id, max_num_accesses, mode_str, type(item), num_bytes / mb, elapsed, (num_bytes / mb) / elapsed),
123-
file=sys.stderr)
124-
# END handle access mode
125-
del buf
126-
# END for each manager
127-
# END for each input
128-
os.close(fd)
28+
with FileCreator(self.k_window_test_size, "buffer_test") as fc:
29+
30+
# invalid paths fail upon construction
31+
c = man_optimal.make_cursor(fc.path)
32+
self.assertRaises(ValueError, SlidingWindowMapBuffer, type(c)()) # invalid cursor
33+
self.assertRaises(ValueError, SlidingWindowMapBuffer, c, fc.size) # offset too large
34+
35+
buf = SlidingWindowMapBuffer() # can create uninitailized buffers
36+
assert buf.cursor() is None
37+
38+
# can call end access any time
39+
buf.end_access()
40+
buf.end_access()
41+
assert len(buf) == 0
42+
43+
# begin access can revive it, if the offset is suitable
44+
offset = 100
45+
assert buf.begin_access(c, fc.size) == False
46+
assert buf.begin_access(c, offset) == True
47+
assert len(buf) == fc.size - offset
48+
assert buf.cursor().is_valid()
49+
50+
# empty begin access keeps it valid on the same path, but alters the offset
51+
assert buf.begin_access() == True
52+
assert len(buf) == fc.size
53+
assert buf.cursor().is_valid()
54+
55+
# simple access
56+
with open(fc.path, 'rb') as fp:
57+
data = fp.read()
58+
assert data[offset] == buf[0]
59+
assert data[offset:offset * 2] == buf[0:offset]
60+
61+
# negative indices, partial slices
62+
assert buf[-1] == buf[len(buf) - 1]
63+
assert buf[-10:] == buf[len(buf) - 10:len(buf)]
64+
65+
# end access makes its cursor invalid
66+
buf.end_access()
67+
assert not buf.cursor().is_valid()
68+
assert buf.cursor().is_associated() # but it remains associated
69+
70+
# an empty begin access fixes it up again
71+
assert buf.begin_access() == True and buf.cursor().is_valid()
72+
del(buf) # ends access automatically
73+
del(c)
74+
75+
assert man_optimal.num_file_handles() == 1
76+
77+
# PERFORMANCE
78+
# blast away with random access and a full mapping - we don't want to
79+
# exaggerate the manager's overhead, but measure the buffer overhead
80+
# We do it once with an optimal setting, and with a worse manager which
81+
# will produce small mappings only !
82+
max_num_accesses = 100
83+
fd = os.open(fc.path, os.O_RDONLY)
84+
for item in (fc.path, fd):
85+
for manager, man_id in ((man_optimal, 'optimal'),
86+
(man_worst_case, 'worst case'),
87+
(static_man, 'static optimal')):
88+
buf = SlidingWindowMapBuffer(manager.make_cursor(item))
89+
assert manager.num_file_handles() == 1
90+
for access_mode in range(2): # single, multi
91+
num_accesses_left = max_num_accesses
92+
num_bytes = 0
93+
fsize = fc.size
94+
95+
st = time()
96+
buf.begin_access()
97+
while num_accesses_left:
98+
num_accesses_left -= 1
99+
if access_mode: # multi
100+
ofs_start = randint(0, fsize)
101+
ofs_end = randint(ofs_start, fsize)
102+
d = buf[ofs_start:ofs_end]
103+
assert len(d) == ofs_end - ofs_start
104+
assert d == data[ofs_start:ofs_end]
105+
num_bytes += len(d)
106+
del d
107+
else:
108+
pos = randint(0, fsize)
109+
assert buf[pos] == data[pos]
110+
num_bytes += 1
111+
# END handle mode
112+
# END handle num accesses
113+
114+
buf.end_access()
115+
assert manager.num_file_handles()
116+
assert manager.collect()
117+
assert manager.num_file_handles() == 0
118+
elapsed = max(time() - st, 0.001) # prevent zero division errors on windows
119+
mb = float(1000 * 1000)
120+
mode_str = (access_mode and "slice") or "single byte"
121+
print("%s: Made %i random %s accesses to buffer created from %s reading a total of %f mb in %f s (%f mb/s)"
122+
% (man_id, max_num_accesses, mode_str, type(item), num_bytes / mb, elapsed, (num_bytes / mb) / elapsed),
123+
file=sys.stderr)
124+
# END handle access mode
125+
del buf
126+
# END for each manager
127+
# END for each input
128+
os.close(fd)

0 commit comments

Comments
 (0)