The get_highest_row() method has been deprecated, you can get the highest row or column by calling the max_row or max_column properties of the worksheet.
ws=wb.get_sheet_by_name('Sheet1')
print(ws.max_row)
Answer from idemello on Stack Overflowopenpyxl - 'NoneType' object has no attribute 'max_row' - Stack Overflow
openpyxl - Python script having errorr 'NoneType' object has no attribute 'max_row' - Stack Overflow
python - AttributeError: 'property' object has no attribute - Stack Overflow
python 2.7 - Openpyxl AttributeError - Stack Overflow
Your issue is nothing to do with max_row, the error is saying that there is no max_row available on an object which is NoneType, which indicates that the line workbook = load_workbook(directory) is not working correctly.
I would suggest looking at whatever directory is, because it seems to be empty.
Form the documentation of workbook.active:
Get the currently active sheet or None
Your workbook does not have an active sheet. As a result, ws = workbook.active sets ws to None instead of a worksheet. This causes ws.max_row to fail because it only works on worksheets.
You either have to a) fix your workbook so that it does have an active sheet, or b) do not precede if you load a workbook without an active sheet.
workbook = load_workbook(directory)
ws = workbook.active
if ws is None:
return # or `continue` a loop, `raise` an exception, `sys.exit` the program, ...
max_row = ws.max_row
In addition to needing to inherit from object, properties only work on instances.
a = A()
a.db.doSomething("blah")
To make a property work on the class, you can define a metaclass. (A class is an instance of a metaclass, so properties defined on the metaclass work on the class, just as properties defined on a class work on an instance of that class.)
You aren't using classes correctly. A class is (normally) two things:
- A factory for creating a family of related objects
- A definition of the common behaviour of those objects
These related objects are the instances of the class. Normal methods are invoked on instances of the class, not on the class itself. If you want methods that can be invoked from the class, without an instance, you need to label the methods with @classmethod (or @staticmethod).
However I don't actually know whether properties work when retrieved from a class object. I can't check right now, but I don't think so. The error you are getting is that A.db is retrieving the property object which defines the property itself, it isn't "evaluating" the property to get A.__db. Property objects have no doSomething attribute. Properties are designed to be created in classes as descriptions of how the instances of those classes work.
If you did intend to be working with an instance of A, then you'll need to create one:
my_a = A()
my_a.db.doSomething("blah")
However, this will also fail. You have not correctly written getDB as any kind of method. Normal methods need an argument to represent the instance it was invoked on (traditionally called self):
def getDB(self):
...
Static methods don't, but need a decorator to label them as static:
@staticmethod
def getDB():
...
Class methods need both an argument to receive the class they were invoked on, and a decorator:
@classmethod
def getDB(cls):
...
Your indentation is goofed, and you've mixed tabs and spaces. Run the script with python -tt to verify.
If you’re using python 3+ this may also occur if you’re using private variables that start with double underscore, e.g., self.__yourvariable. Just something to take note of for some of you who may run into this issue.
I'm sure that many people have encountered the following (code for reproduction below) behavior: if during the execution of `@property`, an `AttributeError` is raised and the same class implements `__getattr__` then `__getattr__` is invoked with the name of the property resulting in a confusing message: `AttributeError: 'Foo' object has no attribute 'something'`. If we remove `__getattr__` then we get a more meaningful and correct message: `AttributeError: 'Foo' object has no attribute 'bar'`.
from dataclasses import dataclass
@dataclass
class Foo: val = 'foo_value'
class Test:
def __init__(self):
self.foo = Foo()
def __getattr__(self, name):
return getattr(self.foo, name)
@property
def something(self):
return self.foo.bar
t = Test() t.somethingThe error message is misleading and the behavior catches many people (myself including) in surprise and results in many wasted hours of debugging. I've seen people recommend using a custom decorator (instead of `@property` that catches attribute error) or wrapping your `@property` bodies in `try/except`. But it seems to me that this should be dealt with on language level.
I'm trying to understand a few things:
Is this behavior in Python intentional (i.e. is there a good reason) or just stems from the fact that `__getattr__` is invoked when `AttributeError` is raised when an instance attribute is accessed?
If not intentional, is there a relatively easy way to detect `AttributeErrors` cause by `@property` execution in CPython? If so, why hasn't this been handled on language level?
I've searched CPython issues on Github and I saw someone trying to correct documentation but couldn't find issues asking about this behavior or suggestions to fix - am I missing something?