| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,6 +13,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 13 | 13 | - Added function that sets Py_NoSiteFlag to 1. | |
| 14 | 14 | - Added support for Jetson Nano. | |
| 15 | 15 | - Added support for __len__ for .NET classes that implement ICollection | |
| 16 | + - Added `PyExport` attribute to hide .NET types from Python | ||
| 16 | 17 | - Added PythonException.Format method to format exceptions the same as traceback.format_exception | |
| 17 | 18 | - Added Runtime.None to be able to pass None as parameter into Python from .NET | |
| 18 | 19 | - Added PyObject.IsNone() to check if a Python object is None in .NET. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -306,6 +306,7 @@ def build_extension(self, ext): | |||
| 306 | 306 | _config = "{0}Win".format(CONFIG) | |
| 307 | 307 | _solution_file = "pythonnet.sln" | |
| 308 | 308 | _custom_define_constants = False | |
| 309 | + defines.append("NET40") | ||
| 309 | 310 | elif DEVTOOLS == "MsDev15": | |
| 310 | 311 | _xbuild = '"{0}"'.format(self._find_msbuild_tool_15()) | |
| 311 | 312 | _config = "{0}Win".format(CONFIG) | |
@@ -316,6 +317,7 @@ def build_extension(self, ext): | |||
| 316 | 317 | _config = "{0}Mono".format(CONFIG) | |
| 317 | 318 | _solution_file = "pythonnet.sln" | |
| 318 | 319 | _custom_define_constants = False | |
| 320 | + defines.append("NET40") | ||
| 319 | 321 | elif DEVTOOLS == "dotnet": | |
| 320 | 322 | _xbuild = "dotnet msbuild" | |
| 321 | 323 | _config = "{0}Mono".format(CONFIG) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,16 @@ | |||
| 1 | + namespace Python.Runtime { | ||
| 2 | + using System; | ||
| 3 | + | ||
| 4 | + /// <summary> | ||
| 5 | + /// Controls visibility to Python for public .NET type or an entire assembly | ||
| 6 | + /// </summary> | ||
| 7 | + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | ||
| 8 | + | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Assembly, | ||
| 9 | + AllowMultiple = false, | ||
| 10 | + Inherited = false)] | ||
| 11 | + public class PyExportAttribute : Attribute | ||
| 12 | + { | ||
| 13 | + internal readonly bool Export; | ||
| 14 | + public PyExportAttribute(bool export) { this.Export = export; } | ||
| 15 | + } | ||
| 16 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,46 +29,46 @@ | |||
| 29 | 29 | <PlatformTarget>x64</PlatformTarget> | |
| 30 | 30 | </PropertyGroup>--> | |
| 31 | 31 | <PropertyGroup Condition=" '$(Configuration)' == 'ReleaseMono'"> | |
| 32 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS4</DefineConstants> | ||
| 32 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON2;PYTHON27;UCS4</DefineConstants> | ||
| 33 | 33 | <Optimize>true</Optimize> | |
| 34 | 34 | <DebugType>pdbonly</DebugType> | |
| 35 | 35 | </PropertyGroup> | |
| 36 | 36 | <PropertyGroup Condition=" '$(Configuration)' == 'ReleaseMonoPY3'"> | |
| 37 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON38;UCS4</DefineConstants> | ||
| 37 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON3;PYTHON38;UCS4</DefineConstants> | ||
| 38 | 38 | <Optimize>true</Optimize> | |
| 39 | 39 | <DebugType>pdbonly</DebugType> | |
| 40 | 40 | </PropertyGroup> | |
| 41 | 41 | <PropertyGroup Condition=" '$(Configuration)' == 'DebugMono'"> | |
| 42 | 42 | <DebugSymbols>true</DebugSymbols> | |
| 43 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS4;TRACE;DEBUG</DefineConstants> | ||
| 43 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON2;PYTHON27;UCS4;TRACE;DEBUG</DefineConstants> | ||
| 44 | 44 | <Optimize>false</Optimize> | |
| 45 | 45 | <DebugType>full</DebugType> | |
| 46 | 46 | </PropertyGroup> | |
| 47 | 47 | <PropertyGroup Condition=" '$(Configuration)' == 'DebugMonoPY3'"> | |
| 48 | 48 | <DebugSymbols>true</DebugSymbols> | |
| 49 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON38;UCS4;TRACE;DEBUG</DefineConstants> | ||
| 49 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON3;PYTHON38;UCS4;TRACE;DEBUG</DefineConstants> | ||
| 50 | 50 | <Optimize>false</Optimize> | |
| 51 | 51 | <DebugType>full</DebugType> | |
| 52 | 52 | </PropertyGroup> | |
| 53 | 53 | <PropertyGroup Condition=" '$(Configuration)' == 'ReleaseWin'"> | |
| 54 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS2</DefineConstants> | ||
| 54 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON2;PYTHON27;UCS2</DefineConstants> | ||
| 55 | 55 | <Optimize>true</Optimize> | |
| 56 | 56 | <DebugType>pdbonly</DebugType> | |
| 57 | 57 | </PropertyGroup> | |
| 58 | 58 | <PropertyGroup Condition=" '$(Configuration)' == 'ReleaseWinPY3'"> | |
| 59 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON38;UCS2</DefineConstants> | ||
| 59 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON3;PYTHON38;UCS2</DefineConstants> | ||
| 60 | 60 | <Optimize>true</Optimize> | |
| 61 | 61 | <DebugType>pdbonly</DebugType> | |
| 62 | 62 | </PropertyGroup> | |
| 63 | 63 | <PropertyGroup Condition=" '$(Configuration)' == 'DebugWin'"> | |
| 64 | 64 | <DebugSymbols>true</DebugSymbols> | |
| 65 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS2;TRACE;DEBUG</DefineConstants> | ||
| 65 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON2;PYTHON27;UCS2;TRACE;DEBUG</DefineConstants> | ||
| 66 | 66 | <Optimize>false</Optimize> | |
| 67 | 67 | <DebugType>full</DebugType> | |
| 68 | 68 | </PropertyGroup> | |
| 69 | 69 | <PropertyGroup Condition=" '$(Configuration)' == 'DebugWinPY3'"> | |
| 70 | 70 | <DebugSymbols>true</DebugSymbols> | |
| 71 | - <DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON38;UCS2;TRACE;DEBUG</DefineConstants> | ||
| 71 | + <DefineConstants Condition="'$(DefineConstants)' == ''">NET40;PYTHON3;PYTHON38;UCS2;TRACE;DEBUG</DefineConstants> | ||
| 72 | 72 | <Optimize>false</Optimize> | |
| 73 | 73 | <DebugType>full</DebugType> | |
| 74 | 74 | </PropertyGroup> | |
@@ -131,6 +131,7 @@ | |||
| 131 | 131 | <Compile Include="propertyobject.cs" /> | |
| 132 | 132 | <Compile Include="pyansistring.cs" /> | |
| 133 | 133 | <Compile Include="pydict.cs" /> | |
| 134 | + <Compile Include="PyExportAttribute.cs" /> | ||
| 134 | 135 | <Compile Include="pyfloat.cs" /> | |
| 135 | 136 | <Compile Include="pyint.cs" /> | |
| 136 | 137 | <Compile Include="pyiter.cs" /> | |
@@ -151,6 +152,7 @@ | |||
| 151 | 152 | <Compile Include="Util.cs" /> | |
| 152 | 153 | <Compile Include="platform\Types.cs" /> | |
| 153 | 154 | <Compile Include="platform\LibraryLoader.cs" /> | |
| 155 | + <Compile Include="polyfill\ReflectionPolifills.cs" /> | ||
| 154 | 156 | <Compile Include="slots\mp_length.cs" /> | |
| 155 | 157 | </ItemGroup> | |
| 156 | 158 | <ItemGroup Condition=" '$(PythonInteropFile)' != '' "> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -346,6 +346,10 @@ public static bool LoadImplicit(string name, bool warn = true) | |||
| 346 | 346 | /// </summary> | |
| 347 | 347 | internal static void ScanAssembly(Assembly assembly) | |
| 348 | 348 | { | |
| 349 | + if (assembly.GetCustomAttribute<PyExportAttribute>()?.Export == false) | ||
| 350 | + { | ||
| 351 | + return; | ||
| 352 | + } | ||
| 349 | 353 | // A couple of things we want to do here: first, we want to | |
| 350 | 354 | // gather a list of all of the namespaces contributed to by | |
| 351 | 355 | // the assembly. | |
@@ -458,7 +462,7 @@ public static Type LookupType(string qname) | |||
| 458 | 462 | foreach (Assembly assembly in assemblies) | |
| 459 | 463 | { | |
| 460 | 464 | Type type = assembly.GetType(qname); | |
| 461 | - if (type != null) | ||
| 465 | + if (type != null && IsExported(type)) | ||
| 462 | 466 | { | |
| 463 | 467 | return type; | |
| 464 | 468 | } | |
@@ -472,33 +476,35 @@ public static Type LookupType(string qname) | |||
| 472 | 476 | /// type. | |
| 473 | 477 | /// </summary> | |
| 474 | 478 | public static IEnumerable<Type> LookupTypes(string qualifiedName) | |
| 475 | - => assemblies.Select(assembly => assembly.GetType(qualifiedName)).Where(type => type != null); | ||
| 479 | + => assemblies.Select(assembly => assembly.GetType(qualifiedName)).Where(type => type != null && IsExported(type)); | ||
| 476 | 480 | ||
| 477 | 481 | internal static Type[] GetTypes(Assembly a) | |
| 478 | 482 | { | |
| 479 | 483 | if (a.IsDynamic) | |
| 480 | 484 | { | |
| 481 | 485 | try | |
| 482 | 486 | { | |
| 483 | - return a.GetTypes(); | ||
| 487 | + return a.GetTypes().Where(IsExported).ToArray(); | ||
| 484 | 488 | } | |
| 485 | 489 | catch (ReflectionTypeLoadException exc) | |
| 486 | 490 | { | |
| 487 | 491 | // Return all types that were successfully loaded | |
| 488 | - return exc.Types.Where(x => x != null).ToArray(); | ||
| 492 | + return exc.Types.Where(x => x != null && IsExported(x)).ToArray(); | ||
| 489 | 493 | } | |
| 490 | 494 | } | |
| 491 | 495 | else | |
| 492 | 496 | { | |
| 493 | 497 | try | |
| 494 | 498 | { | |
| 495 | - return a.GetExportedTypes(); | ||
| 499 | + return a.GetExportedTypes().Where(IsExported).ToArray(); | ||
| 496 | 500 | } | |
| 497 | 501 | catch (FileNotFoundException) | |
| 498 | 502 | { | |
| 499 | 503 | return new Type[0]; | |
| 500 | 504 | } | |
| 501 | 505 | } | |
| 502 | 506 | } | |
| 507 | + | ||
| 508 | + static bool IsExported(Type type) => type.GetCustomAttribute<PyExportAttribute>()?.Export != false; | ||
| 503 | 509 | } | |
| 504 | 510 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,12 +1,14 @@ | |||
| 1 | 1 | using System; | |
| 2 | + using System.Linq; | ||
| 2 | 3 | using System.Reflection; | |
| 3 | 4 | using System.Reflection.Emit; | |
| 4 | 5 | ||
| 5 | 6 | namespace Python.Runtime | |
| 6 | 7 | { | |
| 7 | - #if NETSTANDARD | ||
| 8 | + [Obsolete("This API is for internal use only")] | ||
| 8 | 9 | public static class ReflectionPolifills | |
| 9 | 10 | { | |
| 11 | + #if NETSTANDARD | ||
| 10 | 12 | public static AssemblyBuilder DefineDynamicAssembly(this AppDomain appDomain, AssemblyName assemblyName, AssemblyBuilderAccess assemblyBuilderAccess) | |
| 11 | 13 | { | |
| 12 | 14 | return AssemblyBuilder.DefineDynamicAssembly(assemblyName, assemblyBuilderAccess); | |
@@ -16,6 +18,21 @@ public static Type CreateType(this TypeBuilder typeBuilder) | |||
| 16 | 18 | { | |
| 17 | 19 | return typeBuilder.GetTypeInfo().GetType(); | |
| 18 | 20 | } | |
| 19 | - } | ||
| 20 | 21 | #endif | |
| 22 | + #if NET40 | ||
| 23 | + public static T GetCustomAttribute<T>(this Type type) where T: Attribute | ||
| 24 | + { | ||
| 25 | + return type.GetCustomAttributes(typeof(T), inherit: false) | ||
| 26 | + .Cast<T>() | ||
| 27 | + .SingleOrDefault(); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public static T GetCustomAttribute<T>(this Assembly assembly) where T: Attribute | ||
| 31 | + { | ||
| 32 | + return assembly.GetCustomAttributes(typeof(T), inherit: false) | ||
| 33 | + .Cast<T>() | ||
| 34 | + .SingleOrDefault(); | ||
| 35 | + } | ||
| 36 | + #endif | ||
| 37 | + } | ||
| 21 | 38 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -92,6 +92,7 @@ | |||
| 92 | 92 | <Compile Include="doctest.cs" /> | |
| 93 | 93 | <Compile Include="subclasstest.cs" /> | |
| 94 | 94 | <Compile Include="ReprTest.cs" /> | |
| 95 | + <Compile Include="nonexportable.cs" /> | ||
| 95 | 96 | <Compile Include="mp_lengthtest.cs" /> | |
| 96 | 97 | </ItemGroup> | |
| 97 | 98 | <ItemGroup> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,8 @@ | |||
| 1 | + namespace Python.Test | ||
| 2 | + { | ||
| 3 | + using Python.Runtime; | ||
| 4 | + | ||
| 5 | + // this class should not be visible to Python | ||
| 6 | + [PyExport(false)] | ||
| 7 | + public class NonExportable { } | ||
| 8 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,7 +14,6 @@ def test_basic_reference_type(): | |||
| 14 | 14 | """Test usage of CLR defined reference types.""" | |
| 15 | 15 | assert System.String.Empty == "" | |
| 16 | 16 | ||
| 17 | - | ||
| 18 | 17 | def test_basic_value_type(): | |
| 19 | 18 | """Test usage of CLR defined value types.""" | |
| 20 | 19 | assert System.Int32.MaxValue == 2147483647 | |
@@ -29,7 +28,6 @@ def test_class_standard_attrs(): | |||
| 29 | 28 | assert isinstance(ClassTest.__dict__, DictProxyType) | |
| 30 | 29 | assert len(ClassTest.__doc__) > 0 | |
| 31 | 30 | ||
| 32 | - | ||
| 33 | 31 | def test_class_docstrings(): | |
| 34 | 32 | """Test standard class docstring generation""" | |
| 35 | 33 | from Python.Test import ClassTest | |
@@ -58,6 +56,14 @@ def test_non_public_class(): | |||
| 58 | 56 | with pytest.raises(AttributeError): | |
| 59 | 57 | _ = Test.InternalClass | |
| 60 | 58 | ||
| 59 | + def test_non_exported(): | ||
| 60 | + """Test [PyExport(false)]""" | ||
| 61 | + with pytest.raises(ImportError): | ||
| 62 | + from Python.Test import NonExportable | ||
| 63 | + | ||
| 64 | + with pytest.raises(AttributeError): | ||
| 65 | + _ = Test.NonExportable | ||
| 66 | + | ||
| 61 | 67 | ||
| 62 | 68 | def test_basic_subclass(): | |
| 63 | 69 | """Test basic subclass of a managed class.""" | |
| Back | FazBrowse Home | New Git URL |
0 commit comments