IronPython Override Builtin Method - c#

I am trying to override the default __import__ method provided by IronPython to handle database imports. I have already run through the example provided here: https://stackoverflow.com/a/4127766/862319
Everything is working so far, but there is a minor issue related to namespace resolution within CLR types. I am able to import using the syntax import ClrAssembly.Type but the syntax from ClrAssembly import Type does not work. This is a minor inconvenience, but I would like to get it resolved. My suspicion is that there are two method signatures tied to the __import__method in IronPython:
But, the SO link above results in only a single method being applied with the 5 parameter signature. Here is the __import__ variable after being set:
How would I go about constructing a custom IronPython.Runtime.Types.BuiltinFunction that maps to 2 method signatures (5 param and 2 param version of DoDatabaseImport) and assign it back to the __import__ variable?

Hopefully this answer helps someone who is looking at this old question.
Looking at the source for IronPython 2.7.7 specifically the builtin.cs file from
https://github.com/IronLanguages/main/blob/3d9c336e1b6f0a86914a89ece171a22f48b0cc6e/Languages/IronPython/IronPython/Modules/Builtin.cs
you can see that the 2 parameter function calls the 5 parameter overload with default values.
public static object __import__(CodeContext/*!*/ context, string name) {
return __import__(context, name, null, null, null, -1);
}
To replicate this I used a delegate with similar default values.
delegate object ImportDelegate(CodeContext context, string moduleName, object globals = null, object locals = null, object fromlist = null, int level = -1);
protected object ImportOverride(CodeContext context, string moduleName, object globals = null, object locals = null, object fromlist = null, int level = -1)
{
// do custom import logic here
return IronPython.Modules.Builtin.__import__(context, moduleName, globals, locals, fromlist, level);
}
Overriding the builtin import function is shown below
private ScriptEngine pyengine;
private ScriptingEngine()
{
Dictionary<string, object> options = new Dictionary<string, object>();
options["Debug"] = true;
pyengine = Python.CreateEngine(options);
var builtinscope = Python.GetBuiltinModule(pyengine);
builtinscope.SetVariable("__import__", new ImportDelegate(ImportOverride));
}

I had the same problem. My solution was, to search for all clr types and store them in a HashSet. If IronPython tries to import some thing from the clr, i ingored my own set of rules and called the built-in importer from IronPython. This is working pretty well for a while now.
Hope this helps.

Related

Roslyn Check If Field Declaration has been assigned to

I'm writing an app which converts keys to use resources from a RESX File. This code was working with local variables before:
public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
{
var fieldDeclaration = (FieldDeclarationSyntax)context.Node;
if (false == IsValidFieldDeclaration(context, fieldDeclaration))
{
return;
}
var firstVariable = fieldDeclaration.Declaration.Variables.FirstOrDefault();
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(firstVariable);
var variableSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
var firstSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation(), firstSymbol.Name));
}
However when I try to get the dataFlowAnalysis I receive an error:
Additional information: statementOrExpression is not a StatementSyntax or an ExpressionSyntax.
How can Ideally just need to see if anyone has written to this variable outside of the declaration.
DataFlow works by analyzing order of execution within a single method.
It doesn't make sense for class-level fields.
Instead, you should use a simple syntax visitor (or SymbolFinder) to search the entire class for assignments to the field.
You'll probably also want to check whether it's ever passed as a ref parameter.

How to evaluate local variable/ parameter state with Roslyn

