coc.py
coc.py copied to clipboard
Doc fix
finally found the problem with the docs
Can you point to what the commit is with the problem with the docs? Removing slots (I can see the commit, but the code isn't showing up in files changed, so I'm not sure what the issue is there) isn't something I want to do, since they give memory improvements to the dataclasses, and the async-related changes seem to be changing a lot with not much code - are you trying to change the login_with_keys
to match coc.login
? Either way, if we're changing any async-non-async behaviour that'd be a breaking change and I'd want to think hard about when and how to do it. I'll just leave this here for a bit, and if you could clarify what change fixes the docs that'd be great!
The story is a bit longer.
After we merged the raidlog stuff, we noticed, that the docs aren't generated properly. The build failed simply. After some playing around with sphinx I was able to identify the problem. The hero, pet, troops and spell class had a name parameter, but sphinx claimed during the build, that they don't have the attribute.
By defining __slots__
for all those classes, I was able to properly build the docs. But we then noticed, that this fixes the docs, but breaks it for the normal usage. So this was reverted.
At the same time, @Ibo0815 reported a bug which was also related to this part of the code. Together we found out that the problem is in print(p.hero_cls)
(or pet_cls etc).
I looked further into that and found that the error above is related to the problem we have with the documentation. The hero class is a child of DataContainer
which itself is a child of DataContainerMetaClass
. There is a __repr__
definied which relies on cls.name and cls.id being set. but in the non initialized class, this isn't the case. So it breaks during calling Hero.__repr__()
which falls back to DataContainerMetaClass.__repr__()
. I was able to fix it by escaping non set attributes in DataContainerMetaClass.__repr__()
, should work as fix until someone fix this properly.
To give you more context and some example code:
p = await client.get_player('#2PP')
print(p.heroes)
x = p.hero_cls
x1 = x({"name":"test", "level": 2, "maxLevel": 5, "village": "t", "superTroopIsActive": True}, 2)
print('[] type x')
print(type(x))
print('[] type x1')
print(type(x1))
print('[] print x')
print(x)
print('[] print x1')
print(x1)
Note: I added into all the repr functions here a print statement to see what is called.
returns (with added fix)
[]
[] type x
<class 'coc.abc.DataContainerMetaClass'>
[] type x1
DataContainerMetaClass __repr__
<Hero name='not initialized' id='not initialized'>
[] print x
DataContainerMetaClass __repr__
<Hero name='not initialized' id='not initialized'>
[] print x1
DataContainer __repr__
<Hero name='test' level=2 is_active=True>
returns (without fix)
[]
[] type x
<class 'coc.abc.DataContainerMetaClass'>
[] type x1
DataContainerMetaClass __repr__
Traceback (most recent call last):
File "C:\Users\doluk\PycharmProjects\coc.py\test.py", line 245, in <module>
asyncio.run(main(), debug=True)
File "C:\Users\doluk\PycharmProjects\coc.py\pycord\lib\site-packages\nest_asyncio.py", line 35, in run
return loop.run_until_complete(task)
File "C:\Users\doluk\PycharmProjects\coc.py\pycord\lib\site-packages\nest_asyncio.py", line 90, in run_until_complete
return f.result()
File "C:\Users\doluk\AppData\Local\Programs\Python\Python39\lib\asyncio\futures.py", line 201, in result
raise self._exception
File "C:\Users\doluk\AppData\Local\Programs\Python\Python39\lib\asyncio\tasks.py", line 256, in __step
result = coro.send(None)
File "C:\Users\doluk\PycharmProjects\coc.py\test.py", line 156, in main
print(type(x1))
File "C:\Users\doluk\PycharmProjects\coc.py\coc\abc.py", line 154, in __repr__
("name", cls.name ),
AttributeError: type object 'Hero' has no attribute 'name'
returns (with fix and added __str__()
)
The problem doesn't end here. If I now also add a __str__()
function to DataContainerMetaClass
and DataContainer
we can see it gets even more weird when we execute the same code as above.
[]
[] type x
<class 'coc.abc.DataContainerMetaClass'>
[] type x1
DataContainerMetaClass __str__
<Hero name='not initialized' id='not initialized'>
[] print x
DataContainerMetaClass __str__
<Hero name='not initialized' id='not initialized'>
[] print x1
DataContainer __str__
<Hero name='test' level=2 is_active=True>
TL;DR
Something in those metaclass construct is broken. My proposal would be to completely remove the metaclass construct and define Hero, Pet , Spell and Troop as individual classes. The amount of code lines we save with the metaclasses isn't that big in my opinion to deal with all the problems we currently have. Also in the recent state, we don't have to carry over some unused attributes for the consistency with the metaclass like is_active
for non supertroops or training costs.
@mathsman5133 @majordoobie
are you trying to change the login_with_keys to match coc.login? Either way, if we're changing any async-non-async behaviour that'd be a breaking change and I'd want to think hard about when and how to do it. Yes, I had that included in one commit sadly. We can seperate it out. But at the end it just makes
Client.login_with_keys()
async similiar toClient.login()
. To not break anything, thelogin.login_with_keys()
was edited similiar tologin.login()
. So unless you useClient.login_with_keys()
directly, this change is not breaking.
The code change in the docs is just an edit of the example to update it to the newest recommended way to login.