ladok3 4.10__py3-none-any.whl → 5.4__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.
ladok3/cli.nw CHANGED
@@ -71,10 +71,21 @@ We will use the function [[err]] for errors and [[warn]] for warnings, both
71
71
  inspired by err(3) and warn(3) in the BSD world.
72
72
  <<functions>>=
73
73
  def err(rc, msg):
74
+ """Print error message to stderr and exit with given return code.
75
+
76
+ Args:
77
+ rc (int): Return code to exit with.
78
+ msg (str): Error message to display.
79
+ """
74
80
  print(f"{sys.argv[0]}: error: {msg}", file=sys.stderr)
75
81
  sys.exit(rc)
76
82
 
77
83
  def warn(msg):
84
+ """Print warning message to stderr.
85
+
86
+ Args:
87
+ msg (str): Warning message to display.
88
+ """
78
89
  print(f"{sys.argv[0]}: {msg}", file=sys.stderr)
79
90
  @
80
91
 
@@ -188,6 +199,18 @@ But we also want to encrypt the stored object using authenticated encryption.
188
199
  That way, we know that we can trust the pickle (which is otherwise a problem).
189
200
  <<functions>>=
190
201
  def store_ladok_session(ls, credentials):
202
+ """Store a LadokSession object to disk with encryption.
203
+
204
+ Saves the session object as an encrypted pickle file in the user's cache directory.
205
+ The credentials are used to derive an encryption key for security.
206
+
207
+ Args:
208
+ ls (LadokSession): The session object to store.
209
+ credentials (tuple): Tuple of (institution, vars) used for key derivation.
210
+
211
+ Raises:
212
+ ValueError: If credentials are missing or invalid.
213
+ """
191
214
  if not os.path.isdir(dirs.user_cache_dir):
192
215
  os.makedirs(dirs.user_cache_dir)
193
216
 
@@ -200,6 +223,17 @@ def store_ladok_session(ls, credentials):
200
223
  file.write(encrypted_ls)
201
224
 
202
225
  def restore_ladok_session(credentials):
226
+ """Restore a LadokSession object from disk.
227
+
228
+ Attempts to load and decrypt a previously stored session object. Returns None
229
+ if no cached session exists or decryption fails.
230
+
231
+ Args:
232
+ credentials (tuple): Tuple of (institution, vars) used for key derivation.
233
+
234
+ Returns:
235
+ LadokSession or None: The restored session object, or None if unavailable.
236
+ """
203
237
  file_path = dirs.user_cache_dir + "/LadokSession"
204
238
 
205
239
  if os.path.isfile(file_path):
@@ -299,21 +333,17 @@ the user.
299
333
  Manages the user's LADOK login credentials. There are three ways to supply the
300
334
  login credentials, in order of priority:
301
335
 
302
- 1) Through the system keyring: Just run `ladok login` and you'll be asked to
303
- enter the credentials and they will be stored in the keyring. Note that for
304
- this to work on the WSL platform (and possibly on Windows), you need to
305
- install the `keyrings.alt` package: `python3 -m pip install keyrings.alt`.
336
+ 1) Through the environment: Just set the environment variables
306
337
 
307
- 2) Through the environment: Just set the environment variables
338
+ a) LADOK_INST, the name of the institution, e.g. KTH Royal Institute of
339
+ Technology;
308
340
 
309
- a) LADOK_INST, the name of the institution, e.g. KTH Royal Institute of
310
- Technology;
311
- b) LADOK_VARS, a colon-separated list of environment variables, similarly to
312
- what's done in `ladok login` --- most don't need this, but can rather set
313
- LADOK_USER (the username, e.g. dbosk@ug.kth.se) and
314
- LADOK_PASS (the password) instead.
341
+ b) LADOK_VARS, a colon-separated list of environment variables, similarly to
342
+ what's done in `ladok login` --- most don't need this, but can rather set
343
+ LADOK_USER (the username, e.g. dbosk@ug.kth.se) and LADOK_PASS (the
344
+ password) instead.
315
345
 
