Cookbook in runlist does not see overriden value of attribute - attributes

I have several cookbooks in a runlist 'wrapper' cookbook. On one of the coobooks, I override the value of a node attribute, and then I restore it back after I do run some methods. When the next cookbook in the rulist runs, it does not see the restored value.
On the first cookbook in the runlist, I do node.override['my_attribute'] = 'new_value'.
I run some commands, and then I do node.override['my_attribute'] = 'original_value'.
When the next cookbook in the runlist runs, it still sees that node['my_attribute'] = 'new_value'.
How can I make sure the second cookbook uses the restored value?

Related

How to check if node has property without instancing?

I'm trying to check if a certain node type has a property
without actually needing to make an instance of it
like this:
print("z_index" in Position2D);
Classes in ClassDB
If we are talking about a build-in class (not a custom class that you created, but one that is part of Godot), you can use ClassDB to get the property:
var properties := ClassDB.class_get_property_list("Position2D")
Classes from Godot Scripts
If the class is not in ClassDB (which is the case custom classes), but you have the script, you can use the script to get the property list:
var properties := preload("res://custom_class.gd").get_script_property_list()
If you don't have the script, perhaps you can find it. This code uses the hidden project setting "_global_script_classes" to find the path of the script for a class given the name_of_class you are looking for, and loads it:
if ProjectSettings.has_setting("_global_script_classes"):
for x in ProjectSettings.get_setting("_global_script_classes"):
if x.class == name_of_class:
return load(x.path)
Addendum: This is no longer available in Godot 4.
Other classes
However, the above approach will not work for every type of script. In those cases, I'm afraid the best way is to instance it. You can still get the properties from the instance and cache them (perhaps put them in a dictionary) so that you are not creating a new instance every time you need to query:
var properties := (CustomClass.new()).get_property_list()
Query the properties
Regardless of how you got the property list, you can query them the same way. For example this code looks for a property with name "z_index" and gets its type:
var found := false
var type := TYPE_NIL
for property in properties:
if property.name == "z_index":
found = true
type = property.type
break
prints(found, type)
The type is a Variant.Type constant.
Theraot's answer is correct, since it provides a way to check attributes without creating an instance of a node/gdscript.
You can also check the properties of an existing instance of a node/scene by doing this:
if "attribute_name" in thing:
pass # do stuff here
Practical example; During a signal triggered by two Area2Ds colliding, check if one node's attribute item_type is set:
func _on_area_2d_area_entered(area):
if "item_type" in area:
print(area["item_type"])

Attempt to call function 'get_position' in base 'null instance' on a null instance. ERROR

I am trying to create a topdown shooter with a player and a bullet on a separate scene. But whenever I run the game it says
Attempt to call function 'get_position' in base 'null instance' on a null instance.
BTW I am new to Godot.
The problem seems to be in this function:
const SPEED = 300
var bullet = preload("res://Mini-Scenes/Bullet.tscn")
func shoot():
var b = bullet.instance()
add_child(b)
b.set_position(position)
b.move_and_slide(Vector2(1, 0).rotated(rotation) * SPEED)
And I also don't think that I understand how instancing works,
so my questions are:
How does Instancing work?
What makes the above function fail?
Alright, in order:
Instancing is simple in principle. Godot takes the base Node of a scene and all its children, and copy-and-pastes them into memory. Then, when you add this Node as child to another in the scene, _ready is called, the Nodes begin to _process and _physics_process, as well as a few other things like receive events (as a Node must be within a SceneTree in order to interact with other nodes, and the most common way to add one to a tree is making it the child of another).
For more information, see the documentation on Instancing
The above function actually works flawlessly, I just created a new project in Godot 3.1.1 and duplicated your setup, no errors occur. The problem must be somewhere else in your code or your scene setup, and we'd need to see your full script and scene layout to determine the cause of the problem. If you update your question with that information, or shoot me a message on Discord (Mantissa#2558), I'll be able to fully answer your question.

How can I override a Nix derivative without throwing `cannot coerce a set to a string`?

