diff --git a/src/gam/cmd/admin.py b/src/gam/cmd/admin.py index 020a84a3..31cb6fe8 100644 --- a/src/gam/cmd/admin.py +++ b/src/gam/cmd/admin.py @@ -1,9 +1,7 @@ """GAM admin roles, privileges, and admin user management.""" import json -import sys -from gam.cmd.customer import PRINT_PRIVILEGES_FIELDS import re @@ -50,6 +48,7 @@ from gam.util.display import ( ) from gam.util.entity import ( ALL_GROUP_ROLES, + PRINT_PRIVILEGES_FIELDS, convertEmailAddressToUID, convertOrgUnitIDtoPath, convertUIDtoEmailAddressWithType, @@ -65,17 +64,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def _listPrivileges(cd): fields = f'items({",".join(PRINT_PRIVILEGES_FIELDS)})' try: @@ -109,7 +97,7 @@ def doPrintShowPrivileges(): Ind.Decrement() cd = buildGAPIObject(API.DIRECTORY) - csvPF = CSVPrintFile(_getMain().PRINT_PRIVILEGES_FIELDS, 'sortall') if Act.csvFormat() else None + csvPF = CSVPrintFile(PRINT_PRIVILEGES_FIELDS, 'sortall') if Act.csvFormat() else None getTodriveOnly(csvPF) privileges = _listPrivileges(cd) if not csvPF: diff --git a/src/gam/cmd/aliases.py b/src/gam/cmd/aliases.py index 59a320b2..df466c01 100644 --- a/src/gam/cmd/aliases.py +++ b/src/gam/cmd/aliases.py @@ -1,7 +1,6 @@ """GAM user and group alias management.""" import re -import sys import time from gamlib import glaction @@ -43,6 +42,7 @@ from gam.util.display import ( printGettingEntityItemForWhom, ) from gam.util.entity import ( + _getDomainList, convertEntityToList, getEntityArgument, getEntityList, @@ -52,6 +52,7 @@ from gam.util.entity import ( from gam.util.errors import entityActionFailedExit, unknownArgumentExit from gam.util.orgunits import getOrgUnitItem from gam.util.output import setSysExitRC +from gam.constants import ENTITY_IS_NOT_AN_ALIAS_RC, NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -59,18 +60,9 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def doCreateUpdateAliases(): + from gam.cmd.ciuserinvitations import _getIsInvitableUser + from gam.cmd.orgunits import ALIAS_TARGET_TYPES def verifyAliasTargetExists(): if targetType != 'group': try: @@ -131,7 +123,7 @@ def doCreateUpdateAliases(): ci = None updateCmd = Act.Get() == Act.UPDATE aliasList = getEntityList(Cmd.OB_EMAIL_ADDRESS_ENTITY) - targetType = getChoice(_getMain().ALIAS_TARGET_TYPES) + targetType = getChoice(ALIAS_TARGET_TYPES) targetEmails = getEntityList(Cmd.OB_GROUP_ENTITY) entityLists = targetEmails if isinstance(targetEmails, dict) else None verifyNotInvitable = False @@ -155,7 +147,7 @@ def doCreateUpdateAliases(): targetEmails = entityLists[aliasEmail] aliasEmail = normalizeEmailAddressOrUID(aliasEmail, noUid=True, noLower=True) if verifyNotInvitable: - isInvitableUser, ci = _getMain()._getIsInvitableUser(ci, aliasEmail) + isInvitableUser, ci = _getIsInvitableUser(ci, aliasEmail) if isInvitableUser: entityActionNotPerformedWarning([Ent.ALIAS_EMAIL, aliasEmail], Msg.EMAIL_ADDRESS_IS_UNMANAGED_ACCOUNT) continue @@ -213,8 +205,9 @@ def doCreateUpdateAliases(): # gam delete aliases|nicknames [user|group|target] def doDeleteAliases(): + from gam.cmd.orgunits import ALIAS_TARGET_TYPES cd = buildGAPIObject(API.DIRECTORY) - targetType = getChoice(_getMain().ALIAS_TARGET_TYPES, defaultChoice='target') + targetType = getChoice(ALIAS_TARGET_TYPES, defaultChoice='target') entityList = getEntityList(Cmd.OB_EMAIL_ADDRESS_ENTITY) checkForExtraneousArguments() i = 0 @@ -357,7 +350,7 @@ def deleteUsersAliases(users): jcount = len(user_aliases['aliases']) if ('aliases' in user_aliases) else 0 entityPerformActionNumItems([Ent.USER, user_primary], jcount, Ent.ALIAS, i, count) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) continue Ind.Increment() j = 0 @@ -377,6 +370,8 @@ def deleteUsersAliases(users): def infoAliases(entityList): + from gam.cmd.groups.members import INFO_GROUP_OPTIONS + from gam.cmd.users.manage import INFO_USER_OPTIONS def _showAliasInfo(uid, email, aliasEmail, entityType, aliasEntityType, i, count): if email.lower() != aliasEmail: printEntity([aliasEntityType, aliasEmail], i, count) @@ -385,7 +380,7 @@ def infoAliases(entityList): printEntity([Ent.UNIQUE_ID, uid]) Ind.Decrement() else: - setSysExitRC(_getMain().ENTITY_IS_NOT_AN_ALIAS_RC) + setSysExitRC(ENTITY_IS_NOT_AN_ALIAS_RC) printEntityKVList([Ent.EMAIL, aliasEmail], [f'Is a {Ent.Singular(entityType)}, not a {Ent.Singular(aliasEntityType)}'], i, count) @@ -394,7 +389,7 @@ def infoAliases(entityList): while Cmd.ArgumentsRemaining(): myarg = getArgument() # Ignore info group/user arguments that may have come from whatis - if (myarg in _getMain().INFO_GROUP_OPTIONS) or (myarg in _getMain().INFO_USER_OPTIONS): + if (myarg in INFO_GROUP_OPTIONS) or (myarg in INFO_USER_OPTIONS): if myarg == 'schemas': getString(Cmd.OB_SCHEMA_NAME_LIST) else: @@ -503,6 +498,7 @@ def userFilters(kwargs, query, orgUnitPath): # [suppressnoaliasrows] # (addcsvdata )* def doPrintAliases(): + from gam.cmd.groups.members import groupFilters def writeAliases(target, targetEmail, targetType): if not oneRowPerTarget: for alias in target.get('aliases', []): @@ -648,7 +644,7 @@ def doPrintAliases(): for kwargsQuery in makeUserGroupDomainQueryFilters(kwargsDict, None, None, None): kwargs = kwargsQuery[0] query = kwargsQuery[1] - query, pquery = _getMain().groupFilters(kwargs, query) + query, pquery = groupFilters(kwargs, query) printGettingAllAccountEntities(Ent.GROUP, pquery) try: entityList = callGAPIpages(cd.groups(), 'list', 'groups', @@ -755,7 +751,7 @@ def doPrintAddresses(): return for resource in entityList: csvPF.WriteRow({'Type': 'Resource', 'Email': resource['resourceEmail']}) - domains = _getMain()._getDomainList(cd, GC.Values[GC.CUSTOMER_ID], f'domains({",".join(domainFields)})') + domains = _getDomainList(cd, GC.Values[GC.CUSTOMER_ID], f'domains({",".join(domainFields)})') for domain in domains: domainEmail = domain['domainName'] csvPF.WriteRow({'Type': 'DomainPrimary' if domain['isPrimary'] else 'DomainSecondary', 'Email': domainEmail}) diff --git a/src/gam/cmd/analytics.py b/src/gam/cmd/analytics.py index 09cb4895..808eb75f 100644 --- a/src/gam/cmd/analytics.py +++ b/src/gam/cmd/analytics.py @@ -1,7 +1,6 @@ """GAM Google Analytics commands.""" import json -import sys from gamlib import glaction from gamlib import glapi as API @@ -39,19 +38,9 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def printShowAnalyticItems(users, entityType): - analyticEntityMap = _getMain().ANALYTIC_ENTITY_MAP[entityType] + from gam.cmd.reseller import ANALYTIC_ENTITY_MAP + analyticEntityMap = ANALYTIC_ENTITY_MAP[entityType] csvPF = CSVPrintFile(analyticEntityMap['titles'], 'sortall') if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) kwargs = {'pageSize': analyticEntityMap['pageSize']} diff --git a/src/gam/cmd/audit.py b/src/gam/cmd/audit.py index 0e36047e..fe965a80 100644 --- a/src/gam/cmd/audit.py +++ b/src/gam/cmd/audit.py @@ -1,7 +1,6 @@ """GAM audit monitor commands (GDATA).\n\nExtracted from gam/__init__.py. Provides mailbox monitor\ncreation/deletion/listing and doWhatIs command.""" import re -import sys from gamlib import glaction from gamlib import glapi as API @@ -33,6 +32,7 @@ from gam.util.display import ( ) from gam.util.errors import invalidArgumentExit, unknownArgumentExit from gam.util.output import setSysExitRC +from gam.constants import NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -40,17 +40,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def getAuditParameters(emailAddressRequired=True, requestIdRequired=True, destUserRequired=False): auditObject = getEmailAuditObject() emailAddress = getEmailAddress(noUid=True, optional=not emailAddressRequired) @@ -155,7 +144,7 @@ def doShowMonitors(): jcount = len(results) if (results) else 0 entityPerformActionNumItems([Ent.USER, parameters['auditUser']], jcount, Ent.AUDIT_MONITOR_REQUEST) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return Ind.Increment() j = 0 diff --git a/src/gam/cmd/browsers.py b/src/gam/cmd/browsers.py index 5a58bfd4..6615b04d 100644 --- a/src/gam/cmd/browsers.py +++ b/src/gam/cmd/browsers.py @@ -1,7 +1,6 @@ """GAM Chrome browser and browser token management.""" import json -import sys from gamlib import glaction from gamlib import glapi as API @@ -25,6 +24,7 @@ from gam.util.args import ( getString, getStringWithCRsNLs, getTimeOrDeltaFromNow, + substituteQueryTimes, ) from gam.util.csv_pf import ( CSVPrintFile, @@ -49,6 +49,8 @@ from gam.util.display import ( printLine, ) from gam.util.entity import ( + _getCustomerId, + _getCustomerIdNoC, convertEntityToList, getDeviceQueries, getEntitiesFromCSVFile, @@ -59,6 +61,7 @@ from gam.util.entity import ( ) from gam.util.errors import entityActionFailedExit, missingArgumentExit, unknownArgumentExit from gam.util.orgunits import getOrgUnitItem +from gam.constants import PROJECTION_CHOICE_MAP Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -66,20 +69,9 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def doDeleteBrowsers(): cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() deviceId = getString(Cmd.OB_DEVICE_ID) checkForExtraneousArguments() try: @@ -148,7 +140,7 @@ BROWSER_FULL_ACCESS_FIELDS = {'browsers', 'lastDeviceUsers', 'lastStatusReportTi # [formatjson] def doInfoBrowsers(): cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() deviceId = getString(Cmd.OB_DEVICE_ID) projection = 'BASIC' fieldsList = [] @@ -159,8 +151,8 @@ def doInfoBrowsers(): if myarg == 'annotated': projection = 'BASIC' fieldsList = BROWSER_ANNOTATED_FIELDS_LIST - elif myarg in _getMain().PROJECTION_CHOICE_MAP: - projection = _getMain().PROJECTION_CHOICE_MAP[myarg] + elif myarg in PROJECTION_CHOICE_MAP: + projection = PROJECTION_CHOICE_MAP[myarg] fieldsList = [] elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'): pass @@ -190,7 +182,7 @@ def doInfoBrowsers(): # [batchsize ] def doMoveBrowsers(): cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() deviceIds = [] batch_size = GC.Values[GC.BATCH_SIZE] orgUnitPath = '' @@ -220,7 +212,7 @@ def doMoveBrowsers(): unknownArgumentExit() if not orgUnitPath: missingArgumentExit('orgunit') - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) if queries: deviceIds.extend(getItemsToModify(Cmd.ENTITY_BROWSER_QUERIES, queries)) body = {'org_unit_path': orgUnitPath} @@ -264,7 +256,7 @@ BROWSER_DEVICEID_ANNOTATED_FIELDS = 'deviceId,annotatedAssetId,annotatedLocation # gam update browser + [updatenotes ] def doUpdateBrowsers(): cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() _, entityList = getEntityToModify(defaultEntityType=Cmd.ENTITY_BROWSER, browserAllowed=True, crosAllowed=False, userAllowed=False) body = {} updateNotes = None @@ -302,7 +294,7 @@ def doUpdateBrowsers(): def _getChromeProfileName(): profileName = getString(Cmd.OB_CHROMEPROFILE_NAME) if not profileName.startswith('customers'): - customerId = _getMain()._getCustomerId() + customerId = _getCustomerId() profileName = f'customers/{customerId}/profiles/{profileName}' return profileName @@ -454,7 +446,7 @@ def doPrintShowChromeProfiles(): for filterTimeName, filterTimeValue in filterTimes.items(): cbfilter = cbfilter.replace(f'#{filterTimeName}#', filterTimeValue) fields = getItemFieldsFromFieldsList('chromeBrowserProfiles', fieldsList) - customerId = _getMain()._getCustomerId() + customerId = _getCustomerId() parent = f'customers/{customerId}' printGettingAllAccountEntities(Ent.CHROME_PROFILE, cbfilter) pageMessage = getPageMessage() @@ -494,7 +486,7 @@ def _initChromeProfileNameParameters(): cm = buildGAPIObject(API.CHROMEMANAGEMENT) return (cm, {'profileNameList': _getChromeProfileNameList(), 'commandNameList': [], - 'customerId': _getMain()._getCustomerId(), + 'customerId': _getCustomerId(), 'cbfilter': None, 'filterTimes': {}, 'OBY': OrderBy(CHROMEPROFILE_ORDERBY_CHOICE_MAP)}) @@ -742,7 +734,7 @@ def doPrintShowBrowsers(): ensure_ascii=False, sort_keys=True)}) cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() csvPF = CSVPrintFile(['deviceId']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) fieldsList = [] @@ -771,11 +763,11 @@ def doPrintShowBrowsers(): elif myarg == 'annotated': projection = 'BASIC' fieldsList = BROWSER_ANNOTATED_FIELDS_LIST - elif (myarg == 'projection') or myarg in _getMain().PROJECTION_CHOICE_MAP: + elif (myarg == 'projection') or myarg in PROJECTION_CHOICE_MAP: if myarg == 'projection': - projection = getChoice(_getMain().PROJECTION_CHOICE_MAP, mapChoice=True) + projection = getChoice(PROJECTION_CHOICE_MAP, mapChoice=True) else: - projection = _getMain().PROJECTION_CHOICE_MAP[myarg] + projection = PROJECTION_CHOICE_MAP[myarg] fieldsList = [] elif myarg == 'allfields': projection = 'FULL' @@ -794,7 +786,7 @@ def doPrintShowBrowsers(): projection = 'FULL' if FJQC.formatJSON: sortHeaders = False - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) if entityList is None: fields = getItemFieldsFromFieldsList('browsers', fieldsList) if not rawFields else f'nextPageToken,browsers({rawFields})' for query in queries: @@ -871,7 +863,7 @@ def _showBrowserToken(browser, FJQC, i=0, count=0): # [formatjson] def doCreateBrowserToken(): cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() FJQC = FormatJSONQuoteChar() body = {'token_type': 'CHROME_BROWSER'} while Cmd.ArgumentsRemaining(): @@ -899,7 +891,7 @@ def doCreateBrowserToken(): # gam revoke browsertoken def doRevokeBrowserToken(): cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() tokenPermanentId = getString(Cmd.OB_BROWSER_ENROLLEMNT_TOKEN_ID) checkForExtraneousArguments() try: @@ -951,7 +943,7 @@ def doPrintShowBrowserTokens(): ensure_ascii=False, sort_keys=True)}) cbcm = buildGAPIObject(API.CBCM) - customerId = _getMain()._getCustomerIdNoC() + customerId = _getCustomerIdNoC() csvPF = CSVPrintFile(['token']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) fieldsList = [] @@ -985,7 +977,7 @@ def doPrintShowBrowserTokens(): fields = getItemFieldsFromFieldsList('chromeEnrollmentTokens', fieldsList) if FJQC.formatJSON: sortHeaders = False - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) for query in queries: printGettingAllAccountEntities(Ent.CHROME_BROWSER_ENROLLMENT_TOKEN, query) pageMessage = getPageMessage() diff --git a/src/gam/cmd/caa.py b/src/gam/cmd/caa.py index fe5aaa4f..70c17c47 100644 --- a/src/gam/cmd/caa.py +++ b/src/gam/cmd/caa.py @@ -2,7 +2,6 @@ import json import string -import sys from gamlib import glaction from gamlib import glapi as API @@ -39,6 +38,7 @@ from gam.util.display import ( ) from gam.util.errors import expectedArgumentExit, invalidChoiceExit, unknownArgumentExit from gam.util.output import systemErrorExit +from gam.constants import ACCESS_POLICY_ERROR_RC, NO_SA_ACCESS_CONTEXT_MANAGER_EDITOR_ROLE_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -46,20 +46,9 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def CAARoleErrorExit(caa): sa_email = caa._http.credentials.signer_email - systemErrorExit(_getMain().NO_SA_ACCESS_CONTEXT_MANAGER_EDITOR_ROLE_RC, + systemErrorExit(NO_SA_ACCESS_CONTEXT_MANAGER_EDITOR_ROLE_RC, f'Please grant service account {sa_email} the Access Context Manager Editor role in your GCP organization.') def buildCAAServiceObject(): @@ -67,9 +56,10 @@ def buildCAAServiceObject(): return caa def getAccessPolicy(caa=None): + from gam.cmd.project import getCRMOrgId if not caa: caa = buildCAAServiceObject() - parent = _getMain().getCRMOrgId() + parent = getCRMOrgId() if not parent: CAARoleErrorExit(caa) try: @@ -79,13 +69,13 @@ def getAccessPolicy(caa=None): except GAPI.permissionDenied: CAARoleErrorExit(caa) if not aps: - systemErrorExit(_getMain().ACCESS_POLICY_ERROR_RC, 'You don\'t seem to have any access policies. That is odd.') + systemErrorExit(ACCESS_POLICY_ERROR_RC, 'You don\'t seem to have any access policies. That is odd.') elif len(aps) == 1: return aps[0]['name'] for ap in aps: if ap.get('title') == 'Access policy created in Cloud Identity Console': return ap['name'] - systemErrorExit(_getMain().ACCESS_POLICY_ERROR_RC, 'Could not find a org level access policy. That is odd.') + systemErrorExit(ACCESS_POLICY_ERROR_RC, 'Could not find a org level access policy. That is odd.') def normalizeCAALevelName(caa, name): if name.startswith('accessPolicies/'): @@ -292,6 +282,7 @@ def doDeleteCAALevel(): # gam show caalevels # [formatjson] def doPrintShowCAALevels(): + from gam.cmd.notes import NOTES_TIME_OBJECTS caa = buildCAAServiceObject() ap_name = getAccessPolicy(caa) csvPF = CSVPrintFile(['name', 'title']) if Act.csvFormat() else None @@ -329,7 +320,7 @@ def doPrintShowCAALevels(): csvPF.WriteRowTitles(row) elif csvPF.CheckRowTitles(row): row = {'name': level['name'], 'title': level['title']} - row['JSON'] = json.dumps(cleanJSON(level, timeObjects=_getMain().NOTES_TIME_OBJECTS), + row['JSON'] = json.dumps(cleanJSON(level, timeObjects=NOTES_TIME_OBJECTS), ensure_ascii=False, sort_keys=True) csvPF.WriteRowNoFilter(row) if csvPF: diff --git a/src/gam/cmd/calendar.py b/src/gam/cmd/calendar.py index 11c8520d..9b4f6839 100644 --- a/src/gam/cmd/calendar.py +++ b/src/gam/cmd/calendar.py @@ -2,7 +2,6 @@ import re import json -import sys from gam.util.csv_pf import RI_ENTITY, RI_J, RI_JCOUNT, RI_ITEM, FormatJSONQuoteChar import uuid @@ -95,6 +94,7 @@ from gam.util.errors import ( ) from gam.util.fileio import UNKNOWN from gam.util.output import executeBatch, setSysExitRC +from gam.constants import DAYS_OF_WEEK, GOOGLE_MEETID_FORMAT_REQUIRED, GOOGLE_MEETID_PATTERN, NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -102,17 +102,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def normalizeCalendarId(calId, user): if not user or calId.lower() != 'primary': return convertUIDtoEmailAddress(calId, emailTypes=['user', 'resource']) @@ -239,15 +228,16 @@ def _normalizeCalIdGetRuleIds(origUser, user, origCal, calId, j, jcount, ACLScop return (calId, cal, None, 0) kcount = len(ruleIds) if kcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if showAction: entityPerformActionNumItems([Ent.CALENDAR, calId], kcount, Ent.CALENDAR_ACL, j, jcount) return (calId, cal, ruleIds, kcount) def _processCalendarACLs(cal, function, entityType, calId, j, jcount, k, kcount, role, ruleId, sendNotifications): + from gam import formatACLScopeRole, makeRoleRuleIdBody result = True if function == 'insert': - kwargs = {'body': _getMain().makeRoleRuleIdBody(role, ruleId), 'fields': '', 'sendNotifications': sendNotifications} + kwargs = {'body': makeRoleRuleIdBody(role, ruleId), 'fields': '', 'sendNotifications': sendNotifications} elif function == 'patch': kwargs = {'ruleId': ruleId, 'body': {'role': role}, 'fields': '', 'sendNotifications': sendNotifications} else: # elif function == 'delete': @@ -259,26 +249,27 @@ def _processCalendarACLs(cal, function, entityType, calId, j, jcount, k, kcount, GAPI.CANNOT_CHANGE_OWNER_ACL, GAPI.CANNOT_MODIFY_ACL_OF_CALENDAR_OWNER, GAPI.FORBIDDEN, GAPI.AUTH_ERROR, GAPI.CONDITION_NOT_MET], calendarId=calId, **kwargs) - entityActionPerformed([entityType, calId, Ent.CALENDAR_ACL, _getMain().formatACLScopeRole(ruleId, role)], k, kcount) + entityActionPerformed([entityType, calId, Ent.CALENDAR_ACL, formatACLScopeRole(ruleId, role)], k, kcount) except GAPI.notFound as e: if not checkCalendarExists(cal, calId, j, jcount): entityUnknownWarning(entityType, calId, j, jcount) result = False else: - entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, _getMain().formatACLScopeRole(ruleId, role)], str(e), k, kcount) + entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, formatACLScopeRole(ruleId, role)], str(e), k, kcount) except (GAPI.invalid, GAPI.invalidParameter, GAPI.invalidScopeValue, GAPI.illegalAccessRoleForDefault, GAPI.cannotChangeOwnAcl, GAPI.cannotChangeOwnerAcl, GAPI.cannotModifyAclOfCalendarOwner, GAPI.forbidden, GAPI.authError, GAPI.conditionNotMet) as e: - entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, _getMain().formatACLScopeRole(ruleId, role)], str(e), k, kcount) + entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, formatACLScopeRole(ruleId, role)], str(e), k, kcount) return result def _createCalendarACLs(cal, entityType, calId, j, jcount, role, ruleIds, kcount, sendNotifications): + from gam import normalizeRuleId Ind.Increment() k = 0 for ruleId in ruleIds: k += 1 - ruleId = _getMain().normalizeRuleId(ruleId) + ruleId = normalizeRuleId(ruleId) if not _processCalendarACLs(cal, 'insert', entityType, calId, j, jcount, k, kcount, role, ruleId, sendNotifications): break Ind.Decrement() @@ -303,11 +294,12 @@ def doCalendarsCreateACLs(calIds): _doCalendarsCreateACLs(None, None, None, calIds, len(calIds), role, ACLScopeEntity, sendNotifications) def _updateDeleteCalendarACLs(cal, function, entityType, calId, j, jcount, role, ruleIds, kcount, sendNotifications): + from gam import normalizeRuleId Ind.Increment() k = 0 for ruleId in ruleIds: k += 1 - ruleId = _getMain().normalizeRuleId(ruleId) + ruleId = normalizeRuleId(ruleId) if not _processCalendarACLs(cal, function, entityType, calId, j, jcount, k, kcount, role, ruleId, sendNotifications): break Ind.Decrement() @@ -342,6 +334,7 @@ def doCalendarsDeleteACLs(calIds): _doUpdateDeleteCalendarACLs(None, None, None, 'delete', calIds, len(calIds), ACLScopeEntity, role, False) def _showCalendarACL(user, entityType, calId, acl, k, kcount, FJQC): + from gam import ACLRuleKeyValueList if FJQC.formatJSON: if entityType == Ent.CALENDAR: if user: @@ -354,14 +347,15 @@ def _showCalendarACL(user, entityType, calId, acl, k, kcount, FJQC): printLine(json.dumps(cleanJSON({'resourceId': user, 'resourceEmail': calId, 'acl': acl}), ensure_ascii=False, sort_keys=True)) else: - printKeyValueListWithCount(_getMain().ACLRuleKeyValueList(acl), k, kcount) + printKeyValueListWithCount(ACLRuleKeyValueList(acl), k, kcount) def _infoCalendarACLs(cal, user, entityType, calId, j, jcount, ruleIds, kcount, FJQC): + from gam import formatACLScopeRole, normalizeRuleId Ind.Increment() k = 0 for ruleId in ruleIds: k += 1 - ruleId = _getMain().normalizeRuleId(ruleId) + ruleId = normalizeRuleId(ruleId) try: result = callGAPI(cal.acl(), 'get', throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID, GAPI.INVALID_SCOPE_VALUE, GAPI.FORBIDDEN, GAPI.AUTH_ERROR], @@ -371,9 +365,9 @@ def _infoCalendarACLs(cal, user, entityType, calId, j, jcount, ruleIds, kcount, if not checkCalendarExists(cal, calId, j, jcount): entityUnknownWarning(entityType, calId, j, jcount) break - entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, _getMain().formatACLScopeRole(ruleId, None)], str(e), k, kcount) + entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, formatACLScopeRole(ruleId, None)], str(e), k, kcount) except (GAPI.invalidScopeValue, GAPI.forbidden, GAPI.authError) as e: - entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, _getMain().formatACLScopeRole(ruleId, None)], str(e), k, kcount) + entityActionFailedWarning([entityType, calId, Ent.CALENDAR_ACL, formatACLScopeRole(ruleId, None)], str(e), k, kcount) Ind.Decrement() def _doInfoCalendarACLs(origUser, user, origCal, calIds, count, ACLScopeEntity, FJQC): @@ -410,7 +404,7 @@ def _printShowCalendarACLs(cal, user, entityType, calId, i, count, csvPF, FJQC, return jcount = len(acls) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if not csvPF: if not FJQC.formatJSON: if not noSelfOwner: @@ -810,8 +804,8 @@ def _getCalendarEventAttribute(myarg, body, parameters, function): elif myarg == 'conferencedata': checkArgumentPresent(['meet'], True) epLabel = getString(Cmd.OB_MEET_ID) - if not _getMain().GOOGLE_MEETID_PATTERN.match(epLabel): - invalidArgumentExit(_getMain().GOOGLE_MEETID_FORMAT_REQUIRED) + if not GOOGLE_MEETID_PATTERN.match(epLabel): + invalidArgumentExit(GOOGLE_MEETID_FORMAT_REQUIRED) body['conferenceData'] = {"conferenceId": epLabel, "conferenceSolution": {"key": {"type": "hangoutsMeet"}}, "entryPoints": [{"entryPointType": "video", "label": f'meet.google.com/{epLabel}', @@ -1076,7 +1070,7 @@ def _validateCalendarGetEventIDs(origUser, user, origCal, calId, j, jcount, cale kcount = len(calEventIds) if kcount == 0: entityNumEntitiesActionNotPerformedWarning([Ent.CALENDAR, calId], Ent.EVENT, kcount, Msg.NO_ENTITIES_MATCHED.format(Ent.Plural(Ent.EVENT)), j, jcount) - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (calId, cal, None, 0) except GAPI.notFound: entityUnknownWarning(Ent.CALENDAR, calId, j, jcount) @@ -1090,7 +1084,7 @@ def _validateCalendarGetEventIDs(origUser, user, origCal, calId, j, jcount, cale else: kcount = len(calEventIds) if kcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if not doIt: if showAction: entityNumEntitiesActionNotPerformedWarning([Ent.CALENDAR, calId], Ent.EVENT, kcount, Msg.USE_DOIT_ARGUMENT_TO_PERFORM_ACTION, j, jcount) @@ -1162,7 +1156,7 @@ def _validateCalendarGetEvents(origUser, user, origCal, calId, j, jcount, calend if showAction: entityPerformActionNumItems([Ent.CALENDAR, calId], kcount, Ent.EVENT, j, jcount) if kcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (calId, cal, eventsList, kcount) except (GAPI.notFound, GAPI.deleted) as e: if not checkCalendarExists(cal, calId, j, jcount): @@ -1222,13 +1216,13 @@ def _getEventDaysOfWeek(event): if 'date' in event[attr]: try: dateTime = arrow.Arrow.strptime(event[attr]['date'], YYYYMMDD_FORMAT) - event[attr]['dayOfWeek'] = _getMain().DAYS_OF_WEEK[dateTime.weekday()] + event[attr]['dayOfWeek'] = DAYS_OF_WEEK[dateTime.weekday()] except ValueError: pass elif 'dateTime' in event[attr]: try: dateTime = arrow.get(event[attr]['dateTime']) - event[attr]['dayOfWeek'] = _getMain().DAYS_OF_WEEK[dateTime.weekday()] + event[attr]['dayOfWeek'] = DAYS_OF_WEEK[dateTime.weekday()] except (arrow.parser.ParserError, OverflowError): pass @@ -2216,7 +2210,7 @@ def _normalizeResourceIdGetRuleIds(cd, resourceId, i, count, ACLScopeEntity, sho if showAction: entityPerformActionNumItems([Ent.RESOURCE_CALENDAR, resourceId], jcount, Ent.CALENDAR_ACL, i, count) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (calId, ruleIds, jcount) # gam resource create calendaracls [sendnotifications ] diff --git a/src/gam/cmd/chat/members.py b/src/gam/cmd/chat/members.py index 5a438731..5e77e9e1 100644 --- a/src/gam/cmd/chat/members.py +++ b/src/gam/cmd/chat/members.py @@ -4,7 +4,6 @@ Part of the _chat_tmp sub-package.""" """GAM Google Chat management.""" -import sys import uuid from gamlib import glaction @@ -30,6 +29,7 @@ from gam.util.args import ( getString, getStringOrFile, normalizeEmailAddressOrUID, + substituteQueryTimes, ) from gam.util.csv_pf import ( CSVPrintFile, @@ -62,17 +62,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def _getChatMemberEmail(cd, member): if 'member' in member: if member['member']['type'] == 'HUMAN': @@ -684,7 +673,7 @@ def printShowChatMembers(users): if useAdminAccess: if not parentList: kwargsCS['orderBy'] = OBY.orderBy - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) kwargsCS['query'] = queries[0] kwargsCS['useAdminAccess'] = True else: diff --git a/src/gam/cmd/chat/setup.py b/src/gam/cmd/chat/setup.py index c7634db8..564351d6 100644 --- a/src/gam/cmd/chat/setup.py +++ b/src/gam/cmd/chat/setup.py @@ -61,6 +61,8 @@ from gam.util.entity import getEntityArgument, splitEmailAddressOrUID from gam.util.errors import entityDoesNotExistExit, missingArgumentExit, unknownArgumentExit, usageErrorExit from gam.util.fileio import setFilePath from gam.util.output import setSysExitRC, systemErrorExit, writeStdout +from gam.constants import ADMIN_ACCESS_OPTIONS, API_ACCESS_DENIED_RC, GOOGLE_API_ERROR_RC, NO_ENTITIES_FOUND_RC +from gam.util.tags import _substituteForUser Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -68,17 +70,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def buildChatServiceObject(api=API.CHAT, user=None, i=0, count=0, entityTypeList=None, useAdminAccess=False): if user is None: _, chat = buildGAPIServiceObject(API.CHAT, user) @@ -107,11 +98,11 @@ def exitIfChatNotConfigured(chat, kvList, errMsg, i, count): if (('No bot associated with this project.' in errMsg) or ('Invalid project number.' in errMsg) or ('Google Chat app not found.' in errMsg)): - systemErrorExit(_getMain().API_ACCESS_DENIED_RC, Msg.TO_SET_UP_GOOGLE_CHAT.format(setupChatURL(chat), GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'])) + systemErrorExit(API_ACCESS_DENIED_RC, Msg.TO_SET_UP_GOOGLE_CHAT.format(setupChatURL(chat), GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'])) entityActionFailedWarning(kvList, errMsg, i, count) def _getChatAdminAccess(adminAPI, userAPI): - if checkArgumentPresent(_getMain().ADMIN_ACCESS_OPTIONS) or GC.Values[GC.USE_CHAT_ADMIN_ACCESS]: + if checkArgumentPresent(ADMIN_ACCESS_OPTIONS) or GC.Values[GC.USE_CHAT_ADMIN_ACCESS]: return (True, adminAPI, {'useAdminAccess': True}) return (False, userAPI, {}) @@ -207,7 +198,7 @@ def createChatEmoji(users): if not chat: continue user, userName, _ = splitEmailAddressOrUID(user) - filename = os.path.join(sourceFolder, _getMain()._substituteForUser(filenamePattern, user, userName)) + filename = os.path.join(sourceFolder, _substituteForUser(filenamePattern, user, userName)) try: with open(filename, 'rb') as f: image_data = f.read() @@ -484,7 +475,7 @@ def createUpdateChatSection(users): userChatServiceNotEnabledWarning(user, i, count) continue except AttributeError: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) + systemErrorExit(GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) # gam delete chatsection def deleteChatSection(users): @@ -516,7 +507,7 @@ def deleteChatSection(users): userChatServiceNotEnabledWarning(user, i, count) continue except AttributeError: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) + systemErrorExit(GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) # gam show chatsections # [formatjson] @@ -552,10 +543,10 @@ def printShowChatSections(users): userChatServiceNotEnabledWarning(user, i, count) continue except AttributeError: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) + systemErrorExit(GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) jcount = len(sections) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if not csvPF: if not FJQC.formatJSON: entityPerformActionNumItems(kvList, jcount, Ent.CHAT_SECTION, i, count) @@ -608,7 +599,7 @@ def moveShowChatSectionItem(users): userChatServiceNotEnabledWarning(user, i, count) continue except AttributeError: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) + systemErrorExit(GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) # gam show chatsectionitems # [space ] @@ -681,10 +672,10 @@ def printShowChatSectionItems(users): userChatServiceNotEnabledWarning(user, i, count) continue except AttributeError: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) + systemErrorExit(GOOGLE_API_ERROR_RC, Msg.DEVELOPER_PREVIEW_REQUIRED) jcount = len(sectionItems) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if not csvPF: if not FJQC.formatJSON: entityPerformActionNumItems(kvList, jcount, Ent.CHAT_SECTION_ITEM, i, count) diff --git a/src/gam/cmd/chat/spaces.py b/src/gam/cmd/chat/spaces.py index 18df6018..2eaac21e 100644 --- a/src/gam/cmd/chat/spaces.py +++ b/src/gam/cmd/chat/spaces.py @@ -30,6 +30,7 @@ from gam.util.args import ( getStringOrFile, getTimeOrDeltaFromNow, normalizeEmailAddressOrUID, + substituteQueryTimes, ) from gam.util.csv_pf import ( CSVPrintFile, @@ -56,6 +57,7 @@ from gam.util.errors import ( usageErrorExit, ) from gam.util.output import setSysExitRC, systemErrorExit, writeStdout +from gam.constants import NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -63,17 +65,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def getSpaceName(myarg): if myarg == 'space': chatSpace = getString(Cmd.OB_CHAT_SPACE) @@ -582,7 +573,7 @@ def printShowChatSpaces(users): if useAdminAccess: _chkChatAdminAccess(count) kwargsCS['orderBy'] = OBY.orderBy - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) pfilter = kwargsCS['query'] = queries[0] kwargsCS['useAdminAccess'] = True sortName = 'displayName' if 'displayName' in fieldsList else 'name' @@ -620,7 +611,7 @@ def printShowChatSpaces(users): continue jcount = len(spaces) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if not csvPF: if not FJQC.formatJSON: entityPerformActionNumItems(kvList, jcount, Ent.CHAT_SPACE, i, count) diff --git a/src/gam/cmd/chromeapps.py b/src/gam/cmd/chromeapps.py index 84ea2d9b..366a1374 100644 --- a/src/gam/cmd/chromeapps.py +++ b/src/gam/cmd/chromeapps.py @@ -2,7 +2,6 @@ import re import json -import sys from gamlib import glaction from gamlib import glapi as API @@ -18,6 +17,7 @@ from gam.util.api import buildGAPIObject, buildGAPIObjectNoAuthentication, callG from gam.util.args import ( OrderBy, YYYYMMDD_FORMAT, + _getFilterDateTime, getArgument, getBoolean, getCharacter, @@ -47,7 +47,7 @@ from gam.util.display import ( printKeyValueList, printLine, ) -from gam.util.entity import convertEntityToList, getEntityList +from gam.util.entity import _getCustomersCustomerIdWithC, convertEntityToList, getEntityList from gam.util.errors import missingArgumentExit, unknownArgumentExit from gam.util.fileio import UNKNOWN from gam.util.orgunits import getOrgUnitId @@ -58,20 +58,10 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def doInfoChromeApp(): + from gam.cmd.printers import CHROME_APPS_TIME_OBJECTS, CHROME_APPS_TYPE_CHOICES cm = buildGAPIObject(API.CHROMEMANAGEMENT_APPDETAILS) - app_type = getChoice(_getMain().CHROME_APPS_TYPE_CHOICES) + app_type = getChoice(CHROME_APPS_TYPE_CHOICES) app_id = getString(Cmd.OB_APP_ID) FJQC = FormatJSONQuoteChar() while Cmd.ArgumentsRemaining(): @@ -92,7 +82,7 @@ def doInfoChromeApp(): return printEntity([Ent.CHROME_APP, app_id]) Ind.Increment() - showJSON(None, appDetails, timeObjects=_getMain().CHROME_APPS_TIME_OBJECTS) + showJSON(None, appDetails, timeObjects=CHROME_APPS_TIME_OBJECTS) Ind.Decrement() except (GAPI.badRequest, GAPI.notFound, GAPI.forbidden): checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_APP, f'{app_type}/{app_id}') @@ -138,6 +128,7 @@ CHROME_APPS_TITLES = [ # [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] # [formatjson] def doPrintShowChromeApps(): + from gam.cmd.printers import ORGUNIT_ENTITIES_MAP def _printApp(app): if showOrgUnit: app['orgUnitPath'] = orgUnitPath @@ -161,7 +152,7 @@ def doPrintShowChromeApps(): cd = buildGAPIObject(API.DIRECTORY) cm = buildGAPIObject(API.CHROMEMANAGEMENT) - customerId = _getMain()._getCustomersCustomerIdWithC() + customerId = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['appId']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER] @@ -173,8 +164,8 @@ def doPrintShowChromeApps(): myarg = getArgument() if csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ORGUNIT_ENTITIES_MAP: - myarg = _getMain().ORGUNIT_ENTITIES_MAP[myarg] + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} elif myarg == 'filter': @@ -264,6 +255,7 @@ CHROME_APP_DEVICES_TITLES = ['appType', 'deviceId', 'machine'] # [orderby deviceid|machine] # [formatjson] def doPrintShowChromeAppDevices(): + from gam.cmd.printers import ORGUNIT_ENTITIES_MAP def _printDevice(device): device['appId'] = appId device['appType'] = appType @@ -291,7 +283,7 @@ def doPrintShowChromeAppDevices(): cd = buildGAPIObject(API.DIRECTORY) cm = buildGAPIObject(API.CHROMEMANAGEMENT) - customerId = _getMain()._getCustomersCustomerIdWithC() + customerId = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['appId']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) ous = [None] @@ -303,8 +295,8 @@ def doPrintShowChromeAppDevices(): myarg = getArgument() if csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ORGUNIT_ENTITIES_MAP: - myarg = _getMain().ORGUNIT_ENTITIES_MAP[myarg] + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} elif myarg == 'appid': @@ -312,10 +304,10 @@ def doPrintShowChromeAppDevices(): elif myarg == 'apptype': appType = getChoice(CHROME_APP_DEVICES_APPTYPE_CHOICE_MAP, mapChoice=True) elif myarg in CROS_START_ARGUMENTS: - startDate, _ = _getMain()._getFilterDateTime() + startDate, _ = _getFilterDateTime() startDate = startDate.strftime(YYYYMMDD_FORMAT) elif myarg in CROS_END_ARGUMENTS: - endDate, _ = _getMain()._getFilterDateTime() + endDate, _ = _getFilterDateTime() endDate = endDate.strftime(YYYYMMDD_FORMAT) elif myarg == 'orderby': orderBy = getChoice(CHROME_APP_DEVICES_ORDERBY_CHOICE_MAP, mapChoice=True) @@ -399,6 +391,7 @@ CHROME_AUE_TITLES = ['aueMonth', 'aueYear', 'expired'] # [minauedate ] [maxauedate ] # [formatjson] def doPrintShowChromeAues(): + from gam.cmd.printers import ORGUNIT_ENTITIES_MAP def _printAue(aue): if showOrgUnit: aue['orgUnitPath'] = orgUnitPath @@ -422,7 +415,7 @@ def doPrintShowChromeAues(): cd = buildGAPIObject(API.DIRECTORY) cm = buildGAPIObject(API.CHROMEMANAGEMENT) - customerId = _getMain()._getCustomersCustomerIdWithC() + customerId = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['model', 'count']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) ous = [None] @@ -433,15 +426,15 @@ def doPrintShowChromeAues(): myarg = getArgument() if csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ORGUNIT_ENTITIES_MAP: - myarg = _getMain().ORGUNIT_ENTITIES_MAP[myarg] + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} elif myarg == 'minauedate': - minAueDate, _ = _getMain()._getFilterDateTime() + minAueDate, _ = _getFilterDateTime() minAueDate = minAueDate.strftime(YYYYMMDD_FORMAT) elif myarg == 'maxauedate': - maxAueDate, _ = _getMain()._getFilterDateTime() + maxAueDate, _ = _getFilterDateTime() maxAueDate = maxAueDate.strftime(YYYYMMDD_FORMAT) else: FJQC.GetFormatJSONQuoteChar(myarg, True) @@ -514,6 +507,7 @@ CHROME_NEEDSATTN_TITLES = ['noRecentPolicySyncCount', 'noRecentUserActivityCount # (ous )|(ous_and_children )] # [formatjson] def doPrintShowChromeNeedsAttn(): + from gam.cmd.printers import ORGUNIT_ENTITIES_MAP def _printNeedsAttn(needsattn): if showOrgUnit: needsattn['orgUnitPath'] = orgUnitPath @@ -539,7 +533,7 @@ def doPrintShowChromeNeedsAttn(): cd = buildGAPIObject(API.DIRECTORY) cm = buildGAPIObject(API.CHROMEMANAGEMENT) - customerId = _getMain()._getCustomersCustomerIdWithC() + customerId = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile([]) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) ous = [None] @@ -549,8 +543,8 @@ def doPrintShowChromeNeedsAttn(): myarg = getArgument() if csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ORGUNIT_ENTITIES_MAP: - myarg = _getMain().ORGUNIT_ENTITIES_MAP[myarg] + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} else: @@ -627,7 +621,7 @@ CHROME_DEVICE_COUNTS_MODE_CSV_TITLE = { # [formatjson] def doPrintShowChromeDeviceCounts(): cm = buildGAPIObject(API.CHROMEMANAGEMENT) - customerId = _getMain()._getCustomersCustomerIdWithC() + customerId = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['date']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) pdate = todaysDate() @@ -695,6 +689,7 @@ CHROME_VERSIONS_TITLES = ['channel', 'system', 'deviceOsVersion'] # [recentfirst []] # [formatjson] def doPrintShowChromeVersions(): + from gam.cmd.printers import ORGUNIT_ENTITIES_MAP def _getVersionKey(v): if 'version' not in v: return (0, 0, 0, 0) @@ -730,7 +725,7 @@ def doPrintShowChromeVersions(): cd = buildGAPIObject(API.DIRECTORY) cm = buildGAPIObject(API.CHROMEMANAGEMENT) - customerId = _getMain()._getCustomersCustomerIdWithC() + customerId = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['version', 'count']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) ous = [None] @@ -741,15 +736,15 @@ def doPrintShowChromeVersions(): myarg = getArgument() if csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ORGUNIT_ENTITIES_MAP: - myarg = _getMain().ORGUNIT_ENTITIES_MAP[myarg] + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} elif myarg in CROS_START_ARGUMENTS: - startDate, _ = _getMain()._getFilterDateTime() + startDate, _ = _getFilterDateTime() startDate = startDate.strftime(YYYYMMDD_FORMAT) elif myarg in CROS_END_ARGUMENTS: - endDate, _ = _getMain()._getFilterDateTime() + endDate, _ = _getFilterDateTime() endDate = endDate.strftime(YYYYMMDD_FORMAT) elif myarg == 'recentfirst': reverse = getBoolean() diff --git a/src/gam/cmd/chromepolicies.py b/src/gam/cmd/chromepolicies.py index 200d356d..9232ac8c 100644 --- a/src/gam/cmd/chromepolicies.py +++ b/src/gam/cmd/chromepolicies.py @@ -2,7 +2,6 @@ import re import json -import sys import mimetypes import os @@ -63,7 +62,7 @@ from gam.util.display import ( printKeyValueListWithCount, printLine, ) -from gam.util.entity import convertEmailAddressToUID, convertOrgUnitIDtoPath, getGroupEmailFromID +from gam.util.entity import _getCustomersCustomerIdWithC, convertEmailAddressToUID, convertOrgUnitIDtoPath, getGroupEmailFromID from gam.util.errors import ( entityDoesNotExistExit, invalidArgumentExit, @@ -82,17 +81,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def _getOrgunitsOrgUnitIdPath(cd, orgUnit): if orgUnit.startswith('orgunits/'): orgUnit = f'id:{orgUnit[9:]}' @@ -280,7 +268,7 @@ def updatePolicyRequests(body, targetResource, printer_id, app_id): def doDeleteChromePolicy(): cp = buildGAPIObject(API.CHROMEPOLICY) cd = buildGAPIObject(API.DIRECTORY) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() app_id = groupEmail = orgUnit = printer_id = targetResource = None body = {'requests': []} schemaNameList = [] @@ -562,6 +550,7 @@ CHROME_TARGET_VERSION_PATTERN = re.compile(r'^(\d{1,4}\.){1,4}$') # ((ou|orgunit )|(group )) # [(printerid )|(appid )] def doUpdateChromePolicy(): + from gam.cmd.chromeapps import getPlatformChannelMap, getRelativeMilestone def getSpecialVtypeValue(vtype, value): if vtype in {'duration', 'value', 'downloadUri'}: return {vtype: value} @@ -574,7 +563,7 @@ def doUpdateChromePolicy(): cp = buildGAPIObject(API.CHROMEPOLICY) cd = buildGAPIObject(API.DIRECTORY) cv = None - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() app_id = channelMap = groupEmail = orgUnit = printer_id = targetResource = None body = {'requests': []} schemaNameList = [] @@ -644,10 +633,10 @@ def doUpdateChromePolicy(): if mg: channel = mg.group(1).lower().replace('_', '') if channelMap is None: - cv, channelMap = _getMain().getPlatformChannelMap(cv, Ent.CHROME_CHANNEL) + cv, channelMap = getPlatformChannelMap(cv, Ent.CHROME_CHANNEL) if channel not in channelMap: invalidChoiceExit(value, channelMap, True) - cv, status, milestone = _getMain().getRelativeMilestone(cv, channelMap[channel], int(mg.group(2))) + cv, status, milestone = getRelativeMilestone(cv, channelMap[channel], int(mg.group(2))) if not status: Cmd.Backup() invalidArgumentExit(f'{milestone} for {casedField}: {value}') @@ -708,16 +697,16 @@ def doUpdateChromePolicy(): elif vtype == 'TYPE_LIST': value = value.split(',') if value else [] elif vtype == 'TYPE_STRING' and convertCRsNLs: - value = _getMain().un_getMain().escapeCRsNLs(value) + value = escapeCRsNLs(value) if myarg == 'chrome.users.chromebrowserupdates' and casedField == 'targetVersionPrefixSetting': mg = CHROME_TARGET_VERSION_CHANNEL_MINUS_PATTERN.match(value) if mg: channel = mg.group(1).lower().replace('_', '') if channelMap is None: - cv, channelMap = _getMain().getPlatformChannelMap(cv, Ent.CHROME_CHANNEL) + cv, channelMap = getPlatformChannelMap(cv, Ent.CHROME_CHANNEL) if channel not in channelMap: invalidChoiceExit(value, channelMap, True) - cv, status, milestone = _getMain().getRelativeMilestone(cv, channelMap[channel], int(mg.group(2))) + cv, status, milestone = getRelativeMilestone(cv, channelMap[channel], int(mg.group(2))) if not status: Cmd.Backup() invalidArgumentExit(f'{milestone} for {casedField}: {value}') @@ -774,6 +763,7 @@ CHROME_POLICY_SHOW_CHOICE_MAP = { # [show all|direct|inherited] [shownopolicy] # [[formatjson [quotechar ]] def doPrintShowChromePolicies(): + from gam.cmd.cigroups.members import _showPolicy def normalizedPolicy(policy): norm = {'name': policy['value']['policySchema']} if app_id: @@ -893,7 +883,7 @@ def doPrintShowChromePolicies(): cp = buildGAPIObject(API.CHROMEPOLICY) cd = buildGAPIObject(API.DIRECTORY) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['name'], indexedTitles=CHROME_POLICY_INDEXED_TITLES) if Act.csvFormat() else None if csvPF: csvPF.SetNoEscapeChar(True) @@ -1012,7 +1002,7 @@ def doPrintShowChromePolicies(): j = 0 for policy in policies: j += 1 - _getMain()._showPolicy(policy, j, jcount) + _showPolicy(policy, j, jcount) Ind.Decrement() else: for policy in policies: @@ -1031,10 +1021,11 @@ CHROME_IMAGE_SCHEMAS_MAP = { # gam create chromepolicyimage def doCreateChromePolicyImage(): + from gam.cmd.drive.core import DFA_URL, getMediaBody cp = buildGAPIObject(API.CHROMEPOLICY) - parent = _getMain()._getCustomersCustomerIdWithC() + parent = _getCustomersCustomerIdWithC() schema = getChoice(CHROME_IMAGE_SCHEMAS_MAP, mapChoice=True) - parameters = {_getMain().DFA_URL: None} + parameters = {DFA_URL: None} parameters[DFA_LOCALFILEPATH] = setFilePath(getString(Cmd.OB_FILE_NAME), GC.INPUT_DIR) try: f = open(parameters[DFA_LOCALFILEPATH], 'rb') @@ -1047,7 +1038,7 @@ def doCreateChromePolicyImage(): if parameters[DFA_LOCALMIMETYPE] is None: parameters[DFA_LOCALMIMETYPE] = 'image/jpeg' checkForExtraneousArguments() - media_body = _getMain().getMediaBody(parameters) + media_body = getMediaBody(parameters) try: result = callGAPI(cp.media(), 'upload', throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.FORBIDDEN], @@ -1139,7 +1130,7 @@ def doPrintShowChromePolicySchemas(): doShowChromePolicySchemasStd(cp) return unknownArgumentExit() - parent = _getMain()._getCustomersCustomerIdWithC() + parent = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['name', 'schemaName', 'policyDescription', 'policyApiLifecycle.policyApiLifecycleStage', 'policyApiLifecycle.description', @@ -1254,7 +1245,7 @@ def doShowChromePolicySchemasStd(cp): sfilter = getString(Cmd.OB_STRING) else: unknownArgumentExit() - parent = _getMain()._getCustomersCustomerIdWithC() + parent = _getCustomersCustomerIdWithC() result = callGAPIpages(cp.customers().policySchemas(), 'list', 'policySchemas', retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS, parent=parent, filter=sfilter) @@ -1271,7 +1262,7 @@ def doShowChromePolicySchemasStd(cp): def doCreateChromeNetwork(): cp = buildGAPIObject(API.CHROMEPOLICY) cd = buildGAPIObject(API.DIRECTORY) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() body = {} orgUnitPath, body['targetResource'] = _getOrgunitsOrgUnitIdPath(cd, getString(Cmd.OB_ORGUNIT_PATH)) body['name'] = getString(Cmd.OB_STRING) @@ -1295,7 +1286,7 @@ def doCreateChromeNetwork(): def doDeleteChromeNetwork(): cp = buildGAPIObject(API.CHROMEPOLICY) cd = buildGAPIObject(API.DIRECTORY) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() body = {} orgUnitPath, body['targetResource'] = _getOrgunitsOrgUnitIdPath(cd, getString(Cmd.OB_ORGUNIT_PATH)) body['networkId'] = getString(Cmd.OB_NETWORK_ID) diff --git a/src/gam/cmd/cidevices.py b/src/gam/cmd/cidevices.py index 27573a08..ef138419 100644 --- a/src/gam/cmd/cidevices.py +++ b/src/gam/cmd/cidevices.py @@ -32,6 +32,7 @@ from gam.util.args import ( getInteger, getString, getTimeOrDeltaFromNow, + substituteQueryTimes, ) from gam.util.csv_pf import ( CSVPrintFile, @@ -54,7 +55,7 @@ from gam.util.display import ( printGettingAllAccountEntities, printLine, ) -from gam.util.entity import _validateDeviceQuery, convertEntityToList, getDeviceQueries +from gam.util.entity import _getCustomersCustomerIdNoC, _validateDeviceQuery, convertEntityToList, getDeviceQueries, setTrueCustomerId from gam.util.errors import ( csvFieldErrorExit, invalidArgumentExit, @@ -72,17 +73,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def buildGAPICIDeviceServiceObject(): if not GC.Values[GC.ENABLE_DASA]: _, ci = buildGAPIServiceObject(API.CLOUDIDENTITY_DEVICES, _getAdminEmail(), displayError=True) @@ -114,7 +104,7 @@ def getUpdateDeleteCIDeviceOptions(entityType, count, action, doit, actionChoice def getCIDeviceEntity(): ci = buildGAPICIDeviceServiceObject() - customer = _getMain()._getCustomersCustomerIdNoC() + customer = _getCustomersCustomerIdNoC() if checkArgumentPresent('devicesn'): query = f'serial:{getString(Cmd.OB_SERIAL_NUMBER)}' elif checkArgumentPresent('query'): @@ -152,7 +142,7 @@ DEVICE_USERNAME_CLIENT_STATE_PATTERN = re.compile(r'^(devices/.+/deviceUsers/.+) DEVICE_USERNAME_FORMAT_REQUIRED = 'devices//deviceUsers/' def getCIDeviceUserEntity(): ci = buildGAPICIDeviceServiceObject() - customer = _getMain()._getCustomersCustomerIdNoC() + customer = _getCustomersCustomerIdNoC() if checkArgumentPresent('query'): query = getString(Cmd.OB_QUERY) else: @@ -206,7 +196,7 @@ DEVICE_TIME_OBJECTS = {'createTime', 'firstSyncTime', 'lastSyncTime', 'lastUpdat # gam create device serialnumber devicetype [assettag ] def doCreateCIDevice(): ci = buildGAPICIDeviceServiceObject() - customer = _getMain()._getCustomersCustomerIdNoC() + customer = _getCustomersCustomerIdNoC() body = {'deviceType': '', 'serialNumber': ''} while Cmd.ArgumentsRemaining(): myarg = getArgument() @@ -300,7 +290,7 @@ DEVICE_MISSING_ACTION_MAP = { # [preview] def doSyncCIDevices(): ci = buildGAPICIDeviceServiceObject() - customer = _getMain()._getCustomersCustomerIdNoC() + customer = _getCustomersCustomerIdNoC() queryTimes = {} queries = [None] filename = None @@ -365,7 +355,7 @@ def doSyncCIDevices(): fields = f'nextPageToken,devices({",".join(fieldsList)})' remoteDevices = {} remoteDeviceMap = {} - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) for query in queries: printGettingAllAccountEntities(Ent.COMPANY_DEVICE, query) pageMessage = getPageMessage() @@ -603,7 +593,7 @@ DEVICE_ORDERBY_CHOICE_MAP = { # [showitemcountonly] def doPrintCIDevices(): ci = buildGAPICIDeviceServiceObject() - customer = _getMain()._getCustomersCustomerIdNoC() + customer = _getCustomersCustomerIdNoC() parent = 'devices/-' csvPF = CSVPrintFile(['name'], 'sortall') if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) @@ -646,7 +636,7 @@ def doPrintCIDevices(): FJQC.GetFormatJSONQuoteChar(myarg, True) fields = getItemFieldsFromFieldsList('devices', fieldsList) userFields = getItemFieldsFromFieldsList('deviceUsers', userFieldsList) - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) if FJQC.formatJSON and oneUserPerRow: csvPF.SetJSONTitles(['name', 'user.name', 'JSON']) itemCount = 0 @@ -841,7 +831,7 @@ def doInfoCIDeviceUser(): # [showitemcountonly] def doPrintCIDeviceUsers(): ci = buildGAPICIDeviceServiceObject() - customer = _getMain()._getCustomersCustomerIdNoC() + customer = _getCustomersCustomerIdNoC() csvPF = CSVPrintFile(['name'], 'sortall') if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) OBY = OrderBy(DEVICE_ORDERBY_CHOICE_MAP) @@ -873,7 +863,7 @@ def doPrintCIDeviceUsers(): else: FJQC.GetFormatJSONQuoteChar(myarg, True) userFields = getItemFieldsFromFieldsList('deviceUsers', userFieldsList) - _getMain().substituteQueryTimes(queries, queryTimes) + substituteQueryTimes(queries, queryTimes) itemCount = 0 for query in queries: printGettingAllAccountEntities(Ent.DEVICE_USER, query) @@ -930,7 +920,7 @@ DEVICE_USER_CUSTOM_VALUE_TYPE_CHOICE_MAP = { # gam info deviceuserstate [clientid ] def doInfoCIDeviceUserState(): - _getMain().setTrueCustomerId() + setTrueCustomerId() entityList, ci, customer, _ = getCIDeviceUserEntity() customerID = customer[10:] client_id = f'{customerID}-gam' @@ -968,7 +958,7 @@ def doInfoCIDeviceUserState(): # [healthscore verypoor|poor|neutral|good|verygood] [scorereason clear|] # (customvalue clear|(bool|boolean )|(number )(string ))* def doUpdateCIDeviceUserState(): - _getMain().setTrueCustomerId() + setTrueCustomerId() entityList, ci, customer, _ = getCIDeviceUserEntity() customerID = customer[10:] client_id = f'{customerID}-gam' diff --git a/src/gam/cmd/cigroups/groups.py b/src/gam/cmd/cigroups/groups.py index 821d11e5..68c6f528 100644 --- a/src/gam/cmd/cigroups/groups.py +++ b/src/gam/cmd/cigroups/groups.py @@ -5,7 +5,6 @@ Part of the _cigroups_tmp sub-package.""" """GAM Cloud Identity group management.""" import re -import sys from gam.util.entity import GROUP_ROLES_MAP @@ -62,27 +61,18 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - CIGROUP_DISCUSSION_FORUM_LABEL = 'cloudidentity.googleapis.com/groups.discussion_forum' CIGROUP_DYNAMIC_LABEL = 'cloudidentity.googleapis.com/groups.dynamic' CIGROUP_SECURITY_LABEL = 'cloudidentity.googleapis.com/groups.security' CIGROUP_LOCKED_LABEL = 'cloudidentity.googleapis.com/groups.locked' -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") NEVER_TIME = '1970-01-01T00:00:00.000Z' def doCreateCIGroup(): - _getMain().doCreateGroup(ciGroupsAPI=True) + from gam.cmd.groups.groups import doCreateGroup + doCreateGroup(ciGroupsAPI=True) # gam update cigroups [email ] # [updateprimaryemail [preview]] @@ -117,6 +107,7 @@ def doCreateCIGroup(): # [preview] [actioncsv] def doUpdateCIGroups(): + from gam.cmd.groups.groups import GROUP_ACCESS_TYPE_CHOICE_MAP, GROUP_CIGROUP_FIELDS_MAP, GROUP_JSON_SKIP_FIELDS, GROUP_PREVIEW_TITLES, GroupIsAbuseOrPostmaster, UPDATE_GROUP_SUBCMDS, checkReplyToCustom, getGroupAttrValue, getSettingsFromGroup, getSyncOperation, mapGroupEmailForSettings def _getExpireTime(role): if role == Ent.ROLE_MEMBER and checkArgumentPresent(['expire', 'expires']): return getTimeOrDeltaFromNow() @@ -125,7 +116,7 @@ def doUpdateCIGroups(): def _getPreviewActionCSV(): preview = checkArgumentPresent('preview') if checkArgumentPresent('actioncsv'): - csvPF = CSVPrintFile(_getMain().GROUP_PREVIEW_TITLES) + csvPF = CSVPrintFile(GROUP_PREVIEW_TITLES) else: csvPF = None return (preview, csvPF) @@ -268,7 +259,7 @@ def doUpdateCIGroups(): csvPF = None getBeforeUpdate = preview = False entityList = getEntityList(Cmd.OB_GROUP_ENTITY) - CL_subCommand = getChoice(_getMain().UPDATE_GROUP_SUBCMDS, defaultChoice=None) + CL_subCommand = getChoice(UPDATE_GROUP_SUBCMDS, defaultChoice=None) lockGroup = None if not CL_subCommand: gs_body = {} @@ -310,15 +301,15 @@ def doUpdateCIGroups(): elif myarg == 'unlocked': lockGroup = False elif myarg == 'json': - gs_body.update(getJSON(_getMain().GROUP_JSON_SKIP_FIELDS)) + gs_body.update(getJSON(GROUP_JSON_SKIP_FIELDS)) elif myarg == 'accesstype': - gs_body.update(getChoice(_getMain().GROUP_ACCESS_TYPE_CHOICE_MAP, mapChoice=True)) + gs_body.update(getChoice(GROUP_ACCESS_TYPE_CHOICE_MAP, mapChoice=True)) else: - _getMain().getGroupAttrValue(myarg, gs_body) + getGroupAttrValue(myarg, gs_body) if gs_body: gs = buildGAPIObject(API.GROUPSSETTINGS) - gs_body = _getMain().getSettingsFromGroup(cd, ','.join(entityList), gs, gs_body) - for k, v in _getMain().GROUP_CIGROUP_FIELDS_MAP.items(): + gs_body = getSettingsFromGroup(cd, ','.join(entityList), gs, gs_body) + for k, v in GROUP_CIGROUP_FIELDS_MAP.items(): if k in gs_body: ci_body[v] = gs_body.pop(k) if gs_body: @@ -343,7 +334,7 @@ def doUpdateCIGroups(): else: entityActionNotPerformedWarning([Ent.GROUP, group], Msg.PRIMARY_EMAIL_DID_NOT_MATCH_PATTERN.format(updatePrimaryEmail[0].pattern), i, count) continue - if gs_body and not _getMain().GroupIsAbuseOrPostmaster(group): + if gs_body and not GroupIsAbuseOrPostmaster(group): try: if group.find('@') == -1: # group settings API won't take uid so we make sure cd API is used so that we can grab real email. group = callGAPI(cd.groups(), 'get', @@ -352,9 +343,9 @@ def doUpdateCIGroups(): if getBeforeUpdate: settings = callGAPI(gs.groups(), 'get', throwReasons=GAPI.GROUP_SETTINGS_THROW_REASONS, retryReasons=GAPI.GROUP_SETTINGS_RETRY_REASONS, - groupUniqueId=_getMain().mapGroupEmailForSettings(group), fields='*') + groupUniqueId=mapGroupEmailForSettings(group), fields='*') settings.update(gs_body) - if not _getMain().checkReplyToCustom(group, settings, i, count): + if not checkReplyToCustom(group, settings, i, count): continue except GAPI.notFound: entityActionFailedWarning([entityType, group], Msg.DOES_NOT_EXIST, i, count) @@ -364,12 +355,12 @@ def doUpdateCIGroups(): GAPI.systemError, GAPI.serviceLimit, GAPI.serviceNotAvailable, GAPI.authError) as e: entityActionFailedWarning([entityType, group], str(e), i, count) continue - if gs_body and not _getMain().GroupIsAbuseOrPostmaster(group): + if gs_body and not GroupIsAbuseOrPostmaster(group): try: callGAPI(gs.groups(), 'update', bailOnInvalidError='messageModerationLevel' in settings, throwReasons=GAPI.GROUP_SETTINGS_THROW_REASONS, retryReasons=GAPI.GROUP_SETTINGS_RETRY_REASONS, - groupUniqueId=_getMain().mapGroupEmailForSettings(group), body=settings, fields='') + groupUniqueId=mapGroupEmailForSettings(group), body=settings, fields='') except GAPI.notFound: entityActionFailedWarning([entityType, group], Msg.DOES_NOT_EXIST, i, count) continue @@ -534,7 +525,7 @@ def doUpdateCIGroups(): elif CL_subCommand == 'sync': baseRole, groupMemberType = _getRoleGroupMemberType(allowIgnoreRole=True) ignoreRole = baseRole == Ent.ROLE_ALL - syncOperation = _getMain().getSyncOperation() + syncOperation = getSyncOperation() isSuspended, isArchived = _getOptionalIsSuspendedIsArchived() expireTime = _getExpireTime(baseRole) preview, csvPF = _getPreviewActionCSV() @@ -754,7 +745,7 @@ def doUpdateCIGroups(): elif myarg == 'preview': preview = True elif myarg == 'actioncsv': - csvPF = CSVPrintFile(_getMain().GROUP_PREVIEW_TITLES) + csvPF = CSVPrintFile(GROUP_PREVIEW_TITLES) else: unknownArgumentExit() Act.Set(Act.REMOVE) @@ -809,7 +800,8 @@ def doUpdateCIGroups(): # gam delete cigroups def doDeleteCIGroups(): - _getMain().doDeleteGroups(ciGroupsAPI=True) + from gam.cmd.groups.groups import doDeleteGroups + doDeleteGroups(ciGroupsAPI=True) CIGROUP_MEMBER_TYPES_MAP = { 'cbcmbrowser': Ent.TYPE_CBCM_BROWSER, diff --git a/src/gam/cmd/cigroups/members.py b/src/gam/cmd/cigroups/members.py index 001d9d6f..4f933c98 100644 --- a/src/gam/cmd/cigroups/members.py +++ b/src/gam/cmd/cigroups/members.py @@ -6,7 +6,6 @@ Part of the _cigroups_tmp sub-package.""" import re import json -import sys from gam.util.args import formatLocalTime @@ -26,8 +25,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] from gam.cmd.groups.groups import ( MEMBEROPTION_INCLUDEDERIVEDMEMBERSHIP, MEMBEROPTION_ISARCHIVED, @@ -84,6 +81,7 @@ from gam.util.entity import ( _checkMemberIsSuspendedIsArchived, _checkMemberRole, _getCIRoleVerification, + _getCustomersCustomerIdWithC, convertEmailAddressToUID, convertGroupCloudIDToEmail, convertGroupEmailToCloudID, @@ -93,6 +91,7 @@ from gam.util.entity import ( getCIGroupTransitiveMemberRoleFixType, getEntityList, getEntityToModify, + setTrueCustomerId, shlexSplitList, ) from gam.util.errors import ( @@ -104,17 +103,9 @@ from gam.util.errors import ( usageErrorExit, ) from gam.util.fileio import UNKNOWN -from gam.util.orgunits import _getMain from gam.util.output import systemErrorExit, writeStdout CIGROUP_DISCUSSION_FORUM_LABEL = 'cloudidentity.googleapis.com/groups.discussion_forum' -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") UNKNOWN = 'Unknown' @@ -139,6 +130,7 @@ def getCIGroupMemberTypes(myarg, typesSet): # [memberemaildisplaypattern|memberemailskippattern ] # [formatjson] def doInfoCIGroups(): + from gam.cmd.groups.members import CIGROUP_FIELDS_CHOICE_MAP, CIGROUP_TIME_OBJECTS, _checkCIMemberMatch, _showCIGroup, finalizeIPSGMGroupRolesMemberDisplayOptions, getIPSGMGroupRolesMemberDisplayOptions, getMemberMatchOptions, initIPSGMGroupMemberDisplayOptions, initMemberOptions def printCIGroupMemberTree(group_id, showRole): if not group_id in cachedGroupMembers: try: @@ -185,8 +177,8 @@ def doInfoCIGroups(): entityType = Ent.MEMBER rolesSet = set() typesSet = set() - memberOptions = _getMain().initMemberOptions() - memberDisplayOptions = _getMain().initIPSGMGroupMemberDisplayOptions() + memberOptions = initMemberOptions() + memberDisplayOptions = initIPSGMGroupMemberDisplayOptions() cachedGroupMembers = {} while Cmd.ArgumentsRemaining(): myarg = getArgument() @@ -196,29 +188,29 @@ def doInfoCIGroups(): getUsers = False elif myarg == 'membertree': showMemberTree = True - elif _getMain().getIPSGMGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): + elif getIPSGMGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): getUsers = True elif getCIGroupMemberTypes(myarg, typesSet): pass - elif _getMain().getMemberMatchOptions(myarg, memberOptions): + elif getMemberMatchOptions(myarg, memberOptions): pass elif myarg == 'noaliases': getAliases = False elif myarg in {'allfields', 'ciallfields', 'allcifields'}: if not groupFieldsLists['ci']: groupFieldsLists['ci'] = [] - for field in _getMain().CIGROUP_FIELDS_CHOICE_MAP: - addFieldToFieldsList(field, _getMain().CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) - elif myarg in _getMain().CIGROUP_FIELDS_CHOICE_MAP: + for field in CIGROUP_FIELDS_CHOICE_MAP: + addFieldToFieldsList(field, CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) + elif myarg in CIGROUP_FIELDS_CHOICE_MAP: initGroupFieldsLists() - addFieldToFieldsList(myarg, _getMain().CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) + addFieldToFieldsList(myarg, CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) elif myarg in {'fields', 'cifields'}: initGroupFieldsLists() for field in _getFieldsList(): - if field in _getMain().CIGROUP_FIELDS_CHOICE_MAP: - addFieldToFieldsList(field, _getMain().CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) + if field in CIGROUP_FIELDS_CHOICE_MAP: + addFieldToFieldsList(field, CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) else: - invalidChoiceExit(field, _getMain().CIGROUP_FIELDS_CHOICE_MAP, True) + invalidChoiceExit(field, CIGROUP_FIELDS_CHOICE_MAP, True) elif myarg == 'nojoindate': showJoinDate = False elif myarg == 'showupdatedate': @@ -236,7 +228,7 @@ def doInfoCIGroups(): else: view = 'FULL' pageSize = 500 - showCategory, checkShowCategory = _getMain().finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, False) + showCategory, checkShowCategory = finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, False) i = 0 count = len(entityList) for group in entityList: @@ -260,7 +252,7 @@ def doInfoCIGroups(): getCIGroupMemberRoleFixType(member) if ((member['type'] in typesSet) and _checkMemberRole(member, rolesSet) and - _getMain()._checkCIMemberMatch(member, memberOptions) and + _checkCIMemberMatch(member, memberOptions) and (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions))): members.append(member) if getSecuritySettings: @@ -270,9 +262,9 @@ def doInfoCIGroups(): if FJQC.formatJSON: if getUsers and not showMemberTree: cigInfo['members'] = members - printLine(json.dumps(cleanJSON(cigInfo, timeObjects=_getMain().CIGROUP_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) + printLine(json.dumps(cleanJSON(cigInfo, timeObjects=CIGROUP_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) continue - _getMain()._showCIGroup(cigInfo, group, i, count) + _showCIGroup(cigInfo, group, i, count) if getUsers and not showMemberTree: Ind.Increment() printEntitiesCount(entityType, members) @@ -315,10 +307,11 @@ def checkCIGroupShowOwnedBy(showOwnedBy, members): return False def updateFieldsForCIGroupMatchPatterns(matchPatterns, fieldsList, csvPF=None): + from gam.cmd.groups.members import CIGROUP_FIELDS_CHOICE_MAP for field in ['displayName', 'description']: if field in matchPatterns: if csvPF is not None: - csvPF.AddField(field, _getMain().CIGROUP_FIELDS_CHOICE_MAP, fieldsList) + csvPF.AddField(field, CIGROUP_FIELDS_CHOICE_MAP, fieldsList) else: fieldsList.append(field) @@ -439,6 +432,7 @@ def _checkPoliciesWithDASA(): # json # [(ou|orgunit )|(group )|(query )] def doCreateUpdateCIPolicy(): + from gam.cmd.chromepolicies import _getOrgunitsOrgUnitIdPath _checkPoliciesWithDASA() ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY) cd = buildGAPIObject(API.DIRECTORY) @@ -478,7 +472,7 @@ def doCreateUpdateCIPolicy(): if query: Cmd.Backup() usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format(myarg, 'query')) - orgUnit, targetResource = _getMain()._getOrgunitsOrgUnitIdPath(cd, getString(Cmd.OB_ORGUNIT_PATH)) + orgUnit, targetResource = _getOrgunitsOrgUnitIdPath(cd, getString(Cmd.OB_ORGUNIT_PATH)) policy['policyQuery'] = {'orgUnit': f"orgUnits/{targetResource}"} elif myarg == 'group': if orgUnit: @@ -503,7 +497,7 @@ def doCreateUpdateCIPolicy(): unknownArgumentExit() if 'policyQuery' not in policy: missingArgumentExit('ou|org|orgunit|group|query') - policy['customer'] = _getMain()._getCustomersCustomerIdWithC() + policy['customer'] = _getCustomersCustomerIdWithC() try: if updateCmd: result = callGAPI(ci.policies(), 'patch', @@ -701,6 +695,7 @@ def doPrintShowCIPolicies(): # [formatjson [quotechar ]] # [showitemcountonly] def doPrintCIGroups(): + from gam.cmd.groups.members import CIGROUP_FIELDS_CHOICE_MAP, CIGROUP_FULL_FIELDS, CIGROUP_PRINT_ORDER, CIGROUP_TIME_OBJECTS, addMemberInfoToRow, checkGroupMatchPatterns, finalizeIPSGMGroupRolesMemberDisplayOptions, getGroupAllowExternalMembers, getGroupMatchPatterns, getMemberMatchOptions, getPGGroupRolesMemberDisplayOptions, initIPSGMGroupMemberDisplayOptions, initMemberOptions, mapCIGroupFieldNames, setMemberDisplaySortTitles, setMemberDisplayTitles def _printGroupRow(groupEntity, groupMembers): nonlocal itemCount for member in groupMembers: @@ -721,39 +716,39 @@ def doPrintCIGroups(): row['email'] = groupEntity['groupKey']['id'].lower() if addCSVData and includeCSVDataInJSON: groupEntity.update(addCSVData) - row['JSON'] = json.dumps(cleanJSON(groupEntity, timeObjects=_getMain().CIGROUP_TIME_OBJECTS), ensure_ascii=False, sort_keys=True) + row['JSON'] = json.dumps(cleanJSON(groupEntity, timeObjects=CIGROUP_TIME_OBJECTS), ensure_ascii=False, sort_keys=True) if rolesSet and groupMembers is not None: row['JSON-members'] = json.dumps(groupMembers, ensure_ascii=False, sort_keys=True) csvPF.WriteRowNoFilter(row) return - _getMain().mapCIGroupFieldNames(groupEntity) + mapCIGroupFieldNames(groupEntity) for k, v in groupEntity.pop('labels', {}).items(): if v == '': groupEntity[f'labels{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{k}'] = True else: groupEntity[f'labels{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{k}'] = v - for key, value in sorted(flattenJSON(groupEntity, flattened={}, timeObjects=_getMain().CIGROUP_TIME_OBJECTS).items()): + for key, value in sorted(flattenJSON(groupEntity, flattened={}, timeObjects=CIGROUP_TIME_OBJECTS).items()): csvPF.AddTitles(key) row[key] = value if rolesSet and groupMembers is not None: - _getMain().addMemberInfoToRow(row, groupMembers, typesSet, memberOptions, memberDisplayOptions, delimiter, + addMemberInfoToRow(row, groupMembers, typesSet, memberOptions, memberDisplayOptions, delimiter, False, False, True) csvPF.WriteRow(row) cd = buildGAPIObject(API.DIRECTORY) ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS) - _getMain().setTrueCustomerId(cd) + setTrueCustomerId(cd) parent = f'customers/{GC.Values[GC.CUSTOMER_ID]}' delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER] memberRestrictions = sortHeaders = False - memberDisplayOptions = _getMain().initIPSGMGroupMemberDisplayOptions() + memberDisplayOptions = initIPSGMGroupMemberDisplayOptions() pageSize = 500 groupFieldsLists = {'ci': ['groupKey']} csvPF = CSVPrintFile(['email']) FJQC = FormatJSONQuoteChar(csvPF) rolesSet = set() typesSet = set() - memberOptions = _getMain().initMemberOptions() + memberOptions = initMemberOptions() allowExternalMembers = entitySelection = groupMembers = memberQuery = query = showOwnedBy = None matchPatterns = {} showItemCountOnly = False @@ -774,7 +769,7 @@ def doPrintCIGroups(): elif myarg == 'query': query = getString(Cmd.OB_QUERY) entitySelection = None - elif _getMain().getGroupMatchPatterns(myarg, matchPatterns, True): + elif getGroupMatchPatterns(myarg, matchPatterns, True): pass elif myarg == 'select': entitySelection = getEntityList(Cmd.OB_GROUP_ENTITY) @@ -786,26 +781,26 @@ def doPrintCIGroups(): elif myarg in {'allfields', 'ciallfields', 'allcifields'}: sortHeaders = True groupFieldsLists = {'ci': []} - for field in _getMain().CIGROUP_FIELDS_CHOICE_MAP: - addFieldToFieldsList(field, _getMain().CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) + for field in CIGROUP_FIELDS_CHOICE_MAP: + addFieldToFieldsList(field, CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) elif myarg == 'basic': sortHeaders = True groupFieldsLists = {'ci': ['*']} elif myarg == 'sortheaders': sortHeaders = getBoolean() - elif myarg in _getMain().CIGROUP_FIELDS_CHOICE_MAP: - csvPF.AddField(myarg, _getMain().CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) + elif myarg in CIGROUP_FIELDS_CHOICE_MAP: + csvPF.AddField(myarg, CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) elif myarg in {'fields', 'cifields'}: for field in _getFieldsList(): - if field in _getMain().CIGROUP_FIELDS_CHOICE_MAP: - csvPF.AddField(field, _getMain().CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) + if field in CIGROUP_FIELDS_CHOICE_MAP: + csvPF.AddField(field, CIGROUP_FIELDS_CHOICE_MAP, groupFieldsLists['ci']) else: - invalidChoiceExit(field, list(_getMain().CIGROUP_FIELDS_CHOICE_MAP), True) - elif _getMain().getPGGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): + invalidChoiceExit(field, list(CIGROUP_FIELDS_CHOICE_MAP), True) + elif getPGGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): pass elif getCIGroupMemberTypes(myarg, typesSet): pass - elif _getMain().getMemberMatchOptions(myarg, memberOptions): + elif getMemberMatchOptions(myarg, memberOptions): pass elif myarg == 'memberrestrictions': memberRestrictions = True @@ -819,7 +814,7 @@ def doPrintCIGroups(): FJQC.GetFormatJSONQuoteChar(myarg, False) if not typesSet: typesSet = ALL_CIGROUP_MEMBER_TYPES - showCategory, _ = _getMain().finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, False) + showCategory, _ = finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, False) fields = ','.join(set(groupFieldsLists['ci'])) csvPF.MapTitles('name', 'id') csvPF.MapTitles('displayName', 'name') @@ -853,7 +848,7 @@ def doPrintCIGroups(): getRolesSet.add(Ent.ROLE_OWNER) getRoles = ','.join(sorted(getRolesSet)) if rolesSet: - _getMain().setMemberDisplayTitles(memberDisplayOptions, csvPF) + setMemberDisplayTitles(memberDisplayOptions, csvPF) if memberQuery: printGettingAllAccountEntities(Ent.CLOUD_IDENTITY_GROUP, memberQuery) try: @@ -872,10 +867,10 @@ def doPrintCIGroups(): if entitySelection is None: if groupFieldsLists['ci']: for field in groupFieldsLists['ci']: - if field in _getMain().CIGROUP_FULL_FIELDS: + if field in CIGROUP_FULL_FIELDS: getFullFieldsList.append(field) else: - getFullFieldsList = list(_getMain().CIGROUP_FULL_FIELDS) + getFullFieldsList = list(CIGROUP_FULL_FIELDS) getFullFields = ','.join(getFullFieldsList)# if query: method = 'search' @@ -926,7 +921,7 @@ def doPrintCIGroups(): for groupEntity in entityList: i += 1 groupEmail = groupEntity['groupKey']['id'].lower() - if not _getMain().checkGroupMatchPatterns(groupEmail, groupEntity, matchPatterns): + if not checkGroupMatchPatterns(groupEmail, groupEntity, matchPatterns): continue kvList = [Ent.CLOUD_IDENTITY_GROUP, groupEmail] if getFullFields: @@ -940,7 +935,7 @@ def doPrintCIGroups(): GAPI.systemError, GAPI.permissionDenied, GAPI.serviceNotAvailable) as e: entityActionFailedWarning(kvList, str(e), i, count) if showCategory: - allowExternalMembers = _getMain().getGroupAllowExternalMembers(memberDisplayOptions['gs'], groupEmail, False, + allowExternalMembers = getGroupAllowExternalMembers(memberDisplayOptions['gs'], groupEmail, False, kvList, i, count) if allowExternalMembers is None: continue @@ -979,22 +974,25 @@ def doPrintCIGroups(): sortTitles.append('allowExternalMembers') if addCSVData: sortTitles.extend(sorted(addCSVData.keys())) - sortTitles.extend(_getMain().CIGROUP_PRINT_ORDER) + sortTitles.extend(CIGROUP_PRINT_ORDER) if rolesSet: - _getMain().setMemberDisplaySortTitles(memberDisplayOptions, sortTitles) + setMemberDisplaySortTitles(memberDisplayOptions, sortTitles) csvPF.SetSortTitles(sortTitles) csvPF.SortRows('email', False) csvPF.writeCSVfile('Cloud Identity Groups') # gam info cimember def infoCIGroupMembers(entityList): - _getMain().infoGroupMembers(entityList, True) + from gam.cmd.groups.members import infoGroupMembers + infoGroupMembers(entityList, True) # gam info cimember def doInfoCIGroupMembers(): - _getMain().infoGroupMembers(getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)[1], True) + from gam.cmd.groups.members import infoGroupMembers + infoGroupMembers(getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)[1], True) def getCIGroupMembersEntityList(ci, entityList, query, subTitle, matchPatterns, fieldsList, csvPF): + from gam.cmd.groups.members import clearUnneededGroupMatchPatterns if query: printGettingAllAccountEntities(Ent.CLOUD_IDENTITY_GROUP, query) parent = 'groups/-' @@ -1024,7 +1022,7 @@ def getCIGroupMembersEntityList(ci, entityList, query, subTitle, matchPatterns, GAPI.systemError, GAPI.permissionDenied, GAPI.serviceNotAvailable) as e: entityActionFailedExit([Ent.CLOUD_IDENTITY_GROUP, parent], str(e)) else: - _getMain().clearUnneededGroupMatchPatterns(matchPatterns) + clearUnneededGroupMatchPatterns(matchPatterns) return entityList def getCIGroupTransitiveMembers(ci, groupName, membersList, i, count): @@ -1046,6 +1044,8 @@ def getCIGroupTransitiveMembers(ci, groupName, membersList, i, count): def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i, count, memberOptions, memberDisplayOptions, level, typesSet, groupEmail, kwargs): + from gam.cmd.chat.members import _getChatSpaceMembers + from gam.cmd.groups.members import _checkCIMemberMatch nameToPrint = groupEmail if groupEmail else groupName printGettingAllEntityItemsForWhom(memberRoles if memberRoles else Ent.ROLE_MANAGER_MEMBER_OWNER, nameToPrint, i, count) validRoles = _getCIRoleVerification(memberRoles) @@ -1055,7 +1055,7 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i return for member in groupMembers: if _checkMemberRole(member, validRoles): - if member['type'] in typesSet and _getMain()._checkCIMemberMatch(member, memberOptions): + if member['type'] in typesSet and _checkCIMemberMatch(member, memberOptions): membersList.append(member) return if not groupEmail.startswith('space/'): @@ -1070,7 +1070,7 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i entityUnknownWarning(Ent.CLOUD_IDENTITY_GROUP, nameToPrint, i, count) return else: - groupMembers = _getMain()._getChatSpaceMembers(cd, groupEmail, groupName) + groupMembers = _getChatSpaceMembers(cd, groupEmail, groupName) checkShowCategory = memberDisplayOptions['checkShowCategory'] if not memberOptions[MEMBEROPTION_RECURSIVE]: if memberOptions[MEMBEROPTION_NODUPLICATES]: @@ -1081,14 +1081,14 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions)) and memberName not in membersSet): membersSet.add(memberName) - if member['type'] in typesSet and _getMain()._checkCIMemberMatch(member, memberOptions): + if member['type'] in typesSet and _checkCIMemberMatch(member, memberOptions): membersList.append(member) else: for member in groupMembers: getCIGroupMemberRoleFixType(member) if (_checkMemberRole(member, validRoles) and (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions))): - if member['type'] in typesSet and _getMain()._checkCIMemberMatch(member, memberOptions): + if member['type'] in typesSet and _checkCIMemberMatch(member, memberOptions): membersList.append(member) elif memberOptions[MEMBEROPTION_NODUPLICATES]: groupMemberList = [] @@ -1097,7 +1097,7 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i memberName = member.get('preferredMemberKey', {}).get('id', '') if member['type'] != Ent.TYPE_GROUP: if (member['type'] in typesSet and - _getMain()._checkCIMemberMatch(member, memberOptions) and + _checkCIMemberMatch(member, memberOptions) and _checkMemberRole(member, validRoles) and (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions)) and memberName not in membersSet): @@ -1109,7 +1109,7 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i if memberName not in membersSet: membersSet.add(memberName) if (member['type'] in typesSet and - _getMain()._checkCIMemberMatch(member, memberOptions) and + _checkCIMemberMatch(member, memberOptions) and (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions))): member['level'] = level member['subgroup'] = nameToPrint @@ -1125,7 +1125,7 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i memberName = member.get('preferredMemberKey', {}).get('id', '') if member['type'] != Ent.TYPE_GROUP: if (member['type'] in typesSet and - _getMain()._checkCIMemberMatch(member, memberOptions) and + _checkCIMemberMatch(member, memberOptions) and _checkMemberRole(member, validRoles) and (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions))): member['level'] = level @@ -1133,7 +1133,7 @@ def getCIGroupMembers(cd, ci, groupName, memberRoles, membersList, membersSet, i membersList.append(member) else: if (member['type'] in typesSet and - _getMain()._checkCIMemberMatch(member, memberOptions) and + _checkCIMemberMatch(member, memberOptions) and (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions))): member['level'] = level member['subgroup'] = nameToPrint @@ -1193,12 +1193,13 @@ def _getCIListGroupMembersArgs(listView): # (addcsvdata )* [includecsvdatainjson []] # [formatjson [quotechar ]] def doPrintCIGroupMembers(): + from gam.cmd.groups.members import checkGroupMatchPatterns, finalizeIPSGMGroupRolesMemberDisplayOptions, getGroupAllowExternalMembers, getGroupMatchPatterns, getIPSGMGroupRolesMemberDisplayOptions, getMemberMatchOptions, initIPSGMGroupMemberDisplayOptions, initMemberOptions, mapCIGroupMemberFieldNames cd = buildGAPIObject(API.DIRECTORY) ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS) - _getMain().setTrueCustomerId(cd) + setTrueCustomerId(cd) parent = f'customers/{GC.Values[GC.CUSTOMER_ID]}' - memberOptions = _getMain().initMemberOptions() - memberDisplayOptions = _getMain().initIPSGMGroupMemberDisplayOptions() + memberOptions = initMemberOptions() + memberDisplayOptions = initIPSGMGroupMemberDisplayOptions() groupColumn = True subTitle = f'{Msg.ALL} {Ent.Plural(Ent.CLOUD_IDENTITY_GROUP)}' fieldsList = [] @@ -1228,17 +1229,17 @@ def doPrintCIGroupMembers(): entityList = [getString(Cmd.OB_EMAIL_ADDRESS)] subTitle = f'{Ent.Singular(Ent.CLOUD_IDENTITY_GROUP)}={entityList[0]}' query = None - elif _getMain().getGroupMatchPatterns(myarg, matchPatterns, True): + elif getGroupMatchPatterns(myarg, matchPatterns, True): pass elif myarg == 'select': entityList = getEntityList(Cmd.OB_GROUP_ENTITY) subTitle = f'{Msg.SELECTED} {Ent.Plural(Ent.CLOUD_IDENTITY_GROUP)}' query = None - elif _getMain().getIPSGMGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): + elif getIPSGMGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): pass elif getCIGroupMemberTypes(myarg, typesSet): pass - elif _getMain().getMemberMatchOptions(myarg, memberOptions): + elif getMemberMatchOptions(myarg, memberOptions): pass elif getFieldsList(myarg, CIGROUPMEMBERS_FIELDS_CHOICE_MAP, fieldsList, initialField='preferredMemberKey'): pass @@ -1264,7 +1265,7 @@ def doPrintCIGroupMembers(): usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('minimal', 'recursive')) if not typesSet: typesSet = {Ent.TYPE_USER} if memberOptions[MEMBEROPTION_RECURSIVE] else ALL_CIGROUP_MEMBER_TYPES - showCategory, _ = _getMain().finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, verifyAllowExternal) + showCategory, _ = finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, verifyAllowExternal) fields = ','.join(set(groupFieldsLists['ci'])) entityList = getCIGroupMembersEntityList(ci, entityList, query, subTitle, matchPatterns, groupFieldsLists['ci'], csvPF) if not fieldsList: @@ -1323,11 +1324,11 @@ def doPrintCIGroupMembers(): groupEmail = groupEntity['groupKey']['id'].lower() kvList = [Ent.CLOUD_IDENTITY_GROUP, groupEmail] if showCategory: - allowExternalMembers = _getMain().getGroupAllowExternalMembers(memberDisplayOptions['gs'], groupEmail, verifyAllowExternal, + allowExternalMembers = getGroupAllowExternalMembers(memberDisplayOptions['gs'], groupEmail, verifyAllowExternal, kvList, i, count) if allowExternalMembers is None: continue - if not _getMain().checkGroupMatchPatterns(groupEmail, groupEntity, matchPatterns): + if not checkGroupMatchPatterns(groupEmail, groupEntity, matchPatterns): continue membersList = [] membersSet = set() @@ -1352,7 +1353,7 @@ def doPrintCIGroupMembers(): row['category'] = member['category'] if listView == 'minimal': dmember.pop('type', None) - _getMain().mapCIGroupMemberFieldNames(dmember) + mapCIGroupMemberFieldNames(dmember) if not FJQC.formatJSON: if allowExternalMembers is not None: row['allowExternalMembers'] = allowExternalMembers @@ -1400,6 +1401,7 @@ def doPrintCIGroupMembers(): # [minimal|basic|full] # [(depth ) | includederivedmembership] def doShowCIGroupMembers(): + from gam.cmd.groups.members import _checkCIMemberMatch, checkGroupMatchPatterns, finalizeIPSGMGroupRolesMemberDisplayOptions, getGroupMatchPatterns, getIPSGMGroupRolesMemberDisplayOptions, getMemberMatchOptions, initIPSGMGroupMemberDisplayOptions, initMemberOptions def _roleOrder(key): return {Ent.ROLE_OWNER: 0, Ent.ROLE_MANAGER: 1, Ent.ROLE_MEMBER: 2}.get(key, 3) @@ -1436,7 +1438,7 @@ def doShowCIGroupMembers(): (not checkShowCategory or _checkCIMemberCategory(member, memberDisplayOptions))): if (_checkMemberRole(member, rolesSet) and member['type'] in typesSet and - _getMain()._checkCIMemberMatch(member, memberOptions)): + _checkCIMemberMatch(member, memberOptions)): if listView != 'minimal': memberDetails = f'{member.get("role", Ent.ROLE_MEMBER)}, {member["type"]}, {member["preferredMemberKey"]["id"]}' else: @@ -1455,15 +1457,15 @@ def doShowCIGroupMembers(): cd = buildGAPIObject(API.DIRECTORY) ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS) - _getMain().setTrueCustomerId(cd) + setTrueCustomerId(cd) parent = f'customers/{GC.Values[GC.CUSTOMER_ID]}' subTitle = f'{Msg.ALL} {Ent.Plural(Ent.CLOUD_IDENTITY_GROUP)}' groupFieldsLists = {'ci': ['groupKey', 'name']} entityList = query = showOwnedBy = None rolesSet = set() typesSet = set() - memberOptions = _getMain().initMemberOptions() - memberDisplayOptions = _getMain().initIPSGMGroupMemberDisplayOptions() + memberOptions = initMemberOptions() + memberDisplayOptions = initIPSGMGroupMemberDisplayOptions() matchPatterns = {} maxdepth = -1 includeDerivedMembership = False @@ -1482,17 +1484,17 @@ def doShowCIGroupMembers(): entityList = [getString(Cmd.OB_EMAIL_ADDRESS)] subTitle = f'{Ent.Singular(Ent.CLOUD_IDENTITY_GROUP)}={entityList[0]}' query = None - elif _getMain().getGroupMatchPatterns(myarg, matchPatterns, False): + elif getGroupMatchPatterns(myarg, matchPatterns, False): pass elif myarg == 'select': entityList = getEntityList(Cmd.OB_GROUP_ENTITY) subTitle = f'{Msg.SELECTED} {Ent.Plural(Ent.CLOUD_IDENTITY_GROUP)}' query = None - elif _getMain().getIPSGMGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): + elif getIPSGMGroupRolesMemberDisplayOptions(myarg, rolesSet, memberDisplayOptions): pass elif getCIGroupMemberTypes(myarg, typesSet): pass - elif _getMain().getMemberMatchOptions(myarg, memberOptions): + elif getMemberMatchOptions(myarg, memberOptions): pass elif myarg == 'depth': maxdepth = getInteger(minVal=-1) @@ -1506,7 +1508,7 @@ def doShowCIGroupMembers(): rolesSet = ALL_GROUP_ROLES if not typesSet: typesSet = ALL_CIGROUP_MEMBER_TYPES - showCategory, checkShowCategory = _getMain().finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, False) + showCategory, checkShowCategory = finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, False) fields = ','.join(set(groupFieldsLists['ci'])) entityList = getCIGroupMembersEntityList(ci, entityList, query, subTitle, matchPatterns, groupFieldsLists['ci'], None) kwargs = _getCIListGroupMembersArgs(listView) @@ -1530,7 +1532,7 @@ def doShowCIGroupMembers(): entityActionFailedWarning([Ent.CLOUD_IDENTITY_GROUP, groupEmail], str(e), i, count) continue groupEmail = groupEntity['groupKey']['id'].lower() - if _getMain().checkGroupMatchPatterns(groupEmail, groupEntity, matchPatterns): + if checkGroupMatchPatterns(groupEmail, groupEntity, matchPatterns): _showGroup(groupEntity['name'], groupEmail, 0) # gam print licenses [todrive *] diff --git a/src/gam/cmd/ciuserinvitations.py b/src/gam/cmd/ciuserinvitations.py index e6e9305f..e994299a 100644 --- a/src/gam/cmd/ciuserinvitations.py +++ b/src/gam/cmd/ciuserinvitations.py @@ -2,7 +2,6 @@ import re import json -import sys from gamlib import glaction from gamlib import glapi as API @@ -40,7 +39,7 @@ from gam.util.display import ( printGettingAllAccountEntities, printLine, ) -from gam.util.entity import convertUIDtoEmailAddress, getEntityArgument +from gam.util.entity import _getCustomersCustomerIdWithC, convertUIDtoEmailAddress, getEntityArgument Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -48,17 +47,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - from urllib.parse import quote_plus def isolateCIUserInvitatonsEmail(name): @@ -71,7 +59,7 @@ def quotedCIUserInvitatonsEmail(customer, email): def _getCIUserInvitationsEntity(ci=None, email=None): if ci is None: ci = buildGAPIObject(API.CLOUDIDENTITY_USERINVITATIONS) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() if email is None: email = getString(Cmd.OB_EMAIL_ADDRESS) pattern = re.compile(rf'^{customer}/userinvitations/(.+)$') @@ -198,7 +186,7 @@ def doPrintShowCIUserInvitations(): ensure_ascii=False, sort_keys=True)}) ci = buildGAPIObject(API.CLOUDIDENTITY_USERINVITATIONS) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['email']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) OBY = OrderBy(CI_USERINVITATION_ORDERBY_CHOICE_MAP) @@ -244,7 +232,7 @@ def doPrintShowCIUserInvitations(): # Current serial implementation will be SLOW... def checkCIUserIsInvitable(users): ci = buildGAPIObject(API.CLOUDIDENTITY_USERINVITATIONS) - customer = _getMain()._getCustomersCustomerIdWithC() + customer = _getCustomersCustomerIdWithC() csvPF = CSVPrintFile(['invitableUsers']) getTodriveOnly(csvPF) i, count, users = getEntityArgument(users) diff --git a/src/gam/cmd/cloudstorage.py b/src/gam/cmd/cloudstorage.py index d88d3bda..4a9e33ae 100644 --- a/src/gam/cmd/cloudstorage.py +++ b/src/gam/cmd/cloudstorage.py @@ -1,7 +1,6 @@ """GAM cloud storage management.""" import re -import sys import googleapiclient.http import hashlib @@ -52,6 +51,7 @@ from gam.util.output import ( writeStderr, writeStdout, ) +from gam.constants import GOOGLE_API_ERROR_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -59,17 +59,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def _copyStorageObjects(objects, target_bucket, target_prefix): """Copies objects to target_bucket. @@ -108,7 +97,7 @@ def _copyStorageObjects(objects, target_bucket, target_prefix): source_md5 = files_to_copy[fileIndex]['md5Hash'] target_md5 = response['resource']['md5Hash'] if source_md5 != target_md5: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, f'Target file {target_displayname} checksum {target_md5} does not match source {source_md5}. This should not happen') + systemErrorExit(GOOGLE_API_ERROR_RC, f'Target file {target_displayname} checksum {target_md5} does not match source {source_md5}. This should not happen') entityActionPerformedMessage([Ent.CLOUD_STORAGE_FILE, None], f'{1:>7.2%} Complete', fileIndex+1, totalFiles) Ind.Increment() writeStdout(formatKeyValueList(Ind.Spaces(), ['Source', source_displayname], '\n')) @@ -186,6 +175,7 @@ def md5MatchesFile(filename, expected_md5, j=0, jcount=0): systemErrorExit(FILE_ERROR_RC, fileErrorMessage(filename, e)) def _getCloudStorageObject(s, bucket, s_object, localFilename, expectedMd5=None, zipToStdout=False, j=0, jcount=0): + from gam.cmd.drive.transfer.fileops import HTTP_ERROR_PATTERN if not zipToStdout: localFilename = cleanFilepath(localFilename) entityValueList = [Ent.DRIVE_FILE, localFilename] @@ -217,7 +207,7 @@ def _getCloudStorageObject(s, bucket, s_object, localFilename, expectedMd5=None, if expectedMd5 and not md5MatchesFile(localFilename, expectedMd5): systemErrorExit(FILE_ERROR_RC, fileErrorMessage(localFilename, Msg.CORRUPT_FILE)) except googleapiclient.http.HttpError as e: - mg = _getMain().HTTP_ERROR_PATTERN.match(str(e)) + mg = HTTP_ERROR_PATTERN.match(str(e)) entityModifierNewValueActionFailedWarning([Ent.CLOUD_STORAGE_FILE, s_object], Act.MODIFIER_TO, localFilename, mg.group(1) if mg else str(e), j, jcount) TAKEOUT_EXPORT_PATTERN = re.compile(r'(takeout-export-[a-f,0-9,-]*)') @@ -301,6 +291,7 @@ def doDownloadCloudStorageBucket(): # gam download storagefile # [targetfolder ] [overwrite []] [nogcspath [Boolean>]] def doDownloadCloudStorageFile(): + from gam.cmd.drive.transfer.fileops import HTTP_ERROR_PATTERN bucket, s_object, bucketObject = getBucketObjectName() targetFolder = GC.Values[GC.DRIVE_DIR] overwrite = nogcspath = False @@ -336,6 +327,6 @@ def doDownloadCloudStorageFile(): entityModifierNewValueActionPerformed([Ent.CLOUD_STORAGE_FILE, s_object], Act.MODIFIER_TO, filename) closeFile(f, True) except googleapiclient.http.HttpError as e: - mg = _getMain().HTTP_ERROR_PATTERN.match(str(e)) + mg = HTTP_ERROR_PATTERN.match(str(e)) entityActionFailedWarning([Ent.CLOUD_STORAGE_FILE, bucketObject], mg.group(1) if mg else str(e)) diff --git a/src/gam/cmd/contacts.py b/src/gam/cmd/contacts.py index 83381c91..7eedec89 100644 --- a/src/gam/cmd/contacts.py +++ b/src/gam/cmd/contacts.py @@ -2,7 +2,6 @@ import re import json -import sys import gdata.apps.contacts @@ -15,6 +14,7 @@ from gamlib import glgapi as GAPI from gamlib import glglobals as GM from gamlib import glindent from gamlib import glmsgs as Msg +from gam.constants import NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -22,9 +22,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - from gamlib import glgdata as GDATA from gam.util.access import entityUnknownWarning from gam.util.api import callGData, callGDataPages, getContactsObject, getContactsQuery @@ -65,15 +62,9 @@ from gam.util.entity import getEntityList from gam.util.errors import invalidChoiceExit, missingArgumentExit, unknownArgumentExit, usageErrorExit from gam.util.output import setSysExitRC, writeStdout -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def _getCreateContactReturnOptions(parameters): + from gam.cmd.users.manage import ADDRESS_ARGUMENT_TO_FIELD_MAP, ORGANIZATION_ARGUMENT_TO_FIELD_MAP myarg = getArgument() if myarg == 'returnidonly': parameters['returnIdOnly'] = True @@ -219,7 +210,7 @@ class ContactsManager(): gdata.apps.contacts.REL_OTHER: 'other', } - _getMain().ADDRESS_ARGUMENT_TO_FIELD_MAP = { + ADDRESS_ARGUMENT_TO_FIELD_MAP = { 'streetaddress': 'street', 'pobox': 'pobox', 'neighborhood': 'neighborhood', @@ -363,7 +354,7 @@ class ContactsManager(): gdata.apps.contacts.REL_OTHER: 'other', } - _getMain().ORGANIZATION_ARGUMENT_TO_FIELD_MAP = { + ORGANIZATION_ARGUMENT_TO_FIELD_MAP = { 'location': 'where', 'department': 'department', 'title': 'title', @@ -1210,7 +1201,7 @@ def _clearUpdateContacts(updateContacts): jcount = len(entityList) entityPerformActionModifierNumItems([entityType, user], Msg.MAXIMUM_OF, jcount, Ent.CONTACT) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return Ind.Increment() for contact in entityList: @@ -1293,7 +1284,7 @@ def doDedupDomainContacts(): jcount = len(contacts) entityPerformActionModifierNumItems([entityType, user], Msg.MAXIMUM_OF, jcount, Ent.CONTACT) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return Ind.Increment() for contact in contacts: @@ -1339,7 +1330,7 @@ def doDeleteDomainContacts(): jcount = len(entityList) entityPerformActionModifierNumItems([entityType, user], Msg.MAXIMUM_OF, jcount, Ent.CONTACT) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return Ind.Increment() for contact in entityList: @@ -1461,7 +1452,7 @@ def doInfoDomainContacts(): if not FJQC.formatJSON: entityPerformActionNumItems([entityType, user], jcount, Ent.CONTACT) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return Ind.Increment() for contact in entityList: @@ -1614,6 +1605,7 @@ def normalizeContactGroupResourceName(resourceName): return f'contactGroups/{resourceName}' def normalizeOtherContactsResourceName(resourceName): + from gam.cmd.users.manage import ADDRESS_ARGUMENT_TO_FIELD_MAP, ORGANIZATION_ARGUMENT_TO_FIELD_MAP if resourceName.startswith('otherContacts/'): return resourceName return f'otherContacts/{resourceName}' @@ -1774,7 +1766,7 @@ class PeopleManager(): 'removecontactgroups': PEOPLE_REMOVE_GROUPS, } - _getMain().ADDRESS_ARGUMENT_TO_FIELD_MAP = { + ADDRESS_ARGUMENT_TO_FIELD_MAP = { 'formatted': 'formattedValue', 'unstructured': 'formattedValue', 'pobox': 'poBox', @@ -1813,7 +1805,7 @@ class PeopleManager(): 'yahoo': 'yahoo', } - _getMain().ORGANIZATION_ARGUMENT_TO_FIELD_MAP = { + ORGANIZATION_ARGUMENT_TO_FIELD_MAP = { 'startdate': 'startDate', 'enddate': 'endDate', 'current': 'current', diff --git a/src/gam/cmd/courses/courses.py b/src/gam/cmd/courses/courses.py index fd734765..38d80e63 100644 --- a/src/gam/cmd/courses/courses.py +++ b/src/gam/cmd/courses/courses.py @@ -6,7 +6,6 @@ Part of the _courses_tmp sub-package.""" import re import json -import sys import time from gamlib import glaction @@ -70,6 +69,7 @@ from gam.util.entity import getEntityList from gam.util.errors import invalidChoiceExit, missingArgumentExit, unknownArgumentExit from gam.util.fileio import UNKNOWN from gam.util.output import currentCount, formatKeyValueList, writeStdout +from gam.constants import OWNER_ACCESS_OPTIONS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -77,17 +77,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def checkCourseExists(croom, courseId, i=0, count=0, entityType=Ent.COURSE): courseId = addCourseIdScope(courseId) try: @@ -1111,7 +1100,7 @@ def _doInfoCourses(courseIdList): myarg = getArgument() if _getCourseShowProperties(myarg, courseShowProperties): pass - elif myarg in _getMain().OWNER_ACCESS_OPTIONS: + elif myarg in OWNER_ACCESS_OPTIONS: useOwnerAccess = True else: FJQC.GetFormatJSON(myarg) diff --git a/src/gam/cmd/courses/guardians.py b/src/gam/cmd/courses/guardians.py index c1e8a0e3..85a71db2 100644 --- a/src/gam/cmd/courses/guardians.py +++ b/src/gam/cmd/courses/guardians.py @@ -6,7 +6,6 @@ Part of the _courses_tmp sub-package.""" import re import json -import sys from gamlib import gluprop as UProp @@ -63,6 +62,7 @@ from gam.util.output import ( writeStderr, writeStdout, ) +from gam.constants import ADMIN_ACCESS_OPTIONS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -70,17 +70,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def studentUnknownWarning(studentId, errMsg, i, count): setSysExitRC(SERVICE_NOT_APPLICABLE_RC) writeStderr(formatKeyValueList(Ind.Spaces(), @@ -757,7 +746,7 @@ def createClassroomInvitations(users): FJQC.SetCsvPF(csvPF) elif csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useOwnerAccess = False else: FJQC.GetFormatJSONQuoteChar(myarg, False) diff --git a/src/gam/cmd/courses/participants.py b/src/gam/cmd/courses/participants.py index 09568d94..7c766069 100644 --- a/src/gam/cmd/courses/participants.py +++ b/src/gam/cmd/courses/participants.py @@ -6,7 +6,6 @@ Part of the _courses_tmp sub-package.""" import re import json -import sys from gam.util.csv_pf import RI_ENTITY, RI_J, RI_JCOUNT, RI_ITEM @@ -44,6 +43,7 @@ from gam.util.display import entityActionFailedWarning, entityActionPerformed, e from gam.util.entity import getEntityList, getEntityToModify, getItemsToModify from gam.util.errors import missingArgumentExit, unknownArgumentExit from gam.util.output import executeBatch, writeStdout +from gam.constants import OWNER_ACCESS_OPTIONS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -51,17 +51,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def doPrintCourseParticipants(): croom = buildGAPIObject(API.CLASSROOM) csvPF = CSVPrintFile(['courseId', 'courseName']) @@ -530,7 +519,7 @@ def doCourseRemoveItems(courseIdList, getEntityListArg): if not getEntityListArg: if removeType in {Ent.STUDENT, Ent.TEACHER}: useOwnerAccess = GC.Values[GC.USE_COURSE_OWNER_ACCESS] - if checkArgumentPresent(_getMain().OWNER_ACCESS_OPTIONS): + if checkArgumentPresent(OWNER_ACCESS_OPTIONS): useOwnerAccess = True removeItems = getStringReturnInList(Cmd.OB_EMAIL_ADDRESS) elif removeType == Ent.COURSE_ALIAS: @@ -545,7 +534,7 @@ def doCourseRemoveItems(courseIdList, getEntityListArg): courseParticipantLists = None else: if removeType in {Ent.STUDENT, Ent.TEACHER}: - useOwnerAccess = checkArgumentPresent(_getMain().OWNER_ACCESS_OPTIONS) + useOwnerAccess = checkArgumentPresent(OWNER_ACCESS_OPTIONS) _, removeItems = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS, typeMap={Cmd.ENTITY_COURSEPARTICIPANTS: PARTICIPANT_EN_MAP[removeType]}) elif removeType == Ent.COURSE_ALIAS: @@ -652,13 +641,14 @@ def doCourseClearParticipants(courseIdList, _): # gam courses sync teachers [addonly|removeonly] [makefirstteacherowner] # gam course sync teachers [addonly|removeonly] [makefirstteacherowner] def doCourseSyncParticipants(courseIdList, _): + from gam.cmd.groups.groups import getSyncOperation croom = buildGAPIObject(API.CLASSROOM) role = getChoice(CLEAR_SYNC_PARTICIPANT_TYPES_MAP, mapChoice=True) if role == Ent.TEACHER: makeFirstTeacherOwner = checkArgumentPresent(['makefirstteacherowner']) else: makeFirstTeacherOwner = False - syncOperation = _getMain().getSyncOperation() + syncOperation = getSyncOperation() _, syncParticipants = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS, typeMap={Cmd.ENTITY_COURSEPARTICIPANTS: PARTICIPANT_EN_MAP[role]}, isSuspended=False, isArchived=False) diff --git a/src/gam/cmd/cros.py b/src/gam/cmd/cros.py index 7012dd4f..fd47454c 100644 --- a/src/gam/cmd/cros.py +++ b/src/gam/cmd/cros.py @@ -34,6 +34,7 @@ from gam.util.args import ( StartEndTime, YYYYMMDDTHHMMSS_FORMAT_REQUIRED, YYYYMMDD_FORMAT, + _getFilterDateTime, checkArgumentPresent, escapeCRsNLs, formatLocalDatestamp, @@ -51,6 +52,7 @@ from gam.util.args import ( getYYYYMMDD, makeOrgUnitPathAbsolute, makeOrgUnitPathRelative, + substituteQueryTimes, ) from gam.util.csv_pf import ( CSVPrintFile, @@ -85,6 +87,7 @@ from gam.util.display import ( printLine, ) from gam.util.entity import ( + _getCustomersCustomerIdWithC, convertEntityToList, getDeviceQueries, getEntityArgument, @@ -111,6 +114,7 @@ from gam.util.output import ( writeStderr, writeStdout, ) +from gam.constants import PROJECTION_CHOICE_MAP Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -118,17 +122,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - UNKNOWN = 'Unknown' WARNING_PREFIX = 'WARNING: ' @@ -187,6 +180,7 @@ CROS_ACTION_NAME_MAP = { # gam update action [acknowledge_device_touch_requirement] # [actionbatchsize ] [maxtodeprov ] def updateCrOSDevices(entityList): + from gam.cmd.orgunits import _batchMoveCrOSesToOrgUnit, checkOrgUnitPathExists cd = buildGAPIObject(API.DIRECTORY) noBatchUpdate = False update_body = {} @@ -229,7 +223,7 @@ def updateCrOSDevices(entityList): Cmd.SetLocation(actionLocation-1) usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('action', '')) if orgUnitPath: - status, orgUnitPath, orgUnitId = _getMain().checkOrgUnitPathExists(cd, orgUnitPath) + status, orgUnitPath, orgUnitId = checkOrgUnitPathExists(cd, orgUnitPath) if not status: entityActionFailedWarning([Ent.CROS_DEVICE, ''], f'{Ent.Singular(Ent.ORGANIZATIONAL_UNIT)}: {orgUnitPath}, {Msg.DOES_NOT_EXIST}') return @@ -276,7 +270,7 @@ def updateCrOSDevices(entityList): kwargs = {parmId: None, 'body': update_body, 'fields': ''} if orgUnitPath: Act.Set(Act.ADD) - _getMain()._batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, 0, 0, entityList, quickCrOSMove) + _batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, 0, 0, entityList, quickCrOSMove) Act.Set(Act.UPDATE) if function is None: return @@ -591,9 +585,6 @@ def _computeDVRstorageFreePercentage(cros): else: volume['storageFreePercentage'] = '0' -def _getFilterDateTime(): - filterDate = getYYYYMMDD(returnDateTime=True) - return (filterDate, filterDate.replace(tzinfo='UTC')) CROS_FIELDS_CHOICE_MAP = { 'activetimeranges': 'activeTimeRanges', @@ -765,8 +756,8 @@ def infoCrOSDevices(entityList): elif myarg == 'allfields': projection = 'FULL' fieldsList = [] - elif myarg in _getMain().PROJECTION_CHOICE_MAP: - projection = _getMain().PROJECTION_CHOICE_MAP[myarg] + elif myarg in PROJECTION_CHOICE_MAP: + projection = PROJECTION_CHOICE_MAP[myarg] if projection == 'FULL': fieldsList = [] else: @@ -1118,13 +1109,6 @@ def getCrOSDeviceFiles(entityList): def doGetCrOSDeviceFiles(): getCrOSDeviceFiles(getCrOSDeviceEntity()) -def substituteQueryTimes(queries, queryTimes): - if queryTimes: - for i, query in enumerate(queries): - if query is not None: - for queryTimeName, queryTimeValue in queryTimes.items(): - query = query.replace(f'#{queryTimeName}#', queryTimeValue) - queries[i] = query # Get CrOS devices from gam.cfg print_cros_ous and print_cros_ous_and_children def getCfgCrOSEntities(): @@ -1364,8 +1348,8 @@ def doPrintCrOSDevices(entityList=None): endDate, endTime = _getFilterDateTime() elif myarg == 'timerangeorder': activeTimeRangesOrder = getChoice(SORTORDER_CHOICE_MAP, mapChoice=True) - elif myarg in _getMain().PROJECTION_CHOICE_MAP: - projection = _getMain().PROJECTION_CHOICE_MAP[myarg] + elif myarg in PROJECTION_CHOICE_MAP: + projection = PROJECTION_CHOICE_MAP[myarg] sortHeaders = True if projection == 'FULL': fieldsList = [] @@ -1931,7 +1915,7 @@ def doInfoPrintShowCrOSTelemetry(): cm = buildGAPIObject(API.CHROMEMANAGEMENT) cd = None - parent = _getMain()._getCustomersCustomerIdWithC() + parent = _getCustomersCustomerIdWithC() fieldsList = [] reverseLists = [] action = Act.Get() diff --git a/src/gam/cmd/customer.py b/src/gam/cmd/customer.py index be812996..3930fcf6 100644 --- a/src/gam/cmd/customer.py +++ b/src/gam/cmd/customer.py @@ -1,7 +1,6 @@ """GAM customer info/update and instance info commands.""" import json -import sys from gamlib import glaction from gamlib import glapi as API @@ -37,6 +36,16 @@ from gam.util.display import ( from gam.util.errors import unknownArgumentExit from gam.util.fileio import UNKNOWN from gam.util.output import printWarningMessage, writeStdout +from gam.util.entity import ( + PRINT_PRIVILEGES_FIELDS, + _getCustomerId, + _getCustomerIdNoC, + _getCustomersCustomerIdNoC, + _getCustomersCustomerIdWithC, + _getDomainList, + setTrueCustomerId, +) +from gam.constants import DATA_NOT_AVALIABLE_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -44,18 +53,9 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def _showCustomerLicenseInfo(customerInfo, FJQC): + from gam.cmd.domains import CUSTOMER_LICENSE_MAP + from gam.cmd.reports import _adjustTryDate, _checkDataRequiredServices def numUsersAvailable(result): usageReports = result.get('usageReports', []) if usageReports: @@ -65,7 +65,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC): return None rep = buildGAPIObject(API.REPORTS) - parameters = ','.join(_getMain().CUSTOMER_LICENSE_MAP) + parameters = ','.join(CUSTOMER_LICENSE_MAP) tryDate = todaysDate().strftime(YYYYMMDD_FORMAT) dataRequiredServices = {'accounts'} while True: @@ -77,15 +77,15 @@ def _showCustomerLicenseInfo(customerInfo, FJQC): usageReports = numUsersAvailable(result) if usageReports: break - fullData, tryDate, usageReports = _getMain()._checkDataRequiredServices(result, tryDate, dataRequiredServices) + fullData, tryDate, usageReports = _checkDataRequiredServices(result, tryDate, dataRequiredServices) if fullData < 0: - printWarningMessage(_getMain().DATA_NOT_AVALIABLE_RC, Msg.NO_USER_COUNTS_DATA_AVAILABLE) + printWarningMessage(DATA_NOT_AVALIABLE_RC, Msg.NO_USER_COUNTS_DATA_AVAILABLE) return if fullData == 0: continue break except (GAPI.invalid, GAPI.failedPrecondition) as e: - tryDate = _getMain()._adjustTryDate(str(e), 0, -1, tryDate) + tryDate = _adjustTryDate(str(e), 0, -1, tryDate) if not tryDate: return continue @@ -95,7 +95,7 @@ def _showCustomerLicenseInfo(customerInfo, FJQC): printKeyValueList([f'User counts as of {tryDate}:']) Ind.Increment() for item in usageReports[0]['parameters']: - api_name = _getMain().CUSTOMER_LICENSE_MAP.get(item['name']) + api_name = CUSTOMER_LICENSE_MAP.get(item['name']) api_value = int(item.get('intValue', '0')) if api_name and api_value: if not FJQC.formatJSON: @@ -105,59 +105,11 @@ def _showCustomerLicenseInfo(customerInfo, FJQC): if not FJQC.formatJSON: Ind.Decrement() -def setTrueCustomerId(cd=None, forceUpdate=False): - if GC.Values[GC.CUSTOMER_ID] == GC.MY_CUSTOMER or forceUpdate: - if not cd: - cd = buildGAPIObject(API.DIRECTORY) - try: - customerInfo = callGAPI(cd.customers(), 'get', - throwReasons=[GAPI.BAD_REQUEST, GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, - GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED], - customerKey=GC.MY_CUSTOMER, - fields='id') - GC.Values[GC.CUSTOMER_ID] = customerInfo['id'] - except (GAPI.badRequest, GAPI.invalidInput, GAPI.resourceNotFound): - pass - except (GAPI.forbidden, GAPI.permissionDenied) as e: - ClientAPIAccessDeniedExit(str(e)) -def _getCustomerId(): - customerId = GC.Values[GC.CUSTOMER_ID] - if customerId != GC.MY_CUSTOMER and customerId[0] != 'C': - customerId = 'C' + customerId - return customerId - -def _getCustomerIdNoC(): - customerId = GC.Values[GC.CUSTOMER_ID] - if customerId[0] == 'C': - return customerId[1:] - return customerId - -def _getCustomersCustomerIdNoC(): - customerId = GC.Values[GC.CUSTOMER_ID] - if customerId.startswith('C'): - customerId = customerId[1:] - return f'customers/{customerId}' - -def _getCustomersCustomerIdWithC(): - customerId = GC.Values[GC.CUSTOMER_ID] - if customerId != GC.MY_CUSTOMER and customerId[0] != 'C': - customerId = 'C' + customerId - return f'customers/{customerId}' - -def _getDomainList(cd, customer, fields): - try: - return callGAPIitems(cd.domains(), 'list', 'domains', - throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, - GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED], - customer=customer, fields=fields) - except (GAPI.badRequest, GAPI.notFound): - accessErrorExit(cd) - except (GAPI.forbidden, GAPI.permissionDenied) as e: - ClientAPIAccessDeniedExit(str(e)) # gam info customer [formatjson] def doInfoCustomer(returnCustomerInfo=None, FJQC=None): + from gam.cmd.reseller import _showCustomerAddressPhoneNumber cd = buildGAPIObject(API.DIRECTORY) customerId = _getCustomerId() if FJQC is None: @@ -200,7 +152,7 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None): printKeyValueList(['Primary Domain Verified', customerInfo['verified']]) printKeyValueList(['Customer Creation Time', customerInfo['customerCreationTime']]) printKeyValueList(['Default Language', customerInfo.get('language', 'Unset or Unknown (defaults to en)')]) - _getMain()._showCustomerAddressPhoneNumber(customerInfo) + _showCustomerAddressPhoneNumber(customerInfo) printKeyValueList(['Admin Secondary Email', customerInfo.get('alternateEmail', UNKNOWN)]) _showCustomerLicenseInfo(customerInfo, FJQC) except (GAPI.badRequest, GAPI.invalidInput, GAPI.domainNotFound, GAPI.notFound, GAPI.resourceNotFound): @@ -213,14 +165,15 @@ def doInfoCustomer(returnCustomerInfo=None, FJQC=None): # [address1|addressline1 ] [address2|addressline2 ] [address3|addressline3 ] # [locality ] [region ] [postalcode ] [country|countrycode ] def doUpdateCustomer(): + from gam.cmd.reseller import ADDRESS_FIELDS_ARGUMENT_MAP cd = buildGAPIObject(API.DIRECTORY) customerId = _getCustomerId() body = {} while Cmd.ArgumentsRemaining(): myarg = getArgument() - if myarg in _getMain().ADDRESS_FIELDS_ARGUMENT_MAP: + if myarg in ADDRESS_FIELDS_ARGUMENT_MAP: body.setdefault('postalAddress', {}) - body['postalAddress'][_getMain().ADDRESS_FIELDS_ARGUMENT_MAP[myarg]] = getString(Cmd.OB_STRING, minLen=0) + body['postalAddress'][ADDRESS_FIELDS_ARGUMENT_MAP[myarg]] = getString(Cmd.OB_STRING, minLen=0) elif myarg == 'primary': body['customerDomain'] = getString(Cmd.OB_DOMAIN_NAME) elif myarg in {'adminsecondaryemail', 'alternateemail'}: @@ -259,8 +212,9 @@ DOMAIN_PRINT_ORDER = ['customerDomain', 'creationTime', 'isPrimary', 'verified'] DOMAIN_SKIP_OBJECTS = {'domainName', 'domainAliases'} def _showDomain(result, FJQC, i=0, count=0): + from gam.cmd.domains import DOMAIN_ALIAS_SKIP_OBJECTS, DOMAIN_TIME_OBJECTS, _showDomainAlias if FJQC.formatJSON: - printLine(json.dumps(cleanJSON(result, timeObjects=_getMain().DOMAIN_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) + printLine(json.dumps(cleanJSON(result, timeObjects=DOMAIN_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)) return skipObjects = DOMAIN_SKIP_OBJECTS printEntity([Ent.DOMAIN, result['domainName']], i, count) @@ -275,9 +229,9 @@ def _showDomain(result, FJQC, i=0, count=0): aliases = result.get(field) if aliases: skipObjects.add(field) - aliasSkipObjects = _getMain().DOMAIN_ALIAS_SKIP_OBJECTS + aliasSkipObjects = DOMAIN_ALIAS_SKIP_OBJECTS for alias in aliases: - _getMain()._showDomainAlias(alias, FJQC, aliasSkipObjects) + _showDomainAlias(alias, FJQC, aliasSkipObjects) showJSON(None, alias, aliasSkipObjects) showJSON(None, result, skipObjects) Ind.Decrement() @@ -312,6 +266,7 @@ DOMAIN_SORT_TITLES = ['domainName', 'parentDomainName', 'creationTime', 'type', # [formatjson] # [showitemcountonly] def doPrintShowDomains(): + from gam.cmd.domains import DOMAIN_TIME_OBJECTS, _printDomain cd = buildGAPIObject(API.DIRECTORY) csvPF = CSVPrintFile(['domainName'], DOMAIN_SORT_TITLES) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) @@ -337,17 +292,17 @@ def doPrintShowDomains(): elif not FJQC.formatJSON: domain['type'] = 'primary' if domain.pop('isPrimary') else 'secondary' domainAliases = domain.pop('domainAliases', []) - _getMain()._printDomain(domain, csvPF) + _printDomain(domain, csvPF) for domainAlias in domainAliases: domainAlias['type'] = 'alias' domainAlias['domainName'] = domainAlias.pop('domainAliasName') - _getMain()._printDomain(domainAlias, csvPF) + _printDomain(domainAlias, csvPF) else: csvPF.WriteRowNoFilter({'domainName': domain['domainName'], - 'JSON': json.dumps(cleanJSON(domain, timeObjects=_getMain().DOMAIN_TIME_OBJECTS), + 'JSON': json.dumps(cleanJSON(domain, timeObjects=DOMAIN_TIME_OBJECTS), ensure_ascii=False, sort_keys=True)}) if csvPF: csvPF.writeCSVfile('Domains') -PRINT_PRIVILEGES_FIELDS = ['serviceId', 'serviceName', 'privilegeName', 'isOuScopable', 'childPrivileges'] + diff --git a/src/gam/cmd/datatransfer.py b/src/gam/cmd/datatransfer.py index 8b1a80f8..ae18a11f 100644 --- a/src/gam/cmd/datatransfer.py +++ b/src/gam/cmd/datatransfer.py @@ -14,7 +14,6 @@ from gamlib import glgapi as GAPI from gamlib import glglobals as GM from gamlib import glindent from gamlib import glmsgs as Msg -from gam.util.orgunits import _getMain from gam.util.api import buildGAPIObject, callGAPI, callGAPIpages from gam.util.args import ( checkForExtraneousArguments, diff --git a/src/gam/cmd/delegates.py b/src/gam/cmd/delegates.py index aec60e0e..40299eea 100644 --- a/src/gam/cmd/delegates.py +++ b/src/gam/cmd/delegates.py @@ -1,6 +1,5 @@ """GAM contact delegate management.""" -import sys from gamlib import glaction from gamlib import glapi as API @@ -27,6 +26,7 @@ from gam.util.display import ( from gam.util.entity import checkUserExists, getEntityArgument, getUserObjectEntity from gam.util.errors import unknownArgumentExit from gam.util.output import setSysExitRC, writeStdout +from gam.constants import NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -34,17 +34,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - def _validateUserGetDelegateList(cd, user, i, count, entity): if entity['dict']: entityList = entity['dict'][user] @@ -56,7 +45,7 @@ def _validateUserGetDelegateList(cd, user, i, count, entity): jcount = len(entityList) entityPerformActionNumItems([Ent.USER, user], jcount, entity['item'], i, count) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (user, entityList, jcount) def _getDelegateName(cd, delegateEmail, delegateNames): diff --git a/src/gam/cmd/drive/copymove/copymove_move.py b/src/gam/cmd/drive/copymove/copymove_move.py index f66f8398..3b7c2a05 100644 --- a/src/gam/cmd/drive/copymove/copymove_move.py +++ b/src/gam/cmd/drive/copymove/copymove_move.py @@ -9,7 +9,6 @@ Part of the drive sub-package, extracted from drive.py.""" """GAM Google Drive file, permission, shared drive, and label management.""" import re -import sys from gam.cmd.drive.core import DFA_SEARCHARGS @@ -35,8 +34,12 @@ from gam.util.display import ( entityPerformActionModifierItemValueList, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, +) from gam.util.errors import unknownArgumentExit +from gam.constants import ANY_NON_TRASHED_WITH_PARENTS, WITH_PARENTS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -71,16 +74,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") MY_DRIVE = 'My Drive' TEAM_DRIVE = 'Drive' @@ -274,7 +267,7 @@ def _recursiveUpdateMovePermissions(drive, user, i, count, sourceChildren = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=_getMain().WITH_PARENTS.format(fileId), + q=WITH_PARENTS.format(fileId), orderBy='folder desc,name,modifiedTime desc', fields='nextPageToken,files(id,name,mimeType)', pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **sourceSearchArgs) @@ -595,7 +588,7 @@ def moveDriveFile(users): sourceChildren = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=_getMain().WITH_PARENTS.format(folderId), + q=WITH_PARENTS.format(folderId), orderBy='folder desc,name,modifiedTime desc', fields='nextPageToken,files(id,name,parents,appProperties,capabilities,contentHints,copyRequiresWriterPermission,'\ 'description,folderColorRgb,mimeType,modifiedTime,properties,starred,driveId,trashed,viewedByMeTime,writersCanShare)', @@ -606,7 +599,7 @@ def moveDriveFile(users): subTargetChildren = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=_getMain().ANY_NON_TRASHED_WITH_PARENTS.format(newFolderId), + q=ANY_NON_TRASHED_WITH_PARENTS.format(newFolderId), orderBy='folder desc,name,modifiedTime desc', fields='nextPageToken,files(id,name,capabilities,mimeType,modifiedTime)', **parentParms[DFA_SEARCHARGS]) @@ -623,7 +616,7 @@ def moveDriveFile(users): continue trashed = child.pop('trashed', False) if (childId == newFolderId) or (copyMoveOptions['destDriveId'] and trashed): - entityActionNotPerformedWarning([Ent.USER, user, _getMain()._getEntityMimeType(child), childNameId], + entityActionNotPerformedWarning([Ent.USER, user, _getEntityMimeType(child), childNameId], [Msg.NOT_MOVABLE, Msg.NOT_MOVABLE_IN_TRASH][trashed], k, kcount) _incrStatistic(statistics, STAT_FILE_NOT_COPYABLE_MOVABLE) continue @@ -722,7 +715,7 @@ def moveDriveFile(users): sourceName = source['name'] sourceNameId = f"{sourceName}({source['id']})" copyMoveOptions['sourceDriveId'] = source.get('driveId') - kvList = [Ent.USER, user, _getMain()._getEntityMimeType(source), sourceNameId] + kvList = [Ent.USER, user, _getEntityMimeType(source), sourceNameId] if fileId in movedFiles: entityActionNotPerformedWarning(kvList, Msg.DUPLICATE, j, jcount) _incrStatistic(statistics, STAT_FILE_DUPLICATE) diff --git a/src/gam/cmd/drive/copymove/copymove_util.py b/src/gam/cmd/drive/copymove/copymove_util.py index 46352176..91b8fa0a 100644 --- a/src/gam/cmd/drive/copymove/copymove_util.py +++ b/src/gam/cmd/drive/copymove/copymove_util.py @@ -9,7 +9,6 @@ Part of the drive sub-package, extracted from drive.py.""" """GAM Google Drive file, permission, shared drive, and label management.""" import re -import sys from gam.cmd.drive.core import DFA_IGNORE_DEFAULT_VISIBILITY, DFA_KEEP_REVISION_FOREVER, DFA_SEARCHARGS import os @@ -50,11 +49,15 @@ from gam.util.display import ( printEntityKVList, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, +) from gam.util.errors import deprecatedArgument, invalidChoiceExit, unknownArgumentExit, usageErrorExit from gam.util.fileio import UNKNOWN, closeFile from gam.util.gdoc import openCSVFileReader from gam.util.output import writeStdout +from gam.constants import ANY_NON_TRASHED_WITH_PARENTS, WITH_PARENTS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -89,16 +92,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") MY_DRIVE = 'My Drive' TEAM_DRIVE = 'Drive' @@ -1229,7 +1222,7 @@ def copyDriveFile(users): sourceChildren = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=_getMain().WITH_PARENTS.format(folderId), + q=WITH_PARENTS.format(folderId), orderBy='folder desc,name,modifiedTime desc', fields='nextPageToken,files(id,name,parents,appProperties,capabilities,contentHints,copyRequiresWriterPermission,'\ 'description,folderColorRgb,mimeType,modifiedTime,ownedByMe,properties,starred,driveId,trashed,viewedByMeTime,writersCanShare,'\ @@ -1241,7 +1234,7 @@ def copyDriveFile(users): subTargetChildren = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=_getMain().ANY_NON_TRASHED_WITH_PARENTS.format(newFolderId), + q=ANY_NON_TRASHED_WITH_PARENTS.format(newFolderId), orderBy='folder desc,name,modifiedTime desc', fields='nextPageToken,files(id,name,capabilities,mimeType,modifiedTime)', **parentParms[DFA_SEARCHARGS]) @@ -1257,7 +1250,7 @@ def copyDriveFile(users): childMimeType = child['mimeType'] if childId in copiedTargetFiles: # Don't recopy file/folder copied into a sub-folder continue - kvList = [Ent.USER, user, _getMain()._getEntityMimeType(child), childNameId] + kvList = [Ent.USER, user, _getEntityMimeType(child), childNameId] if childId in skipFileIdEntity['list']: if not suppressNotSelectedMessages: entityActionNotPerformedWarning(kvList, Msg.IN_SKIPIDS, k, kcount) @@ -1281,7 +1274,7 @@ def copyDriveFile(users): newChildName = childName # If source child has already been copied, make shortcut to its copy if childId in copiedSourceFiles: - _makeCopyShortcut(drive, user, k, kcount, _getMain()._getEntityMimeType(child), childId, childName, + _makeCopyShortcut(drive, user, k, kcount, _getEntityMimeType(child), childId, childName, newChildName, newFolderId, newFolderName, copiedSourceFiles[childId]) continue child.pop('parents', []) @@ -1451,7 +1444,7 @@ def copyDriveFile(users): sourceName = source['name'] sourceNameId = f"{sourceName}({source['id']})" copyMoveOptions['sourceDriveId'] = source.get('driveId') - kvList = [Ent.USER, user, _getMain()._getEntityMimeType(source), sourceNameId] + kvList = [Ent.USER, user, _getEntityMimeType(source), sourceNameId] if fileId in copiedSourceFiles: entityActionNotPerformedWarning(kvList, Msg.DUPLICATE, j, jcount) _incrStatistic(statistics, STAT_FILE_DUPLICATE) @@ -1557,7 +1550,7 @@ def copyDriveFile(users): targetId = shortcut['targetId'] if targetId in copiedSourceFiles and copyMoveOptions['copiedShortcutsPointToCopiedFiles']: targetId = copiedSourceFiles[targetId] - _makeCopyShortcut(drive, user, k, kcount, _getMain()._getEntityMimeType(shortcut), shortcut['childId'], shortcut['childName'], + _makeCopyShortcut(drive, user, k, kcount, _getEntityMimeType(shortcut), shortcut['childId'], shortcut['childName'], shortcut['newChildName'], shortcut['newFolderId'], shortcut['newFolderName'], targetId) Ind.Decrement() else: diff --git a/src/gam/cmd/drive/core.py b/src/gam/cmd/drive/core.py index 2c45d1eb..c18ca815 100644 --- a/src/gam/cmd/drive/core.py +++ b/src/gam/cmd/drive/core.py @@ -49,7 +49,12 @@ from gam.util.display import ( printGotEntityItemsForWhom, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import convertUIDtoEmailAddress, getEntitySelection, getEntitySelector +from gam.util.entity import ( + _getEntityMimeType, + convertUIDtoEmailAddress, + getEntitySelection, + getEntitySelector, +) from gam.util.errors import ( deprecatedArgument, entityActionFailedExit, @@ -59,6 +64,7 @@ from gam.util.errors import ( ) from gam.util.fileio import FILE_ERROR_RC, fileErrorMessage, setFilePath from gam.util.output import setSysExitRC, stderrWarningMsg, systemErrorExit +from gam.constants import ANY_NON_TRASHED_FOLDER_NAME, MY_NON_TRASHED_FOLDER_NAME, NO_ENTITIES_FOUND_RC, TEAM_DRIVE Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -93,16 +99,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") ROOTID = 'rootid' @@ -504,7 +500,7 @@ def _getSharedDriveNameFromId(drive, sharedDriveId, useDomainAdminAccess=False): useDomainAdminAccess=useDomainAdminAccess, driveId=sharedDriveId, fields='name')['name'] except (GAPI.fileNotFound, GAPI.notFound, GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy): - sharedDriveName = _getMain().TEAM_DRIVE + sharedDriveName = TEAM_DRIVE GM.Globals[GM.MAP_SHAREDDRIVE_ID_TO_NAME][sharedDriveId] = sharedDriveName return sharedDriveName @@ -515,11 +511,11 @@ def _getDriveFileNameFromId(drive, fileId, combineTitleId=True, useDomainAdminAc fileId=fileId, fields='name,mimeType,driveId', supportsAllDrives=True) if result: fileName = result['name'] - if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == _getMain().TEAM_DRIVE): + if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == TEAM_DRIVE): fileName = _getSharedDriveNameFromId(drive, result['driveId']) if combineTitleId: fileName += '('+fileId+')' - return (fileName, _getMain()._getEntityMimeType(result), result['mimeType']) + return (fileName, _getEntityMimeType(result), result['mimeType']) except GAPI.fileNotFound: if useDomainAdminAccess: try: @@ -587,19 +583,19 @@ def _validateUserGetFileIDs(user, i, count, fileIdEntity, drive=None, entityType if fileIdEntity['query']: fileIdEntity['list'] = doDriveSearch(drive, user, i, count, query=fileIdEntity['query'], orderBy=orderBy) if fileIdEntity['list'] is None: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (user, None, 0) elif fileIdEntity['shareddriveadminquery']: fileIdEntity['list'] = doSharedDriveSearch(drive, user, i, count, fileIdEntity['shareddriveadminquery'], useDomainAdminAccess) if fileIdEntity['list'] is None: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (user, None, 0) elif fileIdEntity['shareddrivefilequery']: if not fileIdEntity['shareddrive'].get('driveId'): fileIdEntity['shareddrive']['corpora'] = CORPORA_ALL_DRIVES fileIdEntity['list'] = doDriveSearch(drive, user, i, count, query=fileIdEntity['shareddrivefilequery'], orderBy=orderBy, sharedDriveOnly=True, **fileIdEntity['shareddrive']) if fileIdEntity['list'] is None or not fileIdEntity['list']: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (user, None, 0) fileIdEntity['shareddrive'].pop('driveId', None) fileIdEntity['shareddrive'].pop('corpora', None) @@ -608,7 +604,7 @@ def _validateUserGetFileIDs(user, i, count, fileIdEntity, drive=None, entityType return (user, None, 0) l = len(fileIdEntity['list']) if l == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if entityType: entityPerformActionNumItems([Ent.USER, user], l, entityType, i, count) return (user, drive, l) @@ -674,7 +670,7 @@ def _getDriveFileParentInfo(drive, user, i, count, body, parameters, emptyQueryO if parameters[DFA_PARENTQUERY]: parents = doDriveSearch(drive, user, i, count, query=parameters[DFA_PARENTQUERY], parentQuery=True, emptyQueryOK=emptyQueryOK) if parents is None: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return False body.setdefault('parents', []) for parent in parents: @@ -725,7 +721,7 @@ def _getDriveFileParentInfo(drive, user, i, count, body, parameters, emptyQueryO parents = doDriveSearch(drive, user, i, count, query=parameters[DFA_SHAREDDRIVE_PARENTQUERY], parentQuery=True, emptyQueryOK=emptyQueryOK, sharedDriveOnly=True, **parameters[DFA_KWARGS]) if parents is None: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return False body.setdefault('parents', []) for parent in parents: @@ -744,14 +740,14 @@ def _getDriveFileAddRemoveParentInfo(user, i, count, parameters, drive): for query in parameters[DFA_ADD_PARENT_NAMES]: parents = doDriveSearch(drive, user, i, count, query=query, parentQuery=True) if parents is None: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (False, None, None) addParents.extend(parents) removeParents = parameters[DFA_REMOVE_PARENT_IDS][:] for query in parameters[DFA_REMOVE_PARENT_NAMES]: parents = doDriveSearch(drive, user, i, count, query=query, parentQuery=True) if parents is None: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (False, None, None) removeParents.extend(parents) return (True, addParents, removeParents) @@ -770,13 +766,13 @@ def _validateUserGetSharedDriveFileIDs(user, i, count, fileIdEntity, drive=None, if fileIdEntity['shareddrivefilequery']: fileIdEntity['list'] = doDriveSearch(drive, user, i, count, query=fileIdEntity['shareddrivefilequery'], sharedDriveOnly=True, **fileIdEntity['shareddrive']) if fileIdEntity['list'] is None or not fileIdEntity['list']: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) return (user, None, 0) fileIdEntity['shareddrive'].pop('driveId', None) fileIdEntity['shareddrive'].pop('corpora', None) l = len(fileIdEntity['list']) if l == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if entityType: entityPerformActionNumItems([Ent.USER, user], l, entityType, i, count) return (user, drive, l) @@ -949,15 +945,15 @@ def getDriveFileParentAttribute(myarg, parameters): if myarg == 'parentid': parameters[DFA_PARENTID] = getString(Cmd.OB_DRIVE_FOLDER_ID) elif myarg == 'parentname': - parameters[DFA_PARENTQUERY] = _getMain().MY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName()) + parameters[DFA_PARENTQUERY] = MY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName()) elif myarg in {'anyownerparentname', 'sharedparentname'}: - parameters[DFA_PARENTQUERY] = _getMain().ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName()) + parameters[DFA_PARENTQUERY] = ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName()) elif myarg in {'teamdriveparent', 'shareddriveparent'}: parameters[DFA_SHAREDDRIVE_PARENT] = getString(Cmd.OB_SHAREDDRIVE_NAME) elif myarg in {'teamdriveparentid', 'shareddriveparentid'}: parameters[DFA_SHAREDDRIVE_PARENTID] = getString(Cmd.OB_DRIVE_FOLDER_ID) elif myarg in {'teamdriveparentname', 'shareddriveparentname'}: - parameters[DFA_SHAREDDRIVE_PARENTQUERY] = _getMain().ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName()) + parameters[DFA_SHAREDDRIVE_PARENTQUERY] = ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName()) parameters[DFA_KWARGS]['corpora'] = CORPORA_ALL_DRIVES parameters[DFA_KWARGS]['includeItemsFromAllDrives'] = True parameters[DFA_KWARGS]['supportsAllDrives'] = True @@ -973,13 +969,13 @@ def getDriveFileAddRemoveParentAttribute(myarg, parameters): elif myarg in {'removeparent', 'removeparents'}: parameters[DFA_REMOVE_PARENT_IDS].extend(getString(Cmd.OB_DRIVE_FOLDER_ID_LIST).replace(',', ' ').split()) elif myarg == 'addparentname': - parameters[DFA_ADD_PARENT_NAMES].append(_getMain().MY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) + parameters[DFA_ADD_PARENT_NAMES].append(MY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) elif myarg == 'removeparentname': - parameters[DFA_REMOVE_PARENT_NAMES].append(_getMain().MY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) + parameters[DFA_REMOVE_PARENT_NAMES].append(MY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) elif myarg in {'addanyownerparentname', 'addsharedparentname'}: - parameters[DFA_ADD_PARENT_NAMES].append(_getMain().ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) + parameters[DFA_ADD_PARENT_NAMES].append(ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) elif myarg in {'removeanyownerparentname', 'removesharedparentname'}: - parameters[DFA_REMOVE_PARENT_NAMES].append(_getMain().ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) + parameters[DFA_REMOVE_PARENT_NAMES].append(ANY_NON_TRASHED_FOLDER_NAME.format(getEscapedDriveFolderName())) elif myarg == 'enforcesingleparent': deprecatedArgument(myarg) else: diff --git a/src/gam/cmd/drive/fileinfo.py b/src/gam/cmd/drive/fileinfo.py index e24a9b0a..bcc8ac2b 100644 --- a/src/gam/cmd/drive/fileinfo.py +++ b/src/gam/cmd/drive/fileinfo.py @@ -5,7 +5,6 @@ Part of the drive sub-package, extracted from drive.py.""" """GAM Google Drive file, permission, shared drive, and label management.""" import re -import sys import platform from gam.cmd.drive.core import _getDriveFileNameFromId, _validateUserGetFileIDs, getDriveFileEntity @@ -20,6 +19,7 @@ from gamlib import glgapi as GAPI from gamlib import glglobals as GM from gamlib import glindent from gamlib import glmsgs as Msg +from gam.constants import WITH_PARENTS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -54,8 +54,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] from gam.cmd.drive.core import ( MimeTypeCheck, _getSharedDriveNameFromId, _simpleFileIdEntityList, @@ -103,21 +101,14 @@ from gam.util.display import ( printKeyValueListWithCount, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, +) from gam.util.errors import invalidChoiceExit, unknownArgumentExit, usageErrorExit from gam.util.output import writeStdout - - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - SHARED_DRIVE_MAX_FILES_FOLDERS = 500000 TEAM_DRIVE = 'Drive' MY_DRIVE = 'My Drive' @@ -462,7 +453,7 @@ DISKUSAGE_SHOW_CHOICES = {'all', 'summary', 'summaryandtrash'} def printDiskUsage(users): def _getChildDriveFolderInfo(drive, fileEntry, user, i, count, depth): fileEntry['depth'] = depth - q = _getMain().WITH_PARENTS.format(fileEntry['id']) + q = WITH_PARENTS.format(fileEntry['id']) try: children = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID], @@ -588,7 +579,7 @@ def printDiskUsage(users): topFolder['name'] = _stripControlCharsFromName(topFolder['name']) mimeType = topFolder.pop('mimeType') if mimeType != MIMETYPE_GA_FOLDER: - entityValueList = [Ent.USER, user, _getMain()._getEntityMimeType(topFolder), topFolder['name']] + entityValueList = [Ent.USER, user, _getEntityMimeType(topFolder), topFolder['name']] entityActionNotPerformedWarning(entityValueList, Msg.INVALID_MIMETYPE.format(mimeType, MIMETYPE_GA_FOLDER), i, count) continue if topFolder['trashed']: @@ -610,7 +601,7 @@ def printDiskUsage(users): topFolder['path'] = topFolder['name'] topFolder.pop('ownedByMe', None) elif topFolder['name'] == MY_DRIVE and not topFolder.get('parents'): - topFolder['path'] = _getMain().MY_DRIVE + topFolder['path'] = MY_DRIVE else: topFolder['path'] = topFolder['name'] topFolder['User'] = user @@ -688,6 +679,7 @@ FILESHARECOUNTS_CATEGORIES = { # [internaldomains all|primary|] # [summary none|only|plus] [summaryuser ] def printShowFileShareCounts(users): + from gam.cmd.groups.members import finalizeInternalDomains def incrementCounter(counter): if not counterSet[counter]: userShareCounts[counter] += 1 @@ -732,7 +724,7 @@ def printShowFileShareCounts(users): summaryUser = getString(Cmd.OB_STRING) else: unknownArgumentExit() - internalDomains = _getMain().finalizeInternalDomains(cd, internalDomains) + internalDomains = finalizeInternalDomains(cd, internalDomains) summaryShareCounts = FILESHARECOUNTS_ZEROCOUNTS.copy() i, count, users = getEntityArgument(users) for user in users: @@ -888,7 +880,7 @@ def printShowFileTree(users): def _showChildDriveFolderContents(drive, fileEntry, user, i, count, depth): if not DLP.CheckExcludeTrashed(fileEntry): return - q = _getMain().WITH_PARENTS.format(fileEntry['id']) + q = WITH_PARENTS.format(fileEntry['id']) if selectSubQuery: q += ' and ('+selectSubQuery+')' try: diff --git a/src/gam/cmd/drive/filelist.py b/src/gam/cmd/drive/filelist.py index d13b1aca..0cb47fcd 100644 --- a/src/gam/cmd/drive/filelist.py +++ b/src/gam/cmd/drive/filelist.py @@ -6,7 +6,6 @@ Part of the drive sub-package, extracted from drive.py.""" import re import json -import sys from gam.util.args import formatLocalTime @@ -24,6 +23,7 @@ from gamlib import glgapi as GAPI from gamlib import glglobals as GM from gamlib import glindent from gamlib import glmsgs as Msg +from gam.constants import NO_ENTITIES_FOUND_RC, TEAM_DRIVE, WITH_PARENTS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -58,8 +58,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] from gam.cmd.drive.filepaths import ( DRIVEFILE_BASIC_PERMISSION_FIELDS, DRIVEFILE_ORDERBY_CHOICE_MAP, @@ -153,13 +151,6 @@ from gam.util.output import ( writeStdout, ) -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") MY_DRIVE = 'My Drive' NEVER_TIME = '1970-01-01T00:00:00.000Z' @@ -325,7 +316,7 @@ def printFileList(users): if childEntry['info']['mimeType'] == MIMETYPE_GA_FOLDER and (maxdepth == -1 or depth < maxdepth): _printChildDriveFolderContents(drive, childEntry['info'], user, i, count, depth+1) return - q = _getMain().WITH_PARENTS.format(fileEntry['id']) + q = WITH_PARENTS.format(fileEntry['id']) if selectSubQuery: q += ' and ('+selectSubQuery+')' if depth == 0: @@ -402,7 +393,7 @@ def printFileList(users): pmselect = True showLabels = None rootFolderId = ROOT - rootFolderName = _getMain().MY_DRIVE + rootFolderName = MY_DRIVE maxdepth = -1 nodataFields = [] simpleLists = ['permissionIds', 'spaces'] @@ -784,7 +775,7 @@ def printFileList(users): titlePrefix = f'{Cmd.Argument(GM.Globals[GM.ENTITY_CL_START])} {Cmd.Argument(GM.Globals[GM.ENTITY_CL_START]+1)} ' if GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE] is None else '' if not countsOnly: if not csvPF.rows: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) sortTitles = ['Owner'] if addCSVData: sortTitles.extend(sorted(addCSVData.keys())) @@ -796,7 +787,7 @@ def printFileList(users): csvPF.writeCSVfile(f'{titlePrefix}Drive Files') else: if not csvPFco.rows: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if summary != FILECOUNT_SUMMARY_NONE: writeMimeTypeCountsRow(summaryUser, 'Various', 'Various', summaryMimeTypeInfo) csvPFco.todrive = csvPF.todrive @@ -1130,7 +1121,7 @@ def printShowFilePaths(users): result['name'] = _stripControlCharsFromName(result['name']) driveId = result.get('driveId') if driveId: - if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == _getMain().TEAM_DRIVE: + if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE: result['name'] = _getSharedDriveNameFromId(drive, driveId) if returnPathOnly: if fullpath: @@ -1219,7 +1210,7 @@ def printFileParentTree(users): else: driveId = result.get('driveId') if driveId: - if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == _getMain().TEAM_DRIVE: + if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE: result['name'] = _getSharedDriveNameFromId(drive, driveId) result['isRoot'] = True result['parents'] = [''] diff --git a/src/gam/cmd/drive/filepaths.py b/src/gam/cmd/drive/filepaths.py index d1e63a93..dbe25b6f 100644 --- a/src/gam/cmd/drive/filepaths.py +++ b/src/gam/cmd/drive/filepaths.py @@ -6,7 +6,6 @@ Part of the drive sub-package, extracted from drive.py.""" import re import json -import sys from gam.cmd.drive.core import _getSharedDriveNameFromId, _validateUserGetFileIDs, getDriveFileEntity from gam.cmd.drive.filetree import addFilePathsToInfo, extendFileTree, extendFileTreeParents, initFileTree @@ -23,6 +22,7 @@ from gamlib import glgapi as GAPI from gamlib import glglobals as GM from gamlib import glindent from gamlib import glmsgs as Msg +from gam.constants import MY_DRIVE, TEAM_DRIVE Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -57,16 +57,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from gam.cmd.drive.core import DRIVE_LABEL_CHOICE_MAP # cross-module ref from gam.util.api import callGAPI, callGAPIitems, callGAPIpages @@ -94,7 +84,11 @@ from gam.util.display import ( printLine, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument, getEntityList +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, + getEntityList, +) from gam.util.errors import invalidChoiceExit from gam.util.output import writeStdout @@ -104,9 +98,9 @@ def initFilePathInfo(delimiter): def getFilePaths(drive, fileTree, initialResult, filePathInfo, addParentsToTree=False, fullpath=False, showDepth=False, folderPathOnly=False, parentPathOnly=False): def _getParentName(result): - if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == _getMain().TEAM_DRIVE): + if (result['mimeType'] == MIMETYPE_GA_FOLDER) and result.get('driveId') and (result['name'] == TEAM_DRIVE): parentName = _getSharedDriveNameFromId(drive, result['driveId']) - if parentName != _getMain().TEAM_DRIVE: + if parentName != TEAM_DRIVE: return f'{SHARED_DRIVES}{filePathInfo["delimiter"]}{parentName}' return result['name'] @@ -178,11 +172,11 @@ def getFilePaths(drive, fileTree, initialResult, filePathInfo, addParentsToTree= maxDepth = _makeFilePaths(filePathInfo['localPaths'], fplist, filePaths, initialResult['name'], -1) else: if (fullpath and initialMimeType == MIMETYPE_GA_FOLDER and - ((initialResult['name'] == _getMain().MY_DRIVE) or + ((initialResult['name'] == MY_DRIVE) or (initialResult.get('driveId') and initialResult['name'].startswith(SHARED_DRIVES)))): filePaths.append(initialResult['name']) maxDepth = 0 - return (_getMain()._getEntityMimeType(initialResult), filePaths, maxDepth) + return (_getEntityMimeType(initialResult), filePaths, maxDepth) DRIVEFILE_ORDERBY_CHOICE_MAP = { 'createddate': 'createdTime', @@ -805,7 +799,7 @@ def showFileInfo(users): result['name'] = _stripControlCharsFromName(result['name']) driveId = result.get('driveId') if driveId: - if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == _getMain().TEAM_DRIVE: + if result['mimeType'] == MIMETYPE_GA_FOLDER and result['name'] == TEAM_DRIVE: result['name'] = _getSharedDriveNameFromId(drive, driveId) if DFF.showSharedDriveNames: result['driveName'] = _getSharedDriveNameFromId(drive, driveId) @@ -830,7 +824,7 @@ def showFileInfo(users): fileId=fileId) _formatFileDriveLabels(showLabels, labels, result, False, ' ') if not FJQC.formatJSON: - printEntity([_getMain()._getEntityMimeType(result), f'{result["name"]} ({fileId})'], j, jcount) + printEntity([_getEntityMimeType(result), f'{result["name"]} ({fileId})'], j, jcount) Ind.Increment() if filepath: if fullpath: diff --git a/src/gam/cmd/drive/files.py b/src/gam/cmd/drive/files.py index 875c7106..dcf8d3d2 100644 --- a/src/gam/cmd/drive/files.py +++ b/src/gam/cmd/drive/files.py @@ -5,7 +5,6 @@ Part of the drive sub-package, extracted from drive.py.""" """GAM Google Drive file, permission, shared drive, and label management.""" import re -import sys from gam.cmd.drive.core import DFA_IGNORE_DEFAULT_VISIBILITY, DFA_KEEP_REVISION_FOREVER, DFA_LOCALFILENAME, DFA_LOCALFILEPATH, DFA_LOCALMIMETYPE, DFA_OCRLANGUAGE, DFA_PARENTID, DFA_PRESERVE_FILE_TIMES, DFA_REPLACEFILENAME, DFA_SHAREDDRIVE_PARENT, DFA_STRIPNAMEPREFIX, DFA_TIMEFORMAT, DFA_TIMESTAMP, DFA_URL, DFA_USE_CONTENT_AS_INDEXABLE_TEXT, _getDriveFileAddRemoveParentInfo, _getDriveFileParentInfo, _validateUserGetFileIDs, escapeDriveFileName, getDriveFileAddRemoveParentAttribute, getDriveFileAttribute, getDriveFileEntity, getDriveFileParentAttribute, getMediaBody, initDriveFileAttributes, setPreservedFileTimes from gam.cmd.drive.fileinfo import writeReturnIdLink @@ -44,10 +43,16 @@ from gam.util.display import ( entityPerformActionSubItemModifierNumItems, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument, shlexSplitList +from gam.util.entity import ( + _getEntityMimeType, + _getTargetEntityMimeType, + getEntityArgument, + shlexSplitList, +) from gam.util.errors import emptyArgumentExit, unknownArgumentExit, usageErrorExit from gam.util.fileio import UNKNOWN, readFile from gam.util.output import writeStdout +from gam.constants import AND_NOT_SHORTCUT, ANY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS, MY_DRIVE, MY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -82,16 +87,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def processFilenameReplacements(name, replacements): for replacement in replacements: @@ -187,7 +182,7 @@ def createDriveFile(users): continue if not _getDriveFileParentInfo(drive, user, i, count, body, parameters): continue - entityType = _getMain()._getEntityMimeType(body) if 'mimeType' in body else Ent.DRIVE_FILE + entityType = _getEntityMimeType(body) if 'mimeType' in body else Ent.DRIVE_FILE try: if noDuplicate: # Check for existing file/folder, do not duplicate @@ -221,7 +216,7 @@ def createDriveFile(users): if parameters[DFA_LOCALFILENAME]: kvList.extend([Ent.DRIVE_FILE, titleInfo]) else: - kvList.extend([_getMain()._getEntityMimeType(result), titleInfo]) + kvList.extend([_getEntityMimeType(result), titleInfo]) else: if result['mimeType'] != MIMETYPE_GA_FOLDER: kvList.extend([Ent.DRIVE_FILE, result['name'], Ent.DRIVE_FILE_ID, result['id']]) @@ -273,14 +268,14 @@ def createDriveFolderPath(users): folderPathLocation = Cmd.Location() driveFolderNameList = getString(Cmd.OB_DRIVE_FOLDER_PATH).lstrip(pathDelimiter).strip(' ').split(pathDelimiter) if len(driveFolderNameList) > 0: - if driveFolderNameList[0].lower() == _getMain().MY_DRIVE.lower(): + if driveFolderNameList[0].lower() == MY_DRIVE.lower(): parentParms[DFA_PARENTID] = ROOT driveFolderNameList = driveFolderNameList[1:] elif driveFolderNameList[0].lower() == SHARED_DRIVES.lower() and len(driveFolderNameList) > 1: parentParms[DFA_SHAREDDRIVE_PARENT] = driveFolderNameList[1] driveFolderNameList = driveFolderNameList[2:] else: - usageErrorExit(Msg.FULL_PATH_MUST_START_WITH_DRIVE.format(_getMain().MY_DRIVE, f'{SHARED_DRIVES}{pathDelimiter}')) + usageErrorExit(Msg.FULL_PATH_MUST_START_WITH_DRIVE.format(MY_DRIVE, f'{SHARED_DRIVES}{pathDelimiter}')) fullPath = True elif myarg == 'path': folderPathLocation = Cmd.Location() @@ -323,9 +318,9 @@ def createDriveFolderPath(users): continue parentId = parentBody['parents'][0] if parentParms.get('searchargs', {}).get('corpora', ''): - query = _getMain().ANY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS + query = ANY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS else: - query = _getMain().MY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS + query = MY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS errors = False createOnly = False if not returnIdOnly and not csvPF: @@ -419,9 +414,9 @@ def createDriveFileShortcut(users): else: unknownArgumentExit() if fileIdEntity['query']: - fileIdEntity['query'] = fileIdEntity['query']+_getMain().AND_NOT_SHORTCUT + fileIdEntity['query'] = fileIdEntity['query']+AND_NOT_SHORTCUT elif fileIdEntity['shareddrivefilequery']: - fileIdEntity['shareddrivefilequery'] = fileIdEntity['shareddrivefilequery']+_getMain().AND_NOT_SHORTCUT + fileIdEntity['shareddrivefilequery'] = fileIdEntity['shareddrivefilequery']+AND_NOT_SHORTCUT i, count, users = getEntityArgument(users) for user in users: i += 1 @@ -467,7 +462,7 @@ def createDriveFileShortcut(users): shortcutName = baseShortcutName.replace('#filename#', targetName) else: shortcutName = targetName - targetEntityType = _getMain()._getEntityMimeType(target) + targetEntityType = _getEntityMimeType(target) if convertParents: newParents = target.get('parents', [])[:-1] numNewParents = len(newParents) @@ -586,7 +581,7 @@ def checkDriveFileShortcut(users): row['name'] = scresult['name'] if scresult['mimeType'] != MIMETYPE_GA_SHORTCUT: if not csvPF: - entityActionFailedWarning([Ent.USER, user, _getMain()._getEntityMimeType(scresult), fileId], + entityActionFailedWarning([Ent.USER, user, _getEntityMimeType(scresult), fileId], Msg.INVALID_MIMETYPE.format(scresult['mimeType'], MIMETYPE_GA_SHORTCUT), j, jcount) else: row['code'] = SHORTCUT_CODE_NOT_A_SHORTCUT @@ -606,7 +601,7 @@ def checkDriveFileShortcut(users): row['targetId'] = trresult['id'] row['targetMimeType'] = trresult['mimeType'] entityList = [Ent.USER, user, Ent.DRIVE_FILE_SHORTCUT, f"{scresult['name']}({fileId})", - _getMain()._getEntityMimeType(trresult), f"{trresult['name']}({trfileId})"] + _getEntityMimeType(trresult), f"{trresult['name']}({trfileId})"] if scresult['shortcutDetails']['targetMimeType'] == trresult['mimeType']: if not csvPF: entityActionPerformed(entityList, j, jcount) @@ -620,7 +615,7 @@ def checkDriveFileShortcut(users): except GAPI.fileNotFound: if not csvPF: entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE_SHORTCUT, f"{scresult['name']}({fileId})", - _getMain()._getTargetEntityMimeType(scresult), trfileId], Msg.NOT_FOUND, j, jcount) + _getTargetEntityMimeType(scresult), trfileId], Msg.NOT_FOUND, j, jcount) else: row['code'] = SHORTCUT_CODE_TARGET_NOT_FOUND except GAPI.fileNotFound: @@ -852,7 +847,7 @@ def updateDriveFile(users): entityModifierNewValueActionPerformed([Ent.USER, user, Ent.DRIVE_FILE, result['name']], Act.MODIFIER_WITH_CONTENT_FROM, parameters[DFA_LOCALFILENAME] or parameters[DFA_URL], j, jcount) else: - entityActionPerformed([Ent.USER, user, _getMain()._getEntityMimeType(result), result['name']], j, jcount) + entityActionPerformed([Ent.USER, user, _getEntityMimeType(result), result['name']], j, jcount) else: if returnIdLink: writeStdout(f'{fileId}\n') diff --git a/src/gam/cmd/drive/filetree.py b/src/gam/cmd/drive/filetree.py index 55622257..d45fef22 100644 --- a/src/gam/cmd/drive/filetree.py +++ b/src/gam/cmd/drive/filetree.py @@ -5,7 +5,6 @@ Part of the drive sub-package, extracted from drive.py.""" """GAM Google Drive file, permission, shared drive, and label management.""" import re -import sys from gam.cmd.drive.core import _getSharedDriveNameFromId, _mapDrive2QueryToDrive3, cleanFileIDsList, escapeDriveFileName, getEscapedDriveFileName, initDriveFileEntity from gam.cmd.drive.revisions import _stripMeInOwners, _stripNotMeInOwners, _updateAnyOwnerQuery @@ -19,6 +18,8 @@ from gamlib import glgapi as GAPI from gamlib import glglobals as GM from gamlib import glindent from gamlib import glmsgs as Msg +from gam.util.entity import QUERY_SHORTCUTS_MAP +from gam.constants import MY_DRIVE, TEAM_DRIVE Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -53,8 +54,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] from gam.cmd.drive.core import ( MimeTypeCheck, @@ -87,13 +86,6 @@ from gam.util.args import ( from gam.util.display import entityActionFailedWarning, userDriveServiceNotEnabledWarning from gam.util.errors import invalidChoiceExit, unknownArgumentExit, usageErrorExit -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def initFileTree(drive, shareddrive, DLP, shareddriveFields, showParent, user, i, count): fileTree = { @@ -157,7 +149,7 @@ def extendFileTree(fileTree, feed, DLP, stripCRsFromName): fileId = f_file['id'] if not f_file.get('parents', []): if not f_file.get('driveId'): - if f_file['mimeType'] == MIMETYPE_GA_FOLDER and f_file['name'] == _getMain().MY_DRIVE: + if f_file['mimeType'] == MIMETYPE_GA_FOLDER and f_file['name'] == MY_DRIVE: f_file['parents'] = [] else: f_file['parents'] = [ORPHANS] if f_file.get('ownedByMe', False) and 'sharedWithMeTime' not in f_file else [SHARED_WITHME] @@ -182,7 +174,7 @@ def extendFileTreeParents(drive, fileTree, fields): if not result.get('driveId'): result['parents'] = [ORPHANS] if result.get('ownedByMe', False) and 'sharedWithMeTime' not in result else [SHARED_WITHME] else: - if result['name'] == _getMain().TEAM_DRIVE: + if result['name'] == TEAM_DRIVE: result['name'] = _getSharedDriveNameFromId(drive, result['driveId']) result['parents'] = [SHARED_DRIVES] if 'sharedWithMeTime' not in result else [SHARED_WITHME] fileTree[fileId]['info'] = result @@ -609,9 +601,9 @@ class DriveListParameters(): self.AppendToQuery(Cmd.Previous().strip()[6:]) elif self.myargOptions['allowQuery'] and myarg == 'fullquery': self.SetQuery(getString(Cmd.OB_QUERY, minLen=0)) - elif self.myargOptions['allowQuery'] and myarg in _getMain().QUERY_SHORTCUTS_MAP: + elif self.myargOptions['allowQuery'] and myarg in QUERY_SHORTCUTS_MAP: self.UpdateAnyOwnerQuery() - self.AppendToQuery(_getMain().QUERY_SHORTCUTS_MAP[myarg]) + self.AppendToQuery(QUERY_SHORTCUTS_MAP[myarg]) elif self.myargOptions['allowChoose'] and myarg == 'choose': myarg = checkGetArgument() if myarg in DRIVE_BY_NAME_CHOICE_MAP: @@ -641,7 +633,7 @@ class DriveListParameters(): if (myarg == 'query' or myarg.startswith('query:') or myarg == 'fullquery' or - myarg in _getMain().QUERY_SHORTCUTS_MAP or + myarg in QUERY_SHORTCUTS_MAP or myarg in DRIVE_BY_NAME_CHOICE_MAP): usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('select', myarg)) return False diff --git a/src/gam/cmd/drive/labels.py b/src/gam/cmd/drive/labels.py index 05421006..b94ba063 100644 --- a/src/gam/cmd/drive/labels.py +++ b/src/gam/cmd/drive/labels.py @@ -6,7 +6,6 @@ Part of the drive sub-package, extracted from drive.py.""" import re import json -import sys from gam.cmd.drive.core import _validateUserGetFileIDs, getDriveFileEntity @@ -60,6 +59,7 @@ from gam.util.entity import ( getUserObjectEntity, ) from gam.util.errors import missingArgumentExit, unknownArgumentExit, usageErrorExit +from gam.constants import ADMIN_ACCESS_OPTIONS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -94,23 +94,13 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def _getDisplayDriveLabelsParameters(myarg, parameters): if myarg in DRIVELABELS_PROJECTION_CHOICE_MAP: parameters['view'] = DRIVELABELS_PROJECTION_CHOICE_MAP[myarg] elif myarg == 'language': parameters['languageCode'] = getLanguageCode(BCP47_LANGUAGE_CODES_MAP) - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: parameters['useAdminAccess'] = True elif myarg == 'publishedonly': parameters['publishedOnly'] = getBoolean() @@ -297,7 +287,7 @@ def createDriveLabelPermissions(users, useAdminAccess=False): showDetails = True while Cmd.ArgumentsRemaining(): myarg = getArgument() - if myarg in _getMain().ADMIN_ACCESS_OPTIONS: + if myarg in ADMIN_ACCESS_OPTIONS: parameters['useAdminAccess'] = True elif myarg == 'role': body['role'] = getChoice(DRIVELABELS_PERMISSION_ROLE_MAP, mapChoice=True) @@ -374,7 +364,7 @@ def deleteDriveLabelPermissions(users, useAdminAccess=False): labelperm = '' while Cmd.ArgumentsRemaining(): myarg = getArgument() - if myarg in _getMain().ADMIN_ACCESS_OPTIONS: + if myarg in ADMIN_ACCESS_OPTIONS: parameters['useAdminAccess'] = True elif doDelete and myarg in {'user', 'group'}: labelperm = ['people/', 'groups/'][myarg == 'group']+convertEmailAddressToUID(getEmailAddress(), cd=None, emailType=myarg, savedLocation=None) @@ -439,7 +429,7 @@ def printShowDriveLabelPermissions(users, useAdminAccess=False): myarg = getArgument() if csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: parameters['useAdminAccess'] = True else: FJQC.GetFormatJSONQuoteChar(myarg, True) diff --git a/src/gam/cmd/drive/permissions.py b/src/gam/cmd/drive/permissions.py index d685ec82..4d6373f5 100644 --- a/src/gam/cmd/drive/permissions.py +++ b/src/gam/cmd/drive/permissions.py @@ -6,7 +6,6 @@ Part of the drive sub-package, extracted from drive.py.""" import re import json -import sys from gam.cmd.drive.core import _getDriveFileNameFromId, _getSharedDriveNameFromId, _validateUserGetFileIDs, _validateUserSharedDrive, cleanFileIDsList, getDriveFileEntity, getSharedDriveEntity, initDriveFileEntity from gam.cmd.drive.filepaths import _finalizeIncludePermissionsForView, _getIncludePermissionsForView, _mapDrivePermissionNames @@ -73,7 +72,11 @@ from gam.util.display import ( printLine, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument, getEntityList +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, + getEntityList, +) from gam.util.errors import ( deprecatedArgument, invalidChoiceExit, @@ -83,6 +86,7 @@ from gam.util.errors import ( ) from gam.util.fileio import UNKNOWN from gam.util.output import executeBatch +from gam.constants import ADMIN_ACCESS_OPTIONS, WITH_PARENTS Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -117,20 +121,10 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def printEmptyDriveFolders(users): def _checkChildDriveFolderContents(drive, fileEntry, user, i, count, pathList): - query = _getMain().WITH_PARENTS.format(fileEntry ['id']) + query = WITH_PARENTS.format(fileEntry ['id']) try: children = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID, @@ -195,7 +189,7 @@ def printEmptyDriveFolders(users): pathList = [fileEntryInfo['name']] mimeType = fileEntryInfo['mimeType'] if mimeType != MIMETYPE_GA_FOLDER: - entityValueList = [Ent.USER, user, _getMain()._getEntityMimeType(fileEntryInfo), fileEntryInfo['name']] + entityValueList = [Ent.USER, user, _getEntityMimeType(fileEntryInfo), fileEntryInfo['name']] entityActionNotPerformedWarning(entityValueList, Msg.INVALID_MIMETYPE.format(mimeType, MIMETYPE_GA_FOLDER), i, count) continue _checkChildDriveFolderContents(drive, fileEntryInfo, user, i, count, pathList) @@ -214,7 +208,7 @@ def printEmptyDriveFolders(users): # [pathdelimiter ] def deleteEmptyDriveFolders(users): def _deleteEmptyChildDriveFolders(drive, fileEntry, user, i, count, pathList, atTop): - query = _getMain().WITH_PARENTS.format(fileEntry ['id']) + query = WITH_PARENTS.format(fileEntry ['id']) try: children = callGAPIpages(drive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID_QUERY, GAPI.INVALID, @@ -285,7 +279,7 @@ def deleteEmptyDriveFolders(users): pathList = [fileEntryInfo['name']] mimeType = fileEntryInfo['mimeType'] if mimeType != MIMETYPE_GA_FOLDER: - entityValueList = [Ent.USER, user, _getMain()._getEntityMimeType(fileEntryInfo), fileEntryInfo['name']] + entityValueList = [Ent.USER, user, _getEntityMimeType(fileEntryInfo), fileEntryInfo['name']] entityActionNotPerformedWarning(entityValueList, Msg.INVALID_MIMETYPE.format(mimeType, MIMETYPE_GA_FOLDER), i, count) continue _deleteEmptyChildDriveFolders(drive, fileEntryInfo, user, i, count, pathList, True) @@ -497,7 +491,7 @@ def createDriveFileACL(users, useDomainAdminAccess=False): FJQC.SetCsvPF(csvPF) elif csvPF and myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: FJQC.GetFormatJSONQuoteChar(myarg) @@ -657,7 +651,7 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False): elif myarg == 'transferownership': deprecatedArgument(myarg) getBoolean() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: FJQC.GetFormatJSONQuoteChar(myarg) @@ -856,7 +850,7 @@ def createDriveFilePermissions(users, useDomainAdminAccess=False): elif myarg == 'emailmessage': sendNotificationEmail = True emailMessage = getString(Cmd.OB_STRING) - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif PM and PM.ProcessArgument(myarg): pass @@ -942,7 +936,7 @@ def deleteDriveFileACLs(users, useDomainAdminAccess=False): showTitles = getBoolean() elif myarg == 'updatesheetprotectedranges': updateSheetProtectedRanges = getBoolean() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: unknownArgumentExit() @@ -1063,7 +1057,7 @@ def deletePermissions(users, useDomainAdminAccess=False): PM.SetDefaultMatch(False, {'role': 'owner'}) while Cmd.ArgumentsRemaining(): myarg = getArgument() - if myarg in _getMain().ADMIN_ACCESS_OPTIONS: + if myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif PM and PM.ProcessArgument(myarg): pass @@ -1139,7 +1133,7 @@ def infoDriveFileACLs(users, useDomainAdminAccess=False): myarg = getArgument() if myarg == 'showtitles': showTitles = getBoolean() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: FJQC.GetFormatJSON(myarg) @@ -1271,7 +1265,7 @@ def printShowDriveFileACLs(users, useDomainAdminAccess=False): csvPF.SetSortAllTitles() elif getDriveFilePermissionsFields(myarg, fieldsList): pass - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif myarg == 'pmselect': pmselect = True diff --git a/src/gam/cmd/drive/revisions.py b/src/gam/cmd/drive/revisions.py index 0611ea07..e8264272 100644 --- a/src/gam/cmd/drive/revisions.py +++ b/src/gam/cmd/drive/revisions.py @@ -5,7 +5,6 @@ Part of the drive sub-package, extracted from drive.py.""" """GAM Google Drive file, permission, shared drive, and label management.""" import re -import sys from gam.cmd.drive.core import _getDriveFileNameFromId, _validateUserGetFileIDs, getDriveFileEntity @@ -50,6 +49,7 @@ from gam.util.display import ( from gam.util.entity import getEntityArgument, getEntitySelection, getEntitySelector from gam.util.errors import missingArgumentExit, unknownArgumentExit from gam.util.output import _stripControlCharsFromName, setSysExitRC +from gam.constants import AND_ME_IN_OWNERS, AND_NOT_ME_IN_OWNERS, NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -84,16 +84,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def getRevisionsEntity(): revisionsEntity = {'list': [], 'dict': None, 'count': None, 'time': None, 'range': None} @@ -250,7 +240,7 @@ def deleteFileRevisions(users): if kcount == 0: entityNumEntitiesActionNotPerformedWarning([Ent.USER, user, entityType, fileName], Ent.DRIVE_FILE_REVISION, kcount, Msg.NO_ENTITIES_MATCHED.format(Ent.Plural(Ent.DRIVE_FILE_REVISION)), j, jcount) - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) continue if not previewDelete: if maxToProcess and kcount > maxToProcess: @@ -340,7 +330,7 @@ def updateFileRevisions(users): if kcount == 0: entityNumEntitiesActionNotPerformedWarning([Ent.USER, user, entityType, fileName], Ent.DRIVE_FILE_REVISION, kcount, Msg.NO_ENTITIES_MATCHED.format(Ent.Plural(Ent.DRIVE_FILE_REVISION)), j, jcount) - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) continue if not previewUpdate: if maxToProcess and kcount > maxToProcess: @@ -598,14 +588,14 @@ def _stripMeInOwners(query): if not query: return query query = query.replace(ME_IN_OWNERS_AND, '') - query = query.replace(_getMain().AND_ME_IN_OWNERS, '') + query = query.replace(AND_ME_IN_OWNERS, '') return query.replace(ME_IN_OWNERS, '').strip() def _stripNotMeInOwners(query): if not query: return query query = query.replace(NOT_ME_IN_OWNERS_AND, '') - query = query.replace(_getMain().AND_NOT_ME_IN_OWNERS, '') + query = query.replace(AND_NOT_ME_IN_OWNERS, '') return query.replace(NOT_ME_IN_OWNERS, '').strip() def _updateAnyOwnerQuery(query): diff --git a/src/gam/cmd/drive/shareddrives.py b/src/gam/cmd/drive/shareddrives.py index ef0f506a..841408d5 100644 --- a/src/gam/cmd/drive/shareddrives.py +++ b/src/gam/cmd/drive/shareddrives.py @@ -82,7 +82,7 @@ from gam.util.display import ( printLine, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument, getEntityList +from gam.util.entity import _getCustomersCustomerIdWithC, getEntityArgument, getEntityList from gam.util.errors import ( blankArgumentExit, invalidArgumentExit, @@ -93,6 +93,7 @@ from gam.util.errors import ( from gam.util.fileio import UNKNOWN from gam.util.orgunits import getOrgUnitId from gam.util.output import setSysExitRC, systemErrorExit, writeStderr, writeStdout +from gam.constants import ADMIN_ACCESS_OPTIONS, GOOGLE_API_ERROR_RC, NO_ENTITIES_FOUND_RC Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -127,16 +128,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def doPrintShowOwnership(): rep = buildGAPIObject(API.REPORTS) @@ -199,7 +190,7 @@ def doPrintShowOwnership(): except GAPI.badRequest: systemErrorExit(BAD_REQUEST_RC, Msg.BAD_REQUEST) except GAPI.invalid as e: - systemErrorExit(_getMain().GOOGLE_API_ERROR_RC, str(e)) + systemErrorExit(GOOGLE_API_ERROR_RC, str(e)) except GAPI.authError: accessErrorExit(None) for activity in feed: @@ -331,7 +322,7 @@ def _moveSharedDriveToOU(orgUnit, orgUnitId, driveId, user, i, count, ci, return name = f'orgUnits/-/memberships/shared_drive;{driveId}' if ci is None: ci = buildGAPIObject(API.CLOUDIDENTITY_ORGUNITS_BETA) - cibody = {'customer': _getMain()._getCustomersCustomerIdWithC(), + cibody = {'customer': _getCustomersCustomerIdWithC(), 'destinationOrgUnit': f'orgUnits/{orgUnitId[3:]}'} try: callGAPI(ci.orgUnits().memberships(), 'move', @@ -391,7 +382,7 @@ def createSharedDrive(users, useDomainAdminAccess=False): csvPF.GetTodriveParameters() elif csvPF and myarg == 'addcsvdata': getAddCSVData(addCSVData) - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif myarg == 'errorretries': errorRetries = getInteger(minVal=0, maxVal=10) @@ -543,7 +534,7 @@ def updateSharedDrive(users, useDomainAdminAccess=False): pass elif myarg in {'hide', 'hidden'}: hide = getBoolean() - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: unknownArgumentExit() @@ -601,7 +592,7 @@ def deleteSharedDrive(users): myarg = getArgument() if myarg in {'nukefromorbit', 'allowitemdeletion'}: allowItemDeletion = useDomainAdminAccess = True - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: unknownArgumentExit() @@ -740,7 +731,7 @@ def infoSharedDrive(users, useDomainAdminAccess=False): guiRoles = False while Cmd.ArgumentsRemaining(): myarg = getArgument() - if myarg in _getMain().ADMIN_ACCESS_OPTIONS: + if myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif getFieldsList(myarg, SHAREDDRIVE_FIELDS_CHOICE_MAP, fieldsList, initialField=['id', 'name']): pass @@ -809,6 +800,7 @@ SHOWWEBVIEWLINK_CHOICES = {'text', 'hyperlink'} # [guiroles []] [formatjson] # [showitemcountonly] def printShowSharedDrives(users, useDomainAdminAccess=False): + from gam.cmd.orgunits import getOrgUnitIdToPathMap def stripNonShowFields(shareddrive): if orgUnitIdToPathMap: td_ouid = shareddrive.get('orgUnitId') @@ -859,7 +851,7 @@ def printShowSharedDrives(users, useDomainAdminAccess=False): roles |= getACLRoles(SHAREDDRIVE_ACL_ROLES_MAP) elif myarg == 'checkgroups': pass - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif getFieldsList(myarg, SHAREDDRIVE_FIELDS_CHOICE_MAP, fieldsList, initialField=['id', 'name']): pass @@ -890,7 +882,7 @@ def printShowSharedDrives(users, useDomainAdminAccess=False): csvPF.AddJSONTitles(['role']) csvPF.MoveJSONTitlesToEnd(['JSON']) if showOrgUnitPaths and useDomainAdminAccess and ((not showFields) or ('orgUnitId' in showFields)): - orgUnitIdToPathMap = _getMain().getOrgUnitIdToPathMap(cd) + orgUnitIdToPathMap = getOrgUnitIdToPathMap(cd) if showFields: showFields.add('orgUnit') if showWebViewLink: @@ -950,7 +942,7 @@ def printShowSharedDrives(users, useDomainAdminAccess=False): matchedFeed = feed jcount = len(matchedFeed) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if showItemCountOnly: writeStdout(f'{jcount}\n') return @@ -1039,11 +1031,11 @@ def doPrintShowOrgunitSharedDrives(): sds = callGAPIpages(ci.orgUnits().memberships(), 'list', 'orgMemberships', pageMessage=getPageMessageForWhom(), parent=f'orgUnits/{orgUnitId[3:]}', - customer=_getMain()._getCustomersCustomerIdWithC(), + customer=_getCustomersCustomerIdWithC(), filter="type == 'shared_drive'") jcount = len(sds) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if showItemCountOnly: writeStdout(f'{jcount}\n') return @@ -1090,7 +1082,7 @@ def copySyncSharedDriveACLs(users, useDomainAdminAccess=False): myarg = getArgument() if getCopyMoveOptions(myarg, copyMoveOptions): pass - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True else: unknownArgumentExit() @@ -1211,7 +1203,7 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False): maxItems = getInteger(minVal=0) elif getDriveFilePermissionsFields(myarg, fieldsList): pass - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif PM.ProcessArgument(myarg): pass @@ -1349,7 +1341,7 @@ def printShowSharedDriveACLs(users, useDomainAdminAccess=False): pass jcount = len(matchFeed) if jcount == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) if not csvPF: if not FJQC.formatJSON: entityPerformActionNumItems([Ent.USER, user], jcount, Ent.SHAREDDRIVE, i, count) @@ -1470,7 +1462,7 @@ def printSharedDriveOrganizers(users, useDomainAdminAccess=False): orgUnitPath, orgUnitId = getOrgUnitId(cd) orgUnitId = orgUnitId[3:] orgUnitInfo = {'orgUnit': orgUnitPath, 'orgUnitId': orgUnitId} - elif myarg in _getMain().ADMIN_ACCESS_OPTIONS: + elif myarg in ADMIN_ACCESS_OPTIONS: useDomainAdminAccess = True elif myarg == 'domainlist': domainList = set(getString(Cmd.OB_DOMAIN_NAME_LIST, minLen=0).replace(',', ' ').lower().split()) @@ -1590,7 +1582,7 @@ def printSharedDriveOrganizers(users, useDomainAdminAccess=False): GAPI.unknownError, GAPI.invalid): pass if len(matchFeed) == 0: - setSysExitRC(_getMain().NO_ENTITIES_FOUND_RC) + setSysExitRC(NO_ENTITIES_FOUND_RC) for shareddrive in sorted(matchFeed, key=lambda k: k['name']): row = {'id': shareddrive['id'], 'name': shareddrive['name'], 'organizers': delimiter.join(shareddrive['organizers']), diff --git a/src/gam/cmd/drive/transfer/fileops.py b/src/gam/cmd/drive/transfer/fileops.py index e60ea669..8cbde8e6 100644 --- a/src/gam/cmd/drive/transfer/fileops.py +++ b/src/gam/cmd/drive/transfer/fileops.py @@ -59,7 +59,11 @@ from gam.util.display import ( printLine, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument, splitEmailAddressOrUID +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, + splitEmailAddressOrUID, +) from gam.util.errors import invalidChoiceExit, unknownArgumentExit from gam.util.fileio import ( cleanFilename, @@ -69,6 +73,8 @@ from gam.util.fileio import ( writeFile, ) from gam.util.output import setSysExitRC, writeStderr +from gam.constants import MY_NON_TRASHED_FOLDER_NAME +from gam.util.tags import _substituteForUser Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -103,16 +109,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") UNKNOWN = 'Unknown' ORPHANS_COLLECTED_RC = 30 @@ -383,10 +379,10 @@ def getDriveFile(users): _, sheet = buildGAPIServiceObject(API.SHEETS, user, i, count) if not sheet: continue - targetFolder = _getMain()._substituteForUser(targetFolderPattern, user, userName) + targetFolder = _substituteForUser(targetFolderPattern, user, userName) if not os.path.isdir(targetFolder): os.makedirs(targetFolder) - targetName = _getMain()._substituteForUser(targetNamePattern, user, userName) if targetNamePattern else None + targetName = _substituteForUser(targetNamePattern, user, userName) if targetNamePattern else None Ind.Increment() j = 0 for fileId in fileIdEntity['list']: @@ -403,7 +399,7 @@ def getDriveFile(users): throwReasons=GAPI.DRIVE_GET_THROW_REASONS, fileId=fileId, fields='name,fullFileExtension,mimeType,size', supportsAllDrives=True) mimeType = result['mimeType'] - entityValueList = [Ent.USER, user, _getMain()._getEntityMimeType(result), result['name']] + entityValueList = [Ent.USER, user, _getEntityMimeType(result), result['name']] if mimeType in NON_DOWNLOADABLE_MIMETYPES: entityActionNotPerformedWarning(entityValueList, Msg.FORMAT_NOT_DOWNLOADABLE, j, jcount) continue @@ -569,10 +565,10 @@ def getGoogleDocument(users): if not docs: continue _, userName, _ = splitEmailAddressOrUID(user) - targetFolder = _getMain()._substituteForUser(targetFolderPattern, user, userName) + targetFolder = _substituteForUser(targetFolderPattern, user, userName) if not os.path.isdir(targetFolder): os.makedirs(targetFolder) - targetName = _getMain()._substituteForUser(targetNamePattern, user, userName) if targetNamePattern else None + targetName = _substituteForUser(targetNamePattern, user, userName) if targetNamePattern else None Ind.Increment() j = 0 for fileId in fileIdEntity['list']: @@ -704,8 +700,8 @@ def collectOrphans(users): fields='nextPageToken,files(id,name,parents,mimeType,sharedWithMeTime,capabilities(canMoveItemWithinDrive))', pageSize=GC.Values[GC.DRIVE_MAX_RESULTS]) if targetUserFolderPattern: - trgtUserFolderName = _getMain()._substituteForUser(targetUserFolderPattern, user, userName) - targetParms[DFA_PARENTQUERY] = _getMain().MY_NON_TRASHED_FOLDER_NAME.format(escapeDriveFileName(trgtUserFolderName)) + trgtUserFolderName = _substituteForUser(targetUserFolderPattern, user, userName) + targetParms[DFA_PARENTQUERY] = MY_NON_TRASHED_FOLDER_NAME.format(escapeDriveFileName(trgtUserFolderName)) else: targetParms[DFA_PARENTID] = targetUserFolderId trgtUserFolderName = targetUserFolderId @@ -741,7 +737,7 @@ def collectOrphans(users): j += 1 fileId = fileEntry['id'] fileName = fileEntry['name'] - fileType = _getMain()._getEntityMimeType(fileEntry) + fileType = _getEntityMimeType(fileEntry) # Deleted 6.26.16 # if fileType == Ent.DRIVE_FOLDER and not fileEntry['capabilities']['canAddMyDriveParent']: # # Typically Google Backup & Sync images of laptops diff --git a/src/gam/cmd/drive/transfer/ownership.py b/src/gam/cmd/drive/transfer/ownership.py index 0ab8ce8d..dba00de7 100644 --- a/src/gam/cmd/drive/transfer/ownership.py +++ b/src/gam/cmd/drive/transfer/ownership.py @@ -51,10 +51,17 @@ from gam.util.display import ( setGettingAllEntityItemsForWhom, userDriveServiceNotEnabledWarning, ) -from gam.util.entity import getEntityArgument, getEntityList, getEntityToModify +from gam.util.entity import ( + _getEntityMimeType, + getEntityArgument, + getEntityList, + getEntityToModify, +) from gam.util.errors import unknownArgumentExit, usageErrorExit from gam.util.fileio import UNKNOWN from gam.util.output import formatKeyValueList, printWarningMessage, systemErrorExit +from gam.constants import MY_DRIVE, MY_NON_TRASHED_FOLDER_NAME, MY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS, NON_TRASHED, TARGET_DRIVE_SPACE_ERROR_RC, WITH_PARENTS +from gam.util.tags import _substituteForUser Act = glaction.GamAction() Ent = glentity.GamEntity() @@ -89,16 +96,6 @@ ORPHANS = 'Orphans' SHARED_WITHME = 'SharedWithMe' SHARED_DRIVES = 'SharedDrives' -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def transferDrive(users): @@ -123,7 +120,7 @@ def transferDrive(users): throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.BAD_REQUEST], retryReasons=[GAPI.UNKNOWN_ERROR], orderBy=OBY.orderBy, - q=_getMain().MY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS.format(escapeDriveFileName(folderName), folderParentId), + q=MY_NON_TRASHED_FOLDER_NAME_WITH_PARENTS.format(escapeDriveFileName(folderName), folderParentId), fields='nextPageToken,files(id)') if result: return result[0]['id'] @@ -141,13 +138,13 @@ def transferDrive(users): return None def _buildTargetUserFolder(): - folderName = _getMain()._substituteForUser(targetUserFolderPattern, sourceUser, sourceUserName) + folderName = _substituteForUser(targetUserFolderPattern, sourceUser, sourceUserName) if not folderName: return targetFolderId return _buildTargetFile(folderName, targetFolderId) def _buildTargetUserOrphansFolder(): - folderName = _getMain()._substituteForUser(targetUserOrphansFolderPattern, sourceUser, sourceUserName) + folderName = _substituteForUser(targetUserOrphansFolderPattern, sourceUser, sourceUserName) if folderName: targetIds[TARGET_ORPHANS_PARENT_ID] = _buildTargetFile(folderName, targetIds[TARGET_PARENT_ID]) if targetIds[TARGET_ORPHANS_PARENT_ID] is None: @@ -240,7 +237,7 @@ def transferDrive(users): childEntryInfo = childEntry['info'] childFileId = childEntryInfo['id'] childFileName = childEntryInfo['name'] - childFileType = _getMain()._getEntityMimeType(childEntryInfo) + childFileType = _getEntityMimeType(childEntryInfo) # Owned files if childEntryInfo['ownedByMe']: childEntryInfo['sourcePermission'] = {'role': 'owner'} @@ -462,7 +459,7 @@ def transferDrive(users): childEntryInfo = childEntry['info'] childFileId = childEntryInfo['id'] childFileName = childEntryInfo['name'] - childFileType = _getMain()._getEntityMimeType(childEntryInfo) + childFileType = _getEntityMimeType(childEntryInfo) if childEntryInfo['mimeType'] == MIMETYPE_GA_SHORTCUT: if showRetentionMessages: entityActionNotPerformedWarning([Ent.USER, sourceUser, childFileType, childFileName, Ent.ROLE, ownerRetainRoleBody['role']], Msg.NOT_APPROPRIATE, j, jcount) @@ -586,7 +583,7 @@ def transferDrive(users): if not childEntry or childFileId in filesTransferred: continue if childFileId in skipFileIdEntity['list']: - entityActionNotPerformedWarning([Ent.USER, sourceUser, _getMain()._getEntityMimeType(childEntry['info']), f'{childEntry["info"]["name"]} ({childFileId})'], + entityActionNotPerformedWarning([Ent.USER, sourceUser, _getEntityMimeType(childEntry['info']), f'{childEntry["info"]["name"]} ({childFileId})'], Msg.IN_SKIPIDS, j, jcount) continue filesTransferred.add(childFileId) @@ -623,7 +620,7 @@ def transferDrive(users): children = callGAPIpages(sourceDrive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - orderBy=OBY.orderBy, q=_getMain().WITH_PARENTS.format(fileId), + orderBy=OBY.orderBy, q=WITH_PARENTS.format(fileId), fields='nextPageToken,files(id,name,parents,mimeType,ownedByMe,trashed,owners(emailAddress,permissionId),permissions(id,role),shortcutDetails)', pageSize=GC.Values[GC.DRIVE_MAX_RESULTS]) except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e: @@ -633,7 +630,7 @@ def transferDrive(users): if not childEntry['trashed']: childId = childEntry['id'] if childId in skipFileIdEntity['list']: - entityActionNotPerformedWarning([Ent.USER, sourceUser, _getMain()._getEntityMimeType(childEntry), f'{childEntry["name"]} ({childId})'], + entityActionNotPerformedWarning([Ent.USER, sourceUser, _getEntityMimeType(childEntry), f'{childEntry["name"]} ({childId})'], Msg.IN_SKIPIDS) continue fileTree[fileId]['children'].append(childId) @@ -643,7 +640,7 @@ def transferDrive(users): fileId = fileEntry['info']['id'] if fileId in filesTransferred: return - if fileEntry['info']['name'] != _getMain().MY_DRIVE: + if fileEntry['info']['name'] != MY_DRIVE: filesTransferred.add(fileId) if not atSelectTop or not mergeWithTarget: _transferFile(fileEntry, i, count, j, jcount, atSelectTop) @@ -663,7 +660,7 @@ def transferDrive(users): fileId = fileEntry['info']['id'] if fileId in filesTransferred: return - if fileEntry['info']['name'] != _getMain().MY_DRIVE: + if fileEntry['info']['name'] != MY_DRIVE: filesTransferred.add(fileId) if not atSelectTop or not mergeWithTarget: _manageRoleRetention(fileEntry, i, count, j, jcount, atSelectTop) @@ -786,7 +783,7 @@ def transferDrive(users): result = callGAPIpages(targetDrive.files(), 'list', 'files', throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - q=_getMain().MY_NON_TRASHED_FOLDER_NAME.format(escapeDriveFileName(targetFolderName)), + q=MY_NON_TRASHED_FOLDER_NAME.format(escapeDriveFileName(targetFolderName)), fields='nextPageToken,files(id)') if not result: Cmd.SetLocation(targetFolderNameLocation) @@ -830,7 +827,7 @@ def transferDrive(users): throwReasons=GAPI.DRIVE_USER_THROW_REASONS, fileId=ROOT, fields='id')['id'] if (targetDriveFree is not None) and (targetDriveFree < sourceDriveSize): - printWarningMessage(_getMain().TARGET_DRIVE_SPACE_ERROR_RC, + printWarningMessage(TARGET_DRIVE_SPACE_ERROR_RC, (f'{Msg.NO_TRANSFER_LACK_OF_DISK_SPACE} ' f'{formatKeyValueList("", ["Source drive size", formatFileSize(sourceDriveSize), "Target drive free", formatFileSize(targetDriveFree)], "")}')) continue @@ -853,7 +850,7 @@ def transferDrive(users): pageMessage=getPageMessageForWhom(), throwReasons=GAPI.DRIVE_USER_THROW_REASONS, retryReasons=[GAPI.UNKNOWN_ERROR], - orderBy=OBY.orderBy, q=_getMain().NON_TRASHED, + orderBy=OBY.orderBy, q=NON_TRASHED, fields='nextPageToken,files(id,name,parents,mimeType,ownedByMe,owners(emailAddress,permissionId),permissions(id,role),shortcutDetails)', pageSize=GC.Values[GC.DRIVE_MAX_RESULTS]) fileTree = buildFileTree(feed, sourceDrive) @@ -882,7 +879,7 @@ def transferDrive(users): throwReasons=GAPI.DRIVE_GET_THROW_REASONS, fileId=fileId, fields='id,name,parents,mimeType,ownedByMe,trashed,owners(emailAddress,permissionId),permissions(id,role),shortcutDetails') - entityType = _getMain()._getEntityMimeType(fileEntry) + entityType = _getEntityMimeType(fileEntry) if fileId in skipFileIdEntity['list']: entityActionNotPerformedWarning([Ent.USER, sourceUser, entityType, f'{fileEntry["name"]} ({fileId})'], Msg.IN_SKIPIDS, j, jcount) @@ -958,12 +955,12 @@ def transferOwnership(users): childEntryInfo = childEntry['info'] if includeTrashed or not childEntryInfo['trashed']: if childEntryInfo['ownedByMe']: - filesToTransfer[childFileId] = {'name': childEntryInfo['name'], 'type': _getMain()._getEntityMimeType(childEntryInfo)} + filesToTransfer[childFileId] = {'name': childEntryInfo['name'], 'type': _getEntityMimeType(childEntryInfo)} if childEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER: _identifyFilesToTransfer(childEntry) def _identifyChildrenToTransfer(fileEntry, user, i, count): - q = _getMain().WITH_PARENTS.format(fileEntry['id']) + q = WITH_PARENTS.format(fileEntry['id']) setGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, user, query=q) pageMessage = getPageMessageForWhom(clearLastGotMsgLen=False) try: @@ -986,7 +983,7 @@ def transferOwnership(users): filesTransferred.add(childFileId) if includeTrashed or not childEntryInfo['trashed']: if childEntryInfo['ownedByMe']: - filesToTransfer[childFileId] = {'name': childEntryInfo['name'], 'type': _getMain()._getEntityMimeType(childEntryInfo)} + filesToTransfer[childFileId] = {'name': childEntryInfo['name'], 'type': _getEntityMimeType(childEntryInfo)} if childEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER: _identifyChildrenToTransfer(childEntryInfo, user, i, count) @@ -1088,14 +1085,14 @@ def transferOwnership(users): break if filepath: fileTree[fileId] = {'info': fileEntryInfo} - entityType = _getMain()._getEntityMimeType(fileEntryInfo) + entityType = _getEntityMimeType(fileEntryInfo) entityPerformActionItemValue([Ent.USER, user], entityType, f'{fileEntryInfo["name"]} ({fileId})', j, jcount) if fileId in filesTransferred: continue filesTransferred.add(fileId) filesToTransfer = {} if includeTrashed or not fileEntryInfo['trashed']: - if fileEntryInfo['ownedByMe'] and fileEntryInfo['name'] != _getMain().MY_DRIVE: + if fileEntryInfo['ownedByMe'] and fileEntryInfo['name'] != MY_DRIVE: filesToTransfer[fileId] = {'name': fileEntryInfo['name'], 'type': entityType} if changeParents: filesToTransfer[fileId]['addParents'] = addParents @@ -1247,12 +1244,12 @@ def claimOwnership(users): oldOwnerPermissionIds[owner] = childEntryInfo['owners'][0]['permissionId'] filesToClaim.setdefault(owner, {}) if childFileId not in filesToClaim[owner]: - filesToClaim[owner][childFileId] = {'name': childEntryInfo['name'], 'type': _getMain()._getEntityMimeType(childEntryInfo)} + filesToClaim[owner][childFileId] = {'name': childEntryInfo['name'], 'type': _getEntityMimeType(childEntryInfo)} if childEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER: _identifyFilesToClaim(childEntry) def _identifyChildrenToClaim(fileEntry, user, i, count): - q = _getMain().WITH_PARENTS.format(fileEntry['id']) + q = WITH_PARENTS.format(fileEntry['id']) setGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, user, query=q) pageMessage = getPageMessageForWhom(clearLastGotMsgLen=False) try: @@ -1279,7 +1276,7 @@ def claimOwnership(users): oldOwnerPermissionIds[owner] = childEntryInfo['owners'][0]['permissionId'] filesToClaim.setdefault(owner, {}) if childFileId not in filesToClaim[owner]: - filesToClaim[owner][childFileId] = {'name': childEntryInfo['name'], 'type': _getMain()._getEntityMimeType(childEntryInfo)} + filesToClaim[owner][childFileId] = {'name': childEntryInfo['name'], 'type': _getEntityMimeType(childEntryInfo)} if childEntryInfo['mimeType'] == MIMETYPE_GA_FOLDER: _identifyChildrenToClaim(childEntryInfo, user, i, count) @@ -1449,7 +1446,7 @@ def claimOwnership(users): break if filepath: fileTree[fileId] = {'info': fileEntryInfo} - entityType = _getMain()._getEntityMimeType(fileEntryInfo) + entityType = _getEntityMimeType(fileEntryInfo) if fileId in skipFileIdEntity['list']: entityActionNotPerformedWarning([Ent.USER, user, entityType, f'{fileEntryInfo["name"]} ({fileId})'], Msg.IN_SKIPIDS, j, jcount) diff --git a/src/gam/cmd/gmail/delegates.py b/src/gam/cmd/gmail/delegates.py index 2394b32e..4932d0c9 100644 --- a/src/gam/cmd/gmail/delegates.py +++ b/src/gam/cmd/gmail/delegates.py @@ -5,7 +5,6 @@ Part of the _gmail_monolith sub-package.""" """GAM Gmail management: labels, messages, filters, forwarding, sendas, S/MIME, CSE, vacation.""" import re -import sys from gamlib import glaction from gamlib import glapi as API @@ -39,17 +38,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - UTF8 = 'utf-8' def sendCreateDelegateNotification(user, delegate, basenotify, i=0, count=0, msgFrom=None): @@ -90,6 +78,7 @@ def sendCreateDelegateNotification(user, delegate, basenotify, i=0, count=0, msg # ] # gam delete delegate|delegates [convertalias] def processDelegates(users): + from gam.cmd.users.manage import getNotifyArguments cd = buildGAPIObject(API.DIRECTORY) createCmd = Act.Get() != Act.DELETE aliasAllowed = not checkArgumentPresent(['convertalias']) @@ -98,7 +87,7 @@ def processDelegates(users): if createCmd: while Cmd.ArgumentsRemaining(): myarg = getArgument() - if _getMain().getNotifyArguments(myarg, notify, False): + if getNotifyArguments(myarg, notify, False): pass else: unknownArgumentExit() @@ -206,6 +195,7 @@ def updateDelegates(users): # gam print delegates|delegate [todrive *] [shownames] # gam show delegates|delegate [shownames] [csv] def printShowDelegates(users): + from gam.cmd.delegates import _getDelegateName titlesList = ['User', 'delegateAddress', 'delegationStatus'] csvPF = CSVPrintFile() if Act.csvFormat() else None cd = None @@ -249,7 +239,7 @@ def printShowDelegates(users): status = delegate['verificationStatus'] delegateEmail = delegate['delegateEmail'] if cd: - printEntity([Ent.DELEGATE, _getMain()._getDelegateName(cd, delegateEmail, delegateNames)], j, jcount) + printEntity([Ent.DELEGATE, _getDelegateName(cd, delegateEmail, delegateNames)], j, jcount) Ind.Increment() printKeyValueList(['Status', status]) printKeyValueList(['Delegate Email', delegateEmail]) diff --git a/src/gam/cmd/gmail/forms.py b/src/gam/cmd/gmail/forms.py index 7680d6ec..b150e2de 100644 --- a/src/gam/cmd/gmail/forms.py +++ b/src/gam/cmd/gmail/forms.py @@ -6,7 +6,6 @@ Part of the _gmail_monolith sub-package.""" import re import json -import sys from gamlib import glaction from gamlib import glapi as API @@ -52,17 +51,6 @@ Ind = glindent.GamIndent() Cmd = glclargs.GamCLArgs() -def _getMain(): - return sys.modules['gam'] - -def __getattr__(name): - """Fall back to gam module for any undefined names.""" - main = _getMain() - try: - return getattr(main, name) - except AttributeError: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - MIMETYPE_GA_FORM = 'application/vnd.google-apps.form' def findFormRequest(field, newRequest, ubody): @@ -118,13 +106,14 @@ def _getPublishSettings(myarg, pbody): # [drivefilename ] [] # [(csv [todrive *]) | returnidonly] def createForm(users): + from gam.cmd.drive.core import _getDriveFileParentInfo, getDriveFileParentAttribute, initDriveFileAttributes csvPF = None returnIdOnly = False title = '' body = {'mimeType': MIMETYPE_GA_FORM} ubody = {'includeFormInResponse': True, 'requests': []} pbody = _initPublishSettings() - parentParms = _getMain().initDriveFileAttributes() + parentParms = initDriveFileAttributes() while Cmd.ArgumentsRemaining(): myarg = getArgument() if myarg == 'title': @@ -141,7 +130,7 @@ def createForm(users): pass elif myarg == 'drivefilename': body['name'] = getString(Cmd.OB_DRIVE_FILE_NAME) - elif _getMain().getDriveFileParentAttribute(myarg, parentParms): + elif getDriveFileParentAttribute(myarg, parentParms): pass elif myarg == 'returnidonly': returnIdOnly = True @@ -162,7 +151,7 @@ def createForm(users): user, drive = buildGAPIServiceObject(API.DRIVE3, user, i, count) if not drive: continue - if not _getMain()._getDriveFileParentInfo(drive, user, i, count, body, parentParms): + if not _getDriveFileParentInfo(drive, user, i, count, body, parentParms): continue _, gform = buildGAPIServiceObject(API.FORMS, user, i, count) if not gform: @@ -209,9 +198,10 @@ def createForm(users): # [title ] [description ] [isquiz [Boolean>]] [] # [ispublished [] isacceptingresponses []] def updateForm(users): + from gam.cmd.drive.core import _validateUserGetFileIDs, getDriveFileEntity ubody = {'includeFormInResponse': False, 'requests': []} pbody = _initPublishSettings() - fileIdEntity = _getMain().getDriveFileEntity() + fileIdEntity = getDriveFileEntity() while Cmd.ArgumentsRemaining(): myarg = getArgument() if myarg == 'title': @@ -233,7 +223,7 @@ def updateForm(users): i, count, users = getEntityArgument(users) for user in users: i += 1 - user, _, jcount = _getMain()._validateUserGetFileIDs(user, i, count, fileIdEntity, entityType=Ent.FORM) + user, _, jcount = _validateUserGetFileIDs(user, i, count, fileIdEntity, entityType=Ent.FORM) if jcount == 0: continue _, gform = buildGAPIServiceObject(API.FORMS, user, i, count) @@ -263,9 +253,10 @@ def updateForm(users): # gam show forms # [formatjson] def printShowForms(users): + from gam.cmd.drive.core import _validateUserGetFileIDs, getDriveFileEntity csvPF = CSVPrintFile(['User', 'formId', 'name', 'title', 'description'], 'sortall') if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) - fileIdEntity = _getMain().getDriveFileEntity() + fileIdEntity = getDriveFileEntity() addCSVData = {} while Cmd.ArgumentsRemaining(): myarg = getArgument() @@ -284,7 +275,7 @@ def printShowForms(users): i, count, users = getEntityArgument(users) for user in users: i += 1 - user, _, jcount = _getMain()._validateUserGetFileIDs(user, i, count, fileIdEntity, + user, _, jcount = _validateUserGetFileIDs(user, i, count, fileIdEntity, entityType=[Ent.FORM, None][csvPF is not None or FJQC.formatJSON]) if jcount == 0: continue @@ -339,12 +330,13 @@ FORM_RESPONSE_TIME_OBJECTS = {'createTime', 'lastSubmittedTime'} # [filter (filtertime