0

I have following class in file1.py

class api:
  def server(self):
    DEFAULT_SERVER = socket.gethostname()
    try:
      SATELLITE_SERVER = raw_input('Enter RedHat Satellite Server Name [%s]: ' % DEFAULT_SERVER)
    except KeyboardInterrupt:
      print ""
      sys.exit(1)
    if not SATELLITE_SERVER:
      SATELLITE_SERVER = DEFAULT_SERVER
    try:
      SATELLITE_URL = 'http://' + SATELLITE_SERVER + '/rpc/api'
      CLIENT = xmlrpclib.Server(SATELLITE_URL, verbose=0)
      print "Welcome to RedHat Satellite Server %s" % CLIENT.api.systemVersion()
    except socket.error, e:
      print "Incorrect Server Name -", e
      sys.exit(1)
    return CLIENT

  def username(self):
    DEFAULT_LOGIN = getpass.getuser()
    try:
      SATELLITE_LOGIN = raw_input("Enter RedHat Satellite Login Name [%s]: " % DEFAULT_LOGIN)
    except KeyboardInterrupt:
      print ""
      sys.exit(1)
    if not SATELLITE_LOGIN:
      SATELLITE_LOGIN = DEFAULT_LOGIN
    return SATELLITE_LOGIN

  def password(self):
    try:
      SATELLITE_PASSWORD = getpass.getpass("Enter Your Password: ")
    except KeyboardInterrupt:
      print ""
      sys.exit(1)
    if not SATELLITE_PASSWORD:
      self.password()
    return SATELLITE_PASSWORD

  def __init__(self):
    CLIENT = self.server()
    SATELLITE_LOGIN = self.username()
    SATELLITE_PASSWORD = self.password()
    KEY = CLIENT.auth.login(SATELLITE_LOGIN, SATELLITE_PASSWORD)

  def __new__(self):
    return (self.KEY, self.CLIENT)

And I am calling this class in file2.py,

KEY, CLIENT = file1.api()
print KEY
print CLIENT

When I execute the file2.py then I get the error,

Traceback (most recent call last):
  File "./test.py", line 24, in <module>
    KEY, CLIENT = satelliteapi.api()
TypeError: iteration over non-sequence

I am not sure what I am doing wrong, may be something around retuning the values from the class, may be new is not the right way to return in this case. Please help.

  • What does `satlliteapi.api()` return? – Hoopdady Jul 23 '14 at 17:46
  • what version of python is this? – C.B. Jul 23 '14 at 17:47
  • where is `satelliteapi` coming from? Also what are `self.KEY` and `self.CLIENT`? – Padraic Cunningham Jul 23 '14 at 17:49
  • Class instantiation should always return an instance of the class (as you could imagine). If you just want the tuple, why don't you just use a function that creates both objects (CLIENT and KEY) and returns them instead of a class? – jdehesa Jul 23 '14 at 17:51
  • Sorry @Hoopdady and Padraic that was typo, I have corrected that. It is file1.api() –  Jul 23 '14 at 17:54
  • Hi @C.B.the python version is 2.7.5 –  Jul 23 '14 at 17:56
  • This code is attempting to unpack (which involves interation) an instance of ``api`` to assign it to two names, ``KEY`` and ``CLIENT``. Since ``api`` doesn't define an ``__iter__`` method, it is not a sequence that can be iterated over, and this is illegal hence you get the error. – aruisdante Jul 23 '14 at 17:57
  • Also see http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init about why you shouldn't be overriding ``__new__`` like you are. – aruisdante Jul 23 '14 at 17:59

1 Answers1

1

Essentially, overriding __new__ is not the way you should go about doing what you are doing. If you simply want to make it so you can easily unpack the KEY and CLIENT values, you can do the following:

class api(object):
....
def __iter__(self):
    return (value for value in (self.KEY, self.CLIENT))

__iter__ is the special method that defines if a class may be iterated over. It returns an iterator instance (in this case, a generator) that can be used as a 'sequence' representation of an object. This question has a good explanation of the topic.

If you wanted to make it even more explicit, you can do:

class api(object):
....
def get_key_and_client(self):
    return self.KEY, self.CLIENT
def __iter__(self):
    return (value for value in self.get_key_and_client())

This lets you get the same information without needing to actually use the iterator, and makes the iterator an alias of the get_key_and_client() method.

Community
  • 1
  • 1
aruisdante
  • 8,875
  • 2
  • 30
  • 37
  • Got an error `TypeError: __iter__ returned non-iterator of type 'tuple'`after chaning to `__iter__` so end up using the suggestion of @javidcf to use function instead of class. –  Jul 23 '14 at 18:32
  • @SGL Yeah, sorry, I forgot the `__iter__` command wouldn't propagate the unpack to to the returned ``tuple``. I edited the answer to correct, but definitely have a method as per javidcf's answer or my second example is the more clear option. – aruisdante Jul 23 '14 at 18:38