Author: Amaury Forgeot d'Arc <amaur...@gmail.com> Branch: Changeset: r47092:21f8faf13c20 Date: 2011-09-05 23:14 +0200 http://bitbucket.org/pypy/pypy/changeset/21f8faf13c20/
Log: implement the pwd module at interp-level, should help the cyclic imports on some platforms (pwd imported ctypes which needs pwd.pw_dir to find libraries) diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -359,7 +359,7 @@ RegrTest('test_property.py', core=True), RegrTest('test_pstats.py'), RegrTest('test_pty.py', skip="unsupported extension module"), - RegrTest('test_pwd.py', skip=skip_win32), + RegrTest('test_pwd.py', usemodules="pwd", skip=skip_win32), RegrTest('test_py3kwarn.py'), RegrTest('test_pyclbr.py'), RegrTest('test_pydoc.py'), diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -27,7 +27,7 @@ # --allworkingmodules working_modules = default_modules.copy() working_modules.update(dict.fromkeys( - ["_socket", "unicodedata", "mmap", "fcntl", "_locale", + ["_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", @@ -58,6 +58,7 @@ # unix only modules del working_modules["crypt"] del working_modules["fcntl"] + del working_modules["pwd"] del working_modules["termios"] del working_modules["_minimal_curses"] diff --git a/pypy/doc/config/objspace.usemodules.pwd.txt b/pypy/doc/config/objspace.usemodules.pwd.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.usemodules.pwd.txt @@ -0,0 +1,2 @@ +Use the 'pwd' module. +This module is expected to be fully working. diff --git a/pypy/module/pwd/__init__.py b/pypy/module/pwd/__init__.py new file mode 100644 --- /dev/null +++ b/pypy/module/pwd/__init__.py @@ -0,0 +1,25 @@ +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + """ + This module provides access to the Unix password database. + It is available on all Unix versions. + + Password database entries are reported as 7-tuples containing the following + items from the password database (see `<pwd.h>'), in order: + pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell. + The uid and gid items are integers, all others are strings. An + exception is raised if the entry asked for cannot be found. + """ + + interpleveldefs = { + 'getpwuid': 'interp_pwd.getpwuid', + 'getpwnam': 'interp_pwd.getpwnam', + 'getpwall': 'interp_pwd.getpwall', + } + + appleveldefs = { + 'struct_passwd': 'app_pwd.struct_passwd', + 'struct_pwent': 'app_pwd.struct_passwd', + } + diff --git a/pypy/module/pwd/app_pwd.py b/pypy/module/pwd/app_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/pwd/app_pwd.py @@ -0,0 +1,20 @@ +from _structseq import structseqtype, structseqfield + +class struct_passwd: + """ + pwd.struct_passwd: Results from getpw*() routines. + + This object may be accessed either as a tuple of + (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell) + or via the object attributes as named in the above tuple. + """ + __metaclass__ = structseqtype + name = "pwd.struct_passwd" + + pw_name = structseqfield(0, "user name") + pw_passwd = structseqfield(1, "password") + pw_uid = structseqfield(2, "user id") + pw_gid = structseqfield(3, "group id") + pw_gecos = structseqfield(4, "real name") + pw_dir = structseqfield(5, "home directory") + pw_shell = structseqfield(6, "shell program") diff --git a/pypy/module/pwd/interp_pwd.py b/pypy/module/pwd/interp_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/pwd/interp_pwd.py @@ -0,0 +1,89 @@ +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.rpython.tool import rffi_platform +from pypy.rpython.lltypesystem import rffi, lltype +from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.error import OperationError, operationerrfmt + +class CConfig: + _compilation_info_ = ExternalCompilationInfo( + includes=['pwd.h'] + ) + + uid_t = rffi_platform.SimpleType("uid_t") + + passwd = rffi_platform.Struct( + 'struct passwd', + [('pw_name', rffi.CCHARP), + ('pw_passwd', rffi.CCHARP), + ('pw_uid', rffi.INT), + ('pw_gid', rffi.INT), + ('pw_gecos', rffi.CCHARP), + ('pw_dir', rffi.CCHARP), + ('pw_shell', rffi.CCHARP), + ]) + +config = rffi_platform.configure(CConfig) +passwd_p = lltype.Ptr(config['passwd']) +uid_t = config['uid_t'] + +c_getpwuid = rffi.llexternal("getpwuid", [uid_t], passwd_p) +c_getpwnam = rffi.llexternal("getpwnam", [rffi.CCHARP], passwd_p) +c_setpwent = rffi.llexternal("setpwent", [], lltype.Void) +c_getpwent = rffi.llexternal("getpwent", [], passwd_p) +c_endpwent = rffi.llexternal("endpwent", [], lltype.Void) + +def make_struct_passwd(space, pw): + w_passwd_struct = space.getattr(space.getbuiltinmodule('pwd'), + space.wrap('struct_passwd')) + w_tuple = space.newtuple([ + space.wrap(rffi.charp2str(pw.c_pw_name)), + space.wrap(rffi.charp2str(pw.c_pw_passwd)), + space.wrap(pw.c_pw_uid), + space.wrap(pw.c_pw_gid), + space.wrap(rffi.charp2str(pw.c_pw_gecos)), + space.wrap(rffi.charp2str(pw.c_pw_dir)), + space.wrap(rffi.charp2str(pw.c_pw_shell)), + ]) + return space.call_function(w_passwd_struct, w_tuple) + +@unwrap_spec(uid=int) +def getpwuid(space, uid): + """ + getpwuid(uid) -> (pw_name,pw_passwd,pw_uid, + pw_gid,pw_gecos,pw_dir,pw_shell) + Return the password database entry for the given numeric user ID. + See pwd.__doc__ for more on password database entries. + """ + pw = c_getpwuid(uid) + if not pw: + raise operationerrfmt(space.w_KeyError, + "getpwuid(): uid not found: %d", uid) + return make_struct_passwd(space, pw) + +@unwrap_spec(name=str) +def getpwnam(space, name): + """ + getpwnam(name) -> (pw_name,pw_passwd,pw_uid, + pw_gid,pw_gecos,pw_dir,pw_shell) + Return the password database entry for the given user name. + See pwd.__doc__ for more on password database entries. + """ + pw = c_getpwnam(name) + if not pw: + raise operationerrfmt(space.w_KeyError, + "getpwnam(): name not found: %s", name) + return make_struct_passwd(space, pw) + +def getpwall(space): + users_w = [] + c_setpwent() + try: + while True: + pw = c_getpwent() + if not pw: + break + users_w.append(make_struct_passwd(space, pw)) + finally: + c_endpwent() + return space.newlist(users_w) + diff --git a/pypy/module/pwd/test/test_pwd.py b/pypy/module/pwd/test/test_pwd.py new file mode 100644 --- /dev/null +++ b/pypy/module/pwd/test/test_pwd.py @@ -0,0 +1,25 @@ +from pypy.conftest import gettestobjspace + +class AppTestPwd: + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['pwd']) + + def test_getpwuid(self): + import pwd + raises(KeyError, pwd.getpwuid, -1) + pw = pwd.getpwuid(0) + assert pw.pw_name == 'root' + assert isinstance(pw.pw_passwd, str) + assert pw.pw_uid == 0 + assert pw.pw_gid == 0 + assert pw.pw_dir == '/root' + assert pw.pw_shell.startswith('/') + + def test_getpwnam(self): + import pwd + raises(KeyError, pwd.getpwnam, '~invalid~') + assert pwd.getpwnam('root').pw_name == 'root' + + def test_getpwall(self): + import pwd + assert pwd.getpwnam('root') in pwd.getpwall() _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit