44import importlib
55import re
66from pathlib import Path
7- from typing import Dict , List , Set , Tuple , TypedDict , cast
7+ from typing import Dict , List , TypedDict , cast
88
99import pytest
1010
@@ -23,60 +23,52 @@ def project_root(pytestconfig: pytest.Config) -> Path:
2323 return pytestconfig .rootpath
2424
2525
26- def test_client_facades (project_root : Path ) -> None :
26+ def test_facade_version_matches_filename (project_root : Path ) -> None :
27+ ignore_names = dir (_definitions )
28+ for file in (project_root / 'juju' / 'client' ).glob ('_client[0-9]*.py' ):
29+ match = re .search ('_client([0-9]+).py' , file .name )
30+ assert match
31+ version = int (match .group (1 ))
32+ module = importlib .import_module (f'juju.client.{ file .stem } ' )
33+ for cls_name in dir (module ):
34+ if cls_name .startswith ('_' ) or cls_name in ignore_names :
35+ continue
36+ assert getattr (module , cls_name ).version == version
37+
38+
39+ def test_class_name_matches_facade_name (project_root : Path ) -> None :
40+ ignore_names = dir (_definitions )
41+ for file in (project_root / 'juju' / 'client' ).glob ('_client[0-9]*.py' ):
42+ module = importlib .import_module (f'juju.client.{ file .stem } ' )
43+ for cls_name in dir (module ):
44+ if cls_name .startswith ('_' ) or cls_name in ignore_names :
45+ continue
46+ assert getattr (module , cls_name ).name == cls_name .removesuffix ('Facade' )
47+
48+
49+ def test_client_facades_matches_generated_code (project_root : Path ) -> None :
2750 client_facades = cast (ClientFacades , connection .client_facades )
28- good_facades = make_client_facades_from_generated_code (project_root )
51+ expected_facades = make_client_facades_from_generated_code (project_root )
2952 assert {
3053 k : v ['versions' ] for k , v in client_facades .items ()
3154 } == {
32- k : v ['versions' ] for k , v in good_facades .items ()
55+ k : v ['versions' ] for k , v in expected_facades .items ()
3356 }
3457
3558
3659def make_client_facades_from_generated_code (project_root : Path ) -> ClientFacades :
3760 """Return a client_facades dictionary from generated code under project_root.
3861 """
39- files_by_version : List [Tuple [int , Path ]] = []
40- # [(facade_version, Path), ...]
62+ ignore_names = dir (_definitions )
63+ excluded_facades = connection .excluded_facades
64+ facades : Dict [str , List [int ]] = {}
4165 for file in (project_root / 'juju' / 'client' ).glob ('_client[0-9]*.py' ):
42- files_by_version .append ((_version_from_filename (file ), file ))
43- files_by_version .sort ()
44-
45- # _clientN.py files import * from _definitions
46- # so we will ignore any names from there
47- ignore = dir (_definitions )
48-
49- facades_by_version : Dict [int , Set [str ]] = {}
50- # {facade_version: {facade_name, ...}, ...}
51- for version , file in files_by_version :
5266 module = importlib .import_module (f'juju.client.{ file .stem } ' )
53- facades = {
54- name .removesuffix ("Facade" )
55- for name in dir (module )
56- if not (name .startswith ('_' ) or name in ignore )
57- }
58- facades_by_version [version ] = facades
59-
60- # client_facades in connection.py is sorted
61- # so we sort facade names before constructing it
62- first , * rest = facades_by_version .values ()
63- sorted_facade_names : list [str ] = sorted (first .union (* rest ))
64-
65- excluded_facades = connection .excluded_facades
66- client_facades : ClientFacades = {}
67- # {facade_name: {'versions': [1, 2, 3, ...]}, ...}
68- for name in sorted_facade_names :
69- versions : List [int ] = []
70- for version , facades in facades_by_version .items ():
71- if version in excluded_facades .get (name , []):
67+ for cls_name in dir (module ):
68+ if cls_name .startswith ('_' ) or cls_name in ignore_names :
7269 continue
73- if name in facades :
74- versions .append (version )
75- client_facades [name ] = {'versions' : versions }
76- return client_facades
77-
78-
79- def _version_from_filename (path : Path ) -> int :
80- match = re .search ('_client([0-9]+).py' , path .name )
81- assert match
82- return int (match .group (1 ))
70+ cls = getattr (module , cls_name )
71+ if cls .version in excluded_facades .get (cls .name , []):
72+ continue
73+ facades .setdefault (cls .name , []).append (cls .version )
74+ return {name : {'versions' : sorted (facades [name ])} for name in sorted (facades )}
0 commit comments