besapi 4.0.1__tar.gz → 4.1.2__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 (27) hide show
  1. {besapi-4.0.1/src/besapi.egg-info → besapi-4.1.2}/PKG-INFO +1 -1
  2. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/besapi.py +74 -2
  3. {besapi-4.0.1 → besapi-4.1.2/src/besapi.egg-info}/PKG-INFO +1 -1
  4. {besapi-4.0.1 → besapi-4.1.2}/src/bescli/bescli.py +17 -3
  5. {besapi-4.0.1 → besapi-4.1.2}/tests/test_besapi.py +76 -0
  6. {besapi-4.0.1 → besapi-4.1.2}/LICENSE.txt +0 -0
  7. {besapi-4.0.1 → besapi-4.1.2}/MANIFEST.in +0 -0
  8. {besapi-4.0.1 → besapi-4.1.2}/README.md +0 -0
  9. {besapi-4.0.1 → besapi-4.1.2}/pyproject.toml +0 -0
  10. {besapi-4.0.1 → besapi-4.1.2}/setup.cfg +0 -0
  11. {besapi-4.0.1 → besapi-4.1.2}/setup.py +0 -0
  12. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/__init__.py +0 -0
  13. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/__main__.py +0 -0
  14. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/plugin_utilities.py +0 -0
  15. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/plugin_utilities_win.py +0 -0
  16. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/schemas/BES.xsd +0 -0
  17. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/schemas/BESAPI.xsd +0 -0
  18. {besapi-4.0.1 → besapi-4.1.2}/src/besapi/schemas/BESActionSettings.xsd +0 -0
  19. {besapi-4.0.1 → besapi-4.1.2}/src/besapi.egg-info/SOURCES.txt +0 -0
  20. {besapi-4.0.1 → besapi-4.1.2}/src/besapi.egg-info/dependency_links.txt +0 -0
  21. {besapi-4.0.1 → besapi-4.1.2}/src/besapi.egg-info/requires.txt +0 -0
  22. {besapi-4.0.1 → besapi-4.1.2}/src/besapi.egg-info/top_level.txt +0 -0
  23. {besapi-4.0.1 → besapi-4.1.2}/src/bescli/__init__.py +0 -0
  24. {besapi-4.0.1 → besapi-4.1.2}/src/bescli/__main__.py +0 -0
  25. {besapi-4.0.1 → besapi-4.1.2}/tests/test_plugin_utilities.py +0 -0
  26. {besapi-4.0.1 → besapi-4.1.2}/tests/test_plugin_utilities_logging.py +0 -0
  27. {besapi-4.0.1 → besapi-4.1.2}/tests/tests.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: besapi
3
- Version: 4.0.1
3
+ Version: 4.1.2
4
4
  Summary: Library for working with the BigFix REST API
5
5
  Home-page: https://github.com/jgstew/besapi
6
6
  Author: Matt Hansen, James Stewart
@@ -12,6 +12,7 @@ Library for communicating with the BES (BigFix) REST API.
12
12
 
13
13
  import configparser
14
14
  import datetime
15
+ import getpass
15
16
  import hashlib
16
17
  import importlib.resources
17
18
  import json
@@ -20,6 +21,7 @@ import os
20
21
  import random
21
22
  import site
22
23
  import string
24
+ import sys
23
25
  import urllib.parse
24
26
 
25
27
  import lxml.etree
@@ -27,7 +29,7 @@ import lxml.objectify
27
29
  import requests
28
30
  import urllib3.poolmanager
29
31
 
30
- __version__ = "4.0.1"
32
+ __version__ = "4.1.2"
31
33
 
32
34
  besapi_logger = logging.getLogger("besapi")
33
35
 
@@ -304,6 +306,76 @@ def get_bes_conn_using_config_file(conf_file=None):
304
306
  return None
305
307
 
306
308
 
