I'm trying to run an IronPython script in C# but sometimes when I run it I get this error:
IronPython.Runtime.UnboundNameException: name 'str' is not defined
I can't figure out why this is happening; it only happens sometimes; right now it happens when I click a planet in my game to view the report on its abilities.
Here's the script I'm trying to run:
'Mines ' + str(Amount1) + ' minerals each turn (modified by planet value).'
As you can see I'm trying to concatenate some strings, one of which is a stringified Amount1 variable (Amount1 I think is the number 800 but it might be a more complex expression equal to 800, I'd have to check on that), but for some reason I'm getting an error saying the str function is undefined, which makes no sense!
There are other scripts being included before this script runs; if you like I can find those and paste them here in case that might help...
edit: here's the full script that I'm running:
import sys, imp;
import __builtin__ as builtins;
builtins_code = """""";
exec builtins_code in builtins.__dict__;
import clr
clr.AddReference('System.Core')
import System
clr.ImportExtensions(System.Linq)
clr.AddReference('FrEee.Core')
import FrEee
import FrEee.Utility
clr.ImportExtensions(FrEee.Utility.Extensions)
from FrEee.Modding import Mod
from FrEee.Game.Objects.Space import Galaxy
from FrEee.Game.Objects.Civilization import Empire
'Mines ' + str(Amount1) + ' minerals each turn (modified by planet value).'
Could the exec builtins_code line be deleting the str function? If so, how can I make sure that builtins_code gets added to builtins rather than replacing it?
edit2: nope, even if I remove the first four lines, it crashes when I process a turn in a single player game and then click my homeworld!
edit3: if I put the script in a text file and run it as a watch (see below) it runs just fine, even on the breakpoint where it crashes:
FrEee.Modding.ScriptEngine.EvaluateExpression<string>(System.IO.File.ReadAllText("c:/users/edkol/desktop/test.py")), ac
The line:
exec builtins_code in builtins.__dict__
just adds _ to the interactive environment so it repeats the last evaluated variable. Without that line, _ isn't defined. Note that this feature isn't very useful in a script and could be removed. This seems unrelated to your issue.
It looks like the sole interest of IronPython is to be able to interact easily with Microsoft/C# stuff, but it remains "stable" in 2.7 version and it's probably not as bug-free as the official python versions (similar bug was encountered and not solved on reddit, not that it helps, but you know you're not the only one...).
It has to be a bug because you cannot delete a builtin when it's not overridden:
>>> str
<type 'str'>
>>> del str
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'str' is not defined
Now let's be pragmatic: there's no way someone is going to fix that bug in the near future.
So you could try to "restore" the str name by doing:
str = __builtins__.get('str')
I didn't test this, maybe it's not going to work either once you're in this strange state, but there are other workarounds to get hold of "lost" class names, using an instance and __class__ attribute:
>>> "".__class__(34) # "".__class__ is str
'34'
>>> 0 .__class__(1.4) # note the space to help the parser :)
1
The only problem is that is going to look weird in your code. Don't forget to comment!
Anyway, you don't really need str for this, you can workaround your issue by using str.format on a format string (positional):
'Mines {} minerals each turn (modified by planet value).'.format(Amount1)
or by keyword:
'Mines {Amount1} minerals each turn (modified by planet value).'.format(Amount1=Amount1)
That method doesn't involve str built-in. Not saying that you're not going to have other problems, but even when str is available, this is one prefered way to format a string.
Work your way out by avoiding such errors. Fortunately, python exceptions are explicit and can be catched with a nice traceback.
In the process of updating my nuget packages for BundleTransformer.Less from 1.9.20 to 1.9.143 my application's styles no longer appeared correctly.
I tracked the issue to less not compiling a file because of the order of variable declaration and use. My understanding of less says you can define a variable after using it, but it is no longer the case for me. I am able to reproduce with something as simple as
html {
color : #test;
}
#test:green;
Which works in online less sandboxes for me.
My app builds and serves up the .less file when requested without error, but the contents of the file is just
variable #test is undefined on line 17 in file '/icons.less':
[16]: html{
[17]: color : #test;
------------^
[18]: }
What part of compilation would suddenly enforce a requirement about variable orders?
We are looking at using nDepend to start tracking some of our technical debt, particularly around hard to maintain methods and cyclomatic complexity.
I believe this is possibly by taking a baseline report and then running a new analysis to provide the delta. Below is a very basic Powershell I've put together that does this.
$nDepend = "C:\_DEVELOPMENT\nDepend\NDepend.Console.exe"
$targetFile = "C:\_DEVELOPMENT\AssemblyToTest\CodeChallenge.Domain.ndproj"
$projectFolder = Split-Path -Path $targetFile
$outputFolder = "nDepend.Reports"
$previous = ""
Clear-Host
# See if we already have a .ndar file in the output folder, if we do back it up so we can do a comparison
if (Test-Path $projectFolder\$outputFolder\*.ndar)
{
Write-Output "Backing up previous NDAR report"
Copy-Item $projectFolder\$outputFolder\*.ndar $projectFolder\previous.ndar
$previous = ".\previous.ndar"
}
#The output path appears to be relative to the .ndproj file
& $nDepend $targetFile /Silent /OutDir .\$outputFolder /AnalysisResultToCompareWith .\previous.ndar
Here is the rule I've configured in nDepend: -
failif count > 1 bobs
from m in Methods
where m.NbLinesOfCode > 10
where m.WasChanged()
select new { m, m.NbLinesOfCode }
The goal of this is not to break the build if we have methods over 10 lines, but rather to break the build if somebody edits an existing method that is too big and does not improve it (or make it worse). However the where m.WasChanged() part of the rule isn't being triggered regardless of how much code I add. If I comment it out it will alert me that there are plenty of methods that exceed 10 lines, but I only want to know about recently changed ones.
Am I using the rule wrong? Or perhaps my powershell is incorrectly using the /AnalysisResultToCompareWith parameter?
There are default rules like Avoid making complex methods even more complex in the rule group Code Smells Regression that are close to what you want to achieve. You can get inspired by their source code.
The key is to retrieve the methods changed with...
m.IsPresentInBothBuilds() &&
m.CodeWasChanged() &&
and then compare metric evolution since baseline by accessing m.OlderVersion().
A ICompareContext reference two code bases snapshots the newer version and the older version. In this context the OlderVersion() extension method returns actually calls the ICompareContext.OlderVersion(codeElement), from the doc:
Returns the older version of the codeElement object.
If codeElement is already the older version, returns the codeElement object.
If codeElement has been added and has no corresponding older version, returns null.
This method has a constant time complexity.
Hello
I Need to create a template, which is "dynamic", and i'll explain the meanning of "Dynamic":
I need to have a template, that is rendered into text files (c++ code, to be exact).
the user will be able to change some things in the generated files.
After a while, a process is run to update the generated files, i'll be able to "spot" where were the templates regions and update them accordingly.
My Effort
currently, i use a "T4 Template" to create the initial render,
and in the Template, I implant C++ style comments over the regions i need to recognize later.
and another code that find that regions, and regenerates what should go between those "Comment blocks".
the problem is that it is not the same code that generate the boiler-plate, and updates the regions which costs me a lot of headache and buggy features.
it is not very intuitive to write, and the users (the ones who use the generated code) need to know Not to touch the "Comment Blocks".
Questions
How can i recognize location/blocks in a generated file without "littering" the file with "comment"/"unimportant" text?
How can i unify the code that generate the "templated blocks" both for "Generation" and "Update"
Later on, How can i make it work on Non-Code files too,
Edit
I guess I wasn't clear at what i am doing,
I am writing a tool in C#, that generates C++ code.
Also, T4 is just what i used, but any tool/library can be used while C# libraries are prefered
Any idea will be highly appreciated,
Thanks.
Now, I believe your question is totally ["open" and "opinion based"] on one side, and ["why is this code not working" without showing the code] on the other side.. but I want to try pointing some problem with the idea of "improvement" you have now.
Q2: How can I unify the code that generate the "templated blocks" both for "Generation" and "Update"
I'm strongly convinced that you should not, at least not now. Here's why:
'generate' and 'update' are happening in different directions; first is t4template->content, second is content->t4template
those two directions form different functionality
at least one of these directions requires complex logic not present in the other one
'generate' is based on T4 Engine, while 'update' will probably not be able to use it at all
..and probably many other reasons, but that's enough
Q3: Later on, How can i make it work on Non-Code files too
T4 Engine has no idea that what you generate now is a C++ file. T4 works only on a layer of "text files". If the process you have works now, you should be able to "generate" any text file already right now. The "update" part is a bit more tricky, because it depends on how you implemented it. If you assumed/used any correlaction to C++ syntax, you've got a problem. (guess why T4 Templates are called 'text templating engine', agnostic to the actual generated code language) If you kept it clean and worked as if on a free-form text file, then you're already safe to work on, well, free-form text files.
Q1: How can I recognize location/blocks in a generated file without "littering" the file with "comment"/"unimportant" text?
Well, basically, you can't and/or shouldn't. Consider a smart idea of keeping a hidden database that remembers text locations for every file. For every comment that you would put in the file, you put a row in the database, saying file: BAR\FOO.CPP | FROM: line 120 char 1 | TO: line 131 char 15 | XXX: yyy | ZZZ: aaa. That's almost no difference to having comments in the file, all information is preserved, and the file is clean now, right?
Nope. And that's because you want to detect what has changed. Let's take a highly contrived example, here's the generated file with such invisible markers that are managed by database. Each # character denotes a marker, be it start/stop/metainfo nevermind:
class FooBar : public #BaseClass#
{
public:
#void Blargh(Whizz& output);#
#int GetAge() const;#
private:
int #shoeSize#;
#
};
Those # are of course invisible, it's just an information held elsewhere, the user sees a clean file. Now, he edits it to this:
class FooBar : public BaseClass
{
public:
template<T>
void Yeeek(T& output);
int GetAge() const;
private:
int shoeSize;
};
Please note how "template" was added and method renamed to "Yeeek". There were some markers out there, I didn't show them intentionally, just look on the "template<>" line. What if it was accidentally placed a line or a byte too far or too early, so one marker too many was skipped or included? Now the detector and updater may accidentally skip "template<>", and it will be totally happy to just rename the method. This is not a problem with the detector or updater. This is a problem of markers not being visible, so the user was not able to see where should he place his edit.
That's probably the most important point. But, let's see something more algorithmic/technical. Let's try an even simpler edit. User edits the file to:
class FooBarize : publ#ic BaseCl#ass
{
int goat;
# string cheese; #
p#ublic: #
void Blargh(Whizz& output);
i#nt GetA#ge() const;
p#rivate:
int shoeSize;
};
I overlaid those invisible markes from 'the external database of markers' back onto this edited file. What has happened? Simple. User has added two lines more in an odd place (he doesnt see the markes, right?), and the database remembers old places (i.e. 'line:char', but could be 'byte', or really whatever). Now of course, database may (and should!) also remember old shape of the file, so it can see that i.e. the first # was after ":public" and the process can try to map it onto the new file.. but then, you already have a highly complex problem, and this edit was trivial. Of course, you can require the user to enter some information on how to update the markers.. but hey, he don't see them, how can he do it? And since we wanted to hide the markers from him, we probably don't want to ask him about updating them as well..
How about editing the file to:
struct FooBar : One,Two,Three,Four
{
void OhNoes();
};
I didn't care to overlay the markers, because it's utter nonsense. Now, how to map it back to the template? Is OhNoes mappable to GetAge (const removed) or to Blargh (parameters removed)? How the template base class should be updated? Which one of the new bases is the true base? Or maybe all of them? Neither you nor I can decide it, even with our combined human intelligence, not mentioning an automated process.
Of course, you can leave it as a corner case, you can emit an error to the user and inform them that their edit went to far and is unanalyzable and so on. But The complexity of reverse-mapping a change back to the model text is still there.
What I want to show you by these contrived examples is, that if you want to detect and map changes back to the original template, you should keep these markers in the generated content. Having these markers in the code allows you quickly and reliably detect:
which sections changed? (-> content between markers has changed)
which sections were offsetted by edits? (->markers are now at different position than before)
were any sections deleted? (-> both markers and content between removed)
(..)
It also allows the user to see which parts are special so he can place his edits in a reasonable way, which allows you to ignore and not support more corner cases than in the "invisible markers" case.
Finally, let's take a read-world example which you already know. T4 Template. All those ugly <%!#!#^$^!%# littering your precious template text. Couldn't they be removed? Couldn't these be kept in a separate file that describes the transformation? Or at least at the beginning or end of the file? Yes, it could. But it would make the editing a real pain - we're back to 'invisible markers' problem: each your edit to the content may require you to manually update locations of some invisible markers.
Keep the markers in the generated content.
Keep your users aware of the generation and detection and special regions.
If it's too complex for them, change the users to a more technical group, or train your userbase to be more technical. Or prevent them from editing the file. Given them some partial access so they can edit a part of the file, as an excerpt, not as a whole file. Limit their editing power to absolute minimum. Maybe it will allow you to limit the number of visible markers, maybe even down to zero, maybe at the cost of splitting and downsizing editable fragments.
I think you are going about it the wrong way. You have a XY problem here. Allowing your users to modify only part of the generated file and then trying to detect that part it's a lot of headache as you have seen.
Instead, the better solution is to leave the generated file completely unmodifiable and have some configuration available. For instance you can have a config file where users can add their own data members, initializers for them, etc.
This way you have a clear separation of the parts of your system.
The modifications done by the users are now trivially carried to the next iteration and you can easily always re-generate the output.
+------------------+
| Input: Template | ------
+------------------+ \
|
+------------------+ | Generator code +-------------------------+
| Input: Config | -------+----------------------> | Output: Generated code |
+------------------+ | |-------------------------+
|
+------------------+ |
| Input: Config | --------/
+------------------+
This system can be used to generate non-code also.
I have a list of files in a dataGridView that I would like to be able to select 2 of them (I can figure out how to check for the selectedRows count) and pass those files to Beyond Compare 3 for comparison. I looked through their Support page and I couldn't find a way to do that.
In the program I need to open the application (BC3) and pass the application the 2 file paths in an argument to start the comparison.
I am just using System.Diagnostics.Process.Start(bc3.exe path) to launch beyond compare.
Look at their support page for configuring version control systems. The general syntax seems to be
"C:\Program Files\Beyond Compare 3\bcomp.exe" %1% %2% /lefttitle="%3%" /righttitle="%4%"
So it looks like you need to pass four arguments, which are the left and right file, and then the left and right title. So you'll want to use the two-argument form of Start
System.Diagnostics.Process.Start("C:\Program Files\Beyond Compare 3\bcomp.exe",
"file1.txt file2.txt /lefttitle=\"foo\" /righttitle=\"bar\"")
I don't have BC3 installed at the moment so I haven't tested the above, but it should be very close.
There are various other questions on SO for integrating BC with git, svn, etc. They will give you other examples of starting BC from the command line.
The following works for me.
string bc3 = #"C:\Program files (x86)\Beyond Compare 3\bcompare.exe";
Process.Start(bc3, #"c:\temp\File1.cs c:\temp\File2.cs" );
or if your filenames have spaces in them
Process.Start(bc3, #"""c:\temp\File 1.cs"" ""c:\temp\File 2.cs""" );