Skip to content

Instantly share code, notes, and snippets.

@zed

zed/.gitignore Secret

Created October 1, 2011 22:42
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zed/4e72cc3ac15408df452e to your computer and use it in GitHub Desktop.
Save zed/4e72cc3ac15408df452e to your computer and use it in GitHub Desktop.
wrap Person.h in Cython
*.pyxbldc
/.do_buil*
redo test
exec >&2
git clean -x -d -f
cdef extern from "Person.h" nogil:
cdef struct Person_TAG:
pass
ctypedef Person_TAG* Person_ptr
Person_ptr Person_create(char* name)
void Person_destroy(Person_ptr self)
char* Person_get_name(Person_ptr self)
int Person_get_age(Person_ptr self)
void Person_birthday(Person_ptr self)
#!/bin/sh
#
# A minimal alternative to djb redo that doesn't support incremental builds.
# For the full version, visit http://github.com/apenwarr/redo
#
# The author disclaims copyright to this source file and hereby places it in
# the public domain. (2010 12 14)
#
# By default, no output coloring.
green=""
bold=""
plain=""
if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then
green="$(printf '\033[32m')"
bold="$(printf '\033[1m')"
plain="$(printf '\033[m')"
fi
_dirsplit()
{
base=${1##*/}
dir=${1%$base}
}
dirname()
(
_dirsplit "$1"
dir=${dir%/}
echo "${dir:-.}"
)
_dirsplit "$0"
export REDO=$(cd "${dir:-.}" && echo "$PWD/$base")
DO_TOP=
if [ -z "$DO_BUILT" ]; then
DO_TOP=1
[ -n "$*" ] || set all # only toplevel redo has a default target
export DO_BUILT=$PWD/.do_built
: >>"$DO_BUILT"
echo "Removing previously built files..." >&2
sort -u "$DO_BUILT" | tee "$DO_BUILT.new" |
while read f; do printf "%s\0%s.did\0" "$f" "$f"; done |
xargs -0 rm -f 2>/dev/null
mv "$DO_BUILT.new" "$DO_BUILT"
DO_PATH=$DO_BUILT.dir
export PATH=$DO_PATH:$PATH
rm -rf "$DO_PATH"
mkdir "$DO_PATH"
for d in redo redo-ifchange; do
ln -s "$REDO" "$DO_PATH/$d";
done
[ -e /bin/true ] && TRUE=/bin/true || TRUE=/usr/bin/true
for d in redo-ifcreate redo-stamp redo-always; do
ln -s $TRUE "$DO_PATH/$d";
done
fi
_find_dofile_pwd()
{
dofile=default.$1.do
while :; do
dofile=default.${dofile#default.*.}
[ -e "$dofile" -o "$dofile" = default.do ] && break
done
ext=${dofile#default}
ext=${ext%.do}
base=${1%$ext}
}
_find_dofile()
{
local prefix=
while :; do
_find_dofile_pwd "$1"
[ -e "$dofile" ] && break
[ "$PWD" = "/" ] && break
target=${PWD##*/}/$target
tmp=${PWD##*/}/$tmp
prefix=${PWD##*/}/$prefix
cd ..
done
base=$prefix$base
}
_run_dofile()
{
export DO_DEPTH="$DO_DEPTH "
export REDO_TARGET=$PWD/$target
local line1
set -e
read line1 <"$PWD/$dofile"
cmd=${line1#"#!/"}
if [ "$cmd" != "$line1" ]; then
/$cmd "$PWD/$dofile" "$@" >"$tmp.tmp2"
else
:; . "$PWD/$dofile" >"$tmp.tmp2"
fi
}
_do()
{
local dir=$1 target=$2 tmp=$3
if [ ! -e "$target" ] || [ -d "$target" -a ! -e "$target.did" ]; then
printf '%sdo %s%s%s%s\n' \
"$green" "$DO_DEPTH" "$bold" "$dir$target" "$plain" >&2
echo "$PWD/$target" >>"$DO_BUILT"
dofile=$target.do
base=$target
ext=
[ -e "$target.do" ] || _find_dofile "$target"
if [ ! -e "$dofile" ]; then
echo "do: $target: no .do file" >&2
return 1
fi
[ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] ||
: >>"$target.did"
( _run_dofile "$base" "$ext" "$tmp.tmp" )
rv=$?
if [ $rv != 0 ]; then
printf "do: %s%s\n" "$DO_DEPTH" \
"$dir$target: got exit code $rv" >&2
rm -f "$tmp.tmp" "$tmp.tmp2"
return $rv
fi
mv "$tmp.tmp" "$target" 2>/dev/null ||
! test -s "$tmp.tmp2" ||
mv "$tmp.tmp2" "$target" 2>/dev/null
rm -f "$tmp.tmp2"
else
echo "do $DO_DEPTH$target exists." >&2
fi
}
# Make corrections for directories that don't actually exist yet.
_dir_shovel()
{
local dir base
xdir=$1 xbase=$2 xbasetmp=$2
while [ ! -d "$xdir" -a -n "$xdir" ]; do
_dirsplit "${xdir%/}"
xbasetmp=${base}__$xbase
xdir=$dir xbase=$base/$xbase
echo "xbasetmp='$xbasetmp'" >&2
done
}
redo()
{
for i in "$@"; do
_dirsplit "$i"
_dir_shovel "$dir" "$base"
dir=$xdir base=$xbase basetmp=$xbasetmp
( cd "$dir" && _do "$dir" "$base" "$basetmp" ) || return 1
done
}
set -e
redo "$@"
if [ -n "$DO_TOP" ]; then
echo "Removing stamp files..." >&2
[ ! -e "$DO_BUILT" ] ||
while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" |
xargs -0 rm -f 2>/dev/null
fi
all:
Makefile:
@
%: FORCE
+./do $@
.PHONY: FORCE
/* http://stackoverflow.com/q/7619785 */
#include "Person.h"
#include "Person_private.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
Person_ptr Person_create(const char* name)
{
Person_ptr self = PERSON(malloc(sizeof(Person)));
PERSON_CHECK_INSTANCE(self);
person_init(self, name);
return self;
}
void Person_destroy(Person_ptr self)
{
PERSON_CHECK_INSTANCE(self);
if (NULL != self->name) free(self->name);
}
/* Do not free not change the returned string! */
const char* Person_get_name(const Person_ptr self)
{
PERSON_CHECK_INSTANCE(self);
return self->name;
}
int Person_get_age(const Person_ptr self)
{
PERSON_CHECK_INSTANCE(self);
return self->age;
}
void Person_birthday(Person_ptr self)
{
PERSON_CHECK_INSTANCE(self);
++self->age;
}
/* private/protected methods */
void person_init(Person_ptr self, const char* name)
{
self->name = malloc(sizeof(char) * (strlen(name) + 1));
assert(NULL != self->name);
strcpy(self->name, name);
self->age = 0;
}
/* http://stackoverflow.com/q/7619785 */
#ifndef __PERSON_H__
#define __PERSON_H__
#include <assert.h>
typedef struct Person_TAG* Person_ptr;
#define PERSON(x) \
((Person_ptr) (x))
#define PERSON_CHECK_INSTANCE(x) \
assert(PERSON(x) != PERSON(NULL))
/* public interface */
Person_ptr Person_create(const char* name);
void Person_destroy(Person_ptr self);
const char* Person_get_name(const Person_ptr self);
int Person_get_age(const Person_ptr self);
void Person_birthday(Person_ptr self);
# endif /* __PERSON_H__ */
from cperson cimport (Person_ptr, Person_create, Person_destroy,
Person_get_name, Person_get_age, Person_birthday)
cdef extern from *:
ctypedef char* const_char_p "const char*"
import operator
try:
from collections import namedtuple
NT = namedtuple('Person', 'name age')
except ImportError:
NT = lambda *args: args
_NOT_SET = object()
cdef class Person:
cdef Person_ptr thisptr
def __cinit__(self, unicode name not None, *unused_args, **unused_kwargs):
cdef bytes pyname = toutf8(name)
self.thisptr = Person_create(pyname)
if self.thisptr is NULL:
raise MemoryError
def __init__(self, name, age=_NOT_SET):
if age is not _NOT_SET: self.age = age
def __dealloc__(self):
if self.thisptr is not NULL:
Person_destroy(self.thisptr)
def __str__(self):
return u'Person(name="%s", age=%d)' % (self.name, self.age)
def __repr__(self):
return u'person.'+unicode(self).encode('unicode-escape').decode('ascii')
def __richcmp__(x, y, int op):
f = None
if op == 2: # ==
f = operator.eq
elif op == 0: # <
f = operator.lt
elif op == 1: # <=
f = operator.le
if f is not None:
return f(x.astuple(), y.astuple())
return NotImplemented
def astuple(self):
return NT(self.name, self.age)
property name:
def __get__(self):
assert self.thisptr is not NULL
return fromutf8(Person_get_name(self.thisptr))
property age:
def __get__(self):
assert self.thisptr is not NULL
return Person_get_age(self.thisptr)
def __set__(self, int newage):
if newage < self.age:
raise ValueError("can't set smaller age")
cdef Py_ssize_t i
for i in range(newage - self.age):
self.birthday()
def birthday(self):
assert self.thisptr is not NULL
Person_birthday(self.thisptr)
cdef bytes toutf8(unicode s):
return s.encode('utf-8')
cdef unicode fromutf8(const_char_p s):
assert s is not NULL
cdef bytes pys = s
return pys.decode('utf-8')
import os
from distutils.extension import Extension
dirname = os.path.dirname(__file__)
def make_ext(modname, pyxfilename):
return Extension(name=modname,
sources=[pyxfilename, "Person.c"],
include_dirs=[dirname])
/* http://stackoverflow.com/q/7619785 */
#ifndef __PERSON_PRIVATE_H__
#define __PERSON_PRIVATE_H__
#include "Person.h"
typedef struct Person_TAG {
char* name;
int age;
} Person;
void person_init(Person_ptr self, const char* name);
# endif /* __PERSON_PRIVATE_H__ */
exec >&2
DEPS=test_person.py
touch person.pyxbld
python $(which py.test) $DEPS &&
python3 $(which py.test) $DEPS
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try: from future_builtins import ascii
except ImportError: ascii = ascii # py3k
try: unicode = unicode
except NameError: unicode = str # py3k
try: xrange = xrange
except NameError: xrange = range # py3k
import sys
import pyximport; pyximport.install()
U_PREFIX = 'u' if sys.version_info < (3,) else ''
from person import Person
def U(bytes_or_unicode, source_encoding='utf-8'):
if not isinstance(bytes_or_unicode, unicode):
return bytes_or_unicode.decode(source_encoding)
return bytes_or_unicode
def assert_raises(exception_type, func, *args, **kwargs):
try: func(*args,**kwargs)
except exception_type: pass
else: assert 0, (func.__name__, args, kwargs)
def test_1sane():
p = Person(U('Gîl'))
assert p.name == U('Gîl') and p.age == 0
for _ in xrange(10): p.birthday()
assert p.age == 10
assert p == Person(name=U("Gîl"), age=10)
assert unicode(p) == U('Person(name="Gîl", age=10)')
rp = r'person.Person(name="G\xeel", age=10)'
assert repr(p) == rp
assert ascii(p) == rp
def test_none():
for f in [Person, Person.__init__, Person.birthday, Person.__str__]:
assert_raises(TypeError, f, None)
assert_raises(TypeError, Person)
def test_age():
p = Person(U('Brúnor'))
assert p.age == 0
p.age = 1000
assert p.age == 1000
assert_raises(ValueError, setattr, p, 'age', 50)
assert_raises(TypeError, setattr, p, 'age', None)
assert_raises(TypeError, Person, U('Nethon'), None)
assert_raises(TypeError, Person, U("Cílil"), '1')
assert_raises(ValueError, Person, U('Círwen'), -1)
def test_astuple():
p = Person(U("Calemirtôr"), 11)
try:
from collections import namedtuple
assert (ascii(p.astuple()) ==
"Person(name=" + U_PREFIX + r"'Calemirt\xf4r', age=11)")
except ImportError: pass
assert p.astuple() == (U("Calemirtôr"), 11)
def test_new_attr():
p = Person(U('dae'))
try: p.dae = None
except AttributeError: pass
else: assert 0
def test_richcmp():
name = U('Aglareth')
x = Person(name)
y = Person(U('Duron'))
assert x != y
x.birthday()
z = Person(name)
assert z < x
assert not (z == x)
assert x > z
assert z <= x
assert x != z
assert x >= z
def run_tests():
import inspect
import test_person
for name, f in inspect.getmembers(test_person, inspect.isfunction):
if name.startswith('test_'):
f()
if __name__=="__main__":
run_tests()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment