0

I have written some code in Python involving type checks, for safety, but one of them is failing consistently in one spot, but also working in nearly the same spot.

This check works in the Point class:

def __repr__(self) :
    print('we be an instance: {}'.format(isinstance(self,Point)))
    return "(point: state:{}; conns:{})".format(Conversion.getStateAsStr(self), connections[self])

and prints out we be an instance: true successfully.

However, the method Conversion.getStateAsStr is reporting that the given object is not a Point:

def getStateAsStr(p) :
    if not isinstance(p, Point) :
        raise TypeError("Non-point")
    if p.state : # state is a var in Point
        return "On"
    return "Off"

import pointsys
from pointsys import Point

A TypeError is raised consistently when trying to repr() or str() a Point. What is going on, and how do I fix it?

Edit: The entire Conversion.py currently consists of the above getStateAsStr snippet. The imports are at the bottom to prevent errors with cyclic imports.

VERY IMPORTANT: If run from Conversion.py, it works like a charm. Running from the pointsys file produces the TypeError from getStateAsStr

Here is the entire pointsys.py file with the Point class:

connections = {}

def writeConnection(point, connList) :
    connections[point] = connList

def addConnection(point, point2) :
    if point2 not in connections[point] :
        connections[point].append(point2)
    else :
        print("Skipping point {}".format(point2))

def remConnection(point, point2) :
    connections[point].remove(point2)

class Point():

    def __init__(self) :
        self.state = Off
        writeConnection(self, [])

    def __repr__(self) :
        print('we be an instance: {}'.format(isinstance(self,Point)))
        return "(point: state:{}; conns:{})".format(Conversion.getStateAsStr(self), connections[self])

    """

    Makes or removes a connection between this point and p2
    """
    def markConnection(self, p2, connected) :
        if connected :
            addConnection(self, p2)
        elif not connected :
            remConnection(self, p2)
    """

    Returns if this point is connected to p2
    """
    def isConnected(self, p2) :
        return p2 in connections[self]

    """

    Sets the state of this point and it's connections
    """
    def pushState(self, state) :
        self.state = state
        for connection in connections[self][:] :
            connection.pushState(state)

import Conversion
from State import Off, On, Connected, Unconnected
Octavia Togami
  • 4,186
  • 4
  • 31
  • 49
  • 3
    I tried to replicate the error you're getting with a basic Point class but I haven't been able to. I'm guessing you have omitted some code and that code is what's causing your problem. Can you post a more complete code sample? – Taylan Aydinli Nov 04 '13 at 14:51
  • As far as I can understand, pointsys is some internal module/package you've developed and are using. You are also using something called Conversion. There's still a lot of info missing. I think you don't want to share the internal implementation of the project, and you are right. But without seeing some of the *structure* of your code, it's very hard to determine the cause of this error. – Taylan Aydinli Nov 04 '13 at 14:56
  • Okay, I will add a bit more. I just didn't want to overburden the question as I have done before. – Octavia Togami Nov 04 '13 at 14:57
  • That's very considerate of you :) But there's a lot of the internals missing and the issue is definitely in those internals, since this error cannot be reproduced with a basic Point class. – Taylan Aydinli Nov 04 '13 at 14:58
  • What is the code that calls the function `getStateAsStr`? Are you sure you are passing a `Point` instance? – chepner Nov 04 '13 at 15:04
  • It's right in the __repr__ function. The edit I'll be pushing in a sec will help understanding. – Octavia Togami Nov 04 '13 at 15:05
  • Looks like you have a circular dependency (a method in pointsys.Pint depends on some code - `Conversion.getStateAsStr()\=` which in turn depends on `syspoint.Point`. Since such a circular dependancy is not allowed in Python, the code you posted is not your real code (or at least a minimal snippet reproducing your problem). Also I fail to undestand the point of your "typechecking" code - if you think it makes your code "more safe" then you have a lot to learn about Python... Just try to use whatever get passed to your function and let the AttributeError propagate. – bruno desthuilliers Nov 04 '13 at 15:06
  • I've put the code in. Conversion is actually very small as of now. – Octavia Togami Nov 04 '13 at 15:09
  • off topic, but I don't think putting your imports at the bottom will make any difference to cyclic imports. – SpoonMeiser Nov 04 '13 at 15:13
  • @Spoon Weirdly, it does. Check [this question](http://stackoverflow.com/questions/744373/circular-or-cyclic-imports-in-python) – Octavia Togami Nov 04 '13 at 15:16
  • @brunodesthuilliers the cyclic dependency is not a problem, since the existance of those names will only be checked at runtime, not at compile time, which will be after both modules are imported. Cyclic dependencies are typically only a problem when you have code that runs at import time that depends on another module. – SpoonMeiser Nov 04 '13 at 15:17
  • @SpoonMeiser: the cyclic dependency IS an obvious problem as soon as you respect pep08 and put import statements at the top of the modules... BTW : "If a module does exist in sys.modules then an import simply returns that module whether or not it has completed executing. That is the reason why cyclic imports may return modules which appear to be partly empty." – bruno desthuilliers Nov 04 '13 at 15:21
  • @KenzieTogami okay, yes, where imports appear can have an effect. But it will not have any effect on this code, and it won't have an effect on typical modules. I guess doing it that way might make it obvious when you're writing code that would be problematic for cyclic dependencies. But as per that other question, the cyclic import will be a NOP - it only causes an issue if code running at import time needs something from another module in a cyclic loop. That said, it's still a good idea to avoid cycles. – SpoonMeiser Nov 04 '13 at 15:24
  • @KenzieTogami: I copy-pasted your code and it didn't raise a TypeError. Then I moved the import statements to the top and (obviously) got an ImportError. Anyway, I guess your problem is related to this circular import, so my advice is to just put "getStateAsStr" where it belongs, IOW as a method on your Point class - and get rid of this useless "type checcking" which doesn't make your code any safer. – bruno desthuilliers Nov 04 '13 at 15:26
  • Ack, I am wrong - the `from pointsys import Point` line is import-time code that depends on something in the loop. The cyclic dependency wouldn't be a problem if you just refer to `Point` as `pointsys.Point` and skip this line. – SpoonMeiser Nov 04 '13 at 15:28
  • Hmmm. I guess I'll have to rid myself of my overzealous type checking mind. Thanks, I'll post an answer if anything solves it. – Octavia Togami Nov 04 '13 at 15:46
  • Typechecking in Python is really fighting against the language and it's a lost fight - since instance and class attributes can be bound / rebound / unbound at runtime AND the class itself is an attribute instance (so you can change an object's class at runtime - which is a stypid idea but anyway...). – bruno desthuilliers Nov 04 '13 at 16:04

0 Answers0