I just started working with PyCharm Community Edition 2016.3.2 today. Every time I assign a value from my function at_square, it warns me that 'Function at_square doesn't return anything,' but it definitely does in every instance unless an error is raised during execution, and every use of the function is behaving as expected. I want to know why PyCharm thinks it doesn't and if there's anything I can do to correct it. (I know there is an option to suppress the warning for that particular function, but it does so by inserting a commented line in my code above the function, and I find it just as annoying to have to remember to take that out at the end of the project.)
This is the function in question:
def at_square(self, square): """ Return the value at the given square """ if type(square) == str: file, rank = Board.tup_from_an(square) elif type(square) == tuple: file, rank = square else: raise ValueError("Expected tuple or AN str, got " + str(type(square))) if not 0 <= file <= 7: raise ValueError("File out of range: " + str(file)) if not 0 <= rank <= 7: raise ValueError("Rank out of range: " + str(rank)) return self.board[file][rank] If it matters, this is more precisely a method of an object. I stuck with the term 'function' because that is the language PyCharm is using.
My only thought is that my use of error raising might be confusing PyCharm, but that seems too simple. (Please feel free to critique my error raising, as I'm not sure this is the idiomatic way to do it.)
Update: Humorously, if I remove the return line altogether, the warning goes away and returns immediately when I put it back. It also goes away if I replace self.board[file][rank] with a constant value like 8. Changing file or rank to constant values does not remove the warning, so I gather that PyCharm is somehow confused about the nature of self.board, which is a list of 8 other lists.
Update: Per the suggestion of @StephenRauch, I created a minimal example that reflects everything relevant to data assignment done by at_square:
class Obj: def __init__(self): self.nested_list = [[0],[1]] @staticmethod def tup_method(data): return tuple(data) def method(self,data): x,y = Obj.tup_method(data) return self.nested_list[x][y] def other_method(self,data): value = self.method(data) print(value) x = Obj() x.other_method([1,2]) PyCharm doesn't give any warnings for this. In at_square, I've tried commenting out every single line down to the two following:
def at_square(self, square): file, rank = Board.tup_from_an(square) return self.board[file][rank] PyCharm gives the same warning. If I leave only the return line, then and only then does the warning disappear. PyCharm appears to be confused by the simultaneous assignment of file and rank via tup_from_an. Here is the code for that method:
@staticmethod def tup_from_an(an): """ Convert a square in algebraic notation into a coordinate tuple """ if an[0] in Board.a_file_dict: file = Board.a_file_dict[an[0]] else: raise ValueError("Invalid an syntax (file out of range a-h): " + str(an)) if not an[1].isnumeric(): raise ValueError("Invalid an syntax (rank out of range 1-8): " + str(an)) elif int(an[1]) - 1 in Board.n_file_dict: rank = int(an[1]) - 1 else: raise ValueError("Invalid an syntax (rank out of range 1-8): " + str(an)) return file, rank Update: In its constructor, the class Board (which is the parent class for all these methods) saves a reference to the instance in a static variable instance. self.at_square(square) gives the warning, while Board.instance.at_square(square) does not. I'm still going to use the former where appropriate, but that could shed some light on what PyCharm is thinking.
fileas a variable name, and PyCharm will complain about that.fileas a variable name. That is a file as in chess terminology. Thank you for the reference to Minimal, Complete, and Verifiable examples. I learn more about SO every time I post. I'm not sure how I would recreate this, but I will take a stab at it.self.board?