@@ -211,7 +211,7 @@ def format_exception(exc_type, exc, tb, limit=None, chain=True,
211211 message = str (server_error ['arguments' ][0 ])
212212 except Exception :
213213 message = str (server_error ['arguments' ])
214- fault = '%s: %s' % ( server_error ['name' ], message )
214+ fault = f" { server_error ['name' ]} : { message } "
215215 exc_type = server_error .get ('exception_type' , 'internal_error' )
216216 if exc_type != 'internal_error' or message .startswith ('FATAL:' ):
217217 server_tb = None
@@ -247,7 +247,7 @@ def read_config(section=None):
247247 server = shlex .split (env .get ('options' , '' ))
248248 else :
249249 protocol = env .get ('protocol' , 'xmlrpc' )
250- server = '%s ://%s:%s/%s' % ( scheme , env ['host' ], env ['port' ], protocol )
250+ server = f" { scheme } ://{ env ['host' ]} : { env ['port' ]} / { protocol } "
251251 return (server , env ['database' ], env ['username' ], env .get ('password' ))
252252
253253
@@ -320,7 +320,7 @@ def searchargs(params, kwargs=None):
320320 if isinstance (term , str ) and term not in DOMAIN_OPERATORS :
321321 m = _term_re .match (term .strip ())
322322 if not m :
323- raise ValueError (' Cannot parse term %r' % term )
323+ raise ValueError (f" Cannot parse term { term !r } " )
324324 (field , operator , value ) = m .groups ()
325325 try :
326326 value = literal_eval (value )
@@ -366,7 +366,7 @@ def dispatch_jsonrpc(url, service_name, method, args):
366366 'jsonrpc' : '2.0' ,
367367 'method' : 'call' ,
368368 'params' : {'service' : service_name , 'method' : method , 'args' : args },
369- 'id' : '%04x%010x' % ( os .getpid (), ( int (time .time () * 1E6 ) % 2 ** 40 )) ,
369+ 'id' : f" { os .getpid ():04x } { int (time .time () * 1E6 ) % 2 ** 40 :010x } " ,
370370 }
371371 resp = http_post (url , json .dumps (data ).encode ('ascii' ))
372372 if resp .get ('error' ):
@@ -379,7 +379,7 @@ class partial(functools.partial):
379379
380380 def __repr__ (self ):
381381 # Hide arguments
382- return '%s(%r, ...)' % ( self .__class__ .__name__ , self .func )
382+ return f" { self .__class__ .__name__ } ( { self .func !r } , ...)"
383383
384384
385385class Error (Exception ):
@@ -411,15 +411,15 @@ def __init__(self, client, endpoint, methods, verbose=False):
411411 self ._verbose = verbose
412412
413413 def __repr__ (self ):
414- return "<Service '%s|%s'>" % ( self ._rpcpath , self ._endpoint )
414+ return f "<Service '{ self ._rpcpath } | { self ._endpoint } '>"
415415 __str__ = __repr__
416416
417417 def __dir__ (self ):
418418 return sorted (self ._methods )
419419
420420 def __getattr__ (self , name ):
421421 if name not in self ._methods :
422- raise AttributeError ("'Service' object has no attribute %r" % name )
422+ raise AttributeError (f "'Service' object has no attribute { name !r } " )
423423 if self ._verbose :
424424 def sanitize (args ):
425425 if self ._endpoint != 'db' and len (args ) > 2 :
@@ -430,17 +430,17 @@ def sanitize(args):
430430
431431 def wrapper (self , * args ):
432432 snt = ', ' .join ([repr (arg ) for arg in sanitize (args )])
433- snt = '%s.%s(%s)' % ( self ._endpoint , name , snt )
433+ snt = f" { self ._endpoint } . { name } ( { snt } )"
434434 if len (snt ) > maxcol :
435- suffix = ' ... L=%s' % len (snt )
435+ suffix = f" ... L={ len (snt )} "
436436 snt = snt [:maxcol - len (suffix )] + suffix
437- print (' --> ' + snt )
437+ print (f" --> { snt } " )
438438 res = self ._dispatch (name , args )
439439 rcv = str (res )
440440 if len (rcv ) > maxcol :
441- suffix = ' ... L=%s' % len (rcv )
441+ suffix = f" ... L={ len (rcv )} "
442442 rcv = rcv [:maxcol - len (suffix )] + suffix
443- print (' <-- ' + rcv )
443+ print (f" <-- { rcv } " )
444444 return res
445445 else :
446446 wrapper = lambda s , * args : s ._dispatch (name , args )
@@ -497,8 +497,7 @@ def __bool__(self):
497497 __hash__ = object .__hash__
498498
499499 def __repr__ (self ):
500- return "<Env '%s@%s'>" % (self .user .login if self .uid else '' ,
501- self .db_name )
500+ return f"<Env '{ self .user .login if self .uid else '' } @{ self .db_name } '>"
502501
503502 def check_uid (self , uid , password ):
504503 """Check if ``(uid, password)`` is valid.
@@ -541,10 +540,10 @@ def _auth(self, user, password):
541540 if not password and uid is not False :
542541 from getpass import getpass
543542 if user is None :
544- name = 'admin' if uid == SUPERUSER_ID else ( 'UID %d' % uid )
543+ name = 'admin' if uid == SUPERUSER_ID else f 'UID { uid } '
545544 else :
546545 name = user
547- password = getpass (' Password for %r: ' % name )
546+ password = getpass (f" Password for { name !r } : " )
548547 # Check if password is valid
549548 uid = self .check_uid (uid , password ) if (uid and not verified ) else uid
550549 if uid is None :
@@ -784,7 +783,7 @@ def _get(self, name, check=True):
784783 if model_names :
785784 errmsg = 'Model not found. These models exist:'
786785 else :
787- errmsg = 'Model not found: %s' % ( name ,)
786+ errmsg = f 'Model not found: { name } '
788787 raise Error ('\n * ' .join ([errmsg ] + model_names ))
789788
790789 def modules (self , name = '' , installed = None ):
@@ -820,23 +819,23 @@ def _upgrade(self, modules, button):
820819 ir_module = self ._get ('ir.module.module' , False )
821820 updated , added = ir_module .update_list ()
822821 if added :
823- print ('%s module(s) added to the list' % added )
822+ print (f' { added } module(s) added to the list' )
824823 # Find modules
825824 sel = modules and ir_module .search ([('name' , 'in' , modules )])
826825 mods = ir_module .read ([_pending_state ], 'name state' )
827826 if sel :
828827 # Safety check
829828 if any (mod ['name' ] not in modules for mod in mods ):
830829 raise Error ('Pending actions:\n ' + '\n ' .join (
831- ( ' %( state)s \t %( name)s' % mod ) for mod in mods ))
830+ f" { mod [ ' state' ] } \t { mod [ ' name' ] } " for mod in mods ))
832831 if button == 'button_uninstall' :
833832 # Safety check
834833 names = ir_module .read ([('id' , 'in' , sel .ids ),
835834 'state != installed' ,
836835 'state != to upgrade' ,
837836 'state != to remove' ], 'name' )
838837 if names :
839- raise Error (' Not installed: %s' % ' , ' .join (names ))
838+ raise Error (f" Not installed: { ' , ' .join (names )} " )
840839 if self .client .version_info < 7.0 :
841840 # A trick to uninstall dependent add-ons
842841 sel .write ({'state' : 'to remove' })
@@ -849,13 +848,13 @@ def _upgrade(self, modules, button):
849848 print ('Already up-to-date: %s' %
850849 self .modules ([('id' , 'in' , sel .ids )]))
851850 elif modules :
852- raise Error (' Module(s) not found: %s' % ' , ' .join (modules ))
853- print ('%s module(s) updated' % updated )
851+ raise Error (f" Module(s) not found: { ' , ' .join (modules )} " )
852+ print (f' { updated } module(s) updated' )
854853 return
855- print ('%s module(s) selected' % len ( sel ) )
856- print ('%s module(s) to process:' % len ( mods ) )
854+ print (f' { len ( sel ) } module(s) selected' )
855+ print (f' { len ( mods ) } module(s) to process:' )
857856 for mod in mods :
858- print (' %( state)s \t %( name)s' % mod )
857+ print (f" { mod [ ' state' ] } \t { mod [ ' name' ] } " )
859858
860859 # Empty the cache for this database
861860 self .refresh ()
@@ -943,7 +942,7 @@ def get_service(name):
943942 self .server_version = ver = get_service ('db' ).server_version ()
944943 self .major_version = re .search (r'\d+\.?\d*' , ver ).group ()
945944 self .version_info = float_version = float (self .major_version )
946- assert float_version > 6.0 , 'Not supported: %s' % ver
945+ assert float_version > 6.0 , f 'Not supported: { ver } '
947946 # Create the RPC services
948947 self .db = get_service ('db' )
949948 self .common = get_service ('common' )
@@ -983,7 +982,7 @@ def from_config(cls, environment, user=None, verbose=False):
983982 return client
984983
985984 def __repr__ (self ):
986- return "<Client '%s#%s'>" % ( self ._server , self .env .db_name )
985+ return f "<Client '{ self ._server } # { self .env .db_name } '>"
987986
988987 def close (self ):
989988 for conn in self ._connections :
@@ -1026,7 +1025,7 @@ def login(self, user, password=None, database=None):
10261025 try :
10271026 self ._login (user , password = password , database = database )
10281027 except Error as exc :
1029- print ('%s: %s' % ( exc .__class__ .__name__ , exc ) )
1028+ print (f" { exc .__class__ .__name__ } : { exc } " )
10301029 else :
10311030 # Register the new globals()
10321031 self .connect ()
@@ -1043,11 +1042,11 @@ def connect(self, env_name=None):
10431042 self ._globals ['env' ] = client .env
10441043 self ._globals ['self' ] = client .env .user if client .env .uid else None
10451044 # Tweak prompt
1046- sys .ps1 = '%s >>> ' % ( env_name ,)
1045+ sys .ps1 = f' { env_name } >>> '
10471046 sys .ps2 = '... ' .rjust (len (sys .ps1 ))
10481047 # Logged in?
10491048 if client .env .uid :
1050- print ('Logged in as %r' % ( client .env .user .login ,) )
1049+ print (f 'Logged in as { client .env .user .login !r } ' )
10511050
10521051 @classmethod
10531052 def _set_interactive (cls , global_vars = {}):
@@ -1138,7 +1137,7 @@ def _new(cls, env, name):
11381137 return m
11391138
11401139 def __repr__ (self ):
1141- return "<Model '%s'>" % ( self ._name ,)
1140+ return f "<Model '{ self ._name } '>"
11421141
11431142 def keys (self ):
11441143 """Return the keys of the model."""
@@ -1220,12 +1219,12 @@ def get(self, domain, *args, **kwargs):
12201219 rec = self .env .ref (domain )
12211220 if not rec :
12221221 return None
1223- assert rec ._model is self , 'Model mismatch %r %r' % ( rec , self )
1222+ assert rec ._model is self , f 'Model mismatch { rec !r } { self !r } '
12241223 return rec
12251224 assert issearchdomain (domain ) # a search domain
12261225 ids = self ._execute ('search' , domain )
12271226 if len (ids ) > 1 :
1228- raise ValueError ('domain matches too many records (%d)' % len (ids ))
1227+ raise ValueError (f 'domain matches too many records ({ len (ids )} )' )
12291228 return Record (self , ids [0 ]) if ids else None
12301229
12311230 def create (self , values ):
@@ -1327,7 +1326,7 @@ def _unbrowse_values(self, values):
13271326 field_type = self ._fields [key ]['type' ]
13281327 if hasattr (value , 'id' ):
13291328 if field_type == 'reference' :
1330- new_values [key ] = '%s,%s' % ( value ._name , value .id )
1329+ new_values [key ] = f' { value ._name } , { value .id } '
13311330 else :
13321331 new_values [key ] = value = value .id
13331332 if field_type in ('one2many' , 'many2many' ):
@@ -1350,7 +1349,7 @@ def _get_external_ids(self, ids=None):
13501349 ['module' , 'name' , 'res_id' ])
13511350 res = {}
13521351 for rec in existing :
1353- res ['%( module)s.%( name)s' % rec ] = self .get (rec ['res_id' ])
1352+ res [f" { rec [ ' module' ] } . { rec [ ' name' ] } " ] = self .get (rec ['res_id' ])
13541353 return res
13551354
13561355 def __getattr__ (self , attr ):
@@ -1363,7 +1362,7 @@ def __getattr__(self, attr):
13631362 if attr == '_keys' :
13641363 return _memoize (self , attr , sorted (self ._fields ))
13651364 if attr .startswith ('_' ):
1366- raise AttributeError ("'Model' object has no attribute %r" % attr )
1365+ raise AttributeError (f "'Model' object has no attribute { attr !r } " )
13671366
13681367 def wrapper (self , * params , ** kwargs ):
13691368 """Wrapper for client.execute(%r, %r, *params, **kwargs)."""
@@ -1412,11 +1411,10 @@ def __new__(cls, res_model, arg):
14121411
14131412 def __repr__ (self ):
14141413 if len (self .ids ) > 16 :
1415- ids = 'length=%d' % len (self .ids )
1414+ ids = f 'length={ len (self .ids )} '
14161415 else :
14171416 ids = self .id
1418- return "<%s '%s,%s'>" % (self .__class__ .__name__ ,
1419- self ._name , ids )
1417+ return f"<{ self .__class__ .__name__ } '{ self ._name } ,{ ids } '>"
14201418
14211419 def __dir__ (self ):
14221420 attrs = set (self .__dict__ ) | set (self ._model ._keys )
@@ -1511,7 +1509,7 @@ def ensure_one(self):
15111509 recs = self .union ()
15121510 if len (recs .id ) == 1 :
15131511 return recs [0 ]
1514- raise ValueError ("Expected singleton: %s" % self )
1512+ raise ValueError (f "Expected singleton: { self } " )
15151513
15161514 def exists (self ):
15171515 """Return a subset of records that exist."""
@@ -1720,7 +1718,7 @@ def __getattr__(self, attr):
17201718 if attr in self ._model ._keys :
17211719 return self .read (attr )
17221720 if attr .startswith ('_' ):
1723- errmsg = "'RecordList' object has no attribute %r" % attr
1721+ errmsg = f "'RecordList' object has no attribute { attr !r } "
17241722 raise AttributeError (errmsg )
17251723
17261724 def wrapper (self , * params , ** kwargs ):
@@ -1730,10 +1728,10 @@ def wrapper(self, *params, **kwargs):
17301728
17311729 def __setattr__ (self , attr , value ):
17321730 if attr in self ._model ._keys or attr == 'id' :
1733- msg = "attribute %r is read-only; use 'RecordList.write' instead."
1731+ msg = f "attribute { attr !r } is read-only; use 'RecordList.write' instead."
17341732 else :
1735- msg = "has no attribute %r "
1736- raise AttributeError ("'RecordList' object %s" % msg % attr )
1733+ msg = f "has no attribute { attr !r } "
1734+ raise AttributeError ("'RecordList' object " + msg )
17371735
17381736 def __eq__ (self , other ):
17391737 return (isinstance (other , RecordList ) and
@@ -1759,9 +1757,9 @@ def __str__(self):
17591757 def _get_name (self ):
17601758 try :
17611759 (id_name ,) = self ._execute ('name_get' , [self .id ])
1762- name = '%s' % ( id_name [1 ],)
1760+ name = f' { id_name [1 ]} '
17631761 except Exception :
1764- name = '%s,%d' % ( self ._name , self .id )
1762+ name = f' { self ._name } , { self .id } '
17651763 self .__dict__ ['_idnames' ] = [(self .id , name )]
17661764 return _memoize (self , '_Record__name' , name )
17671765
@@ -1827,7 +1825,7 @@ def _set_external_id(self, xml_id):
18271825 domain = ['|' , '&' , ('module' , '=' , mod ), ('name' , '=' , name ),
18281826 '&' , ('model' , '=' , self ._name ), ('res_id' , '=' , self .id )]
18291827 if self .env ['ir.model.data' ].search (domain ):
1830- raise ValueError ('ID %r collides with another entry' % xml_id )
1828+ raise ValueError (f 'ID { xml_id !r } collides with another entry' )
18311829 self .env ['ir.model.data' ].create ({
18321830 'model' : self ._name ,
18331831 'res_id' : self .id ,
@@ -1841,7 +1839,7 @@ def __getattr__(self, attr):
18411839 if attr == '_Record__name' :
18421840 return self ._get_name ()
18431841 if attr .startswith ('_' ):
1844- raise AttributeError ("'Record' object has no attribute %r" % attr )
1842+ raise AttributeError (f "'Record' object has no attribute { attr !r } " )
18451843
18461844 def wrapper (self , * params , ** kwargs ):
18471845 """Wrapper for client.execute(%r, %r, %d, *params, **kwargs)."""
@@ -1856,7 +1854,7 @@ def __setattr__(self, attr, value):
18561854 if attr == '_external_id' :
18571855 return self ._set_external_id (value )
18581856 if attr not in self ._model ._keys :
1859- raise AttributeError ("'Record' object has no attribute %r" % attr )
1857+ raise AttributeError (f "'Record' object has no attribute { attr !r } " )
18601858 if attr == 'id' :
18611859 raise AttributeError ("'Record' object attribute 'id' is read-only" )
18621860 self .write ({attr : value })
@@ -1933,10 +1931,10 @@ def main(interact=_interact):
19331931 help = 'read connection settings from the given section' )
19341932 parser .add_option (
19351933 '-c' , '--config' , default = None ,
1936- help = 'specify alternate config file (default: %r)' % CONF_FILE )
1934+ help = f 'specify alternate config file (default: { CONF_FILE !r } )' )
19371935 parser .add_option (
19381936 '--server' , default = None ,
1939- help = 'full URL of the server (default: %s)' % DEFAULT_URL )
1937+ help = f 'full URL of the server (default: { DEFAULT_URL } )' )
19401938 parser .add_option ('-d' , '--db' , default = DEFAULT_DB , help = 'database' )
19411939 parser .add_option ('-u' , '--user' , default = None , help = 'username' )
19421940 parser .add_option (
0 commit comments