I have a bit of complicated situation. I must create analyzers/ code fix providers for situations such as a parameter is only assigned but never used or local variable are never used.
For the parameter situation, I'm going for the method declaration and looking at the parameter list to get all the analyzer. I'm going through assignment expressions within the method and I filter the parameters that were assigned with an helper method.
Where it gets fuzzy is I have no clue or to know when a local variable/parameter is used or not. I've gone through symbols but they can't tell me that variable used/ not used. I could try to find how many times a variable's name was mentioned inside a method by turning the method declaration syntax context in a string and look for the parameters that were assigned but that's simply such a BAD idea.
I'm really stuck and I would some help for this from anyone who had previous experience with this kind of situation.
For people who might ask, I'm mostly looking for the missing logic for the analyzer. I have no idea how the code fix provider will work. If you have an idea of what I could do, feel free to include it in your answer ! As of now, I was thinking that a local variable that's not used could be deleted from a method and the same could go for an unused parameter. I'm not sure at the moment.
UPDATE
I'm now trying to use the DataFlow API but it's not working for me at the moment. The oldest answer of this thread gave me a starting point but it's actually not working.
I came up with my own way :
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
But this also is not working. When using a test with NUnit :
var input = #"
class TestClass {
void TestMethod ()
{
int i;
}
}";
I get the following message when the runtime gets to either readWrite or result(from oldest answer):
System.ArgumentOutRangeException Index was out of range Must be non negative and lesser than the size of the collection"
But before that in my analyzer, when I try to validate my node to make sure it's not null and create the appropriate elements for the data flow API, there's no code break (not sure if that is the appropriate term) but at the moment I cannot progress.
You can see whether or not most variable are used (read/written) via the DataFlowAnalysis APIs. I've written an introduction to this API on my blog.
I believe in your case, you're looking for variables that are never read.
var tree = CSharpSyntaxTree.ParseText(#"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
Building on JoshVarty's answer, to get this to work in a diagnostic, I would register a SyntaxNodeAction for all MethodDeclaration Syntax Kinds and then look inside the body for unused variables:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}

dynamic method and the MethodAccessException

given the following classes:
class SomeBuilder<T>
{
public static object Build(int index)
{
...
}
}
class SomeHelper
{
public object GetBuildObj(object value)
{
var valuetype = value.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
SomeBuilder was a generic type so i need a call to MakeGenericType() to make things right.
when i pass a normal type like 'class person' for the value, everything just works, that`s fine.
but when i pass a anonymous type like: new { id=1 }, the handler was successfully created. but invoke this dynamic handler i got a MethodAccessException with these messages:
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1<System.Int32>>.Build(int)" failed.
any help would be appreciated, thx.
btw, if you are interested in SomeDynamicHelper, plz see:
http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker
edit1:
i did the call in main like this:
static void Main(string[] args)
{
// pass a normal class, this will be fine
var value = new Person { id = 1};
new SomeHelper().GetBuildObj(value);
// pass a anonymous type
var value = new { id = 1};
new SomeHelper().GetBuildObj(value); // oops, got a exception here!
}
edit2:
based on the comment i changed my code:
class SomeHelper
{
public object GetBuildObj(object value)
{
//this time i do not use the value, but create a new inner value:
var valuenew = new { id = 1 };
var valuetype = valuenew.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
well, this time there is no exception, but...unfortunately a new problem occured...may be i should open a new thread for the new problem.
thank you guys, for your attentions.
edit3:
hi, after some digging, i also found some useful information. say, the SomeDynamicHelper.GetMethodInvoker() code as below:
DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
this is the core we used here to dynamic create a method. for our context, we need to declare the anonymous type in same assembly with the SomeHelper and SomeBuilder. but, if we can`t do the declaration, what should we do?
ok, you can call DynamicMethod() with last parameter(the skipVisibility), set to true!
hope this will help others with the same problem :)
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1>.Build(int)"
From this you can see that dynamic method try to run an internal\private method called Build, for that you got MethodAccessException.
(The anonymous type is kept in a new generated class)
Adding InternalVisibleTo not always helping because it's helping only if you can rewrite the anonymous type assembly (manually or with interception) and only if the type and method are internals and not private.
In dynamic method you can bind the method to type\module, and to skip visibility check, but this help to access private members of the specified module, so again if the type you trying to access is in a different assembly and the type\method are private you can't do anything.
Well almost. There is a "secret" attribute that you inject to your assembly, called IgnoreAccessChecksTo and then in addition to bounded module and skip visibility maybe it will work.
You can try using [assembly: InternalsVisibleTo("Anonymously Hosted DynamicMethods Assembly")] in the same project where you define the anonymous type.
I had a similar error with a C# class I tried to inject using IKVM-converted Guice. The fix was simply making the affected class (in this case probably SomeBuilder) public and everything worked fine.

Why do I have to manually create ExpandoObject to properly use the dynamic keyword?

I was looking at the question Use 'dynamic' throw a RuntimeBinderException. I face a similar problem:
Basically, I want to create a "HTML helper" in ASP.NET MVC that uses dynamic arguments, akin to the htmlArguments parameter for many of the existing helpers (more code below):
public BootstrapCell(Action<string> emitContentAction, dynamic args)
View:
#using (grid.Cell(ViewContext.Writer.Write, new {Position = 4}))
{
<p>zomg!</p>
}
However in the naive approach, i get RuntimeBinderException thrown at me, declaring that 'object' does not contain a definition for 'Position', even though when debugging and hovering over the _args variable, it clearly does have a Position property.
The caller and the callee are in separate assemblies. Why is that problem happening?
(The solution to that has been shown in the same question: Manually create an ExpandoObject to hold the args.)
Implementation:
public class Cell
{
private readonly string _tagName;
private dynamic _args;
private Action<string> EmitContentAction;
public BootstrapCell(Action<string> emitContentAction, dynamic args) : DisposableBaseClass
{
_args = args;
EmitContentAction = emitContentAction;
OnContextEnter();
}
protected void OnContextEnter()
{
var sb = new StringBuilder("<");
sb.Append(_tagName);
if (_args.Position > 0)
{
sb.Append(" class=\"offset");
sb.Append(args.Position);
sb.Append("\"");
}
sb.Append(">");
EmitContentAction(sb.ToString());
}
}
[Edited to make clearer that my problem arises when "obviously" the Position property is set. I am aware that if the property never was defined in the first place, an exception must be raised.]
That code is fatally flawed.
It does work, as long as you specify that property:
void Bar()
{
Foo(new {Position = 0});
}
void Foo(dynamic args)
{
Console.WriteLine(args.Position);
}
That will output 0, it will not throw a RuntimeBinderException.
But the purpose of such code is the possibility for the caller to specify only the properties needed and omit the rest.
You are trying to check for this omission via if(args.Position != null). But that doesn't work, it already requires Position to exist.
When you have a look at the routing API of ASP.NET that also supports those anonymous configuration objects you will notice that the type of the parameter is object and not dynamic.
Using object instead of dynamic will enable your API to be used across assembly boundaries.
So how does it work?
Just like in the linked answer, you need to manually create a dictionary of the properties. Whether you use a plain old Dictionary<string, object> or an ExpandoObject is a matter of preference.
Using ExpandoObject will make your code a bit simpler to read and write, but it is not required.
About the actual exception you are getting:
Please note that it tells you it can't find the Position property on object. If it would be an anonymous type that was missing the Position property the exception message wouldn't refer to object but to an anonymous type. Something like this:
'<>f__AnonymousType0' does not contain a definition for 'Position'

Activator.CreateInstance can't find the constructor (MissingMethodException)

I have a class which has the following constructor
public DelayCompositeDesigner(DelayComposite CompositeObject)
{
InitializeComponent();
compositeObject = CompositeObject;
}
along with a default constructor with no parameters.
Next I'm trying to create an instance, but it only works without parameters:
var designer = Activator.CreateInstance(designerAttribute.Designer);
This works just fine, but if I want to pass parameters it does not:
var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));
This results in an MissingMethodException:
Constructor voor type
Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesigner
was not found
Any ideas here?
The problem is I really need to pass an object during construction.
You see I have a designer which loads all the types that inherit from the CompositeBase. These are then added to a list from which the users can drag them to a designer. Upon doing so an instance of the dragged is added to the designer. Each of these classes have custom properties defined on them:
[CompositeMetaData("Delay","Sets the delay between commands",1)]
[CompositeDesigner(typeof(DelayCompositeDesigner))]
public class DelayComposite : CompositeBase
{
}
When the user selects an item in the designer, it looks at these attributes in order to load up a designer for that type. For example, in the case of the DelayComposite it would load up a user control which has a label and a slider which allow the user to set the "Delay" property of the DelayComposite instance.
So far this works fine if I don't pass any parameters to the constructor. The designer creates an instance of the DelayCompositeDesigner and assigns it to the content property of a WPF ContentPresenter.
But since that designer needs to modify the properties of the selected DelayComposite
in the designer, I have to pass this instance to it. That is why the constructor looks lie this:
public DelayCompositeDesigner(DelayComposite CompositeObject)
{
InitializeComponent();
compositeObject = CompositeObject;
}
Suggestions are welcome
#VolkerK
The result of your code is this:
<---- foo
Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesignerVoid
.ctor()
Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesignerVoid
.ctor(Vialis.LightLink.Controller.Scenarios.Composites.DelayComposite)
param:Vialis.LightLink.Controller.Scenarios.Composites.DelayComposite
foo ---->
Leppie, you were correct, I had for some reason referenced the Composites assembly in my UI application... which is not something I should have done as I was loading it at runtime. The following code works:
object composite = Activator.CreateInstance(item.CompositType,(byte)205);
var designer = Activator.CreateInstance(designerAttribute.Designer, composite);
As you can see the code does not have knowledge of the DelayComposite type.
This solves the current problem, but introduces many new ones for what I want to achieve,
either way thank you and thank you to everyone who has replied here.
As for the following code, suggested by multiple people:
var designer = Activator.CreateInstance(
designerAttribute.Designer,
new object[] { new DelayComposite(4) }
);
The Activator.CreateInstance has a signature that looks like this:
Activator.CreateInstance(Type type, params object[] obj)
So it should accept my code, but I will try the suggested code
UPDATE:
I've tried this as suggested:
var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4)});
The result is the same.
I would think that your call would need to be:
var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4) });
Unless, of course, it is that, in which case the answer is not immediately obvious.
I think you are dealing with a Type mismatch.
Likely the assembly is referenced in different places, or they are compiled against different versions.
I suggest you iterate through the ConstructorInfo's and do a paramtype == typeof(DelayComposite) on the appropriate parameter.
Though I hate printf-like debugging ...
public static void foo(Type t, params object[] p)
{
System.Diagnostics.Debug.WriteLine("<---- foo");
foreach(System.Reflection.ConstructorInfo ci in t.GetConstructors())
{
System.Diagnostics.Debug.WriteLine(t.FullName + ci.ToString());
}
foreach (object o in p)
{
System.Diagnostics.Debug.WriteLine("param:" + o.GetType().FullName);
}
System.Diagnostics.Debug.WriteLine("foo ---->");
}
// ...
foo(designerAttribute.Designer, new DelayComposite(4));
var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));
What does that print in the visual studio's output window?
If you want to call this contructor...
public DelayCompositeDesigner(DelayComposite CompositeObject)
...just use this:
var designer = Activator.CreateInstance(typeof(DelayCompositeDesigner), new DelayComposite(4));
or
var designer = Activator.CreateInstance<DelayCompositeDesigner>(new DelayComposite(4));
I had a similar issue, however my problem was due to the visibility of the constructor. This stack overflow helped me:
Instantiating a constructor with parameters in an internal class with reflection
I discovered another way of creating an instance of an object without calling the constructor at all while answering another question on SF.
In the System.Runtime.Serialization namespace there is a function FormatterServices.GetUninitializedObject(type) that will create an object without calling constructor.
If you look at that function in Reflector you will see it is making an external call. I don't know how black magic is actually happening under the hood. But I did prove to myself that the constructor was never called but the object was instantiated.
When I encountered this problem, I was using a method that returned the parameter list to plug in to Activator.CreateInstance and it had a different number of arguments than the constructor of the object I was trying to create.
In my case, this code work good with .NET Framework but does not work in .NET Core 3.1. It throws ExecutionEngineException which is uncatchable. But when I change target to .NET 5, it works perfectly. Hope this help some one.
Type type = assembly.GetType(dllName + ".dll");
Activator.CreateInstance(type ), new Stream[] { stream };
You can use the following overload on CreateInstance:
public static Object CreateInstance(
Type type,
Object[] args
)
And in your case it'd be (I think):
var designer = Activator.CreateInstance(
typeof(DelayCompositeDesigner),
new object[] { new DelayComposite(4) }
);
I found a solution to the problem, I was struggling with the same issue.
Here is my activator:
private void LoadTask(FileInfo dll)
{
Assembly assembly = Assembly.LoadFrom(dll.FullName);
foreach (Type type in assembly.GetTypes())
{
var hasInterface = type.GetInterface("ITask") != null;
if (type.IsClass && hasInterface)
{
var instance = Activator.CreateInstance(type, _proxy, _context);
_tasks.Add(type.Name, (ITask)instance);
}
}
}
And here is my class to activate, note that I had to change the constructor params to objects, the only way I could get it to work.
public class CalculateDowntimeTask : Task<CalculateDowntimeTask>
{
public CalculateDowntimeTask(object proxy, object context) :
base((TaskServiceClient)proxy, (TaskDataDataContext)context) { }
public override void Execute()
{
LogMessage(new TaskMessage() { Message = "Testing" });
BroadcastMessage(new TaskMessage() { Message = "Testing" });
}
}

Categories

Resources