316
- 3) Through the configuration file: Just write
346
+ 2) Through the configuration file: Just write
317
347
 
318
348
  {{
319
349
  "institution": "the name of the university"
@@ -325,6 +355,17 @@ login credentials, in order of priority:
325
355
  option). (The keys 'username' and 'password' can be renamed to correspond to
326
356
  the necessary values if the university login system uses other names.)
327
357
 
358
+ 3) Through the system keyring: Just run `ladok login` and you'll be asked to
359
+ enter the credentials and they will be stored in the keyring. Note that for
360
+ this to work on the WSL platform (and possibly on Windows), you need to
361
+ install the `keyrings.alt` package: `python3 -m pip install keyrings.alt`.
362
+
363
+ The keyring is the most secure. However, sometimes one want to try different
364
+ credentials, so the environment should override the keyring. Also, on WSL the
365
+ keyring might require you to enter a password in the terminal---this is very
366
+ inconvenient in scripts. However, when logging in, we first try to store the
367
+ credentials in the keyring.
368
+
328
369
  <<add subparsers to subp>>=
329
370
  login_parser = subp.add_parser("login",
330
371
  help="Manage login credentials",
@@ -510,49 +551,17 @@ def load_credentials(filename="config.json"):
510
551
  can be passed to `LadokSession(instiution, credential dictionary)`.
511
552
  """
512
553
 
513
- <<fetch vars from keyring>>
514
- <<fetch username and password from keyring>>
515
554
  <<fetch institution from environment>>
516
555
  <<fetch username and password from environment>>
517
556
  <<fetch vars from environment>>
518
557
  <<fetch vars from config file>>
558
+ <<fetch vars from keyring>>
559
+ <<fetch username and password from keyring>>
519
560
 
520
561
  return None, None
521
562
  @
522
563
 
523
- First we try the newest format.
524
- We try to fetch the institution and vars from the keyring.
525
- <<fetch vars from keyring>>=
526
- try:
527
- institution = keyring.get_password("ladok3", "institution")
528
- vars_keys = keyring.get_password("ladok3", "vars")
529
-
530
- vars = {}
531
- for key in vars_keys.split(";"):
532
- vars[key] = keyring.get_password("ladok3", key)
533
-
534
- if institution and vars:
535
- return institution, vars
536
- except:
537
- pass
538
- @
539
-
540
- However, if that fails, we fall back on the previous format, that only
541
- supported KTH.
542
- <<fetch username and password from keyring>>=
543
- try:
544
- institution = "KTH Royal Institute of Technology"
545
- vars = {
546
- "username": keyring.get_password("ladok3", "username"),
547
- "password": keyring.get_password("ladok3", "password")
548
- }
549
- if vars:
550
- return institution, vars
551
- except:
552
- pass
553
- @
554
-
555
- Next in priority is to read from the environment.
564
+ First in priority is to read from the environment.
556
565
  We try to read the institution.
557
566
  If that fails, we assume we're using the old format that only supported KTH.
558
567
  <<fetch institution from environment>>=
@@ -560,14 +569,13 @@ try:
560
569
  institution = os.environ["LADOK_INST"]
561
570
  except:
562
571
  institution = "KTH Royal Institute of Technology"
563
-
564
572
  <<fetch username and password from environment>>=
565
573
  try:
566
574
  vars = {
567
575
  "username": os.environ["LADOK_USER"],
568
576
  "password": os.environ["LADOK_PASS"]
569
577
  }
570
- if institution and vars:
578
+ if institution and vars["username"] and vars["password"]:
571
579
  return institution, vars
572
580
  except:
573
581
  pass
@@ -575,13 +583,20 @@ except:
575
583
 
576
584
  If we couldn't read the old [[LADOK_USER]] and [[LADOK_PASS]], we try to read
577
585
  the [[vars]] from the environment using [[LADOK_VARS]].
586
+ Note that we need the [[institution]] to be set from [[LADOK_INST]] above for
587
+ this.
578
588
  <<fetch vars from environment>>=
579
589
  try:
580
590
  vars_keys = os.environ["LADOK_VARS"]
581
591
 
582
592
  vars = {}
583
593
  for key in vars_keys.split(":"):
584
- vars[key] = os.environ[key]
594
+ try:
595
+ value = os.environ[key]
596
+ if value:
597
+ vars[key] = value
598
+ except KeyError:
599
+ <<print warning about missing variable in [[LADOK_VARS]]>>
585
600
 
586
601
  if institution and vars:
587
602
  return institution, vars
@@ -589,8 +604,15 @@ except:
589
604
  pass
590
605
  @
591
606
 
592
- If none of the above worked, the last resort is to try to read the
593
- configuration file.
607
+ Unlike in the other cases, we don't just ignore the exception of the key not
608
+ existing.
609
+ Since the user has explicitly specified the variable, we should warn them that
610
+ it doesn't exist.
611
+ <<print warning about missing variable in [[LADOK_VARS]]>>=
612
+ warn(f"Variable {key} not set, ignoring.")
613
+ @
614
+
615
+ If none of the above worked, we try the config file next.
594
616
  We pop the institution from the configuration file (a dictionary), because then
595
617
  the remaining entries will be used as [[vars]].
596
618
  <<fetch vars from config file>>=
@@ -599,12 +621,46 @@ try:
599
621
  config = json.load(conf_file)
600
622
 
601
623
  institution = config.pop("institution",
602
- "KTH Royal Institute of Technology")
624
+ "KTH Royal Institute of Technology")
603
625
  return institution, config
604
626
  except:
605
627
  pass
606
628
  @
607
629
 
630
+ Lastly, if nothing else worked, we try to fetch the institution and vars from
631
+ the keyring.
632
+ Note that [[keyring]] returns [[None]] if the key doesn't exist, it doesn't
633
+ raise an exception.
634
+ <<fetch vars from keyring>>=
635
+ try:
636
+ institution = keyring.get_password("ladok3", "institution")
637
+ vars_keys = keyring.get_password("ladok3", "vars")
638
+
639
+ vars = {}
640
+ for key in vars_keys.split(";"):
641
+ value = keyring.get_password("ladok3", key)
642
+ if value:
643
+ vars[key] = value
644
+
645
+ if institution and vars:
646
+ return institution, vars
647
+ except:
648
+ pass
649
+ @
650
+
651
+ However, if that fails, we fall back on the previous format, that only
652
+ supported KTH.
653
+ <<fetch username and password from keyring>>=
654
+ try:
655
+ institution = "KTH Royal Institute of Technology"
656
+ username = keyring.get_password("ladok3", "username")
657
+ password = keyring.get_password("ladok3", "password")
658
+ if username and password:
659
+ return institution, {"username": username, "password": password}
660
+ except:
661
+ pass
662
+ @
663
+
608
664
 
609
665
  \section{Managing the cache: the \texttt{cache} command and subcommands}
610
666
 
@@ -643,6 +699,15 @@ If we don't exit using [[sys.exit]], the main program will write the cache back
643
699
  again on its exit.
644
700
  <<functions>>=
645
701
  def clear_cache(ls, args):
702
+ """Clear the cached LADOK session data.
703
+
704
+ Removes the stored encrypted session file from the user's cache directory.
705
+ Silently ignores if the file doesn't exist.
706
+
707
+ Args:
708
+ ls (LadokSession): The LADOK session (unused but required by interface).
709
+ args: Command line arguments (unused).
710
+ """
646
711
  try:
647
712
  os.remove(dirs.user_cache_dir + "/LadokSession")
648
713
  except FileNotFoundError as err: