[pypy-commit] pypy default: implement the pwd module at interp-level,
amauryfa
noreply at buildbot.pypy.org
Mon Sep 5 23:20:11 CEST 2011
Author: Amaury Forgeot d'Arc <amauryfa at 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)
+
+ at 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)
+
+ at 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()
More information about the pypy-commit
mailing list