nodes: 0, module; 1, function_definition; 2, function_name:load_drops; 3, parameters; 4, block; 5, identifier:self; 6, identifier:dropin; 7, expression_statement; 8, expression_statement; 9, try_statement; 10, if_statement; 11, if_statement; 12, return_statement; 13, comment:"""Load `drops` from the given dropin.
  
          Args:
              dropin (string): path of a dropin, e.g. dropin.auth
  
          Returns:
              An iterable contains the drops object in the given dropin
  
          This method load drops object by some sort of convension. For example, assuming
          we want to load drops type `models` from dropin `dropin.articls`. The drops are
          discoveried with the following sequence::
  
              import dropin.articles
              drops = dropin.articles.models
  
          if anything goes wrong, next try is ::
  
              import dropin.articles.models as drops
  
          if the current drops object has attribute **__drops__** ::
  
              drops = drops.__drops__
  
          if the current drops object is a callable ::
  
              drops = drops()
  
          if not drops was found, an empty list is returned.
  
          """; 14, assignment; 15, block; 16, except_clause; 17, call; 18, block; 19, call; 20, block; 21, boolean_operator; 22, identifier:obj; 23, call; 24, expression_statement; 25, identifier:AttributeError; 26, block; 27, identifier:hasattr; 28, argument_list; 29, expression_statement; 30, identifier:callable; 31, argument_list; 32, expression_statement; 33, identifier:drops; 34, list; 35, identifier:load_object; 36, argument_list; 37, assignment; 38, try_statement; 39, identifier:drops; 40, string; 41, assignment; 42, identifier:drops; 43, assignment; 44, identifier:dropin; 45, identifier:drops; 46, call; 47, block; 48, except_clause; 49, string_content:__drops__; 50, identifier:drops; 51, attribute; 52, identifier:drops; 53, call; 54, identifier:getattr; 55, argument_list; 56, expression_statement; 57, identifier:ImportError; 58, block; 59, identifier:drops; 60, identifier:__drops__; 61, identifier:drops; 62, argument_list; 63, identifier:obj; 64, attribute; 65, assignment; 66, expression_statement; 67, attribute; 68, identifier:self; 69, identifier:drops_type; 70, identifier:drops; 71, call; 72, assignment; 73, identifier:self; 74, identifier:app; 75, identifier:load_object; 76, argument_list; 77, identifier:drops; 78, None; 79, binary_operator:'%s.%s' % (dropin, self.drops_type); 80, string; 81, tuple; 82, string_content:%s.%s; 83, identifier:dropin; 84, attribute; 85, identifier:self; 86, identifier:drops_type
code: def load_drops(self, dropin):
          """Load `drops` from the given dropin.
  
          Args:
              dropin (string): path of a dropin, e.g. dropin.auth
  
          Returns:
              An iterable contains the drops object in the given dropin
  
          This method load drops object by some sort of convension. For example, assuming
          we want to load drops type `models` from dropin `dropin.articls`. The drops are
          discoveried with the following sequence::
  
              import dropin.articles
              drops = dropin.articles.models
  
          if anything goes wrong, next try is ::
  
              import dropin.articles.models as drops
  
          if the current drops object has attribute **__drops__** ::
  
              drops = drops.__drops__
  
          if the current drops object is a callable ::
  
              drops = drops()
  
          if not drops was found, an empty list is returned.
  
          """
          obj = load_object(dropin)
          try:
              drops = getattr(obj, self.drops_type)
          except AttributeError:
              try:
                  drops = load_object('%s.%s' % (dropin, self.drops_type))
              except ImportError:
                  drops = None
          if hasattr(drops, '__drops__'):
              drops = drops.__drops__
          if callable(drops):
              drops = drops(self.app)
          return drops or []