devopsdriver 0.1.51__tar.gz → 0.1.52__tar.gz

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.
Files changed (50) hide show
  1. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/PKG-INFO +3 -3
  2. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/README.md +1 -1
  3. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/__init__.py +1 -1
  4. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/azureobject.py +2 -2
  5. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/workitem/client.py +10 -10
  6. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/workitem/wiql.py +20 -7
  7. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/sendmail.py +12 -4
  8. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/settings.py +13 -11
  9. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver.egg-info/PKG-INFO +3 -3
  10. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver.egg-info/requires.txt +1 -1
  11. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/pyproject.toml +1 -1
  12. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_workitem_wiql.py +4 -4
  13. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/LICENSE +0 -0
  14. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/__init__.py +0 -0
  15. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/builds/__init__.py +0 -0
  16. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/builds/build.py +0 -0
  17. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/builds/client.py +0 -0
  18. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/clients.py +0 -0
  19. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/pipeline/__init__.py +0 -0
  20. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/pipeline/client.py +0 -0
  21. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/pipeline/log.py +0 -0
  22. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/pipeline/pipeline.py +0 -0
  23. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/pipeline/run.py +0 -0
  24. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/timestamp.py +0 -0
  25. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/azdo/workitem/__init__.py +0 -0
  26. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/dataobject.py +0 -0
  27. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/github/__init__.py +0 -0
  28. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/github/client.py +0 -0
  29. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/manage_settings.py +0 -0
  30. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/template.py +0 -0
  31. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver/templates/manage_settings.txt.mako +0 -0
  32. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver.egg-info/SOURCES.txt +0 -0
  33. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver.egg-info/dependency_links.txt +0 -0
  34. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver.egg-info/entry_points.txt +0 -0
  35. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/devopsdriver.egg-info/top_level.txt +0 -0
  36. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/setup.cfg +0 -0
  37. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_azureobject.py +0 -0
  38. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_build.py +0 -0
  39. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_build_client.py +0 -0
  40. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_clients.py +0 -0
  41. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_pipeline.py +0 -0
  42. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_pipeline_client.py +0 -0
  43. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_pipeline_run.py +0 -0
  44. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_timestamp.py +0 -0
  45. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_azure_workitem_client.py +0 -0
  46. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_dataobject.py +0 -0
  47. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_manage_settings.py +0 -0
  48. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_sendmail.py +0 -0
  49. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_settings.py +0 -0
  50. {devopsdriver-0.1.51 → devopsdriver-0.1.52}/tests/test_template.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devopsdriver
3
- Version: 0.1.51
3
+ Version: 0.1.52
4
4
  Summary: DevOps tools
5
5
  Author-email: Marc Page <marcallenpage@gmail.com>
6
6
  License: This is free and unencumbered software released into the public domain.
@@ -51,7 +51,7 @@ Requires-Dist: keyring==25.6.0
51
51
  Requires-Dist: setuptools==80.9.0
52
52
  Requires-Dist: azure-devops==7.1.0b4
53
53
  Requires-Dist: Mako==1.3.10
54
- Requires-Dist: PyGithub==2.5.0
54
+ Requires-Dist: PyGithub==2.8.1
55
55
  Provides-Extra: dev
56
56
  Requires-Dist: black>=24.3.0; extra == "dev"
57
57
  Requires-Dist: pylint>=3.1.0; extra == "dev"
@@ -64,7 +64,7 @@ Dynamic: license-file
64
64
  # devops-driver
65
65
 