309
+ def get_bes_conn_interactive(
310
+ user=None, password=None, root_server=None, force_prompt=False
311
+ ):
312
+ """Get BESConnection using interactive prompts."""
313
+
314
+ if not (force_prompt or sys.__stdin__.isatty()):
315
+ logging.error("No TTY available for interactive login!")
316
+ return None
317
+
318
+ print(
319
+ "Attempting BESAPI Connection using interactive prompts. Use Ctrl-C to cancel."
320
+ )
321
+ try:
322
+ if not user:
323
+ user = str(input("User [%s]: " % getpass.getuser())).strip()
324
+ if not user:
325
+ user = getpass.getuser()
326
+
327
+ if not root_server:
328
+ root_server = str(
329
+ input("Root Server (ex. %s): " % "https://localhost:52311")
330
+ ).strip()
331
+ if not root_server or root_server == "":
332
+ print("Root Server is required, try again!")
333
+ return get_bes_conn_interactive(
334
+ user=user,
335
+ password=password,
336
+ root_server=None,
337
+ force_prompt=force_prompt,
338
+ )
339
+
340
+ if not password:
341
+ password = str(
342
+ getpass.getpass(f"Password for {user}@{root_server}: ")
343
+ ).strip()
344
+
345
+ if not password or password == "":
346
+ print("Password is required, try again!")
347
+ return get_bes_conn_interactive(
348
+ user=user,
349
+ password=None,
350
+ root_server=root_server,
351
+ force_prompt=force_prompt,
352
+ )
353
+ except (KeyboardInterrupt, EOFError):
354
+ print("\nLogin cancelled.")
355
+ return None
356
+
357
+ try:
358
+ return BESConnection(user, password, root_server)
359
+ except requests.exceptions.HTTPError as err:
360
+ print("Bad Username or Bad Password, Try again!")
361
+ logging.debug(err)
362
+ print(" BES_ROOT_SERVER: ", root_server)
363
+ return get_bes_conn_interactive(
364
+ user=None, password=None, root_server=root_server, force_prompt=force_prompt
365
+ )
366
+ except requests.exceptions.ConnectionError as err:
367
+ print("Bad Root Server Specified, Try again!")
368
+ logging.debug("Connection Error: %s", err)
369
+ print(" BES_USER_NAME: ", user)
370
+ print("BES_PASSWORD length: ", len(password))
371
+ return get_bes_conn_interactive(
372
+ user=user, password=password, root_server=None, force_prompt=force_prompt
373
+ )
374
+ except Exception as e: # pylint: disable=broad-except
375
+ logging.error("Error occurred while establishing BESConnection: %s", e)
376
+ return None
377
+
378
+
307
379
  # https://docs.python-requests.org/en/latest/user/advanced/#transport-adapters
308
380
  class HTTPAdapterBlocksize(requests.adapters.HTTPAdapter):
309
381
  """Custom HTTPAdapter for requests to override blocksize
@@ -543,7 +615,7 @@ class BESConnection:
543
615
  return RESTResult(
544
616
  self.session.post(
545
617
  self.url("query"),
546
- data=f"relevance={urllib.parse.quote(relevance, safe=':+')}",
618
+ data=f"relevance={urllib.parse.quote(relevance, safe=':')}",
547
619
  verify=self.verify,
548
620
  **kwargs,
549
621
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: besapi
3
- Version: 4.0.1
3
+ Version: 4.1.2
4
4
  Summary: Library for working with the BigFix REST API
5
5
  Home-page: https://github.com/jgstew/besapi
6
6
  Author: Matt Hansen, James Stewart
@@ -216,6 +216,20 @@ class BESCLInterface(Cmd):
216
216
  self.pfeedback(" - attempt login using config parameters - ")
217
217
  self.do_login()
218
218
 
219
+ def do_login_new(self, user=None):
220
+ """Login to BigFix Server."""
221
+ if not user or str(user).strip() == "":
222
+ user = self.BES_USER_NAME
223
+ self.bes_conn = besapi.get_bes_conn_interactive(
224
+ user=user,
225
+ password=self.BES_PASSWORD,
226
+ root_server=self.BES_ROOT_SERVER,
227
+ )
228
+ if self.bes_conn:
229
+ self.pfeedback("Login Successful!")
230
+ (self.BES_USER_NAME, self.BES_PASSWORD) = self.bes_conn.session.auth
231
+ self.BES_ROOT_SERVER = self.bes_conn.rootserver
232
+
219
233
  def do_login(self, user=None):
220
234
  """Login to BigFix Server."""
221
235
 
@@ -227,7 +241,7 @@ class BESCLInterface(Cmd):
227
241
  if not user:
228
242
  user = getpass.getuser()
229
243
 
230
- self.BES_USER_NAME = user
244
+ self.BES_USER_NAME = user.strip()
231
245
  if not self.CONFPARSER.has_section("besapi"):
232
246
  self.CONFPARSER.add_section("besapi")
233
247
  self.CONFPARSER.set("besapi", "BES_USER_NAME", user)
@@ -237,14 +251,14 @@ class BESCLInterface(Cmd):
237
251
  if not root_server:
238
252
  root_server = str(input("Root Server [%s]: " % self.BES_ROOT_SERVER))
239
253
 
240
- self.BES_ROOT_SERVER = root_server
254
+ self.BES_ROOT_SERVER = root_server.strip()
241
255
 
242
256
  else:
243
257
  root_server = str(
244
258
  input("Root Server (ex. %s): " % "https://server.institution.edu:52311")
245
259
  )
246
260
  if root_server:
247
- self.BES_ROOT_SERVER = root_server
261
+ self.BES_ROOT_SERVER = root_server.strip()
248
262
  if not self.CONFPARSER.has_section("besapi"):
249
263
  self.CONFPARSER.add_section("besapi")
250
264
  self.CONFPARSER.set("besapi", "BES_ROOT_SERVER", root_server)
@@ -312,10 +312,86 @@ def test_bes_conn_json():
312
312
  assert result is not None
313
313
  assert "TestString" in result
314
314
  assert "BES Support" in result
315
+ print("testing session relevance with + in relevance")
316
+ str_relevance_plus = 'lengths of first matches (regex " +") of " "'
317
+ result = bes_conn.session_relevance_xml(str_relevance_plus)
318
+ print(result)
319
+ assert result is not None
315
320
  else:
316
321
  pytest.skip("Skipping BESConnection test, no config file or login failed.")
317
322
 
318
323
 
324
+ def test_bes_conn_session_relevance_with_plus():
325
+ """Test the BESConnection class with JSON output."""
326
+
327
+ bes_conn = besapi.plugin_utilities.get_besapi_connection(None)
328
+
329
+ if bes_conn and bes_conn.login():
330
+ print("testing session relevance with + in relevance")
331
+ str_relevance_plus = 'lengths of first matches (regex " +") of " "'
332
+ str_relevance_answer = "8"
333
+ result = bes_conn.session_relevance_xml(str_relevance_plus)
334
+ print(result)
335
+ assert result is not None
336
+ print(result.request.request.body)
337
+ assert f'<Answer type="integer">{str_relevance_answer}</Answer>' in str(result)
338
+ result = bes_conn.session_relevance_json_string(str_relevance_plus)
339
+ print(result)
340
+ assert result is not None
341
+ assert str_relevance_answer in str(result)
342
+ result = bes_conn.session_relevance_json(str_relevance_plus)
343
+ print(result)
344
+ assert result is not None
345
+ assert f"[{str_relevance_answer}]" in str(result["result"])
346
+ result = bes_conn.session_relevance_string(str_relevance_plus)
347
+ print(result)
348
+ assert result is not None
349
+ assert str_relevance_answer in str(result)
350
+ result = bes_conn.session_relevance_array(str_relevance_plus)
351
+ print(result)
352
+ assert result is not None
353
+ assert f"['{str_relevance_answer}']" in str(result)
354
+ result = bes_conn.session_relevance_json_array(str_relevance_plus)
355
+ print(result)
356
+ assert result is not None
357
+ assert f"[{str_relevance_answer}]" in str(result)
358
+
359
+ # test already escaped +
360
+ str_relevance_plus = r'lengths of first matches (regex " %2b") of " "'
361
+ print(str_relevance_plus)
362
+ result = bes_conn.session_relevance_xml(str_relevance_plus)
363
+ print(result)
364
+ assert result is not None
365
+ print(result.request.request.body)
366
+ assert f'<Answer type="integer">{str_relevance_answer}</Answer>' in str(result)
367
+ else:
368
+ pytest.skip("Skipping BESConnection test, no config file or login failed.")
369
+
370
+
371
+ def test_bes_conn_upload_always():
372
+ """Test the BESConnection class with JSON output."""
373
+ file_name = "LICENSE.txt"
374
+ file_path = "../" + file_name
375
+ if not os.path.isfile(os.path.abspath(file_path)):
376
+ # handle case where not running from src or tests folder.
377
+ file_path = "./" + file_name
378
+ assert os.path.isfile(os.path.abspath(file_path))
379
+
380
+ bes_conn = besapi.plugin_utilities.get_besapi_connection(None)
381
+ if bes_conn and bes_conn.login():
382
+ # test upload
383
+ # Example Header:: Content-Disposition: attachment; filename="file.xml"
384
+ headers = {"Content-Disposition": f'attachment; filename="{file_name}"'}
385
+ with open(file_path, "rb") as f:
386
+ result = bes_conn.post(bes_conn.url("upload"), data=f, headers=headers)
387
+ print(result)
388
+ assert result is not None
389
+ assert result.besobj.FileUpload.Available == 1
390
+ assert result.besdict["FileUpload"]["Available"] == "1"
391
+ else:
392
+ pytest.skip("Skipping BESConnection upload test, login failed.")
393
+
394
+
319
395
  def test_plugin_utilities_logging():
320
396
  """Test the plugin_utilities module."""
321
397
  print(besapi.plugin_utilities.get_invoke_folder())
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes