-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[apiclient] restructure models and managers #982
Conversation
Do we have test runs/reports on restructured suites? |
This change will not affect to existing test cases, so I didn't trigger any CI build for it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test will fail when import typing.Final
, which is new in python 3.8
and not compatible to our current env.
Ref. harvester-runtests#410
...
'/var/harvester_test_410_harvester-runtests/.tox/py36/lib64/python3.6/site-packages/yaml/__init__.py'>
apiclient/harvester_api/models/base.py:1: in <module>
from typing import Final
E ImportError: cannot import name 'Final'
...
As we are leaving python 3.6 (#970), I will add a temporarily fix to let it compatible with 3.6, then we can revert the commit when we change to use 3.10+ (Executed on |
Hi, could you help to confirm And the 412 report looks empty. 411
412
|
412 will not have test results is expected, it is targeting to execute test cases not existing (then it would be same as —collect-only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As comments, please help to add comment on key properties and some more unittests to increase readability, it will be helpful.
self.assertEqual(B0.for_version('1.2.0'), B120) | ||
self.assertEqual(B0.for_version('1.1.3'), B113) | ||
self.assertEqual(B0.for_version('1.3.0'), B130) | ||
self.assertEqual(B0.for_version('1.1.4'), B114) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to have multi-manager inheritance case which are more close to real usage in code.
for example
>>> from testo import BaseManager
>>> class AManager(BaseManager):
... pass
...
>>> class AManager_110(AManager):
... support_to = '1.1.0'
...
>>> class BManager(BaseManager):
... pass
...
>>> class BManager_110(BManager):
... support_to = '1.1.0'
...
>>> BManager.for_version('1.1.0') == BManager_110
True
>>> BManager.for_version('1.2.0') == BManager_110
True
>>> BManager.for_version('1.0.0') != BManager_110
True
>>> BManager.for_version('1.1.0') != AManager_110
True
>>> AManager.for_version('1.1.0') == AManager_110
True
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unit test is focusing on test class method for_version
, it is designed to seeking the most fit sub-class.
For multiple managers inherited from the BaseManager
, is the flexibility of the class method, so it would not be included in unit test. (out of scope)
It is very general that we will not test inherited class behavior, because it's the contract of inheritance, derived class should follow parents signature and it's parents methods should always able to be used in derived.
The code snippet will help you to understand how to leverage the inheritance to support multiple version: (venv) lanfon@lanfonsuse:~/dev_src/tests> python
Python 3.10.2 (main, Jan 19 2022, 22:05:06) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from harvester_api.managers import HostManager as hm, ImageManager as im
>>> hm._sub_classes[hm] # the attribute `_sub_classes` inherited from BaseManager
[<class 'harvester_api.managers.hosts.HostManager'>]
>>> im._sub_classes[im]
[<class 'harvester_api.managers.images.ImageManager'>]
>>> class H2(hm):
... support_to = '1.1.0'
...
>>> hm._sub_classes[hm] # when new class derived, it would be added into the dict by `__init_sub_classes__`
[<class 'harvester_api.managers.hosts.HostManager'>, <class '__main__.H2'>]
>>> hm._sub_classes[H2] # The list for derived class `H2` would also be added
[<class '__main__.H2'>]
>>>
>>> class H3(H2):
... support_to = '1.2.0'
...
>>> hm._sub_classes[hm]
[<class 'harvester_api.managers.hosts.HostManager'>, <class '__main__.H2'>, <class '__main__.H3'>]
>>> hm._sub_classes[H2] # when H3 inherited from H2, all its parents will have it
[<class '__main__.H2'>, <class '__main__.H3'>]
>>> hm.for_version('1.2.0') # the `for_version` is going to the target version in the class' sub classes (by using `is_support`)
<class '__main__.H3'>
>>> H3.for_version('1.1.0') # so if its sub class don't have any suitable version, we will return itself
<class '__main__.H3'> In the You can check #979 for the similar case (inheritance and seeking) be used in terraform provider version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Changes
managers.py
managers
__init__.py
for the folder as a modulebase.py
forBaseManager
and constants__init__.py
)models.py
models
__init__.py
for the folder as a modulebase.py
for constants.pyi
files intomanagers
folder for related managers.pyi
files intomodels
folder for related specsapi.pyi
forapi.py
py.typed
to mark the lib having type information1api.load_managers
manager.for_version
The restructure is necessary that we are going to support multiple cluster version in the API with new introduced method
api.load_managers
, for implement new api operations, we can simply inherit old managers to overwrite old version. (you can check thetests/test_managers.py::test_for_version
for more details.Footnotes
PEP561 https://peps.python.org/pep-0561/ ↩