gam7 7.20.2__py3-none-any.whl → 7.20.3__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.
gam/__init__.py CHANGED
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
25
25
  """
26
26
 
27
27
  __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
28
- __version__ = '7.20.02'
28
+ __version__ = '7.20.03'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -51247,7 +51247,7 @@ def doCreateCourseStudentGroups():
51247
51247
  while Cmd.ArgumentsRemaining():
51248
51248
  myarg = getArgument()
51249
51249
  if myarg == 'title':
51250
- titles.append(getString(Cmd.OB_STRING))
51250
+ titles.append(getString(Cmd.OB_STRING, maxLen=100))
51251
51251
  elif myarg == 'select':
51252
51252
  titles.extend(getEntityList(Cmd.OB_STRING_ENTITY, shlexSplit=True))
51253
51253
  elif _getCourseSelectionParameters(myarg, courseSelectionParameters):
@@ -51450,8 +51450,26 @@ def doClearCourseStudentGroups():
51450
51450
  # (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
51451
51451
  # [showitemcountonly] [formatjson [quotechar <Character>]]
51452
51452
  def doPrintCourseStudentGroups(showMembers=False):
51453
+ def _getCourseStudents():
51454
+ studentIdEmailMap = {}
51455
+ try:
51456
+ students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
51457
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
51458
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
51459
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
51460
+ courseId=courseId, fields='nextPageToken,students(profile(id,emailAddress))',
51461
+ pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
51462
+ for student in students:
51463
+ studentIdEmailMap[student['profile']['id']] = student['profile']['emailAddress']
51464
+ except GAPI.notFound:
51465
+ pass
51466
+ except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
51467
+ entityActionFailedExit([Ent.COURSE, courseId], str(e))
51468
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
51469
+ ClientAPIAccessDeniedExit(str(e))
51470
+ return studentIdEmailMap
51471
+
51453
51472
  croom = buildGAPIObject(API.CLASSROOM)
51454
- cd = buildGAPIObject(API.DIRECTORY)
51455
51473
  csvPF = CSVPrintFile(['courseId', 'courseName', 'studentGroupId', 'studentGroupTitle'])
51456
51474
  FJQC = FormatJSONQuoteChar(csvPF)
51457
51475
  courseSelectionParameters = _initCourseSelectionParameters()
@@ -51503,6 +51521,8 @@ def doPrintCourseStudentGroups(showMembers=False):
51503
51521
  if not showMembers and showItemCountOnly:
51504
51522
  itemCount += len(studentGroups)
51505
51523
  continue
51524
+ if showMembers:
51525
+ studentIdEmailMap = _getCourseStudents()
51506
51526
  for studentGroup in studentGroups:
51507
51527
  studentGroupId = studentGroup['id']
51508
51528
  if not showMembers:
@@ -51515,7 +51535,7 @@ def doPrintCourseStudentGroups(showMembers=False):
51515
51535
  row['JSON'] = json.dumps(cleanJSON(studentGroup), ensure_ascii=False, sort_keys=False)
51516
51536
  csvPF.WriteRowTitles(row)
51517
51537
  continue
51518
- printGettingEntityItemForWhom(Ent.USER, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId],
51538
+ printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId],
51519
51539
  currentCount(i, count)))
51520
51540
  pageMessage = getPageMessage()
51521
51541
  try:
@@ -51530,7 +51550,7 @@ def doPrintCourseStudentGroups(showMembers=False):
51530
51550
  itemCount += len(students)
51531
51551
  continue
51532
51552
  for member in students:
51533
- member['userEmail'] = convertUIDtoEmailAddress(f"id:{member['userId']}", cd=cd, emailTypes=['user'])
51553
+ member['userEmail'] = studentIdEmailMap.get(member['userId'], member['userId'])
51534
51554
  except GAPI.notFound as e:
51535
51555
  entityActionFailedWarning([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], str(e))
51536
51556
  continue
@@ -51562,8 +51582,29 @@ def doPrintCourseStudentGroups(showMembers=False):
51562
51582
  # gam sync course-studentgroup-members <CourseID> <StudentGroupID> <UserTypeEntity>
51563
51583
  # gam clear course-studentgroup-members <CourseID> <StudentGroupID>
51564
51584
  def doProcessCourseStudentGroupMembers():
51565
- def _getCurrentStudents():
51566
- printGettingEntityItemForWhom(Ent.USER, Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId)
51585
+ def _getCourseStudents():
51586
+ studentIdEmailMap = {}
51587
+ studentEmailIdMap = {}
51588
+ try:
51589
+ students = callGAPIpages(ocroom.courses().students(), 'list', 'students',
51590
+ throwReasons=[GAPI.NOT_FOUND, GAPI.SERVICE_NOT_AVAILABLE,
51591
+ GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED],
51592
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
51593
+ courseId=courseId, fields='nextPageToken,students(profile(id,emailAddress))',
51594
+ pageSize=GC.Values[GC.CLASSROOM_MAX_RESULTS])
51595
+ for student in students:
51596
+ studentIdEmailMap[student['profile']['id']] = student['profile']['emailAddress'].lower()
51597
+ studentEmailIdMap[student['profile']['emailAddress'].lower()] = student['profile']['id']
51598
+ return (studentIdEmailMap, studentEmailIdMap)
51599
+ except GAPI.notFound as e:
51600
+ entityActionFailedExit([Ent.COURSE, courseId], str(e))
51601
+ except (GAPI.serviceNotAvailable, GAPI.notImplemented) as e:
51602
+ entityActionFailedExit([Ent.COURSE, courseId], str(e))
51603
+ except (GAPI.forbidden, GAPI.permissionDenied) as e:
51604
+ ClientAPIAccessDeniedExit(str(e))
51605
+
51606
+ def _getGroupCurrentStudents():
51607
+ printGettingEntityItemForWhom(Ent.STUDENT, formatKeyValueList('', [Ent.Singular(Ent.COURSE_STUDENTGROUP), studentGroupId], ''))
51567
51608
  pageMessage = getPageMessage()
51568
51609
  try:
51569
51610
  return callGAPIpages(ocroom.courses().studentGroups().studentGroupMembers(), 'list', 'studentGroupMembers',
@@ -51581,18 +51622,24 @@ def doProcessCourseStudentGroupMembers():
51581
51622
  except (GAPI.forbidden, GAPI.permissionDenied) as e:
51582
51623
  ClientAPIAccessDeniedExit(str(e))
51583
51624
 
51584
- def _getStudentUserId(kvList, student, i, count):
51585
- normalizedEmailAddressOrUID = normalizeEmailAddressOrUID(student)
51586
- if normalizedEmailAddressOrUID.find('@') == -1:
51587
- return normalizedEmailAddressOrUID
51588
- try:
51589
- return callGAPI(cd.users(), 'get',
51590
- throwReasons=GAPI.USER_GET_THROW_REASONS,
51591
- userKey=normalizedEmailAddressOrUID, fields='id')['id']
51592
- except (GAPI.userNotFound, GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
51593
- GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e:
51594
- entityActionFailedWarning(kvList, str(e), i, count)
51595
- return None
51625
+ def _validateClStudents(clStudents):
51626
+ status = True
51627
+ clStudentIds = []
51628
+ count = len(clStudents)
51629
+ i = 0
51630
+ kvList = [Ent.COURSE, courseId, Ent.STUDENT, '']
51631
+ for student in clStudents:
51632
+ i += 1
51633
+ student = normalizeEmailAddressOrUID(student)
51634
+ if student in studentIdEmailMap:
51635
+ clStudentIds.append(student)
51636
+ elif student in studentEmailIdMap:
51637
+ clStudentIds.append(studentEmailIdMap[student])
51638
+ else:
51639
+ kvList[-1] = student
51640
+ entityActionFailedWarning(kvList, Msg.STUDENT_NOT_IN_COURSE, i, count)
51641
+ status = False
51642
+ return clStudentIds if status else None
51596
51643
 
51597
51644
  def _processStudent(function, kvList, kwargs, i, count):
51598
51645
  try:
@@ -51611,85 +51658,69 @@ def doProcessCourseStudentGroupMembers():
51611
51658
  except (GAPI.forbidden, GAPI.permissionDenied) as e:
51612
51659
  ClientAPIAccessDeniedExit(str(e))
51613
51660
 
51614
- def _addStudents(students, getUserIds):
51661
+ def _addStudents(students):
51615
51662
  count = len(students)
51616
51663
  i = 0
51617
- entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.USER)
51618
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
51664
+ entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.STUDENT)
51665
+ kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.STUDENT, '']
51619
51666
  kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'body': {'userId': ''}}
51667
+ Ind.Increment()
51620
51668
  for student in students:
51621
51669
  i += 1
51622
- if getUserIds:
51623
- userId = _getStudentUserId(kvList, student, i, count)
51624
- if userId is None:
51625
- continue
51626
- kvList[-1] = student
51627
- else:
51628
- userId = student
51629
- kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
51630
- kwargs['body']['userId'] = userId
51670
+ kvList[-1] = studentIdEmailMap[student]
51671
+ kwargs['body']['userId'] = student
51631
51672
  _processStudent('create', kvList, kwargs, i, count)
51673
+ Ind.Decrement()
51632
51674
 
51633
- def _removeStudents(students, getUserIds):
51675
+ def _removeStudents(students):
51634
51676
  count = len(students)
51635
51677
  i = 0
51636
- entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.USER)
51637
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
51678
+ entityPerformActionNumItems([Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId], count, Ent.STUDENT)
51679
+ kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.STUDENT, '']
51638
51680
  kwargs = {'courseId': courseId, 'studentGroupId': studentGroupId, 'userId': ''}
51681
+ Ind.Increment()
51639
51682
  for student in students:
51640
51683
  i += 1
51641
- if getUserIds:
51642
- userId = _getStudentUserId(kvList, student, i, count)
51643
- if userId is None:
51644
- continue
51645
- kvList[-1] = student
51646
- else:
51647
- userId = student
51648
- kvList[-1] = convertUIDtoEmailAddress(f"id:{userId}", cd=cd, emailTypes=['user'])
51649
- kwargs['userId'] = userId
51684
+ kvList[-1] = studentIdEmailMap[student]
51685
+ kwargs['userId'] = student
51650
51686
  _processStudent('delete', kvList, kwargs, i, count)
51687
+ Ind.Decrement()
51651
51688
 
51652
51689
  croom = buildGAPIObject(API.CLASSROOM)
51653
- cd = buildGAPIObject(API.DIRECTORY)
51654
51690
  action = Act.Get()
51655
51691
  courseId = getString(Cmd.OB_COURSE_ID)
51656
51692
  studentGroupId = getString(Cmd.OB_STUDENTGROUP_ID)
51657
51693
  if action != Act.CLEAR:
51658
51694
  _, clStudents = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS, groupMemberType=Ent.TYPE_USER)
51659
- clStudents = [normalizeEmailAddressOrUID(student) for student in clStudents]
51695
+ clStudentIds = []
51660
51696
  checkForExtraneousArguments()
51661
51697
  _, count, coursesInfo = _getCoursesOwnerInfo(croom, [courseId], GC.Values[GC.USE_COURSE_OWNER_ACCESS])
51662
51698
  if count == 0:
51663
51699
  return
51664
51700
  ocroom = coursesInfo[courseId]['croom']
51665
51701
  courseId = coursesInfo[courseId]['id']
51702
+ studentIdEmailMap, studentEmailIdMap = _getCourseStudents()
51666
51703
  if action in {Act.SYNC, Act.CLEAR}:
51667
- currentStudents = [student['userId'] for student in _getCurrentStudents()]
51704
+ currentStudents = [student['userId'] for student in _getGroupCurrentStudents()]
51705
+ if action != Act.CLEAR:
51706
+ clStudentIds = _validateClStudents(clStudents)
51707
+ if clStudentIds is None:
51708
+ return
51668
51709
  if action == Act.CLEAR:
51669
- _removeStudents(currentStudents, False)
51710
+ _removeStudents(currentStudents)
51670
51711
  elif action == Act.DELETE:
51671
- _removeStudents(clStudents, True)
51712
+ _removeStudents(clStudentIds)
51672
51713
  elif action in {Act.ADD, Act.CREATE}:
51673
- _addStudents(clStudents, True)
51714
+ _addStudents(clStudentIds)
51674
51715
  else: # elif action == Act.SYNC:
51675
51716
  currentMembersSet = set(currentStudents)
51676
- syncMembersSet = set()
51677
- count = len(clStudents)
51678
- i = 0
51679
- kvList = [Ent.COURSE, courseId, Ent.COURSE_STUDENTGROUP, studentGroupId, Ent.USER, '']
51680
- for student in clStudents:
51681
- i += 1
51682
- kvList[-1] = student
51683
- userId = _getStudentUserId(kvList, student, i, count)
51684
- if userId is None:
51685
- continue
51686
- syncMembersSet.add(userId)
51717
+ syncMembersSet = set(clStudentIds)
51687
51718
  removeStudentsSet = currentMembersSet-syncMembersSet
51688
51719
  addStudentsSet = syncMembersSet-currentMembersSet
51689
51720
  Act.Set(Act.DELETE)
51690
- _removeStudents(removeStudentsSet, False)
51721
+ _removeStudents(removeStudentsSet)
51691
51722
  Act.Set(Act.ADD)
51692
- _addStudents(addStudentsSet, False)
51723
+ _addStudents(addStudentsSet)
51693
51724
 
51694
51725
  # gam print course-studentgroup-members [todrive <ToDriveAttribute>*]
51695
51726
  # (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
@@ -65073,7 +65104,7 @@ def _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess):
65073
65104
  # (mappermissionsdomain <DomainName> <DomainName>)*
65074
65105
  # [moveToNewOwnersRoot [<Boolean>]]
65075
65106
  # [updatesheetprotectedranges [<Boolean>]]
65076
- # [sendemail] [emailmessage <String>]
65107
+ # [sendemail|sendnotification] [emailmessage <String>]
65077
65108
  # [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
65078
65109
  def createDriveFileACL(users, useDomainAdminAccess=False):
65079
65110
  moveToNewOwnersRoot = False
@@ -65117,7 +65148,7 @@ def createDriveFileACL(users, useDomainAdminAccess=False):
65117
65148
  elif myarg in {'expiration', 'expires'}:
65118
65149
  expirationLocation = Cmd.Location()
65119
65150
  body['expirationTime'] = getTimeOrDeltaFromNow()
65120
- elif myarg == 'sendemail':
65151
+ elif myarg in {'sendemail', 'sendnotification'}:
65121
65152
  sendNotificationEmail = True
65122
65153
  elif myarg == 'emailmessage':
65123
65154
  sendNotificationEmail = True
@@ -65373,7 +65404,7 @@ def doUpdateDriveFileACLs():
65373
65404
  updateDriveFileACLs([_getAdminEmail()], True)
65374
65405
 
65375
65406
  # gam [<UserTypeEntity>] create permissions <DriveFileEntity> <DriveFilePermissionsEntity> [asadmin]
65376
- # [expiration <Time>] [sendmail] [emailmessage <String>]
65407
+ # [expiration <Time>] [sendemail|sendnotification] [emailmessage <String>]
65377
65408
  # [moveToNewOwnersRoot [<Boolean>]]
65378
65409
  # <PermissionMatch>* [<PermissionMatchAction>]
65379
65410
  def createDriveFilePermissions(users, useDomainAdminAccess=False):
@@ -65491,7 +65522,7 @@ def createDriveFilePermissions(users, useDomainAdminAccess=False):
65491
65522
  moveToNewOwnersRoot = getBoolean()
65492
65523
  elif myarg in {'expiration', 'expires'}:
65493
65524
  expiration = getTimeOrDeltaFromNow()
65494
- elif myarg == 'sendemail':
65525
+ elif myarg in {'sendemail', 'sendnotification'}:
65495
65526
  sendNotificationEmail = True
65496
65527
  elif myarg == 'emailmessage':
65497
65528
  sendNotificationEmail = True
gam/gamlib/glmsgs.py CHANGED
@@ -499,6 +499,7 @@ STATISTICS_MOVE_FILE = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut e
499
499
  STATISTICS_MOVE_FOLDER = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Move Failed: {6}, Not writable: {7}'
500
500
  STATISTICS_USER_NOT_ORGANIZER = 'User not organizer: {0}'
501
501
  STRING_LENGTH = 'string length'
502
+ STUDENT_NOT_IN_COURSE = 'Student not in course'
502
503
  SUBKEY_FIELD_MISMATCH = 'subkeyfield {0} does not match saved subkeyfield {1}'
503
504
  SUBSCRIPTION_NOT_FOUND = 'Could not find subscription'
504
505
  SUFFIX_NOT_ALLOWED_WITH_CUSTOMLANGUAGE = 'Suffix {0} not allowed with customLanguage {1}'
gam/gamlib/glskus.py CHANGED
@@ -100,7 +100,7 @@ _SKUS = {
100
100
  '1010470003': {
101
101
  'product': '101047', 'aliases': ['geminibiz'], 'displayName': 'Gemini Business'},
102
102
  '1010470004': {
103
- 'product': '101047', 'aliases': ['geminiedu'], 'displayName': 'Gemini Education'},
103
+ 'product': '101047', 'aliases': ['gaiproedu', 'geminiedu'], 'displayName': 'Google AI Pro for Education'},
104
104
  '1010470005': {
105
105
  'product': '101047', 'aliases': ['geminiedupremium'], 'displayName': 'Gemini Education Premium'},
106
106
  '1010470006': {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gam7
3
- Version: 7.20.2
3
+ Version: 7.20.3
4
4
  Summary: CLI tool to manage Google Workspace
5
5
  Project-URL: Homepage, https://github.com/GAM-team/GAM
6
6
  Project-URL: Issues, https://github.com/GAM-team/GAM/issues
@@ -1,4 +1,4 @@
1
- gam/__init__.py,sha256=Og3IJDcd2aooFJB-qfDqe39cEcQc6-CPGbdHFsv0LqY,3608827
1
+ gam/__init__.py,sha256=Dg18uAagGM_Ri_DQ16DbZHZY_PnpNgXH3VH4_nv1KHs,3610487
2
2
  gam/__main__.py,sha256=amz0-959ph6zkZKqjaar4n60yho-T37w6qWI36qx0CA,1049
3
3
  gam/cacerts.pem,sha256=DUsVo2XlFYwfkhe3gnxa-Km4Z4noz74hSApXwTT-nQE,44344
4
4
  gam/cbcm-v1.1beta1.json,sha256=xO5XloCQQULmPbFBx5bckdqmbLFQ7sJ2TImhE1ysDIY,19439
@@ -31,8 +31,8 @@ gam/gamlib/glgapi.py,sha256=pdBbwNtnCwFWxJGaP-_3hdTjSNoOCJF2yo76WdQOi1k,40426
31
31
  gam/gamlib/glgdata.py,sha256=weRppttWm6uRyqtBoGPKoHiNZ2h28nhfUV4J_mbCszY,2707
32
32
  gam/gamlib/glglobals.py,sha256=oJfaLUQj46XqwrOzRfWhGqO0f1P26xjJZefaILJUFGE,9695
33
33
  gam/gamlib/glindent.py,sha256=RfBa2LDfLIqPLL5vMfC689TCVmqn8xf-qulSzkiatrc,1228
34
- gam/gamlib/glmsgs.py,sha256=uluaFxw5YCG1so9uvOYU6HvAwGJNqJcB1curD8hH-G0,34001
35
- gam/gamlib/glskus.py,sha256=e1u3zw1MGQjBgAFXqjrGWQl2d7eYpVlMYGpIKNwjskQ,15360
34
+ gam/gamlib/glmsgs.py,sha256=ODq-KS3jhXH5DB5DEo6eCX1DHhy4OGv_jeQjiLVPOHM,34049
35
+ gam/gamlib/glskus.py,sha256=29vlBLBJCL4u9GawCt3eNeZq9HQG3hGFZk9-EainNng,15384
36
36
  gam/gamlib/gluprop.py,sha256=IyPLCyvn7-NHTUenM71YPQPXRZXx6CB5q-GtJ-FYd1c,11461
37
37
  gam/gamlib/glverlibs.py,sha256=xoQXiwcE_-HVYKv-VYA8O0mazRsc9mN-_ysj1dAlMyc,992
38
38
  gam/gamlib/yubikey.py,sha256=-UC-3oue9qarYK3LT7YL6Gmqs7TMK8oz9_AoxdaG2FA,7925
@@ -65,8 +65,8 @@ gam/googleapiclient/discovery_cache/base.py,sha256=yCDPtxnbNN-p5_9fzBacC6P3wcUPl
65
65
  gam/googleapiclient/discovery_cache/file_cache.py,sha256=sim3Mg4HgRYo3vX75jvcKy_aV568EvIrtBfvfbw-044,4774
66
66
  gam/iso8601/__init__.py,sha256=Z2PsYbXgAH5a5xzUvgczCboPzqWpm65kRcIngCnhViU,1218
67
67
  gam/iso8601/iso8601.py,sha256=Li2FHZ4sBTWuthuQhyCvmvj0j6At8JbGzkSv2fc2RHU,4384
68
- gam7-7.20.2.dist-info/METADATA,sha256=c9_lWA1fLzDtqEw6pI_v7ReKM3Sy18VnJpq6gU7xnHQ,2940
69
- gam7-7.20.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
70
- gam7-7.20.2.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
71
- gam7-7.20.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
- gam7-7.20.2.dist-info/RECORD,,
68
+ gam7-7.20.3.dist-info/METADATA,sha256=3rEbZ76pZrP2xa_v6tNKqFzRPGFDpZXuVXcgnkTUqgc,2940
69
+ gam7-7.20.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
70
+ gam7-7.20.3.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
71
+ gam7-7.20.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
+ gam7-7.20.3.dist-info/RECORD,,
File without changes