Commit 794e5859 authored by Tres Seaver's avatar Tres Seaver

Replace bulk of uses of 'zLOG' with equivalent Python 'logging' module usage.

Exceptions:

  - 'ZServer' code which uses the 'register_subsystem' stuff.

  - Code which imports custom log levels (BLATHER, TRACE), now pulled from
    'zLOG.EventLogger'.

  - Test jigs which play with zLOG's 'write_log'.

  - Usage in 'svn:externals' modules (ZODB, etc.)
parent e5072ff7
......@@ -15,13 +15,15 @@
import os
import string
import logging
logger = logging.getLogger('Zope Security Policy')
from Acquisition import aq_base
from Acquisition import aq_parent
from Acquisition import aq_inner
from Acquisition import aq_acquire
from ExtensionClass import Base
from zLOG import LOG, BLATHER, PROBLEM
from zLOG.EventLogger import CUSTOM_BLATHER
from zope.interface import implements
# This is used when a permission maps explicitly to no permission. We
......@@ -346,8 +348,8 @@ class ZopeSecurityPolicy:
return 1
except TypeError:
# 'roles' isn't a sequence
LOG('Zope Security Policy', PROBLEM, "'%s' passed as roles"
" during validation of '%s' is not a sequence." % (
logger.warn("'%s' passed as roles"
" during validation of '%s' is not a sequence." % (
`roles`, name))
raise
......@@ -804,7 +806,7 @@ def raiseVerbose(msg, accessed, container, name, value, context,
info.append(s + '.')
text = ' '.join(info)
LOG('Zope Security Policy', BLATHER, 'Unauthorized: %s' % text)
logger.log(CUSTOM_BLATHER, 'Unauthorized: %s' % text)
raise Unauthorized(text)
def getUserRolesInContext(user, context):
......
......@@ -39,12 +39,12 @@
"""
import sys
import logging
logger = logging.getLogger('SecurityInfo')
import Acquisition
from AccessControl.ImplPython import _what_not_even_god_should_do
from zLOG import LOG, WARNING
# Security constants - these are imported into the AccessControl
# namespace and can be referenced as AccessControl.PUBLIC etc.
......@@ -69,8 +69,8 @@ class SecurityInfo(Acquisition.Implicit):
def _setaccess(self, names, access):
for name in names:
if self.names.get(name, access) != access:
LOG('SecurityInfo', WARNING, 'Conflicting security '
'declarations for "%s"' % name)
logger.warn('Conflicting security declarations for "%s"'
% name)
self._warnings = 1
self.names[name] = access
......@@ -111,8 +111,8 @@ class SecurityInfo(Acquisition.Implicit):
for role in roles:
rdict[role] = 1
if self.roles.get(permission_name, rdict) != rdict:
LOG('SecurityInfo', WARNING, 'Conflicting default role'
'declarations for permission "%s"' % permission_name)
logger.warn('Conflicting default role '
'declarations for permission "%s"' % permission_name)
self._warnings = 1
self.roles[permission_name] = rdict
......@@ -193,8 +193,8 @@ class ClassSecurityInfo(SecurityInfo):
access)
if getattr(self, '_warnings', None):
LOG('SecurityInfo', WARNING, 'Class "%s" had conflicting '
'security declarations' % classobj.__name__)
logger.warn('Class "%s" had conflicting security declarations'
% classobj.__name__)
class ClassSecurityInformation(ClassSecurityInfo):
# Default policy is disallow
......@@ -273,8 +273,8 @@ class _ModuleSecurityInfo(SecurityInfo):
dict['__allow_access_to_unprotected_subobjects__'] = self
if getattr(self, '_warnings', None):
LOG('SecurityInfo', WARNING, 'Module "%s" had conflicting '
'security declarations' % dict['__name__'])
logger.warn('Module "%s" had conflicting security declarations'
% dict['__name__'])
declareProtected__roles__=ACCESS_PRIVATE
def declareProtected(self, permission_name, *names):
......
......@@ -15,6 +15,9 @@ __doc__="""System management components"""
__version__='$Revision: 1.94 $'[11:-2]
import sys,os,time,Globals, Acquisition, os, Undo
import logging
logger = logging.getLogger('ApplicationManager')
from Globals import DTMLFile
from OFS.ObjectManager import ObjectManager
from OFS.Folder import Folder
......@@ -31,7 +34,6 @@ from AccessControl import getSecurityManager
from zExceptions import Redirect
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from cgi import escape
import zLOG
import Lifetime
try: import thread
......@@ -391,8 +393,7 @@ class ApplicationManager(Folder,CacheManager):
user = '"%s"' % getSecurityManager().getUser().getUserName()
except:
user = 'unknown user'
zLOG.LOG("ApplicationManager", zLOG.INFO,
"Restart requested by %s" % user)
logger.info("Restart requested by %s" % user)
#for db in Globals.opened: db.close()
Lifetime.shutdown(1)
return """<html>
......@@ -407,8 +408,7 @@ class ApplicationManager(Folder,CacheManager):
user = '"%s"' % getSecurityManager().getUser().getUserName()
except:
user = 'unknown user'
zLOG.LOG("ApplicationManager", zLOG.INFO,
"Shutdown requested by %s" % user)
logger.info("Shutdown requested by %s" % user)
#for db in Globals.opened: db.close()
Lifetime.shutdown(0)
return """<html>
......
......@@ -11,8 +11,10 @@
#
##############################################################################
import logging
logger = logging.getLogger('Hotfixes')
from version_txt import getZopeVersion
from zLOG import LOG, INFO, WARNING
merged_hotfixes = {
'Hotfix_2001-09-28': 1,
......@@ -33,13 +35,13 @@ def isMerged(name):
def logHotfix(id, apply_hotfix):
if apply_hotfix:
LOG('Hotfixes', INFO, 'Applying %s' % id)
logger.info('Applying %s' % id)
elif apply_hotfix is OUTDATED_ZOPE:
LOG('Hotfixes', WARNING, 'Not applying %s. It is not designed for '
logger.warn('Not applying %s. It is not designed for '
'this version of Zope. Please uninstall the hotfix product.'
% id)
else: # ALREADY_MERGED
LOG('Hotfixes', WARNING, 'Not applying %s. The fix has already been '
logger.warn('Not applying %s. The fix has already been '
'merged into Zope. Please uninstall the hotfix product.'
% id)
......
......@@ -17,6 +17,8 @@ $Id$
import os.path, re
import stat
import logging
logger = logging.getLogger('Zope')
from AccessControl.PermissionRole import PermissionRole
import Globals, os, OFS.ObjectManager, OFS.misc_, Products
......@@ -25,7 +27,6 @@ from App.Product import doInstall
from HelpSys import HelpTopic, APIHelpTopic
from HelpSys.HelpSys import ProductHelp
from FactoryDispatcher import FactoryDispatcher
from zLOG import LOG, WARNING
from DateTime import DateTime
from Interface.Implements import instancesOfObjectImplements
from zope.interface import implementedBy
......@@ -312,7 +313,7 @@ class ProductContext:
try:
dir_mod_time=DateTime(os.stat(path)[stat.ST_MTIME])
except OSError, (errno, text):
LOG("Zope", WARNING, '%s: %s' % (text, path))
logger.warn('%s: %s' % (text, path))
return
# test to see if nothing has changed since last registration
......
......@@ -17,11 +17,14 @@ $Id$
import os, sys
from time import time
from traceback import format_exception
import logging
logger = logging.getLogger('Refresh')
import transaction
import Products
from ExtensionClass import Base
from Globals import PersistentMapping
from zLOG import format_exception, LOG, ERROR, INFO
global_classes_timestamp = 0
products_mod_times = {}
......@@ -136,8 +139,8 @@ def listRefreshableModules(productid):
def logBadRefresh(productid):
exc = sys.exc_info()
try:
LOG('Refresh', ERROR, 'Exception while refreshing %s'
% productid, error=exc)
logger.error('Exception while refreshing %s'
% productid, error=exc)
if hasattr(exc[0], '__name__'):
error_type = exc[0].__name__
else:
......@@ -179,7 +182,7 @@ def performRefresh(jar, productid):
def performSafeRefresh(jar, productid):
try:
LOG('Refresh', INFO, 'Refreshing product %s' % productid)
logger.info('Refreshing product %s' % productid)
if not performRefresh(jar, productid):
return 0
except:
......
......@@ -10,10 +10,11 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
from types import InstanceType
import logging
logger = logging.getLogger('ZPublisher')
import DocumentTemplate, Common, Persistence, MethodObject, Globals, os, sys
from types import InstanceType
from zLOG import LOG,WARNING
from App.config import getConfiguration
class HTML(DocumentTemplate.HTML,Persistence.Persistent,):
......@@ -175,8 +176,10 @@ class DTMLFile(Bindings, Explicit, ClassicHTMLFile):
try: result = render_blocks(self._v_blocks, ns)
except DTReturn, v: result = v.v
except AttributeError:
if type(sys.exc_value)==InstanceType and sys.exc_value.args[0]=="_v_blocks":
LOG("ZPublisher",WARNING,"DTML file '%s' could not be read" % self.raw)
if (type(sys.exc_value) == InstanceType
and sys.exc_value.args[0]=="_v_blocks"):
logger.warn("DTML file '%s' could not be read"
% self.raw)
raise ValueError, ("DTML file error: "
"Check logfile for details")
else:
......
......@@ -15,10 +15,12 @@
$Id$
"""
import time, sys
import logging
logger = logging.getLogger('Cache')
import Globals
from Globals import DTMLFile
from Acquisition import aq_get, aq_acquire, aq_inner, aq_parent, aq_base
from zLOG import LOG, WARNING
from AccessControl import getSecurityManager
from AccessControl.Role import _isBeingUsedAsAMethod
from AccessControl import Unauthorized
......@@ -195,8 +197,7 @@ class Cacheable:
mtime_func, default)
return val
except:
LOG('Cache', WARNING, 'ZCache_get() exception',
error=sys.exc_info())
logger.warn('ZCache_get() exception', error=sys.exc_info())
return default
return default
......@@ -213,8 +214,7 @@ class Cacheable:
c.ZCache_set(ob, data, view_name, keywords,
mtime_func)
except:
LOG('Cache', WARNING, 'ZCache_set() exception',
error=sys.exc_info())
logger.warn('ZCache_set() exception', error=sys.exc_info())
def ZCacheable_invalidate(self, view_name='', REQUEST=None):
'''Called after a cacheable object is edited. Causes all
......@@ -231,8 +231,7 @@ class Cacheable:
except:
exc = sys.exc_info()
try:
LOG('Cache', WARNING, 'ZCache_invalidate() exception',
error=exc)
logger.warn('ZCache_invalidate() exception', error=exc)
message = 'An exception occurred: %s: %s' % exc[:2]
finally:
exc = None
......
......@@ -20,6 +20,8 @@ import marshal
import sys, fnmatch, copy, os, re
from cgi import escape
from cStringIO import StringIO
import logging
logger = logging.getLogger('FTP')
from types import StringType, UnicodeType
import App.Common
......@@ -36,7 +38,6 @@ from webdav.Collection import Collection
from webdav.Lockable import ResourceLockedError
from webdav.NullResource import NullResource
from zExceptions import BadRequest
from zLOG import LOG, ERROR
from ZODB.POSException import ConflictError
from zope.interface import implements
......@@ -673,8 +674,8 @@ class ObjectManager(
try:
stat=marshal.loads(v.manage_FTPstat(REQUEST))
except:
LOG("FTP", ERROR, "Failed to stat file '%s'" % k,
error=sys.exc_info())
logger.error("Failed to stat file '%s'" % k,
error=sys.exc_info())
stat=None
if stat is not None:
out=out+((k,stat),)
......
......@@ -13,11 +13,13 @@
"""
Objects for packages that have been uninstalled.
"""
import SimpleItem, Globals, Acquisition
from thread import allocate_lock
import logging
logger = logging.getLogger('ZODB') # ???
import SimpleItem, Globals, Acquisition
from Acquisition import Acquired
import Persistence
from thread import allocate_lock
from zLOG import LOG, WARNING
from cgi import escape
broken_klasses={}
......@@ -71,8 +73,9 @@ def Broken(self, oid, pair):
klass.info=(
'This object\'s class was %s in module %s.' %
(klass.__name__, klass.__module__))
LOG('ZODB', WARNING, 'Could not import class %s '
'from module %s' % (`klass.__name__`, `klass.__module__`))
logger.warn('Could not import class %s '
'from module %s'
% (`klass.__name__`, `klass.__module__`))
finally:
broken_klasses_lock.release()
if oid is None: return klass
......
......@@ -20,7 +20,6 @@ __version__='$Revision: 1.48 $'[11:-2]
import os, AccessControl, Acquisition, sys, types
from types import StringType
from Globals import DTMLFile, ImageFile, MessageDialog, package_home
from zLOG import LOG, ERROR, INFO
from OFS.SimpleItem import SimpleItem
from DateTime.DateTime import DateTime
from Shared.DC.Scripts.Script import Script, BindingsUI
......
......@@ -18,6 +18,8 @@ $Id$
import time
from datetime import date, datetime
from datetime import tzinfo, timedelta
import logging
logger = logging.getLogger('UnIndex')
from types import StringType, FloatType, IntType
import BTrees.Length
......@@ -28,7 +30,6 @@ from DateTime.DateTime import DateTime
from Globals import DTMLFile
from OFS.PropertyManager import PropertyManager
from ZODB.POSException import ConflictError
from zLOG import LOG, ERROR
from zope.interface import implements
from Products.PluginIndexes.common import safe_callable
......@@ -144,7 +145,7 @@ class DateIndex(UnIndex, PropertyManager):
except ConflictError:
raise
except:
LOG('UnIndex', ERROR,
logger.error(
("Should not happen: ConvertedDate was there,"
" now it's not, for document with id %s" %
documentId))
......
......@@ -18,10 +18,11 @@ $Id$
import operator, warnings
import re
from cgi import escape
import logging
logger = logging.getLogger('TextIndex')
from types import *
from Globals import Persistent, DTMLFile
from zLOG import LOG, ERROR
from Acquisition import Implicit
from OFS.SimpleItem import SimpleItem
from BTrees.IOBTree import IOBTree
......@@ -376,9 +377,8 @@ class TextIndex(Persistent, Implicit, SimpleItem):
for wid in wids:
widScores = get(wid, None)
if widScores is None:
LOG('TextIndex', ERROR,
'unindex_object tried to unindex nonexistent'
' document, wid %s, %s' % (i,wid))
logger.error('unindex_object tried to unindex nonexistent'
' document, wid %s, %s' % (i,wid))
continue
if type(widScores) is TupleType:
del index[wid]
......@@ -394,9 +394,8 @@ class TextIndex(Persistent, Implicit, SimpleItem):
else:
del index[wid]
except (KeyError, IndexError, TypeError):
LOG('TextIndex', ERROR,
'unindex_object tried to unindex nonexistent'
' document %s' % str(i))
logger.error('unindex_object tried to unindex nonexistent'
' document %s' % str(i))
def __getitem__(self, word):
"""Return an InvertedIndex-style result "list"
......
......@@ -12,6 +12,9 @@
############################################################################
import re, time, sys
import logging
logger = logging.getLogger('Session Tracking')
import Globals
from OFS.SimpleItem import Item
from Acquisition import Implicit, Explicit, aq_base
......@@ -19,7 +22,7 @@ from Persistence import Persistent
from AccessControl.Owned import Owned
from AccessControl.Role import RoleManager
from App.Management import Tabs
from zLOG import LOG, WARNING, BLATHER
from zLOG.EventLogger import CUSTOM_BLATHER
from AccessControl import ClassSecurityInfo
import SessionInterfaces
from SessionPermissions import *
......@@ -205,7 +208,7 @@ class SessionDataManager(Item, Implicit, Persistent, RoleManager, Owned, Tabs):
transactions for mounted storages. """
if self.obpath is None:
err = 'Session data container is unspecified in %s' % self.getId()
LOG('Session Tracking', WARNING, err)
logger.warn(err)
raise SessionIdManagerErr, err
try:
# This should arguably use restrictedTraverse, but it
......@@ -215,7 +218,7 @@ class SessionDataManager(Item, Implicit, Persistent, RoleManager, Owned, Tabs):
# hasattr hides conflicts
if DEBUG and not getattr(self, '_v_wrote_dc_type', None):
args = '/'.join(self.obpath)
LOG('Session Tracking', BLATHER,
logger.log(CUSTOM_BLATHER,
'External data container at %s in use' % args)
self._v_wrote_dc_type = 1
return self.unrestrictedTraverse(self.obpath)
......@@ -281,7 +284,7 @@ class SessionDataManagerTraverser(Persistent):
getSessionData = sdm.getSessionData
except:
msg = 'Session automatic traversal failed to get session data'
LOG('Session Tracking', WARNING, msg, error=sys.exc_info())
logger.warn(msg, error=sys.exc_info())
return
# set the getSessionData method in the "lazy" namespace
......
......@@ -41,7 +41,7 @@ from OFS.Application import Application
from OFS.Folder import Folder
import sys
import traceback
from zLOG import log_time
from zLOG.EventLogger import log_time
sys.setcheckinterval(200)
from Products.Transience.tests import fauxtime
......
......@@ -15,7 +15,7 @@ $Id$
"""
import time, sys
from zLOG import LOG, INFO
import logging
from DateTime.DateTime import DateTime
......@@ -92,7 +92,8 @@ class ZLogHandler(StdoutHandler):
__implements__ = IProgressHandler
def output(self, text):
LOG(self._ident, INFO, text)
logger = logging.getLogger(self._ident)
logger.info(text)
class FilelogHandler(StdoutHandler):
......
......@@ -37,7 +37,6 @@ from Products.PluginIndexes.common.PluggableIndex \
import PluggableIndexInterface
from Products.PluginIndexes.interfaces import IPluggableIndex
from Products.PluginIndexes.TextIndex import Splitter
from zLOG import LOG
from zope.interface import implements
from Catalog import Catalog, CatalogError
......@@ -47,7 +46,7 @@ from ProgressHandler import ZLogHandler
from ZCatalogIndexes import ZCatalogIndexes
LOG = logging.getLogger('Zope.ZCatalog')
logger = logging.getLogger('Zope.ZCatalog')
manage_addZCatalogForm=DTMLFile('dtml/addZCatalog',globals())
......@@ -304,8 +303,8 @@ class ZCatalog(Folder, Persistent, Implicit):
except ConflictError:
raise
except:
LOG.error('Recataloging object at %s failed' % p,
exc_info=sys.exc_info())
logger.error('Recataloging object at %s failed' % p,
exc_info=sys.exc_info())
if pghandler: pghandler.finish()
......@@ -494,8 +493,8 @@ class ZCatalog(Folder, Persistent, Implicit):
if obj is None:
obj = self.resolve_url(p, REQUEST)
if obj is None:
LOG.error('reindexIndex could not resolve '
'an object from the uid %r.' % p)
logger.error('reindexIndex could not resolve '
'an object from the uid %r.' % p)
else:
# don't update metadata when only reindexing a single
# index via the UI
......@@ -924,7 +923,7 @@ class ZCatalog(Folder, Persistent, Implicit):
classes.
"""
LOG.info('Start migration of indexes for %s' % self.absolute_url(1))
logger.info('Start migration of indexes for %s' % self.absolute_url(1))
for idx in self.Indexes.objectValues():
bases = [str(name) for name in idx.__class__.__bases__]
......@@ -941,7 +940,7 @@ class ZCatalog(Folder, Persistent, Implicit):
if found:
idx_type = idx.meta_type
idx_id = idx.getId()
LOG.info('processing index %s' % idx_id)
logger.info('processing index %s' % idx_id)
indexed_attrs = getattr(idx, 'indexed_attrs', None)
......@@ -963,7 +962,8 @@ class ZCatalog(Folder, Persistent, Implicit):
self.manage_reindexIndex(idx_id, REQUEST)
self._migrated_280 = True
LOG.info('Finished migration of indexes for %s' % self.absolute_url(1))
logger.info('Finished migration of indexes for %s'
% self.absolute_url(1))
if RESPONSE:
RESPONSE.redirect( URL1 +
......
......@@ -15,6 +15,9 @@ __doc__='''Generic Database Connection Support
$Id$'''
__version__='$Revision: 1.39 $'[11:-2]
import logging
logger = logging.getLogger('Shared.DC.ZRDB.Connection')
import Globals, OFS.SimpleItem, AccessControl.Role, Acquisition, sys
from DateTime import DateTime
from App.Dialogs import MessageDialog
......@@ -24,7 +27,6 @@ from Aqueduct import custom_default_report
from cStringIO import StringIO
from Results import Results
from sys import exc_info
from zLOG import LOG, ERROR
from cgi import escape
import DocumentTemplate, RDB
from zExceptions import BadRequest
......@@ -68,10 +70,8 @@ class Connection(
if self.connection_string:
try: self.connect(self.connection_string)
except:
LOG('Shared.DC.ZRDB.Connection',
ERROR,
'Error connecting to relational database.',
error=exc_info())
logger.error('Error connecting to relational database.',
error=exc_info())
def title_and_id(self):
s=Connection.inheritedAttribute('title_and_id')(self)
......@@ -150,10 +150,8 @@ class Connection(
if hasattr(self,'_v_database_connection'):
self._v_database_connection.close()
except:
LOG('Shared.DC.ZRDB.Connection',
ERROR,
'Error closing relational database connection.',
error=exc_info())
logger.error('Error closing relational database connection.',
error=exc_info())
self._v_connected=''
if REQUEST is not None:
return self.manage_main(self, REQUEST)
......
......@@ -16,9 +16,8 @@ Generic expat-based XML parser base class.
"""
import xml.parsers.expat
import zLOG
import logging
logger = logging.getLogger('TAL.XMLParser')
XMLParseError = xml.parsers.expat.ExpatError
......@@ -56,8 +55,7 @@ class XMLParser:
try:
self.parser.ordered_attributes = self.ordered_attributes
except AttributeError:
zLOG.LOG("TAL.XMLParser", zLOG.INFO,
"Can't set ordered_attributes")
logger.info("Can't set ordered_attributes")
self.ordered_attributes = 0
for name in self.handler_names:
method = getattr(self, name, None)
......@@ -65,8 +63,7 @@ class XMLParser:
try:
setattr(p, name, method)
except AttributeError:
zLOG.LOG("TAL.XMLParser", zLOG.PROBLEM,
"Can't set expat handler %s" % name)
logger.warn("Can't set expat handler %s" % name)
def createParser(self, encoding=None):
return xml.parsers.expat.ParserCreate(encoding, ' ')
......
......@@ -13,9 +13,9 @@
__version__='$Revision: 1.12 $'[11:-2]
"""BeforeTraverse interface and helper classes"""
import logging
from Acquisition import aq_base
from zLOG import LOG, ERROR
import sys
# Interface
......@@ -86,6 +86,7 @@ class MultiHook:
MultiHook calls the named hook from the class of the container, then
the prior hook, then all the hooks in its list.
"""
logger = logging.getLogger('MultiHook')
def __init__(self, hookname, prior, defined_in_class):
self._hookname = hookname
self._prior = prior
......@@ -103,7 +104,7 @@ class MultiHook:
try:
cob(container, request)
except TypeError:
LOG('MultiHook', ERROR, '%s call %s failed.' % (
self.logger.error('%s call %s failed.' % (
`self._hookname`, `cob`), error=sys.exc_info())
def add(self, cob):
......@@ -120,6 +121,7 @@ class NameCaller:
>>> registerBeforeTraverse(folder, NameCaller('preop'), 'XApp')
"""
logger = logging.getLogger('BeforeTraverse')
def __init__(self, name):
self.name = name
......@@ -149,8 +151,6 @@ class NameCaller:
# Only catch exceptions that are likely to be logic errors.
# We shouldn't catch Redirects, Unauthorizeds, etc. since
# the programmer may want to raise them deliberately.
from zLOG import LOG, ERROR
import sys
LOG('BeforeTraverse', ERROR,
'Error while invoking hook: "%s"' % self.name, error=
sys.exc_info())
self.logger.error('Error while invoking hook: "%s"'
% self.name, error=sys.exc_info())
......@@ -21,8 +21,10 @@ $Id$
"""
__version__ ='$Revision: 1.1.2.2 $'[11:-2]
import logging
logger = logging.getLogger('TemporaryStorage')
from zLOG import LOG, BLATHER
from zLOG.EventLogger import CUSTOM_BLATHER
from ZODB.serialize import referencesf
from ZODB import POSException
from ZODB.BaseStorage import BaseStorage
......@@ -182,7 +184,7 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
if version:
# we allow a version to be in use although we don't
# support versions in the storage.
LOG('TemporaryStorage', BLATHER,
logging.log(CUSTOM_BLATHER,
('versions in use with TemporaryStorage although Temporary'
'Storage doesnt support versions'),
)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment