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?













6












$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?










share|improve this question









$endgroup$

















    6












    $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?










    share|improve this question









    $endgroup$















      6












      6








      6





      $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?










      share|improve this question









      $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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 20 hours ago









      Piotr KowalczykPiotr Kowalczyk

      765




      765






















          5 Answers
          5






          active

          oldest

          votes


















          5












          $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






          share|improve this answer









          $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



















          2












          $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.






          share|improve this answer









          $endgroup$





















            1












            $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?






            share|improve this answer









            $endgroup$





















              0












              $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)






              share|improve this answer








              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$





















                0












                $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.






                share|improve this answer









                $endgroup$













                  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
                  });


                  }
                  });














                  draft saved

                  draft discarded


















                  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









                  5












                  $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






                  share|improve this answer









                  $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
















                  5












                  $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






                  share|improve this answer









                  $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














                  5












                  5








                  5





                  $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






                  share|improve this answer









                  $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







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  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














                  • 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













                  2












                  $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.






                  share|improve this answer









                  $endgroup$


















                    2












                    $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.






                    share|improve this answer









                    $endgroup$
















                      2












                      2








                      2





                      $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.






                      share|improve this answer









                      $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.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered 19 hours ago









                      Jaroslav Jerryno NovotnyJaroslav Jerryno Novotny

                      39.3k176155




                      39.3k176155























                          1












                          $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?






                          share|improve this answer









                          $endgroup$


















                            1












                            $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?






                            share|improve this answer









                            $endgroup$
















                              1












                              1








                              1





                              $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?






                              share|improve this answer









                              $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?







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered 20 hours ago









                              Piotr KowalczykPiotr Kowalczyk

                              765




                              765























                                  0












                                  $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)






                                  share|improve this answer








                                  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$


















                                    0












                                    $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)






                                    share|improve this answer








                                    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$
















                                      0












                                      0








                                      0





                                      $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)






                                      share|improve this answer








                                      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)







                                      share|improve this answer








                                      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.









                                      share|improve this answer



                                      share|improve this answer






                                      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.























                                          0












                                          $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.






                                          share|improve this answer









                                          $endgroup$


















                                            0












                                            $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.






                                            share|improve this answer









                                            $endgroup$
















                                              0












                                              0








                                              0





                                              $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.






                                              share|improve this answer









                                              $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.







                                              share|improve this answer












                                              share|improve this answer



                                              share|improve this answer










                                              answered 1 hour ago









                                              dr. Sybrendr. Sybren

                                              5,55111239




                                              5,55111239






























                                                  draft saved

                                                  draft discarded




















































                                                  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.




                                                  draft saved


                                                  draft discarded














                                                  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





















































                                                  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







                                                  Popular posts from this blog

                                                  Installing LyX: “No textclass is found.”LyX installation error- text class not found- 'Reconfigure' or...

                                                  (1602) Indiana Índice Designación y nombre Características orbitales Véase...

                                                  Universidad Autónoma de Occidente Índice Historia Campus Facultades Programas Académicos Medios de...