Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
cleaned up the Import methods
  • Loading branch information
yagweb committed Apr 28, 2017
commit 497d7aabebd8719ca9bd226f878eb0640fa89cb3
8 changes: 4 additions & 4 deletions src/embed_tests/TestPyScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void TestImportModule()
{
using (Py.GIL())
{
dynamic sys = ps.ImportModule("sys");
dynamic sys = ps.Import("sys");
Assert.IsTrue(ps.ContainsVariable("sys"));

ps.Exec("sys.attr1 = 2");
Expand All @@ -175,7 +175,7 @@ public void TestImportModule()
Assert.AreEqual(2, value2);

//import as
ps.ImportModule("sys", "sys1");
ps.Import("sys", "sys1");
Assert.IsTrue(ps.ContainsVariable("sys1"));
}
}
Expand All @@ -193,7 +193,7 @@ public void TestImportScope()
ps.SetVariable("cc", 10);

PyScope scope = Py.CreateScope();
scope.ImportScope(ps, "ps");
scope.Import(ps, "ps");

scope.Exec("aa = ps.bb + ps.cc + 3");
var result = scope.GetVariable<int>("aa");
Expand Down Expand Up @@ -281,7 +281,7 @@ public void TestImportScopeByName()
ps.SetVariable("bb", 100);

var scope = Py.CreateScope();
scope.ImportAllFromScope("test");
scope.ImportAll("test");
//scope.ImportModule("test");

Assert.IsTrue(scope.ContainsVariable("bb"));
Expand Down
167 changes: 100 additions & 67 deletions src/runtime/pyscope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,21 @@ public class PyScope : DynamicObject, IDisposable

private bool isDisposed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Private should be _isDisposed.


internal PyScopeManager Manager;
internal readonly PyScopeManager Manager;

public event Action<PyScope> OnDispose;

internal static PyScope New(string name = null)
public PyScope(IntPtr ptr, PyScopeManager manager)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things using IntPtr should not be public, can this be internal instead?

{
if (name == null)
if (Runtime.PyObject_Type(ptr) != Runtime.PyModuleType)
{
name = "";
throw new PyScopeException("object is not a module");
}
var module = Runtime.PyModule_New(name);
if (module == IntPtr.Zero)
if(manager == null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting, just run a Ctrl-K Ctrl-D in Visual Studio.

{
throw new PythonException();
manager = PyScopeManager.Global;
}
return new PyScope(module);
}

private PyScope(IntPtr ptr)
{
Manager = manager;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manager = manager ?? PyScopeManager.Global

obj = ptr;
//Refcount of the variables not increase
variables = Runtime.PyModule_GetDict(obj);
Expand All @@ -77,70 +72,92 @@ public PyDict Variables()

public PyScope NewScope()
{
var scope = PyScope.New();
scope.ImportAllFromScope(this);
var scope = Manager.Create();
scope.ImportAll(this);
return scope;
}

public void ImportAllFromScope(string name)
{
var scope = Manager.Get(name);
ImportAllFromScope(scope);
}

public void ImportAllFromScope(PyScope scope)
public dynamic Import(string name, string asname = null)
{
int result = Runtime.PyDict_Update(variables, scope.variables);
if (result < 0)
Check();
if (asname == null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string.IsNullOrWhitespace instead.

{
throw new PythonException();
asname = name;
}
}

public void ImportScope(string name, string asname = null)
{
var scope = Manager.Get(name);
if(asname == null)
var scope = Manager.TryGet(name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Try the usual "protocol" is to let it return a bool and output to an out variable:

 PyScope scope;
 if (Manager.TryGet(name, out scope)) ...

if(scope != null)
{
asname = name;
Import(scope, asname);
return scope;
}
ImportScope(scope, asname);
PyObject module = PythonEngine.ImportModule(name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap in else branch to make the intention clear.

Import(module, asname);
return module;
}

public void ImportScope(PyScope scope, string asname)
public void Import(PyScope scope, string asname)
{
this.SetVariable(asname, scope.obj);
}

/// <summary>
/// ImportModule Method
/// Import Method
/// </summary>
/// <remarks>
/// The import .. as .. statement in Python.
/// Import a module ,add it to the variables dict and return the resulting module object as a PyObject.
/// Import a module,add it to the variables dict and return the resulting module object as a PyObject.
/// </remarks>
public PyObject ImportModule(string name)
public void Import(PyObject module, string asname = null)
{
return ImportModule(name, name);
if (asname == null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string.IsNullOrWhitespace

{
asname = module.GetAttr("__name__").ToString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use .As<string>() instead? ToString is much too forgiving here.

}
SetVariable(asname, module);
}

/// <summary>
/// ImportModule Method
/// </summary>
/// <remarks>
/// The import .. as .. statement in Python.
/// Import a module ,add it to the variables dict and return the resulting module object as a PyObject.
/// </remarks>
public PyObject ImportModule(string name, string asname)
public void ImportAll(string name)
{
Check();
var scope = Manager.TryGet(name);
if(scope != null)
{
ImportAll(scope);
return;
}
PyObject module = PythonEngine.ImportModule(name);
if (asname == null)
ImportAll(module);
}

public void ImportAll(PyScope scope)
{
int result = Runtime.PyDict_Update(variables, scope.variables);
if (result < 0)
{
asname = name;
throw new PythonException();
}
}

public void ImportAll(PyObject module)
{
if (Runtime.PyObject_Type(module.obj) != Runtime.PyModuleType)
{
throw new PyScopeException("object is not a module");
}
var module_dict = Runtime.PyModule_GetDict(module.obj);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leaks a reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked, the Runtime.PyModule_GetDict method does not increase the refcount of the module dict.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, misread the docs :)

int result = Runtime.PyDict_Update(variables, module_dict);
if (result < 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CheckError... function in all similar places. Or is there a particular reason to do the error check manually here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This usage comes from the Update method of PyDict.

{
throw new PythonException();
}
}

public void ImportAll(PyDict dict)
{
int result = Runtime.PyDict_Update(variables, dict.obj);
if (result < 0)
{
throw new PythonException();
}
SetVariable(asname, module);
return module;
}

/// <summary>
Expand Down Expand Up @@ -263,15 +280,6 @@ private void SetVariable(string name, IntPtr value)
}
}

public void AddVariables(PyDict dict)
{
int result = Runtime.PyDict_Update(variables, dict.obj);
if (result < 0)
{
throw new PythonException();
}
}

/// <summary>
/// RemoveVariable Method
/// </summary>
Expand Down Expand Up @@ -442,13 +450,28 @@ public void Dispose()

public class PyScopeManager
{
public readonly static PyScopeManager Global = new PyScopeManager();

private Dictionary<string, PyScope> NamedScopes = new Dictionary<string, PyScope>();

internal PyScope NewScope(string name)
{
if (name == null)
{
name = "";
}
var module = Runtime.PyModule_New(name);
if (module == IntPtr.Zero)
{
throw new PythonException();
}
return new PyScope(module, this);
}

[PyGIL]
public PyScope Create()
{
var scope = PyScope.New();
scope.Manager = this;
var scope = this.NewScope(null);
return scope;
}

Expand All @@ -457,14 +480,13 @@ public PyScope Create(string name)
{
if (String.IsNullOrEmpty(name))
{
throw new PyScopeException("Name of ScopeStorage must not be empty");
throw new ArgumentNullException(nameof(name));
}
if (name != null && NamedScopes.ContainsKey(name))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contains(name)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not quite understand?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already defined a member function Contains, use that one.

{
throw new PyScopeException(String.Format("ScopeStorage '{0}' has existed", name));
throw new PyScopeException($"PyScope '{name}' has existed");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"A scope of name '{name}' does already exist"

}
var scope = PyScope.New(name);
scope.Manager = this;
var scope = this.NewScope(name);
scope.OnDispose += Remove;
NamedScopes[name] = scope;
return scope;
Expand All @@ -477,11 +499,22 @@ public bool Contains(string name)

public PyScope Get(string name)
{
if (name != null && NamedScopes.ContainsKey(name))
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (NamedScopes.ContainsKey(name))
{
return NamedScopes[name];
}
throw new PyScopeException(String.Format("ScopeStorage '{0}' not exist", name));
throw new PyScopeException($"PyScope '{name}' not exist");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "There is no scope named '{name}' registered in this manager"?

}

public PyScope TryGet(string name)
{
PyScope value;
NamedScopes.TryGetValue(name, out value);
return value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said above, just forward the semantics of TryGetValue directly.

}

public void Remove(PyScope scope)
Expand Down
8 changes: 3 additions & 5 deletions src/runtime/pythonengine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ public static void Shutdown()
{
if (initialized)
{
Py.PyScopeManager.Clear();
PyScopeManager.Global.Clear();
Marshal.FreeHGlobal(_pythonHome);
_pythonHome = IntPtr.Zero;
Marshal.FreeHGlobal(_programName);
Expand Down Expand Up @@ -546,18 +546,16 @@ public static GILState GIL()

return new GILState();
}

internal static PyScopeManager PyScopeManager = new PyScopeManager();

public static PyScope CreateScope()
{
var scope = PyScopeManager.Create();
var scope = PyScopeManager.Global.Create();
return scope;
}

public static PyScope CreateScope(string name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have a default parameter of null.

Copy link
Contributor Author

@yagweb yagweb Apr 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By contrast, I want to split the two methods CreateScope() and CreateScope(string name).
Pass null to the name will be forbidden in the future.

CreateScope() is unique, CreateScope(string name) will be put in the ScopeManager class.

{
var scope = PyScopeManager.Create(name);
var scope = PyScopeManager.Global.Create(name);
return scope;
}

Expand Down