How to determine whether a node_tree is a material or a node group?
How it represents itself.
In as much as it aint pretty have had to rely on this before, may be for same can't remember.  Noticed in console that the representation  &quot;knows&quot;. (echoing in the console uses repr(ob) printing uses str(ob))
&gt;&gt;&gt; D.materials['Material'].node_tree
bpy.data.materials['Material'].node_tree

&gt;&gt;&gt; D.node_groups['Foo']
bpy.data.node_groups['Foo']

as a string is also of little use
&gt;&gt;&gt; print(D.materials['Material'].node_tree)
&lt;bpy_struct, ShaderNodeTree(&quot;Shader Nodetree&quot;) at 0x7f6bd0a86e08&gt;

whereas looking at types et al kept coming up as same.  Hence can use this in your method
&gt;&gt;&gt; def from_material(nodetree):
...     return repr(nodetree).startswith(&quot;bpy.data.materials&quot;)
...     
&gt;&gt;&gt; from_material(D.materials['Material'].node_tree)
True

&gt;&gt;&gt; from_material(D.node_groups['Foo'])
False

alternatively endswith(&quot;node_tree&quot;) is possibly a quicker option.
Extra,

Nice solution. But so how can I get that material into a variable in
this function?

Once we know it's a material, can slice off &quot;.node_tree&quot; and evaluate it.
&gt;&gt;&gt; repr(D.materials['Material'].node_tree)[:-10]
&quot;bpy.data.materials['Material']&quot;

&gt;&gt;&gt; eval(repr(D.materials['Material'].node_tree)[:-10])
bpy.data.materials['Material']

Similarly could slice &quot;bpy.data.materials['&quot; from the start and &quot;'].node_tree&quot; from the end to just keep the name.
&gt;&gt;&gt; matname = repr(D.materials['Material'].node_tree)[20:-12]
&gt;&gt;&gt; matname
'Material'

&gt;&gt;&gt; D.materials.get(matname)
bpy.data.materials['Material']