66
66
  ![status sheild](https://img.shields.io/static/v1?label=status&message=beta&color=blue&style=plastic)
67
- [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.51&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.51/)
67
+ [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.52&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.52/)
68
68
  [![GitHub](https://img.shields.io/github/license/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
69
69
  [![GitHub contributors](https://img.shields.io/github/contributors/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/graphs/contributors)
70
70
  [![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)
@@ -1,7 +1,7 @@
1
1
  # devops-driver
2
2
 
3
3
  ![status sheild](https://img.shields.io/static/v1?label=status&message=beta&color=blue&style=plastic)
4
- [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.51&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.51/)
4
+ [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.52&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.52/)
5
5
  [![GitHub](https://img.shields.io/github/license/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
6
6
  [![GitHub contributors](https://img.shields.io/github/contributors/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/graphs/contributors)
7
7
  [![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)
@@ -7,6 +7,6 @@ from .azdo.clients import Azure
7
7
  from .github.client import Github
8
8
 
9
9
 
10
- __version__ = "0.1.51"
10
+ __version__ = "0.1.52"
11
11
  __author__ = "Marc Page"
12
12
  __credits__ = ""
@@ -17,13 +17,13 @@ class AzureObject(DataObject): # pylint: disable=too-few-public-methods
17
17
  self.raw = azure_object
18
18
  super().__init__(self.raw.as_dict())
19
19
 
20
- def _parse_value(self, data: any) -> any:
20
+ def _parse_value(self, data):
21
21
  if isinstance(data, str) and Timestamp.is_timestamp(data):
22
22
  return Timestamp(data)
23
23
 
24
24
  return super()._parse_value(data)
25
25
 
26
- def _get_field(self, name: str, data: dict) -> any:
26
+ def _get_field(self, name: str, data: dict):
27
27
  value = super()._get_field(name, data)
28
28
 
29
29
  if value is None and "fields" in data:
@@ -21,9 +21,9 @@ class Client:
21
21
  def query(
22
22
  self,
23
23
  wiql: Wiql | str,
24
- team_context: TeamContext = None,
25
- time_precision: bool = None,
26
- top: int = None,
24
+ team_context: TeamContext | None = None,
25
+ time_precision: bool | None = None,
26
+ top: int | None = None,
27
27
  ) -> WorkItemQueryResult:
28
28
  """Perform a wiql query
29
29
 
@@ -46,15 +46,15 @@ class Client:
46
46
  def get_history( # pylint: disable=too-many-positional-arguments,too-many-arguments
47
47
  self,
48
48
  wi_id: int,
49
- project: str = None,
50
- top: int = None,
51
- skip: int = None,
52
- expand: str = None,
49
+ project: str | None = None,
50
+ top: int | None = None,
51
+ skip: int | None = None,
52
+ expand: str | None = None,
53
53
  ) -> list[AzureWorkItem]:
54
54
  """Simple wrapper around get_revisions"""
55
55
  return self.client.get_revisions(wi_id, project, top, skip, expand)
56
56
 
57
- def find_ids(self, wiql: Wiql | str, top: int = None) -> list[int]:
57
+ def find_ids(self, wiql: Wiql | str, top: int | None = None) -> list[int]:
58
58
  """Given a query, find the work item ids
59
59
 
60
60
  Args:
@@ -73,9 +73,9 @@ class Client:
73
73
  # query_results_type: workItem
74
74
  # query_type: flat
75
75
  # columns: list of name, reference_name, url
76
- return [i.id for i in found.work_items]
76
+ return [i.id for i in found.work_items] if found.work_items else []
77
77
 
78
- def find(self, wiql: Wiql | str, top: int = None) -> list[list[AzureObject]]:
78
+ def find(self, wiql: Wiql | str, top: int | None = None) -> list[list[AzureObject]]:
79
79
  """Gets the full history of items found in a WIQL search
80
80
 
81
81
  Args:
@@ -151,7 +151,7 @@ class In(Compare): # pylint: disable=too-few-public-methods
151
151
  def __init__(
152
152
  self,
153
153
  field: Field | str,
154
- *values: list[Value | str | date | datetime | int | float],
154
+ *values: Value | str | date | datetime | int | float,
155
155
  ):
156
156
  super().__init__(
157
157
  field,
@@ -167,7 +167,7 @@ class NotIn(Compare): # pylint: disable=too-few-public-methods
167
167
  def __init__(
168
168
  self,
169
169
  field: Field | str,
170
- *values: list[Value | str | date | datetime | int | float],
170
+ *values: Value | str | date | datetime | int | float,
171
171
  ):
172
172
  super().__init__(
173
173
  field,
@@ -234,7 +234,7 @@ class GreaterThanOrEqual(Compare): # pylint: disable=too-few-public-methods
234
234
  class Expression: # pylint: disable=too-few-public-methods
235
235
  """Join several compares"""
236
236
 
237
- def __init__(self, operator: str, *compares: list[Compare]):
237
+ def __init__(self, operator: str, *compares):
238
238
  self.operator = operator
239
239
  self.expressions = compares
240
240
 
@@ -245,14 +245,14 @@ class Expression: # pylint: disable=too-few-public-methods
245
245
  class And(Expression): # pylint: disable=too-few-public-methods
246
246
  """Join compares via AND"""
247
247
 
248
- def __init__(self, *compares: list[Compare | Expression]):
248
+ def __init__(self, *compares: Compare | Expression):
249
249
  super().__init__("AND", *compares)
250
250
 
251
251
 
252
252
  class Or(Expression): # pylint: disable=too-few-public-methods
253
253
  """join compares via OR"""
254
254
 
255
- def __init__(self, *compares: list[Compare | Expression]):
255
+ def __init__(self, *compares: Compare | Expression):
256
256
  super().__init__("OR", *compares)
257
257
 
258
258
 
@@ -264,8 +264,10 @@ class Wiql:
264
264
  self.search = None
265
265
  self.order = []
266
266
  self.snapshot = None
267
+ self.source = "WorkItems"
268
+ self.mode_type = None
267
269
 
268
- def select(self, *fields: list[Field | str]):
270
+ def select(self, *fields: Field | str):
269
271
  """The fields to select
270
272
 
271
273
  Returns:
@@ -286,6 +288,16 @@ class Wiql:
286
288
  self.search = expression
287
289
  return self
288
290
 
291
+ def from_source(self, source: str):
292
+ """Sets the FROM field"""
293
+ self.source = source
294
+ return self
295
+
296
+ def mode(self, results_mode: str):
297
+ """Sets the mode for link queries"""
298
+ self.mode_type = results_mode
299
+ return self
300
+
289
301
  def order_by(self, *orders):
290
302
  """Set the fields to order the results by
291
303
 
@@ -315,4 +327,5 @@ class Wiql:
315
327
  f" ORDER BY {', '.join(str(o) for o in self.order)}" if self.order else ""
316
328
  )
317
329
  asof = f" ASOF {str(self.snapshot)}" if self.snapshot else ""
318
- return f"SELECT {select} FROM workitems{where}{order}{asof}"
330
+ mode = f" MODE({self.mode_type})" if self.mode_type else ""
331
+ return f"SELECT {select} FROM {self.source}{where}{order}{asof}{mode}"
@@ -41,11 +41,11 @@ def image_extension(data: bytes) -> str:
41
41
  raise AttributeError("Image not a known format: " + ",".join(IMAGE_HEADERS))
42
42
 
43
43
 
44
- def send_email(
44
+ def send_email( # pylint: disable=too-many-locals
45
45
  recipients: str | list[str],
46
46
  subject: str,
47
47
  html_body: str,
48
- settings: Settings = None,
48
+ settings: Settings | None = None,
49
49
  **image_data,
50
50
  ):
51
51
  """Sends an email with embedded images
@@ -65,7 +65,9 @@ def send_email(
65
65
  ", ".join(missing) + " not found in:\n" + "\n".join(settings.search_files)
66
66
  )
67
67
  sender = settings["smtp.sender"]
68
+ assert isinstance(sender, str), sender
68
69
  username = settings.get("smtp.username", sender)
70
+ assert isinstance(username, str), username
69
71
  message = MIMEMULTIPART()
70
72
  message["Subject"] = subject
71
73
  message["From"] = sender
@@ -85,8 +87,14 @@ def send_email(
85
87
  )
86
88
  message.attach(image)
87
89
 
88
- with connection_type(settings["smtp.server"], settings["smtp.port"]) as smtp:
90
+ server = settings["smtp.server"]
91
+ assert isinstance(server, str), server
92
+ port = settings["smtp.port"]
93
+ assert isinstance(port, int), port
94
+ password = settings["smtp.password"]
95
+ assert isinstance(password, str), password
96
+ with connection_type(server, port) as smtp:
89
97
  smtp.set_debuglevel(False)
90
- smtp.login(username, settings["smtp.password"])
98
+ smtp.login(username, password)
91
99
  smtp.sendmail(sender, recipients, message.as_string())
92
100
  smtp.quit()
@@ -147,7 +147,9 @@ class Settings:
147
147
  }
148
148
  ENV_VAR_PATTERN = regex(r"\${(\S+)}")
149
149
 
150
- def __init__(self, file: str, *directories, shared_name: str = None, **settings):
150
+ def __init__(
151
+ self, file: str, *directories, shared_name: str | None = None, **settings
152
+ ):
151
153
  """Create a settings object using a file, directories to search, and settings overrides
152
154
 
153
155
  Args:
@@ -172,7 +174,7 @@ class Settings:
172
174
  self.environ = {}
173
175
  self.secrets = {}
174
176
 
175
- def __bypass(self, key: str, name: str, store: dict):
177
+ def __bypass(self, key: str, name: str | None, store: dict):
176
178
  if name is None:
177
179
  for setting_key, store_name in self.settings.get(key, {}).items():
178
180
  store[setting_key] = store_name
@@ -181,7 +183,7 @@ class Settings:
181
183
  store[key] = name
182
184
  return self
183
185
 
184
- def key(self, key: str, name: str = None):
186
+ def key(self, key: str, name: str | None = None):
185
187
  """Sets a keychain name to map to a settings value.
186
188
 
187
189
  Args:
@@ -195,7 +197,7 @@ class Settings:
195
197
  """
196
198
  return self.__bypass(key, name, self.secrets)
197
199
 
198
- def cli(self, key: str, name: str = None):
200
+ def cli(self, key: str, name: str | None = None):
199
201
  """Sets a command line switch to map to a settings value.
200
202
 
201
203
  Args:
@@ -209,7 +211,7 @@ class Settings:
209
211
  """
210
212
  return self.__bypass(key, name, self.opts)
211
213
 
212
- def env(self, key: str, name: str = None):
214
+ def env(self, key: str, name: str | None = None):
213
215
  """Sets an environment variable to map to a settings value.
214
216
 
215
217
  Args:
@@ -232,7 +234,7 @@ class Settings:
232
234
  return "${" + key + "}"
233
235
 
234
236
  @staticmethod
235
- def __patch(value: any) -> any:
237
+ def __patch(value):
236
238
  if isinstance(value, str):
237
239
  return Settings.ENV_VAR_PATTERN.sub(
238
240
  lambda m: Settings.__patch_instance(m.group(1)), value
@@ -257,7 +259,7 @@ class Settings:
257
259
  secret_name = parts[1] if len(parts) == 2 else parts[0]
258
260
  return (service, secret_name)
259
261
 
260
- def __lookup(self, key: str, check: bool, default: any = None) -> any:
262
+ def __lookup(self, key: str, check: bool, default=None):
261
263
  # Settings passed in override everything
262
264
  if key in self.overrides:
263
265
  return True if check else self.overrides[key]
@@ -293,7 +295,7 @@ class Settings:
293
295
 
294
296
  return Settings.__patch(level.get(keys[-1], default))
295
297
 
296
- def get(self, key: str, default: any = None) -> any:
298
+ def get(self, key: str, default=None):
297
299
  """Dictionary-like get
298
300
 
299
301
  Args:
@@ -314,12 +316,12 @@ class Settings:
314
316
  Returns:
315
317
  bool: True if the key exists
316
318
  """
317
- return self.__lookup(key, check=True)
319
+ return bool(self.__lookup(key, check=True))
318
320
 
319
321
  def __contains__(self, key: str) -> bool:
320
322
  return self.has(key)
321
323
 
322
- def __getitem__(self, key: str) -> any:
324
+ def __getitem__(self, key: str):
323
325
  if not self.has(key):
324
326
  raise KeyError(key)
325
327
 
@@ -371,6 +373,6 @@ class Settings:
371
373
 
372
374
  for extension, name, directory, loader in search_info:
373
375
  contents = loader(join(directory, name + extension))
374
- Settings.__merge(settings, contents)
376
+ Settings.__merge(settings, contents if contents else {})
375
377
 
376
378
  return settings
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devopsdriver
3
- Version: 0.1.51
3
+ Version: 0.1.52
4
4
  Summary: DevOps tools
5
5
  Author-email: Marc Page <marcallenpage@gmail.com>
6
6
  License: This is free and unencumbered software released into the public domain.
@@ -51,7 +51,7 @@ Requires-Dist: keyring==25.6.0
51
51
  Requires-Dist: setuptools==80.9.0
52
52
  Requires-Dist: azure-devops==7.1.0b4
53
53
  Requires-Dist: Mako==1.3.10
54
- Requires-Dist: PyGithub==2.5.0
54
+ Requires-Dist: PyGithub==2.8.1
55
55
  Provides-Extra: dev
56
56
  Requires-Dist: black>=24.3.0; extra == "dev"
57
57
  Requires-Dist: pylint>=3.1.0; extra == "dev"
@@ -64,7 +64,7 @@ Dynamic: license-file
64
64
  # devops-driver
65
65
 
66
66
  ![status sheild](https://img.shields.io/static/v1?label=status&message=beta&color=blue&style=plastic)
67
- [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.51&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.51/)
67
+ [![status sheild](https://img.shields.io/static/v1?label=released&message=v0.1.52&color=active&style=plastic)](https://pypi.org/project/devopsdriver/0.1.52/)
68
68
  [![GitHub](https://img.shields.io/github/license/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)
69
69
  [![GitHub contributors](https://img.shields.io/github/contributors/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/graphs/contributors)
70
70
  [![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)
@@ -3,7 +3,7 @@ keyring==25.6.0
3
3
  setuptools==80.9.0
4
4
  azure-devops==7.1.0b4
5
5
  Mako==1.3.10
6
- PyGithub==2.5.0
6
+ PyGithub==2.8.1
7
7
 
8
8
  [dev]
9
9
  black>=24.3.0
@@ -11,7 +11,7 @@ dependencies = [
11
11
  "setuptools==80.9.0", # neded for azure-devops to use 7.1 API
12
12
  "azure-devops==7.1.0b4",
13
13
  "Mako==1.3.10",
14
- "PyGithub==2.5.0",
14
+ "PyGithub==2.8.1",
15
15
  ]
16
16
  keywords = [
17
17
  "azure",
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- """ Test work item query language """
3
+ """Test work item query language"""
4
4
 
5
5
  from datetime import date, datetime
6
6
 
@@ -13,7 +13,7 @@ from devopsdriver.azdo import GreaterThanOrEqual, LessThanOrEqual
13
13
 
14
14
  def test_no_params() -> None:
15
15
  """Test empty, default wiql"""
16
- assert str(Wiql()) == "SELECT [System.Id] FROM workitems", str(Wiql())
16
+ assert str(Wiql()) == "SELECT [System.Id] FROM WorkItems", str(Wiql())
17
17
 
18
18
 
19
19
  def test_expressions() -> None:
@@ -43,7 +43,7 @@ def test_expressions() -> None:
43
43
  .asof(start)
44
44
  )
45
45
  expected = (
46
- """SELECT [System.State], [System.Id] FROM workitems """
46
+ """SELECT [System.State], [System.Id] FROM WorkItems """
47
47
  + """WHERE [System.State] = "New" AND [System.Title] IS EMPTY """
48
48
  + """AND [Microsoft.VSTS.Common.Priority] IS NOT EMPTY """
49
49
  + """AND [System.CreatedDate] > "06/30/2024" """
@@ -71,7 +71,7 @@ def test_in_and_not_in() -> None:
71
71
  And(In("State", "New", "Ready for Development"), NotIn("Priority", 1, 2))
72
72
  )
73
73
  expected = (
74
- """SELECT [System.Id] FROM workitems WHERE [System.State] """
74
+ """SELECT [System.Id] FROM WorkItems WHERE [System.State] """
75
75
  + """IN ("New", "Ready for Development") AND [Microsoft.VSTS.Common.Priority] """
76
76
  + """NOT IN (1, 2)"""
77
77
  )
File without changes
File without changes