Or, the goal: How can I take a single package from Nix unstable in a declarative manner?
I'm new to NixOS and currently trying to install a newer version of Consul than the default 0.5.2 of my NixOS version (latest stable). I'm attempting this by overriding the derivative in my /etc/nix/configuration.nix.
I'd like to keep running stable, but I found unstable had the version of Consul that I wanted (0.7.0) already, and so I decided to use this package's attributes as a starting point to override https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/consul/default.nix
I copied it for most part into my configuration.nix, here are the relevant sections:
nixpkgs.config.packageOverrides = pkgs: rec {
consul = pkgs.lib.overrideDerivation pkgs.consul (attrs: rec {
version = "0.7.0";
name = "consul-${version}";
rev = "v${version}";
goPackagePath = "github.com/hashicorp/consul";
src = pkgs.fetchFromGitHub {
owner = "hashicorp";
repo = "consul";
inherit rev;
sha256 = "04h5y5vixjh9np9lsrk02ypbqwcq855h7l1jlnl1vmfq3sfqjds7";
};
# Keep consul.ui for backward compatability
passthru.ui = pkgs.consul-ui;
});
};
environment.systemPackages = with pkgs; [
vim
which
telnet
consul-ui
consul-alerts
consul-template
consul
];
I'm running nix-build (Nix) 1.11.2 which throws:
$ nixos-rebuild switch
building Nix...
building the system configuration...
error: cannot coerce a set to a string, at /etc/nixos/configuration.nix:19:7
(use ‘--show-trace’ to show detailed location information)
When I look at line 19 it's where name is set to "consul-${version}".
Why there is type-coercion going on here? Any tips will be greatly appreciated!
I'm also wondering if there is a better way to run just a single package in unstable, yet doing so declaratively from configuration.nix, rather than imperatively?
To add to what Rok said:
Which should point you that an error actually happens at passthru, line. If you comment it out it will probably build. I'm assuming some recursive calls are at play here and error occurs when it tries to evaluate consul/consul-ui packages.
If you're just starting out, you can safely ignore what follows and perhaps come back to it if/when you're curious about the nitty-gritty.
The problem here is that overrideDerivation is a kind of low-level approach to overriding things. Behind stdenv.mkDerivation, we have a much smaller primitive function called derivation. The derivation function takes some attributes and (more or less -- see the docs for the finer details) just passes those attributes as environment variables during the build. The stdenv.mkDerivation function, on the other hand, has a whole bunch of smarts layered on top that massages the attributes given to it before passing them onto derivation -- and in some cases, as is the case with passthru, it doesn't pass the attribute to derivation at all.
Back to overrideDerivation: it takes the final, tweaked attributes that stdenv.mkDerivation would pass to derivation, and just before that happens it allows you to override those attributes with the function you give it (e.g. that implies that, at that point, passthru has already been removed). When your function adds a passthru, that makes its way into derivation, which then wants to coerce the value of passthru into a string so it can make passthru an environment variable during the build; however, because passthru now points at a attribute-set, and such coercion isn't supported, Nix then complains.
So this sort of puts us in an odd situation. To illustrate, I'll copy the source for the consul package here:
{ stdenv, lib, buildGoPackage, consul-ui, fetchFromGitHub }:
buildGoPackage rec {
name = "consul-${version}";
version = "0.6.4";
rev = "v${version}";
goPackagePath = "github.com/hashicorp/consul";
src = fetchFromGitHub {
owner = "hashicorp";
repo = "consul";
inherit rev;
sha256 = "0p6m2rl0d30w418n4fzc4vymqs3vzfa468czmy4znkjmxdl5vp5a";
};
# Keep consul.ui for backward compatability
passthru.ui = consul-ui;
}
(Note that buildGoPackage is a wrapper around stdenv.mkDerivation.)
You might be familiar with e.g. consul.override, which allows you to supply different inputs (e.g. maybe a different version of consul-ui, or buildGoPackage), but it doesn't allow you to override things that aren't inputs (e.g. src, passthru, etc). Meanwhile, overrideDerivation allows you to modify the attrs given to derivation, but not the ones given to stdenv.mkDerivation. Ideally there would be something in-between, that would allow for manipulating the attrs given to stdenv.mkDerivation, and it so happens that there's a PR open to address this:
https://github.com/NixOS/nixpkgs/pull/18660
Welcome to Nix/NixOS :)
Whenever you need to know more about the error you can use --show-trace and that would give you more verbose error. In your case you would see something like
error: while evaluating the attribute ‘passthru’ of the derivation ‘consul-0.7.0’ at /home/rok/tmp/consul.nix:6:3:
cannot coerce a set to a string, at /home/rok/tmp/consul.nix:6:3
Which should point you that an error actually happens at passthru, line. If you comment it out it will probably build. I'm assuming some recursive calls are at play here and error occurs when it tries to evaluate consul/consul-ui packages.
As for overriding only one package from unstable channel something like this is needed
let
unstable_pkgs = import ./path/to/unstabe/nixpkgs {};
# or
# unstable_pkgs = import (pkgs.fetchFromGitHub {...}) {};
in {
...
nixpkgs.config.packageOverrides = pkgs: rec {
consul = unstable_pkgs.consul;
};
...
}
I haven't try the above, but I'm assuming it will work.

