Last active
          November 29, 2016 18:13 
        
      - 
      
 - 
        
Save eliasdorneles/146eb4726738c8ec63e8e8084749ab43 to your computer and use it in GitHub Desktop.  
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | # How one could go about implementing a check for abstract Python classes | |
| # written in the old style (raise NotImplementedError), | |
| # by looking at the methods bytecode | |
| def is_oldstyle_abstract(cls): | |
| def has_raise_notimplemented_code(func_code): | |
| # this is too magic, I know. | |
| # you can see how it works by disassembling the bytes below: | |
| # | |
| # >>> import dis | |
| # >>> dis.dis(raise_varargs_bytecode) | |
| # 0 RAISE_VARARGS 1 | |
| # 3 LOAD_CONST 0 (0) | |
| # 6 RETURN_VALUE | |
| raise_varargs_bytecode = b'\x82\x01\x00d\x00\x00S' | |
| return (func_code.co_names == ('NotImplementedError',) | |
| and func_code.co_code.endswith(raise_varargs_bytecode)) | |
| import inspect | |
| if not inspect.isclass(cls): | |
| return False | |
| methods = [it for _, it in inspect.getmembers(cls) | |
| if inspect.isfunction(it) or inspect.ismethod(it)] | |
| return any(has_raise_notimplemented_code(m.__code__) for m in methods) | |
| class SomeAbstractClass: | |
| some_class_attr = 1 | |
| def __init__(self): | |
| self.some_instance_attr = 2 | |
| def somemethod1(self): | |
| raise NotImplementedError("Needs filling it in") | |
| def somemethod2(self, a, b): | |
| return a + b | |
| class AnotherAbstractClass: | |
| def abs_method(self): | |
| raise NotImplementedError | |
| class NonAbstractClass(SomeAbstractClass): | |
| some_class_attr = 1 | |
| def __init__(self): | |
| self.some_instance_attr = 2 | |
| def somemethod1(self): | |
| return self.some_instance_attr + self.some_class_attr | |
| def somemethod2(self, a, b): | |
| return a + b | |
| class AnotherNonAbstractClass(object): | |
| def method(self): | |
| return ValueError("oopes") | |
| if __name__ == '__main__': | |
| print(is_oldstyle_abstract(SomeAbstractClass)) | |
| print(is_oldstyle_abstract(AnotherAbstractClass)) | |
| print(is_oldstyle_abstract(NonAbstractClass) == False) | |
| print(is_oldstyle_abstract(AnotherNonAbstractClass) == False) | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment