omlish 0.0.0.dev325__py3-none-any.whl → 0.0.0.dev326__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev325'
2
- __revision__ = 'd3d23171448ce4b4fac00e71f7a1c242db8228f9'
1
+ __version__ = '0.0.0.dev326'
2
+ __revision__ = 'c2dd50f058b892485bea3f5ed42bfb88c8439c3c'
3
3
 
4
4
 
5
5
  #
@@ -99,7 +99,7 @@ class Project(ProjectBase):
99
99
  'aiosqlite ~= 0.21',
100
100
  'asyncpg ~= 0.30',
101
101
 
102
- 'apsw ~= 3.49',
102
+ 'apsw ~= 3.50',
103
103
 
104
104
  'sqlean.py ~= 3.49',
105
105
 
omlish/docker/all.py CHANGED
@@ -13,6 +13,10 @@ from .compose import ( # noqa
13
13
  get_compose_port,
14
14
  )
15
15
 
16
+ from .consts import ( # noqa
17
+ DOCKER_FOR_MAC_HOSTNAME,
18
+ )
19
+
16
20
  from .detect import ( # noqa
17
21
  DOCKER_HOST_PLATFORM_KEY,
18
22
  get_docker_host_platform,
@@ -5,6 +5,7 @@ TODO:
5
5
  - dynamic switching (skip docker if not running, skip online if not online, ...)
6
6
  """
7
7
  import dataclasses as dc
8
+ import enum
8
9
  import typing as ta
9
10
 
10
11
  import pytest
@@ -21,20 +22,27 @@ Configable: ta.TypeAlias = pytest.FixtureRequest | pytest.Config
21
22
  ##
22
23
 
23
24
 
25
+ class SwitchState(enum.Enum):
26
+ ENABLED = enum.auto()
27
+ DISABLED = enum.auto()
28
+ ONLY = enum.auto()
29
+ IF_SINGLE = enum.auto()
30
+
31
+
24
32
  @dc.dataclass(frozen=True, eq=False)
25
33
  class Switch:
26
34
  name: str
27
- _default_enabled: bool | ta.Callable[[], bool]
35
+ _default_state: SwitchState | ta.Callable[[pytest.Session], SwitchState]
28
36
 
29
37
  _: dc.KW_ONLY
30
38
 
31
39
  add_marks: ta.Sequence[ta.Any] | None = None
32
40
 
33
- def default_enabled(self) -> bool:
34
- if isinstance(e := self._default_enabled, bool):
41
+ def default_state(self, session: pytest.Session) -> SwitchState:
42
+ if isinstance(e := self._default_state, SwitchState):
35
43
  return e
36
44
  elif callable(e):
37
- return check.isinstance(e(), bool)
45
+ return check.isinstance(e(session), SwitchState)
38
46
  else:
39
47
  raise TypeError(e)
40
48
 
@@ -46,27 +54,27 @@ class Switch:
46
54
  SWITCHES: ta.Sequence[Switch] = [
47
55
  Switch(
48
56
  'name',
49
- docker.has_cli,
57
+ lambda _: SwitchState.ENABLED if docker.has_cli() else SwitchState.DISABLED,
50
58
  ),
51
59
 
52
60
  Switch(
53
61
  'docker-guest',
54
- docker.is_likely_in_docker,
62
+ lambda _: SwitchState.ENABLED if docker.is_likely_in_docker() else SwitchState.DISABLED,
55
63
  ),
56
64
 
57
65
  Switch(
58
66
  'online',
59
- True,
67
+ SwitchState.ENABLED,
60
68
  ),
61
69
 
62
70
  Switch(
63
71
  'integration',
64
- True,
72
+ SwitchState.ENABLED,
65
73
  ),
66
74
 
67
75
  Switch(
68
76
  'high-mem',
69
- True,
77
+ SwitchState.ENABLED,
70
78
  add_marks=[
71
79
  # https://pytest-xdist.readthedocs.io/en/latest/distribution.html
72
80
  pytest.mark.xdist_group('high-mem'),
@@ -76,7 +84,7 @@ SWITCHES: ta.Sequence[Switch] = [
76
84
 
77
85
  Switch(
78
86
  'slow',
79
- False,
87
+ SwitchState.IF_SINGLE,
80
88
  ),
81
89
  ]
82
90
 
@@ -88,12 +96,10 @@ SWITCHES_BY_ATTR: ta.Mapping[str, Switch] = col.make_map_by(lambda sw: sw.attr,
88
96
  ##
89
97
 
90
98
 
91
- SwitchState: ta.TypeAlias = bool | ta.Literal['only']
92
-
93
99
  SWITCH_STATE_OPT_PREFIXES: ta.Mapping[SwitchState, str] = {
94
- True: '--',
95
- False: '--no-',
96
- 'only': '--only-',
100
+ SwitchState.ENABLED: '--',
101
+ SwitchState.DISABLED: '--no-',
102
+ SwitchState.ONLY: '--only-',
97
103
  }
98
104
 
99
105
 
@@ -132,53 +138,99 @@ def get_specified_switches(obj: Configable) -> dict[Switch, SwitchState]:
132
138
  return ret
133
139
 
134
140
 
141
+ @dc.dataclass(frozen=True)
142
+ class ItemSwitches:
143
+ switches: frozenset[Switch]
144
+ not_switches: frozenset[Switch]
145
+
146
+
147
+ def get_item_switches(item: pytest.Item) -> ItemSwitches:
148
+ return ItemSwitches(
149
+ frozenset(sw for sw in SWITCHES if sw.attr in item.keywords),
150
+ frozenset(sw for sw in SWITCHES if ('not_' + sw.attr) in item.keywords),
151
+ )
152
+
153
+
135
154
  @register
136
155
  class SwitchesPlugin:
137
- def pytest_configure(self, config):
138
- for sw in SWITCHES:
139
- config.addinivalue_line('markers', f'{sw.attr}: mark test as {sw.attr}')
140
- config.addinivalue_line('markers', f'not_{sw.attr}: mark test as not {sw.attr}')
141
-
142
156
  def pytest_addoption(self, parser):
143
157
  for sw in SWITCHES:
144
158
  parser.addoption(f'--no-{sw.name}', action='store_true', default=False, help=f'disable {sw.name} tests')
145
159
  parser.addoption(f'--{sw.name}', action='store_true', default=False, help=f'enables {sw.name} tests')
146
160
  parser.addoption(f'--only-{sw.name}', action='store_true', default=False, help=f'enables only {sw.name} tests') # noqa
147
161
 
148
- def pytest_collection_modifyitems(self, config, items):
149
- switch_states: dict[Switch, SwitchState] = {
150
- **{
151
- sw: sw.default_enabled()
162
+ def pytest_configure(self, config):
163
+ for sw in SWITCHES:
164
+ config.addinivalue_line('markers', f'{sw.attr}: mark test as {sw.attr}')
165
+ config.addinivalue_line('markers', f'not_{sw.attr}: mark test as not {sw.attr}')
166
+
167
+ class _States:
168
+ def __init__(self, session: pytest.Session) -> None:
169
+ super().__init__()
170
+
171
+ self.session = session
172
+
173
+ self.default_states_by_switch: dict[Switch, SwitchState] = {
174
+ sw: sw.default_state(session)
152
175
  for sw in SWITCHES
153
- },
154
- **get_specified_switches(config),
155
- }
176
+ }
177
+
178
+ self.states_by_switch: dict[Switch, SwitchState] = {
179
+ **self.default_states_by_switch,
180
+ **get_specified_switches(session.config),
181
+ }
156
182
 
157
- inv_switch_states: dict[SwitchState, list[Switch]] = col.multi_map((st, sw) for sw, st in switch_states.items())
158
- true_switches = frozenset(inv_switch_states.get(True, ()))
159
- false_switches = frozenset(inv_switch_states.get(False, ()))
160
- only_switches = frozenset(inv_switch_states.get('only', ()))
183
+ self.switch_sets_by_state: dict[SwitchState, frozenset[Switch]] = {
184
+ st: frozenset(sws)
185
+ for st, sws in col.multi_map(
186
+ (st, sw)
187
+ for sw, st in self.states_by_switch.items()
188
+ ).items()
189
+ }
161
190
 
162
- def process(item):
163
- item_switches = {sw for sw in SWITCHES if sw.attr in item.keywords}
164
- item_not_switches = {sw for sw in SWITCHES if ('not_' + sw.attr) in item.keywords}
191
+ _states_key: ta.ClassVar[pytest.StashKey[_States]] = pytest.StashKey[_States]()
165
192
 
166
- for sw in item_switches:
193
+ def pytest_sessionstart(self, session):
194
+ session.stash[self._states_key] = self._States(session)
195
+
196
+ def pytest_collection_modifyitems(self, config, items):
197
+ def process_item(item):
198
+ state: SwitchesPlugin._States = item.session.stash[self._states_key]
199
+
200
+ item_switches = get_item_switches(item)
201
+
202
+ for sw in item_switches.switches:
167
203
  for mk in sw.add_marks or []:
168
204
  item.add_marker(mk)
169
205
 
170
- if only_switches:
171
- if not any(sw in only_switches for sw in item_switches):
172
- item.add_marker(pytest.mark.skip(reason=f'skipping switches {item_switches}'))
206
+ if (only_switches := state.switch_sets_by_state.get(SwitchState.ONLY)) is not None:
207
+ if not any(sw in only_switches for sw in item_switches.switches):
208
+ item.add_marker(pytest.mark.skip(
209
+ reason=f'skipping switches ({tuple(sw.name for sw in item_switches.switches)!r} (only)',
210
+ ))
173
211
  return
174
212
 
175
- for sw in item_switches:
176
- if sw in false_switches:
177
- item.add_marker(pytest.mark.skip(reason=f'skipping switches {sw}'))
213
+ disabled_switches = state.switch_sets_by_state.get(SwitchState.DISABLED, frozenset())
214
+ for sw in item_switches.switches:
215
+ if sw in disabled_switches:
216
+ item.add_marker(pytest.mark.skip(reason=f'skipping switch {sw.name!r} (disabled)'))
178
217
 
179
- for sw in item_not_switches:
180
- if sw in true_switches:
181
- item.add_marker(pytest.mark.skip(reason=f'skipping switches {sw}'))
218
+ enabled_switches = state.switch_sets_by_state.get(SwitchState.ENABLED, frozenset())
219
+ for sw in item_switches.not_switches:
220
+ if sw in enabled_switches:
221
+ item.add_marker(pytest.mark.skip(reason=f'skipping switch {sw.name!r} (not-enabled)'))
182
222
 
183
223
  for item in items:
184
- process(item)
224
+ process_item(item)
225
+
226
+ def pytest_collection_finish(self, session):
227
+ state: SwitchesPlugin._States = session.stash[self._states_key]
228
+
229
+ if_single_switches = state.switch_sets_by_state.get(SwitchState.IF_SINGLE, frozenset())
230
+
231
+ if len(session.items) > 1:
232
+ for item in session.items:
233
+ item_switches = get_item_switches(item)
234
+ for sw in item_switches.switches:
235
+ if sw in if_single_switches:
236
+ item.add_marker(pytest.mark.skip(reason=f'skipping switch {sw.name!r} (not-single)'))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev325
3
+ Version: 0.0.0.dev326
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -39,7 +39,7 @@ Requires-Dist: pymysql~=1.1; extra == "all"
39
39
  Requires-Dist: aiomysql~=0.2; extra == "all"
40
40
  Requires-Dist: aiosqlite~=0.21; extra == "all"
41
41
  Requires-Dist: asyncpg~=0.30; extra == "all"
42
- Requires-Dist: apsw~=3.49; extra == "all"
42
+ Requires-Dist: apsw~=3.50; extra == "all"
43
43
  Requires-Dist: sqlean.py~=3.49; extra == "all"
44
44
  Requires-Dist: duckdb~=1.3; extra == "all"
45
45
  Requires-Dist: markupsafe~=3.0; extra == "all"
@@ -87,7 +87,7 @@ Requires-Dist: pymysql~=1.1; extra == "sqldrivers"
87
87
  Requires-Dist: aiomysql~=0.2; extra == "sqldrivers"
88
88
  Requires-Dist: aiosqlite~=0.21; extra == "sqldrivers"
89
89
  Requires-Dist: asyncpg~=0.30; extra == "sqldrivers"
90
- Requires-Dist: apsw~=3.49; extra == "sqldrivers"
90
+ Requires-Dist: apsw~=3.50; extra == "sqldrivers"
91
91
  Requires-Dist: sqlean.py~=3.49; extra == "sqldrivers"
92
92
  Requires-Dist: duckdb~=1.3; extra == "sqldrivers"
93
93
  Provides-Extra: templates
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=orgsRvtpHu8tdhaCvlP9v3P495OJopYYiHKjK68WtWg,8587
2
- omlish/__about__.py,sha256=JzG831_Ux1NSldRoOCPf4bfkuXTYQjLmFHyetsWKjoM,3478
2
+ omlish/__about__.py,sha256=UoJfm6_oqNZqXXNxGuPSwyPZfi4oLWZWRWwT6V3IWhw,3478
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -228,7 +228,7 @@ omlish/dispatch/functions.py,sha256=cwNzGIg2ZIalEgn9I03cnJVbMTHjWloyDTaowlO3UPs,
228
228
  omlish/dispatch/impls.py,sha256=K_okKvpZml4NkTHJmTVyMQSrIaIJcqTEgkreGwukaOw,1895
229
229
  omlish/dispatch/methods.py,sha256=GdVsC-Zo3N-OorE0mr3lFI70dATkD2aWqZ8TvExiR5k,9297
230
230
  omlish/docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
231
- omlish/docker/all.py,sha256=xXRgJgLGPwAtr7bDMJ_Dp9jTfOwfGvohNhc6LsoELJc,514
231
+ omlish/docker/all.py,sha256=t5jBNZAzqCoB05-nwCuSZ6C3PBEBD6T3wsIJvIXJaRg,576
232
232
  omlish/docker/cli.py,sha256=gtb9kitVfGnd4cr587NsVVk8D5Ok5y5SAsqD_SwGrSA,2565
233
233
  omlish/docker/compose.py,sha256=4drmnGQzbkOFJ9B6XSg9rnXkJeZz1ETmdcMe1PE790U,1237
234
234
  omlish/docker/consts.py,sha256=wvwfUtEFrEWZKfREWqSMrx8xjjl8P5MNUSF6qzzgJHY,70
@@ -753,7 +753,7 @@ omlish/testing/pytest/plugins/pydevd.py,sha256=5moE64LrNRV6gKRaeCuONDiwuh-4UFxJP
753
753
  omlish/testing/pytest/plugins/repeat.py,sha256=jiZCI-17042jBvUEbZCxNwqWtr7s3EhTBSeSHh_Uz4E,497
754
754
  omlish/testing/pytest/plugins/skips.py,sha256=eMir_n777Kk2BvOwjQzRROKL4iAMYKSHFwWCHJ-bdPI,1040
755
755
  omlish/testing/pytest/plugins/spacing.py,sha256=tzq-L-exegHe2BImumkYIsVcUwpUUhLJJOuSrsKDuCU,706
756
- omlish/testing/pytest/plugins/switches.py,sha256=t4kzdB_4Isp_cUtseKKMGHZ6cTriX3VGrzuqmNHCgMg,5210
756
+ omlish/testing/pytest/plugins/switches.py,sha256=z3TKe2NHBOaa_cmarWTRJo519iCNDff4e0XSfHkajHU,7365
757
757
  omlish/testing/pytest/plugins/utils.py,sha256=L5C622UXcA_AUKDcvyh5IMiRfqSGGz0McdhwZWvfMlU,261
758
758
  omlish/testing/pytest/plugins/asyncs/__init__.py,sha256=TTNhFmP_krug1973sq_bpWBTIvg68-1nbuVLSs92Z6k,41
759
759
  omlish/testing/pytest/plugins/asyncs/consts.py,sha256=0NOCkzV43dOu3u97BqYMQ4mPG8JuFncpWibkOZpCqX4,55
@@ -857,9 +857,9 @@ omlish/typedvalues/holder.py,sha256=ZTnHiw-K38ciOBLEdwgrltr7Xp8jjEs_0Lp69DH-G-o,
857
857
  omlish/typedvalues/marshal.py,sha256=hWHRLcrGav7lvXJDtb9bNI0ickl4SKPQ6F4BbTpqw3A,4219
858
858
  omlish/typedvalues/reflect.py,sha256=Ih1YgU-srUjsvBn_P7C66f73_VCvcwqE3ffeBnZBgt4,674
859
859
  omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
860
- omlish-0.0.0.dev325.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
861
- omlish-0.0.0.dev325.dist-info/METADATA,sha256=aK9jNtSuLUVs0t58mcypYSFehrEGznoT0CnKud8bUcc,4416
862
- omlish-0.0.0.dev325.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
863
- omlish-0.0.0.dev325.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
864
- omlish-0.0.0.dev325.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
865
- omlish-0.0.0.dev325.dist-info/RECORD,,
860
+ omlish-0.0.0.dev326.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
861
+ omlish-0.0.0.dev326.dist-info/METADATA,sha256=TU88zs941JZBexTmeINDhh8lNdgCPbBLmdDZ8E2kV5I,4416
862
+ omlish-0.0.0.dev326.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
863
+ omlish-0.0.0.dev326.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
864
+ omlish-0.0.0.dev326.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
865
+ omlish-0.0.0.dev326.dist-info/RECORD,,