Does CTreeCtrl::DeleteItem also delete all the node's sub-tree HTREEITEMs

Does CTreeCtrl::DeleteItem also delete all the node's sub-tree HTREEITEMs or must I recursively traverse the sub-tree myself and call DeleteItem on each one?
Looking at the MFC source code for CTreeCtrl::DeleteItem, it does this:
_AFXCMN_INLINE BOOL CTreeCtrl::DeleteItem(_In_ HTREEITEM hItem)
{
ASSERT(::IsWindow(m_hWnd));
return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem);
}
Now looking at the documentation of TVM_DELETEITEM, it says the following (my emphasis):
Removes an item and all its children from a tree-view control
This would imply that recursively deleting is unnecessary, but I must admit that I've not tested it - the documentation may be misleading (as it sometimes is). One way to test is to note this line in the documentation:
The parent window receives a TVN_DELETEITEM notification code when
each item is removed.
So, by providing a handler for that message, you could verify that child items are deleted correctly.
From MSDN Docs on CTreeCtrl::DeleteItem where it says If hitem has the TVI_ROOT value, all items are deleted from the tree view control, I would infer that it will alo delete sub-nodes...

SoapUi: Transferring a response value to a temporary property (missing a non persisting target scope)

Using SoapUI Pro 5.0
I know how to transfer response values to any scoped property (test suite, test case, etc.).
My problem is, that such scoped properties:
must already exist in the target scope
are persisted at the end in the project configuration file. So after each run this configuration file is changed, what is a nightmare for source control.
I need this value only one or two step(s) later for doing complex verifications (usingg a Script-TestStep).
The "Property Transfer"-TestStep is very powerful for extracting from known sources and transferring to known targets. As target one even can choose a Script-TestStep from the same TestCase. But I did not find any hint how to bind the value to be transferred to - let's say - a declared variable within the target script.
Using the context (e.g. context.getProperties().put( 'MY_PROP_NAME', transferValue ) would be nice but the context is not available within the "Property Transfer"-TestStep. The only possibility I figured out is following script code in a Script-TestStep:
def xmlResponse = XMLNamespaceRemover.removeNamespaces(context.expand( '${mySoapTestStep#Response}' ));
def node = new groovy.util.XmlParser(false,false).parseText(xmlResponse);
def transferValue = node["Body"]["tag1"]["tag2"].text();
context.getProperties().put( 'MY_PROP_NAME', transferValue )
Any ideas how to solve this using the "Property Transfer" TestStep?
In your script, you can just use:
def MY_PROP_NAME = context.expand( '${mySoapTestStep#Response//*:Body/*:tag1/*:tag2}' )
Alternatively, you can use a Property Transfer step to transfer your value to a TestCase Property - which, as you pointed out, must already exist. In order to get around the problem you mentioned of persisting and thereby messing around with source control, you can create a TearDown script:
testRunner.testCase.setPropertyValue("MY_PROP_NAME", "default")

Resources