[pypy-commit] pypy reflex-support: o) more informative dir() method for namespaces

wlav noreply at buildbot.pypy.org
Sun Jul 1 23:31:03 CEST 2012


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r55888:3c2792308ebf
Date: 2012-06-29 15:51 -0700
http://bitbucket.org/pypy/pypy/changeset/3c2792308ebf/

Log:	o) more informative dir() method for namespaces o) allow importing
	from namespaces (once loaded)

diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -39,6 +39,20 @@
 c_load_dictionary = backend.c_load_dictionary
 
 # name to opaque C++ scope representation ------------------------------------
+_c_num_scopes = rffi.llexternal(
+    "cppyy_num_scopes",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_scopes(cppscope):
+    return _c_num_scopes(cppscope.handle)
+_c_scope_name = rffi.llexternal(
+    "cppyy_scope_name",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    compilation_info = backend.eci)
+def c_scope_name(cppscope, iscope):
+    return charp2str_free(_c_scope_name(cppscope.handle, iscope))
+
 _c_resolve_name = rffi.llexternal(
     "cppyy_resolve_name",
     [rffi.CCHARP], rffi.CCHARP,
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
--- a/pypy/module/cppyy/include/capi.h
+++ b/pypy/module/cppyy/include/capi.h
@@ -15,6 +15,9 @@
     typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
 
     /* name to opaque C++ scope representation -------------------------------- */
+    int cppyy_num_scopes(cppyy_scope_t parent);
+    char* cppyy_scope_name(cppyy_scope_t parent, int iscope);
+
     char* cppyy_resolve_name(const char* cppitem_name);
     cppyy_scope_t cppyy_get_scope(const char* scope_name);
     cppyy_type_t cppyy_get_template(const char* template_name);
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -533,6 +533,18 @@
     def is_namespace(self):
         return self.space.w_True
 
+    def ns__dir__(self):
+        alldir = []
+        for i in range(capi.c_num_scopes(self)):
+            alldir.append(capi.c_scope_name(self, i))
+        for i in range(capi.c_num_methods(self)):
+            idx = capi.c_method_index_at(self, i)
+            alldir.append(capi.c_method_name(self, idx))
+        for i in range(capi.c_num_datamembers(self)):
+            alldir.append(capi.c_datamember_name(self, i))
+        return self.space.wrap(alldir)
+        
+
 W_CPPNamespace.typedef = TypeDef(
     'CPPNamespace',
     get_method_names = interp2app(W_CPPNamespace.get_method_names),
@@ -540,6 +552,7 @@
     get_datamember_names = interp2app(W_CPPNamespace.get_datamember_names),
     get_datamember = interp2app(W_CPPNamespace.get_datamember, unwrap_spec=['self', str]),
     is_namespace = interp2app(W_CPPNamespace.is_namespace),
+    __dir__ = interp2app(W_CPPNamespace.ns__dir__),
 )
 W_CPPNamespace.typedef.acceptable_as_base_class = False
 
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -1,6 +1,6 @@
 # NOT_RPYTHON
 import cppyy
-import types
+import types, sys
 
 
 # For now, keep namespaces and classes separate as namespaces are extensible
@@ -15,7 +15,8 @@
             raise AttributeError("%s object has no attribute '%s'" % (self, name))
 
 class CppyyNamespaceMeta(CppyyScopeMeta):
-    pass
+    def __dir__(cls):
+        return cls._cpp_proxy.__dir__()
 
 class CppyyClass(CppyyScopeMeta):
     pass
@@ -124,6 +125,8 @@
             setattr(pycppns, dm, pydm)
             setattr(metans, dm, pydm)
 
+        modname = pycppns.__name__.replace('::', '.')
+        sys.modules['cppyy.gbl.'+modname] = pycppns
     return pycppns
 
 def _drop_cycles(bases):
@@ -375,9 +378,11 @@
 # creation of global functions may cause the creation of classes in the global
 # namespace, so gbl must exist at that point to cache them)
 gbl = make_cppnamespace(None, "::", None, False)   # global C++ namespace
+sys.modules['cppyy.gbl'] = gbl
 
 # mostly for the benefit of the CINT backend, which treats std as special
 gbl.std = make_cppnamespace(None, "std", None, False)
+sys.modules['cppyy.gbl.std'] = gbl.std
 
 # user-defined pythonizations interface
 _pythonizations = {}
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -53,6 +53,17 @@
 
 
 /* name to opaque C++ scope representation -------------------------------- */
+int cppyy_num_scopes(cppyy_scope_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    return s.SubScopeSize();
+}
+
+char* cppyy_scope_name(cppyy_scope_t handle, int iscope) {
+    Reflex::Scope s = scope_from_handle(handle);
+    std::string name = s.SubScopeAt(iscope).Name(Reflex::F);
+    return cppstring_to_cstring(name);
+}
+
 char* cppyy_resolve_name(const char* cppitem_name) {
     Reflex::Scope s = Reflex::Scope::ByName(cppitem_name);
     if (s.IsEnum())
diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h
--- a/pypy/module/cppyy/test/fragile.h
+++ b/pypy/module/cppyy/test/fragile.h
@@ -77,4 +77,14 @@
 
 void fglobal(int, double, char);
 
+namespace nested1 {
+    class A {};
+    namespace nested2 {
+        class A {};
+        namespace nested3 {
+            class A {};
+        } // namespace nested3
+    } // namespace nested2
+} // namespace nested1
+
 } // namespace fragile
diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml
--- a/pypy/module/cppyy/test/fragile.xml
+++ b/pypy/module/cppyy/test/fragile.xml
@@ -1,8 +1,14 @@
 <lcgdict>
 
   <namespace name="fragile" />
+  <namespace name="fragile::nested1" />
+  <namespace name="fragile::nested1::nested2" />
+  <namespace name="fragile::nested1::nested2::nested3" />
 
   <class pattern="fragile::[A-Z]" />
+  <class name="fragile::nested1::A" />
+  <class name="fragile::nested1::nested2::A" />
+  <class name="fragile::nested1::nested2::nested3::A" />
 
   <variable name="fragile::gI" />
 
diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py
--- a/pypy/module/cppyy/test/test_fragile.py
+++ b/pypy/module/cppyy/test/test_fragile.py
@@ -19,7 +19,7 @@
         cls.space = space
         env = os.environ
         cls.w_test_dct  = space.wrap(test_dct)
-        cls.w_datatypes = cls.space.appexec([], """():
+        cls.w_fragile = cls.space.appexec([], """():
             import cppyy
             return cppyy.load_reflection_info(%r)""" % (test_dct, ))
 
@@ -194,3 +194,53 @@
 
         f = fragile.fglobal
         assert f.__doc__ == "void fragile::fglobal(int, double, char)"
+
+    def test11_dir(self):
+        """Test __dir__ method"""
+
+        import cppyy
+
+        members = dir(cppyy.gbl.fragile)
+        assert 'A' in members
+        assert 'B' in members
+        assert 'C' in members
+        assert 'D' in members                # classes
+
+        assert 'fglobal' in members          # function
+        assert 'nested1' in members          # namespace
+        assert 'gI'in members                # variable
+
+    def test12_imports(self):
+        """Test ability to import from namespace (or fail with ImportError)"""
+
+        import cppyy
+
+        # TODO: namespaces aren't loaded (and thus not added to sys.modules)
+        # with just the from ... import statement; actual use is needed
+        from cppyy.gbl import fragile
+
+        def fail_import():
+            from cppyy.gbl import does_not_exist
+        raises(ImportError, fail_import)
+
+        from cppyy.gbl.fragile import A, B, C, D
+        assert cppyy.gbl.fragile.A is A
+        assert cppyy.gbl.fragile.B is B
+        assert cppyy.gbl.fragile.C is C
+        assert cppyy.gbl.fragile.D is D
+
+        # according to warnings, can't test "import *" ...
+
+        from cppyy.gbl.fragile import nested1
+        assert cppyy.gbl.fragile.nested1 is nested1
+
+        from cppyy.gbl.fragile.nested1 import A, nested2
+        assert cppyy.gbl.fragile.nested1.A is A
+        assert cppyy.gbl.fragile.nested1.nested2 is nested2
+
+        from cppyy.gbl.fragile.nested1.nested2 import A, nested3
+        assert cppyy.gbl.fragile.nested1.nested2.A is A
+        assert cppyy.gbl.fragile.nested1.nested2.nested3 is nested3
+
+        from cppyy.gbl.fragile.nested1.nested2.nested3 import A
+        assert cppyy.gbl.fragile.nested1.nested2.nested3.A is nested3.A


More information about the pypy-commit mailing list