@@ -15,13 +15,14 @@ public PyScopeException(string message)
1515 }
1616
1717 /// <summary>
18- /// Classes implement this interface must be used with GIL obtained.
18+ /// Classes/methods have this attribute must be used with GIL obtained.
1919 /// </summary>
20- public interface IPyObject : IDisposable
20+ public class PyGILAttribute : Attribute
2121 {
2222 }
2323
24- public class PyScope : DynamicObject , IPyObject
24+ [ PyGIL ]
25+ public class PyScope : DynamicObject , IDisposable
2526 {
2627 public readonly string Name ;
2728
@@ -33,6 +34,10 @@ public class PyScope : DynamicObject, IPyObject
3334 internal readonly IntPtr variables ;
3435
3536 private bool isDisposed ;
37+
38+ internal PyScopeManager Manager ;
39+
40+ public event Action < PyScope > OnDispose ;
3641
3742 internal static PyScope New ( string name = null )
3843 {
@@ -64,8 +69,6 @@ private PyScope(IntPtr ptr)
6469 this . Name = this . GetVariable < string > ( "__name__" ) ;
6570 }
6671
67- public event Action < PyScope > OnDispose ;
68-
6972 public PyDict Variables ( )
7073 {
7174 Runtime . XIncref ( variables ) ;
@@ -81,7 +84,7 @@ public PyScope NewScope()
8184
8285 public void ImportAllFromScope ( string name )
8386 {
84- var scope = Py . GetScope ( name ) ;
87+ var scope = Manager . Get ( name ) ;
8588 ImportAllFromScope ( scope ) ;
8689 }
8790
@@ -96,7 +99,7 @@ public void ImportAllFromScope(PyScope scope)
9699
97100 public void ImportScope ( string name , string asname = null )
98101 {
99- var scope = Py . GetScope ( name ) ;
102+ var scope = Manager . Get ( name ) ;
100103 if ( asname == null )
101104 {
102105 asname = name ;
@@ -436,4 +439,64 @@ public void Dispose()
436439 Dispose ( ) ;
437440 }
438441 }
442+
443+ public class PyScopeManager
444+ {
445+ private Dictionary < string , PyScope > NamedScopes = new Dictionary < string , PyScope > ( ) ;
446+
447+ [ PyGIL ]
448+ public PyScope Create ( )
449+ {
450+ var scope = PyScope . New ( ) ;
451+ scope . Manager = this ;
452+ return scope ;
453+ }
454+
455+ [ PyGIL ]
456+ public PyScope Create ( string name )
457+ {
458+ if ( String . IsNullOrEmpty ( name ) )
459+ {
460+ throw new PyScopeException ( "Name of ScopeStorage must not be empty" ) ;
461+ }
462+ if ( name != null && NamedScopes . ContainsKey ( name ) )
463+ {
464+ throw new PyScopeException ( String . Format ( "ScopeStorage '{0}' has existed" , name ) ) ;
465+ }
466+ var scope = PyScope . New ( name ) ;
467+ scope . Manager = this ;
468+ scope . OnDispose += Remove ;
469+ NamedScopes [ name ] = scope ;
470+ return scope ;
471+ }
472+
473+ public bool Contains ( string name )
474+ {
475+ return NamedScopes . ContainsKey ( name ) ;
476+ }
477+
478+ public PyScope Get ( string name )
479+ {
480+ if ( name != null && NamedScopes . ContainsKey ( name ) )
481+ {
482+ return NamedScopes [ name ] ;
483+ }
484+ throw new PyScopeException ( String . Format ( "ScopeStorage '{0}' not exist" , name ) ) ;
485+ }
486+
487+ public void Remove ( PyScope scope )
488+ {
489+ NamedScopes . Remove ( scope . Name ) ;
490+ }
491+
492+ [ PyGIL ]
493+ public void Clear ( )
494+ {
495+ var scopes = NamedScopes . Values . ToList ( ) ;
496+ foreach ( var scope in scopes )
497+ {
498+ scope . Dispose ( ) ;
499+ }
500+ }
501+ }
439502}
0 commit comments