Is there a better way to make addon working on both blender 2.80 and 2.79?How to create toggle buttons in...
"Murder!" The knight said
What if I store 10TB on azure servers and then keep the vm powered off?
How can I be pwned if I'm not registered on that site?
Where was Karl Mordo in Infinity War?
What is the wife of a henpecked husband called?
Can chords be played on the flute?
Rationale to prefer local variables over instance variables?
Can we carry rice to Japan?
How to acknowledge an embarrassing job interview, now that I work directly with the interviewer?
When should a commit not be version tagged?
If a druid in Wild Shape swallows a creature whole, then turns back to her normal form, what happens?
It took me a lot of time to make this, pls like. (YouTube Comments #1)
Skis versus snow shoes - when to choose which for travelling the backcountry?
I can't die. Who am I?
Avoiding unpacking an array when altering its dimension
How do ISS astronauts "get their stripes"?
CBP Reminds Travelers to Allow 72 Hours for ESTA. Why?
How to deny access to SQL Server to certain login over SSMS, but allow over .Net SqlClient Data Provider
How to count words in a line
Accessing something inside the object when you don't know the key
Where is the fallacy here?
Equivalent to "source" in OpenBSD?
Magento 2: Override XML file from vendor folder to app folder doesn't work/update
How would we write a misogynistic character without offending people?
Is there a better way to make addon working on both blender 2.80 and 2.79?
How to create toggle buttons in blender GUI from dynamic list of items?Python modifier error handlingWhats the best way to make an operator tooltip depend on a Blender version?Conflicts between addons contexts?Modal operators not working when used through pop-up menuinconsistent AttributeError when modifying frame_currentPython: Using pycharm with the blender API gives errorsAdd a Custom c++ Class to Blender and drawing it in the viewport using an Addonbpy_struct for accessing key indentifiers in a keyvalue pair(dict) in a menuWhat is the appropriate way to write and distribute an addon that works with both blender 2.80 and 2.79?
$begingroup$
I know this works:
import bpy
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
if bpy.app.version >= (2, 80, 0):
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
else:
type= bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name= bpy.props.StringProperty(update=unedit)
bpy.utils.register_class(Test)
but it is coping and paste solution (bed for many properties). Is there a better way?
python add-on compatibility
$endgroup$
add a comment |
$begingroup$
I know this works:
import bpy
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
if bpy.app.version >= (2, 80, 0):
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
else:
type= bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name= bpy.props.StringProperty(update=unedit)
bpy.utils.register_class(Test)
but it is coping and paste solution (bed for many properties). Is there a better way?
python add-on compatibility
$endgroup$
add a comment |
$begingroup$
I know this works:
import bpy
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
if bpy.app.version >= (2, 80, 0):
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
else:
type= bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name= bpy.props.StringProperty(update=unedit)
bpy.utils.register_class(Test)
but it is coping and paste solution (bed for many properties). Is there a better way?
python add-on compatibility
$endgroup$
I know this works:
import bpy
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
if bpy.app.version >= (2, 80, 0):
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
else:
type= bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name= bpy.props.StringProperty(update=unedit)
bpy.utils.register_class(Test)
but it is coping and paste solution (bed for many properties). Is there a better way?
python add-on compatibility
python add-on compatibility
asked 20 hours ago
Piotr KowalczykPiotr Kowalczyk
765
765
add a comment |
add a comment |
5 Answers
5
active
oldest
votes
$begingroup$
Two separate addons
The code in question and your answer has versioning for one part of the changes from 2.79 to 2.80, ie annotations in property groups.
I would suggest writing two addons, one that works in 2.79 and one that works in 2.80. (As opposed to having versioning code ad hoc in each py file.)
Distribute as an addon for that version. If using github a branch is often used.
If wish to distribute as a single addon that works in both, suggest putting each in a subfolder of the root folder of the addon, then in the addons __init__.py check once for version and import modules from that version folder.
See this post on fake modules for some cool trickery https://stackoverflow.com/a/27476659/5317130
$endgroup$
1
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
add a comment |
$begingroup$
The problem I have with making a code that works in both versions is it gets more complicated and more evaluation needs to happen at runtime. There is extra code and 'baggage' than in either version would be.
Normally in c/c++ you would implement pre-processor directives into the code to organize it and generate an executable of only what you need.
In python this is not so easy. You can use __debug__ which is pre-processed by the compiler and evaluated based on -O command line argument and any if False: part of code will be skipped by the optimizer, but you have to run the code with arguments which is not convenient for Blender use.
The solution I found is to use pypreprocessor. It lets you do:
from pypreprocessor import pypreprocessor
pypreprocessor.parse()
#define 2_80
#ifdef 2_80
print('2_80 code')
#else
print('2_79 code')
#endif
Normally when you call .parse() it generates a temporary copy with pypreprocessor commented (not to run recursively) and also any unused code commented out and this post-processed code is executed on-the-fly.
The best thing about it is instead of executing the post-processed code you can output to a file with a user-defined filename and even remove all the preprocessor directives and preprocessor specific code:
pypreprocessor.defines.append('define')
pypreprocessor.run = False
pypreprocessor.save = True
pypreprocessor.output = 'addon_2_80.py'
pypreprocessor.removeMeta = True
This way you get clean files for 2.80 or 2.79 versions, that no one knows were generated from the same source.
$endgroup$
add a comment |
$begingroup$
I am answering my own question, maybe someone finds it useful.
import bpy
class Test_2_80(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
class Test(Test_2_80):
if bpy.app.version < (2, 80, 0):
for val, fun in Test_2_80.__annotations__.items():
exec('{} = fun'.format(val))
val, fun = None, None
else:
pass
bpy.utils.register_class(Test)
bpy.types.Scene.test = bpy.props.PointerProperty(type=Test)
bpy.context.scene.test.name = 'g'
Any ideas for better solutions?
$endgroup$
add a comment |
$begingroup$
Note: I have a lot of experience with Python, but no experience with Blender (I found the source code to look through).
Warning: I also have not tested either.
Another option is to create a decorator:
import bpy
def copy_annotations_to_dict_if_old_blender(x):
if bpy.app.version < (2, 80):
x.__dict__.update(x.__annotations__)
return x
@copy_annotations_to_dict_if_old_blender
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
Previous code that used a metaclass instead:
import bpy
if bpy.app.version >= (2, 80):
MyPropertyGroupMeta = bpy.RNAMetaPropGroup
else:
class MyPropertyGroup(bpy.types.PropertyGroup):
def __new__(cls, name, bases, namespace, **kwargs):
result = super().__new__(cls, name, bases, namespace, **kwargs)
result.__dict__.update(result.__annotations__)
return result
class MyPropertyGroup(bpy.types.StructRNA, metaclass=MyPropertyGroupMeta):
__slots__ = ()
class Test(MyPropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
(the decorator code is more readable and more likely to work)
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$begingroup$
You can just use the assignment and accept that it'll show warnings on 2.80. It'll still work, and you can make the step to 2.80+ when 2.80 or 2.81 is released.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
});
});
}, "mathjax-editing");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "502"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fblender.stackexchange.com%2fquestions%2f133457%2fis-there-a-better-way-to-make-addon-working-on-both-blender-2-80-and-2-79%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Two separate addons
The code in question and your answer has versioning for one part of the changes from 2.79 to 2.80, ie annotations in property groups.
I would suggest writing two addons, one that works in 2.79 and one that works in 2.80. (As opposed to having versioning code ad hoc in each py file.)
Distribute as an addon for that version. If using github a branch is often used.
If wish to distribute as a single addon that works in both, suggest putting each in a subfolder of the root folder of the addon, then in the addons __init__.py check once for version and import modules from that version folder.
See this post on fake modules for some cool trickery https://stackoverflow.com/a/27476659/5317130
$endgroup$
1
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
add a comment |
$begingroup$
Two separate addons
The code in question and your answer has versioning for one part of the changes from 2.79 to 2.80, ie annotations in property groups.
I would suggest writing two addons, one that works in 2.79 and one that works in 2.80. (As opposed to having versioning code ad hoc in each py file.)
Distribute as an addon for that version. If using github a branch is often used.
If wish to distribute as a single addon that works in both, suggest putting each in a subfolder of the root folder of the addon, then in the addons __init__.py check once for version and import modules from that version folder.
See this post on fake modules for some cool trickery https://stackoverflow.com/a/27476659/5317130
$endgroup$
1
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
add a comment |
$begingroup$
Two separate addons
The code in question and your answer has versioning for one part of the changes from 2.79 to 2.80, ie annotations in property groups.
I would suggest writing two addons, one that works in 2.79 and one that works in 2.80. (As opposed to having versioning code ad hoc in each py file.)
Distribute as an addon for that version. If using github a branch is often used.
If wish to distribute as a single addon that works in both, suggest putting each in a subfolder of the root folder of the addon, then in the addons __init__.py check once for version and import modules from that version folder.
See this post on fake modules for some cool trickery https://stackoverflow.com/a/27476659/5317130
$endgroup$
Two separate addons
The code in question and your answer has versioning for one part of the changes from 2.79 to 2.80, ie annotations in property groups.
I would suggest writing two addons, one that works in 2.79 and one that works in 2.80. (As opposed to having versioning code ad hoc in each py file.)
Distribute as an addon for that version. If using github a branch is often used.
If wish to distribute as a single addon that works in both, suggest putting each in a subfolder of the root folder of the addon, then in the addons __init__.py check once for version and import modules from that version folder.
See this post on fake modules for some cool trickery https://stackoverflow.com/a/27476659/5317130
answered 19 hours ago
batFINGERbatFINGER
25.1k42674
25.1k42674
1
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
add a comment |
1
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
1
1
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
I think this approach is best since many other changes exist in 2.8 that have to be fixed for a 2.79 script to work there.
$endgroup$
– Craig D Jones
19 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
$begingroup$
That also makes it easier to discontinue/freeze the development 2.79 addon, since the Blender 2.8x code is probably going to differ more and more due to further development.
$endgroup$
– metaphor_set
2 hours ago
add a comment |
$begingroup$
The problem I have with making a code that works in both versions is it gets more complicated and more evaluation needs to happen at runtime. There is extra code and 'baggage' than in either version would be.
Normally in c/c++ you would implement pre-processor directives into the code to organize it and generate an executable of only what you need.
In python this is not so easy. You can use __debug__ which is pre-processed by the compiler and evaluated based on -O command line argument and any if False: part of code will be skipped by the optimizer, but you have to run the code with arguments which is not convenient for Blender use.
The solution I found is to use pypreprocessor. It lets you do:
from pypreprocessor import pypreprocessor
pypreprocessor.parse()
#define 2_80
#ifdef 2_80
print('2_80 code')
#else
print('2_79 code')
#endif
Normally when you call .parse() it generates a temporary copy with pypreprocessor commented (not to run recursively) and also any unused code commented out and this post-processed code is executed on-the-fly.
The best thing about it is instead of executing the post-processed code you can output to a file with a user-defined filename and even remove all the preprocessor directives and preprocessor specific code:
pypreprocessor.defines.append('define')
pypreprocessor.run = False
pypreprocessor.save = True
pypreprocessor.output = 'addon_2_80.py'
pypreprocessor.removeMeta = True
This way you get clean files for 2.80 or 2.79 versions, that no one knows were generated from the same source.
$endgroup$
add a comment |
$begingroup$
The problem I have with making a code that works in both versions is it gets more complicated and more evaluation needs to happen at runtime. There is extra code and 'baggage' than in either version would be.
Normally in c/c++ you would implement pre-processor directives into the code to organize it and generate an executable of only what you need.
In python this is not so easy. You can use __debug__ which is pre-processed by the compiler and evaluated based on -O command line argument and any if False: part of code will be skipped by the optimizer, but you have to run the code with arguments which is not convenient for Blender use.
The solution I found is to use pypreprocessor. It lets you do:
from pypreprocessor import pypreprocessor
pypreprocessor.parse()
#define 2_80
#ifdef 2_80
print('2_80 code')
#else
print('2_79 code')
#endif
Normally when you call .parse() it generates a temporary copy with pypreprocessor commented (not to run recursively) and also any unused code commented out and this post-processed code is executed on-the-fly.
The best thing about it is instead of executing the post-processed code you can output to a file with a user-defined filename and even remove all the preprocessor directives and preprocessor specific code:
pypreprocessor.defines.append('define')
pypreprocessor.run = False
pypreprocessor.save = True
pypreprocessor.output = 'addon_2_80.py'
pypreprocessor.removeMeta = True
This way you get clean files for 2.80 or 2.79 versions, that no one knows were generated from the same source.
$endgroup$
add a comment |
$begingroup$
The problem I have with making a code that works in both versions is it gets more complicated and more evaluation needs to happen at runtime. There is extra code and 'baggage' than in either version would be.
Normally in c/c++ you would implement pre-processor directives into the code to organize it and generate an executable of only what you need.
In python this is not so easy. You can use __debug__ which is pre-processed by the compiler and evaluated based on -O command line argument and any if False: part of code will be skipped by the optimizer, but you have to run the code with arguments which is not convenient for Blender use.
The solution I found is to use pypreprocessor. It lets you do:
from pypreprocessor import pypreprocessor
pypreprocessor.parse()
#define 2_80
#ifdef 2_80
print('2_80 code')
#else
print('2_79 code')
#endif
Normally when you call .parse() it generates a temporary copy with pypreprocessor commented (not to run recursively) and also any unused code commented out and this post-processed code is executed on-the-fly.
The best thing about it is instead of executing the post-processed code you can output to a file with a user-defined filename and even remove all the preprocessor directives and preprocessor specific code:
pypreprocessor.defines.append('define')
pypreprocessor.run = False
pypreprocessor.save = True
pypreprocessor.output = 'addon_2_80.py'
pypreprocessor.removeMeta = True
This way you get clean files for 2.80 or 2.79 versions, that no one knows were generated from the same source.
$endgroup$
The problem I have with making a code that works in both versions is it gets more complicated and more evaluation needs to happen at runtime. There is extra code and 'baggage' than in either version would be.
Normally in c/c++ you would implement pre-processor directives into the code to organize it and generate an executable of only what you need.
In python this is not so easy. You can use __debug__ which is pre-processed by the compiler and evaluated based on -O command line argument and any if False: part of code will be skipped by the optimizer, but you have to run the code with arguments which is not convenient for Blender use.
The solution I found is to use pypreprocessor. It lets you do:
from pypreprocessor import pypreprocessor
pypreprocessor.parse()
#define 2_80
#ifdef 2_80
print('2_80 code')
#else
print('2_79 code')
#endif
Normally when you call .parse() it generates a temporary copy with pypreprocessor commented (not to run recursively) and also any unused code commented out and this post-processed code is executed on-the-fly.
The best thing about it is instead of executing the post-processed code you can output to a file with a user-defined filename and even remove all the preprocessor directives and preprocessor specific code:
pypreprocessor.defines.append('define')
pypreprocessor.run = False
pypreprocessor.save = True
pypreprocessor.output = 'addon_2_80.py'
pypreprocessor.removeMeta = True
This way you get clean files for 2.80 or 2.79 versions, that no one knows were generated from the same source.
answered 19 hours ago
Jaroslav Jerryno NovotnyJaroslav Jerryno Novotny
39.3k176155
39.3k176155
add a comment |
add a comment |
$begingroup$
I am answering my own question, maybe someone finds it useful.
import bpy
class Test_2_80(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
class Test(Test_2_80):
if bpy.app.version < (2, 80, 0):
for val, fun in Test_2_80.__annotations__.items():
exec('{} = fun'.format(val))
val, fun = None, None
else:
pass
bpy.utils.register_class(Test)
bpy.types.Scene.test = bpy.props.PointerProperty(type=Test)
bpy.context.scene.test.name = 'g'
Any ideas for better solutions?
$endgroup$
add a comment |
$begingroup$
I am answering my own question, maybe someone finds it useful.
import bpy
class Test_2_80(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
class Test(Test_2_80):
if bpy.app.version < (2, 80, 0):
for val, fun in Test_2_80.__annotations__.items():
exec('{} = fun'.format(val))
val, fun = None, None
else:
pass
bpy.utils.register_class(Test)
bpy.types.Scene.test = bpy.props.PointerProperty(type=Test)
bpy.context.scene.test.name = 'g'
Any ideas for better solutions?
$endgroup$
add a comment |
$begingroup$
I am answering my own question, maybe someone finds it useful.
import bpy
class Test_2_80(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
class Test(Test_2_80):
if bpy.app.version < (2, 80, 0):
for val, fun in Test_2_80.__annotations__.items():
exec('{} = fun'.format(val))
val, fun = None, None
else:
pass
bpy.utils.register_class(Test)
bpy.types.Scene.test = bpy.props.PointerProperty(type=Test)
bpy.context.scene.test.name = 'g'
Any ideas for better solutions?
$endgroup$
I am answering my own question, maybe someone finds it useful.
import bpy
class Test_2_80(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
class Test(Test_2_80):
if bpy.app.version < (2, 80, 0):
for val, fun in Test_2_80.__annotations__.items():
exec('{} = fun'.format(val))
val, fun = None, None
else:
pass
bpy.utils.register_class(Test)
bpy.types.Scene.test = bpy.props.PointerProperty(type=Test)
bpy.context.scene.test.name = 'g'
Any ideas for better solutions?
answered 20 hours ago
Piotr KowalczykPiotr Kowalczyk
765
765
add a comment |
add a comment |
$begingroup$
Note: I have a lot of experience with Python, but no experience with Blender (I found the source code to look through).
Warning: I also have not tested either.
Another option is to create a decorator:
import bpy
def copy_annotations_to_dict_if_old_blender(x):
if bpy.app.version < (2, 80):
x.__dict__.update(x.__annotations__)
return x
@copy_annotations_to_dict_if_old_blender
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
Previous code that used a metaclass instead:
import bpy
if bpy.app.version >= (2, 80):
MyPropertyGroupMeta = bpy.RNAMetaPropGroup
else:
class MyPropertyGroup(bpy.types.PropertyGroup):
def __new__(cls, name, bases, namespace, **kwargs):
result = super().__new__(cls, name, bases, namespace, **kwargs)
result.__dict__.update(result.__annotations__)
return result
class MyPropertyGroup(bpy.types.StructRNA, metaclass=MyPropertyGroupMeta):
__slots__ = ()
class Test(MyPropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
(the decorator code is more readable and more likely to work)
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$begingroup$
Note: I have a lot of experience with Python, but no experience with Blender (I found the source code to look through).
Warning: I also have not tested either.
Another option is to create a decorator:
import bpy
def copy_annotations_to_dict_if_old_blender(x):
if bpy.app.version < (2, 80):
x.__dict__.update(x.__annotations__)
return x
@copy_annotations_to_dict_if_old_blender
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
Previous code that used a metaclass instead:
import bpy
if bpy.app.version >= (2, 80):
MyPropertyGroupMeta = bpy.RNAMetaPropGroup
else:
class MyPropertyGroup(bpy.types.PropertyGroup):
def __new__(cls, name, bases, namespace, **kwargs):
result = super().__new__(cls, name, bases, namespace, **kwargs)
result.__dict__.update(result.__annotations__)
return result
class MyPropertyGroup(bpy.types.StructRNA, metaclass=MyPropertyGroupMeta):
__slots__ = ()
class Test(MyPropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
(the decorator code is more readable and more likely to work)
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$begingroup$
Note: I have a lot of experience with Python, but no experience with Blender (I found the source code to look through).
Warning: I also have not tested either.
Another option is to create a decorator:
import bpy
def copy_annotations_to_dict_if_old_blender(x):
if bpy.app.version < (2, 80):
x.__dict__.update(x.__annotations__)
return x
@copy_annotations_to_dict_if_old_blender
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
Previous code that used a metaclass instead:
import bpy
if bpy.app.version >= (2, 80):
MyPropertyGroupMeta = bpy.RNAMetaPropGroup
else:
class MyPropertyGroup(bpy.types.PropertyGroup):
def __new__(cls, name, bases, namespace, **kwargs):
result = super().__new__(cls, name, bases, namespace, **kwargs)
result.__dict__.update(result.__annotations__)
return result
class MyPropertyGroup(bpy.types.StructRNA, metaclass=MyPropertyGroupMeta):
__slots__ = ()
class Test(MyPropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
(the decorator code is more readable and more likely to work)
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
Note: I have a lot of experience with Python, but no experience with Blender (I found the source code to look through).
Warning: I also have not tested either.
Another option is to create a decorator:
import bpy
def copy_annotations_to_dict_if_old_blender(x):
if bpy.app.version < (2, 80):
x.__dict__.update(x.__annotations__)
return x
@copy_annotations_to_dict_if_old_blender
class Test(bpy.types.PropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
Previous code that used a metaclass instead:
import bpy
if bpy.app.version >= (2, 80):
MyPropertyGroupMeta = bpy.RNAMetaPropGroup
else:
class MyPropertyGroup(bpy.types.PropertyGroup):
def __new__(cls, name, bases, namespace, **kwargs):
result = super().__new__(cls, name, bases, namespace, **kwargs)
result.__dict__.update(result.__annotations__)
return result
class MyPropertyGroup(bpy.types.StructRNA, metaclass=MyPropertyGroupMeta):
__slots__ = ()
class Test(MyPropertyGroup):
def unedit(self, context):
print(self.type)
type: bpy.props.StringProperty(default='xxxxxxxxxxxxxxxxxx')
name: bpy.props.StringProperty(update=unedit)
(the decorator code is more readable and more likely to work)
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
answered 9 hours ago
Solomon UckoSolomon Ucko
1012
1012
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Solomon Ucko is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |
add a comment |
$begingroup$
You can just use the assignment and accept that it'll show warnings on 2.80. It'll still work, and you can make the step to 2.80+ when 2.80 or 2.81 is released.
$endgroup$
add a comment |
$begingroup$
You can just use the assignment and accept that it'll show warnings on 2.80. It'll still work, and you can make the step to 2.80+ when 2.80 or 2.81 is released.
$endgroup$
add a comment |
$begingroup$
You can just use the assignment and accept that it'll show warnings on 2.80. It'll still work, and you can make the step to 2.80+ when 2.80 or 2.81 is released.
$endgroup$
You can just use the assignment and accept that it'll show warnings on 2.80. It'll still work, and you can make the step to 2.80+ when 2.80 or 2.81 is released.
answered 1 hour ago
dr. Sybrendr. Sybren
5,55111239
5,55111239
add a comment |
add a comment |
Thanks for contributing an answer to Blender Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fblender.stackexchange.com%2fquestions%2f133457%2fis-there-a-better-way-to-make-addon-working-on-both-blender-2-80-and-2-79%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown