ERPpeek’s documentation¶
A versatile tool for browsing Odoo / OpenERP data
The ERPpeek library communicates with any Odoo / OpenERP server (>= 5.0) using the standard XML-RPC interface or the new JSON-RPC interface.
It provides both a fully featured low-level API, and an encapsulation of the methods on Active Record objects. Additional helpers are provided to explore the model and administrate the server remotely.
The Introduction describes its primary uses as a command line tool or within an interactive shell.
The Tutorial gives an in-depth look at the capabilities.
Contents:
Introduction¶
This section gives the bare minimum to use ERPpeek as a command line tool or within an interactive shell.
Command line arguments¶
There are few arguments to query Odoo models from the command line. Although it is quite limited:
$ erppeek --help
Usage: erppeek [options] [search_term_or_id [search_term_or_id ...]]
Inspect data on Odoo objects. Use interactively or query a model (-m)
and pass search terms or ids as positional parameters after the options.
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-l, --list list sections of the configuration
--env=ENV read connection settings from the given section
-c CONFIG, --config=CONFIG
specify alternate config file (default: 'erppeek.ini')
--server=SERVER full URL of the server (default: http://localhost:8069/xmlrpc)
-d DB, --db=DB database
-u USER, --user=USER username
-p PASSWORD, --password=PASSWORD
password, or it will be requested on login
-m MODEL, --model=MODEL
the type of object to find
-f FIELDS, --fields=FIELDS
restrict the output to certain fields (multiple allowed)
-i, --interact use interactively; default when no model is queried
-v, --verbose verbose
$ #
Example:
$ erppeek -d demo -m res.partner -f name -f lang 1
"name","lang"
"Your Company","en_US"
$ erppeek -d demo -m res.groups -f full_name 'id > 0'
"full_name"
"Administration / Access Rights"
"Administration / Configuration"
"Human Resources / Employee"
"Usability / Multi Companies"
"Usability / Extended View"
"Usability / Technical Features"
"Sales Management / User"
"Sales Management / Manager"
"Partner Manager"
Interactive use¶
Edit erppeek.ini
and declare the environment(s):
[DEFAULT]
scheme = http
host = localhost
port = 8069
database = odoo
username = admin
[demo]
username = demo
password = demo
protocol = xmlrpc
[demo_jsonrpc]
username = demo
password = demo
protocol = jsonrpc
[local]
scheme = local
options = -c /path/to/odoo-server.conf --without-demo all
Connect to the Odoo server:
erppeek --list
erppeek --env demo
This is a sample session:
>>> model('res.users')
<Model 'res.users'>
>>> model('res.users').count()
4
>>> model('ir.cron').read(['active = False'], 'active function')
[{'active': False, 'function': 'run_mail_scheduler', 'id': 1},
{'active': False, 'function': 'run_bdr_scheduler', 'id': 2},
{'active': False, 'function': 'scheduled_fetch_new_scans', 'id': 9}]
>>> #
>>> client.modules('delivery')
{'uninstalled': ['delivery', 'sale_delivery_report']}
>>> client.upgrade('base')
1 module(s) selected
42 module(s) to process:
to upgrade account
to upgrade account_chart
to upgrade account_tax_include
to upgrade base
...
>>> #
Note
Use the --verbose
switch to see what happens behind the scene.
Lines are truncated at 79 chars. Use -vv
or -vvv
to print
more.
Note
To preserve the history of commands when closing the session, first
create an empty file in your home directory:
touch ~/.erppeek_history
More details in the Tutorial section.
ERPpeek API¶
The library provides few objects to access the OpenObject model and the associated services of the Odoo API.
The signature of the methods mimics the standard methods provided by the
osv.Model
Odoo class. This is intended to help the developer when
developping addons. What is experimented at the interactive prompt should
be portable in the application with little effort.
Client and Services¶
The Client
object provides thin wrappers around Odoo RPC services
and their methods. Additional helpers are provided to explore the models and
list or install Odoo add-ons.
-
class
erppeek.
Client
(server, db=None, user=None, password=None, transport=None, verbose=False)[source]¶ Connection to an Odoo instance.
This is the top level object. The server is the URL of the instance, like
http://localhost:8069
. If server is anodoo
/openerp
Python package, it is used to connect to the local server (>= 6.1).The db is the name of the database and the user should exist in the table
res.users
. If the password is not provided, it will be asked on login.
-
classmethod
Client.
from_config
(environment, user=None, verbose=False)[source]¶ Create a connection to a defined environment.
Read the settings from the section
[environment]
in theerppeek.ini
file and return a connectedClient
. Seeread_config()
for details of the configuration file format.
-
Client.
create_database
(passwd, database, demo=False, lang='en_US', user_password='admin', login='admin', country_code=None)[source]¶ Create a new database.
The superadmin passwd and the database name are mandatory. By default, demo data are not loaded, lang is
en_US
and no country is set into the database. Login if successful.
-
Client.
clone_database
(passwd, db_name)[source]¶ Clone the current database.
The superadmin passwd and db_name are mandatory. Login if successful.
Supported since OpenERP 7.
-
Client.
login
(user, password=None, database=None)[source]¶ Switch user and (optionally) database.
If the password is not available, it will be asked.
-
Client.
context
¶ Default context used for all the methods (default
None
). In interactive mode, this default context contains the language of the shell environment (variableLANG
). Do not update the context, either copy it or replace it:# Set language to German client.context = {'lang': 'de_DE', 'preferred_color': 'blue'} # ... do something # Switch to Italian client.context = dict(client.context, lang='it_IT') # ... do something # and AVOID (because it changes the context of existing records) client.context['lang'] = 'fr_FR'
Note
In interactive mode, a method
Client.connect(env=None)
exists, to connect to another environment,
and recreate the globals()
.
Note
In interactive mode, when connected to the local
Odoo server, the get_pool(db_name=None) function helps to grab a model
registry for the current database. The cursor factory is available on the
registry as get_pool().cursor()
(Odoo) or get_pool().db.cursor()
(OpenERP <= 7).
Objects¶
-
Client.
search
(obj, domain, offset=0, limit=None, order=None, context=None)[source]¶ Filter the records in the domain, return the
ids
.
-
Client.
read
(obj, domain, fields=None, offset=0, limit=None, order=None, context=None)[source]¶ Wrapper for
client.execute(obj, 'read', [...], ('a', 'b'))
.The first argument obj is the model name (example:
"res.partner"
)- The second argument, domain, accepts:
[('name', '=', 'mushroom'), ('state', '!=', 'draft')]
['name = mushroom', 'state != draft']
[]
- a list of ids
[1, 2, 3]
or a single id42
- The third argument, fields, accepts:
- a single field:
'first_name'
- a tuple of fields:
('street', 'city')
- a space separated string:
'street city'
- a format spec:
'%(street)s %(city)s'
- a single field:
If fields is omitted, all fields are read.
- If domain is a single id, then:
- return a single value if a single field is requested.
- return a string if a format spec is passed in the fields argument.
- else, return a dictionary.
If domain is not a single id, the returned value is a list of items. Each item complies with the rules of the previous paragraph.
The optional keyword arguments offset, limit and order are used to restrict the search. The order is also used to order the results returned. Note: the low-level RPC method
read
itself does not preserve the order of the results.
-
Client.
perm_read
(obj, ids, context=None, details=True)¶ Lookup metadata about the records in the ids list. Return a list of dictionaries with the following keys:
id
: object idcreate_uid
: user who created the recordcreate_date
: date when the record was createdwrite_uid
: last user who changed the recordwrite_date
: date of the last change to the recordxmlid
: External ID to use to refer to this record (if there is one), in formatmodule.name
(not available with OpenERP 5)
If details is True, the
create_uid
andwrite_uid
contain the name of the user.
-
Client.
write
(obj, ids, values, context=None)¶ Update the record(s) with the content of the values dictionary.
-
Client.
create
(obj, values, context=None)¶ Create a new record for the model. The argument values is a dictionary of values for the new record. Return the object
id
.
-
Client.
copy
(obj, id, default=None, context=None)¶ Copy a record and return the new
id
. The optional argument default is a mapping which overrides some values of the new record.
-
Client.
unlink
(obj, ids, context=None)¶ Delete records with the given ids
-
Client.
models
(name='')[source]¶ Return a dictionary of models.
The argument name is a pattern to filter the models returned. If omitted, all models are returned. Keys are camel case names of the models. Values are instances of
Model
.The return value can be used to declare the models in the global namespace:
>>> globals().update(client.models('res.'))
-
Client.
model
(name, check=True)[source]¶ Return a
Model
instance.The argument name is the name of the model. If the optional argument check is
False
, no validity check is done.
-
Client.
keys
(obj)[source]¶ Wrapper for
Model.keys()
method.
-
Client.
fields
(obj, names=None)[source]¶ Wrapper for
Model.fields()
method.
-
Client.
field
(obj, name)[source]¶ Wrapper for
Model.field()
method.
-
Client.
access
(obj, mode='read')[source]¶ Wrapper for
Model.access()
method.
Advanced methods¶
Those methods give more control on the Odoo objects: workflows and reports. Please refer to the Odoo documentation for details.
-
Client.
execute
(obj, method, *params, **kwargs)[source]¶ Wrapper around
object.execute
RPC method.Argument method is the name of an
osv.osv
method or a method available on this obj. Method params are allowed. If needed, keyword arguments are collected in kwargs.
-
Client.
execute_kw
(obj, ids, params, kwargs=None)¶ Wrapper around
object.execute_kw
RPC method.Does not exist if server is OpenERP 5.
-
Client.
exec_workflow
(obj, signal, obj_id)[source]¶ Wrapper around
object.exec_workflow
RPC method.Argument obj is the name of the model. The signal is sent to the object identified by its integer
id
obj_id.
-
Client.
report
(obj, ids, datas=None, context=None)¶ Wrapper around
report.report
RPC method.Removed in Odoo 11.
-
Client.
render_report
(obj, ids, datas=None, context=None)¶ Wrapper around
report.render_report
RPC method.Does not exist if server is OpenERP 5.
Removed in Odoo 11.
-
Client.
report_get
(report_id)¶ Wrapper around
report.report_get
RPC method.Removed in Odoo 11.
-
Client.
wizard
(name, datas=None, action='init', context=<object object>)[source]¶ Wrapper around
wizard.create
andwizard.execute
RPC methods.If only name is provided, a new wizard is created and its
id
is returned. If action is not"init"
, then the action is executed. In this case the name is either anid
or a string. If the name is a string, the wizard is created before the execution. The optional datas argument provides data for the action. The optional context argument is passed to the RPC method.Removed in OpenERP 7.
Removed in OpenERP 7.
Odoo RPC Services¶
The nake Odoo services are exposed too.
The db
and the common
services expose few
methods which might be helpful for server administration. Use the
dir()
function to introspect them. The :attr:~Client._object
service should not be used directly because its methods are wrapped and
exposed on the Client
object itself.
The two last services are deprecated and removed in recent versions of Odoo.
Please refer to the Odoo documentation for more details.
-
Client.
db
¶ Expose the
db
Service
.Examples:
Client.db.list()
orClient.db.server_version()
RPC methods.
-
class
erppeek.
Service
(client, endpoint, methods, verbose=False)[source]¶ A wrapper around XML-RPC endpoints.
The connected endpoints are exposed on the Client instance. The server argument is the URL of the server (scheme+host+port). If server is an
odoo
Python package, it is used to connect to the local server. The endpoint argument is the name of the service (examples:"object"
,"db"
). The methods is the list of methods which should be exposed on this endpoint. Usedir(...)
on the instance to list them.
Manage addons¶
These helpers are convenient to list, install or upgrade addons from a Python script or interactively in a Python session.
-
Client.
modules
(name='', installed=None)[source]¶ Return a dictionary of modules.
The optional argument name is a pattern to filter the modules. If the boolean argument installed is
True
, the modules which are “Not Installed” or “Not Installable” are omitted. If the argument isFalse
, only these modules are returned. If argument installed is omitted, all modules are returned. The return value is a dictionary where module names are grouped in lists according to theirstate
.
Note
It is not recommended to install or upgrade modules in offline mode when any web server is still running: the operation will not be signaled to other processes. This restriction does not apply when connected through XML-RPC or JSON-RPC.
Model and Records¶
In addition to the thin wrapper methods, the Client
provides a high
level API which encapsulates objects into Active Records.
The Model
is instantiated using the Client.model()
method or
directly through camel case attributes.
Example: both client.model('res.company')
and client.ResCompany
return
the same Model
.
-
class
erppeek.
Model
(client, model_name)[source]¶ The class for Odoo models.
-
fields
(names=None)[source]¶ Return a dictionary of the fields of the model.
Optional argument names is a sequence of field names or a space separated string of these names. If omitted, all fields are returned.
-
access
(mode='read')[source]¶ Check if the user has access to this model.
Optional argument mode is the access mode to check. Valid values are
read
,write
,create
andunlink
. If omitted, theread
mode is checked. Return a boolean.
-
browse
(domain, offset=0, limit=None, order=None, context=None)[source]¶ Return a
Record
or aRecordList
.The argument domain accepts a single integer
id
, a list of ids or a search domain. If it is a single integer, the return value is aRecord
. Otherwise, the return value is aRecordList
. To get all the records, pass an empty list along with keyword argumentlimit=None
.
Note
To enable the unsafe behavior (ERPpeek <= 1.7) of
model.browse([])
(i.e. return all records), this class attribute can be set:Model._browse_compat = True
.-
get
(domain, context=None)[source]¶ Return a single
Record
.The argument domain accepts a single integer
id
or a search domain, or an external IDxml_id
. The return value is aRecord
or None. If multiple records are found, aValueError
is raised.
-
create
(values, context=<object object>)[source]¶ Create a
Record
.The argument values is a dictionary of values which are used to create the record. Relationship fields one2many and many2many accept either a list of ids or a RecordList or the extended Odoo syntax. Relationship fields many2one and reference accept either a Record or the Odoo syntax.
The newly created
Record
is returned.
-
-
class
erppeek.
RecordList
(model, ids)[source]¶ A sequence of Odoo
Record
.It has a similar API as the
Record
class, but for a list of records. The attributes of theRecordList
are read-only, and they return list of attribute values in the same order. Themany2one
,one2many
andmany2many
attributes are wrapped inRecordList
and list ofRecordList
objects. Use the methodRecordList.write
to assign a single value to all the selected records.-
read
(fields=None, context=None)[source]¶ Wrapper for the
Record.read()
method.Return a
RecordList
if fields is the name of a singlemany2one
field, else return alist
. SeeClient.read()
for details.
-
perm_read
(context=None)¶ Wrapper for the
Record.perm_read()
method.
-
write
(values, context=None)[source]¶ Wrapper for the
Record.write()
method.
-
unlink
(context=None)[source]¶ Wrapper for the
Record.unlink()
method.
-
_external_id
¶ Retrieve the External IDs of the
RecordList
.Return the list of fully qualified External IDs of the
RecordList
, with default value False if there’s none. If multiple IDs exist for a record, only one of them is returned.
-
-
class
erppeek.
Record
(model, id)[source]¶ A class for all Odoo records.
It maps any Odoo object. The fields can be accessed through attributes. The changes are immediately sent to the server. The
many2one
,one2many
andmany2many
attributes are wrapped inRecord
andRecordList
objects. These attributes support writing too. The attributes are evaluated lazily, and they are cached in the record. The Record’s cache is invalidated if any attribute is changed.-
_external_id
¶ Retrieve the External ID of the
Record
.Return the fully qualified External ID of the
Record
, with default value False if there’s none. If multiple IDs exist, only one of them is returned (randomly).
-
copy
(default=None, context=<object object>)[source]¶ Copy a record and return the new
Record
.The optional argument default is a mapping which overrides some values of the new record.
-
perm_read
(context=<object object>)[source]¶ Read the metadata of the
Record
.Return a dictionary of values. See
Client.perm_read()
for details.
-
read
(fields=None, context=<object object>)[source]¶ Read the fields of the
Record
.The argument fields accepts different kinds of values. See
Client.read()
for details.
-
write
(values, context=<object object>)[source]¶ Write the values in the
Record
.values is a dictionary of values. See
Model.create()
for details.
-
Utilities¶
-
erppeek.
lowercase
(s)[source]¶ Convert to lowercase with dots.
>>> lowercase('ResCompany') 'res.company'
-
erppeek.
issearchdomain
(arg)[source]¶ Check if the argument is a search domain.
- Examples:
[('name', '=', 'mushroom'), ('state', '!=', 'draft')]
['name = mushroom', 'state != draft']
[]
-
erppeek.
searchargs
(params, kwargs=None, context=None, api_v9=False)[source]¶ Compute the ‘search’ parameters.
-
erppeek.
format_exception
(type, value, tb, limit=None, chain=True)[source]¶ Format a stack trace and the exception information.
This wrapper is a replacement of
traceback.format_exception
which formats the error and traceback received by XML-RPC/JSON-RPC. If chain is True, then the original exception is printed too.
-
erppeek.
read_config
(section=None)[source]¶ Read the environment settings from the configuration file.
The config file
erppeek.ini
contains a section for each environment. Each section provides parameters for the connection:host
,port
,database
,username
and (optional)password
. Default values are read from the[DEFAULT]
section. If thepassword
is not in the configuration file, it is requested on login. Return a tuple(server, db, user, password or None)
. Without argument, it returns the list of configured environments.
-
erppeek.
start_odoo_services
(options=None, appname=None)[source]¶ Initialize the Odoo services.
Import the
odoo
Python package and load the Odoo services. The argument options receives the command line arguments forodoo
. Example:['-c', '/path/to/odoo-server.conf', '--without-demo', 'all']
.Return the
odoo
package.
Tutorial¶
This tutorial demonstrates some features of ERPpeek in the interactive shell.
It assumes an Odoo or OpenERP server is installed. The shell is a true Python shell. We have access to all the features and modules of the Python interpreter.
Steps:
First connection¶
The server is freshly installed and does not have an Odoo database yet.
The tutorial creates its own database demo
to play with.
Open the ERPpeek shell:
$ erppeek
It assumes that the server is running locally, and listens on default
port 8069
.
If our configuration is different, then we use arguments, like:
$ erppeek --server http://192.168.0.42:8069
It connects using the XML-RPC protocol. If you want to use the JSON-RPC
protocol instead, then pass the full URL with /jsonrpc
path:
$ erppeek --server http://127.0.0.1:8069/jsonrpc
On login, it prints few lines about the commands available.
$ erppeek
Usage (some commands):
models(name) # List models matching pattern
model(name) # Return a Model instance
model(name).keys() # List field names of the model
model(name).fields(names=None) # Return details for the fields
model(name).field(name) # Return details for the field
model(name).browse(domain)
model(name).browse(domain, offset=0, limit=None, order=None)
# Return a RecordList
rec = model(name).get(domain) # Get the Record matching domain
rec.some_field # Return the value of this field
rec.read(fields=None) # Return values for the fields
client.login(user) # Login with another user
client.connect(env) # Connect to another env.
client.modules(name) # List modules matching pattern
client.upgrade(module1, module2, ...)
# Upgrade the modules
As we’ll see later, the most interesting method here is probably
model()
which returns a Model
object with nice
wrappers.
And it confirms that the default database is not available:
...
Error: Database 'odoo' does not exist: []
Though, we have a connected client, ready to use:
>>> client
<Client 'http://localhost:8069/xmlrpc#()'>
>>> client.server_version
'6.1'
>>> #
Create a database¶
We create the database "demo"
for this tutorial.
We need to know the superadmin password before to continue.
This is the admin_passwd
in the odoo-server.conf
file.
Default password is "admin"
.
Note
This password gives full control on the databases. Set a strong password in the configuration to prevent unauthorized access.
>>> client.create_database('super_password', 'demo')
Logged in as 'admin'
>>> client
<Client 'http://localhost:8069/xmlrpc#demo'>
>>> client.db.list()
['demo']
>>> client.user
'admin'
>>> client.modules(installed=True)
{'installed': ['base', 'web', 'web_mobile', 'web_tests']}
>>> len(client.modules()['uninstalled'])
202
>>> #
Note
Create an erppeek.ini
file in the current directory to declare all our
environments. Example:
[DEFAULT]
host = localhost
port = 8069
[demo]
database = demo
username = joe
Then we connect to any environment with erppeek --env demo
or switch
during an interactive session with client.connect('demo')
.
Clone a database¶
It is sometimes useful to clone a database (testing, backup, migration, …). A shortcut is available for that, the required parameters are the new database name and the superadmin password.
>>> client.clone_database('super_password', 'demo_test')
Logged in as 'admin'
>>> client
<Client 'http://localhost:8069/xmlrpc#demo_test'>
>>> client.db.list()
['demo', 'demo_test']
>>> client.user
'admin'
>>> client.modules(installed=True)
{'installed': ['base', 'web', 'web_mobile', 'web_tests']}
>>> len(client.modules()['uninstalled'])
202
>>> #
Find the users¶
We have created the database "demo"
for the tests.
We are connected to this database as 'admin'
.
Where is the table for the users?
>>> client
<Client 'http://localhost:8069/xmlrpc#demo'>
>>> models('user')
{'ResUsers': <Model 'res.users'>, 'ResWidgetUser': <Model 'res.widget.user'>}
We’ve listed two models which matches the name, res.users
and
res.widget.user
. We reach the users’ model using the model()
method and we want to introspect its fields.
Fortunately, the Model
class provides methods to retrieve all
the details.
>>> model('res.users')
<Model 'res.users'>
>>> print(model('res.users').keys())
['action_id', 'active', 'company_id', 'company_ids', 'context_lang',
'context_tz', 'date', 'groups_id', 'id', 'login', 'menu_id', 'menu_tips',
'name', 'new_password', 'password', 'signature', 'user_email', 'view']
>>> model('res.users').field('view')
{'digits': [16, 2],
'fnct_inv': '_set_interface_type',
'fnct_inv_arg': False,
'fnct_search': False,
'func_obj': False,
'function': '_get_interface_type',
'help': 'OpenERP offers a simplified and an extended user interface. If\
you use OpenERP for the first time we strongly advise you to select the\
simplified interface, which has less features but is easier to use. You\
can switch to the other interface from the User/Preferences menu at any\
time.',
'selection': [['simple', 'Simplified'], ['extended', 'Extended']],
'store': False,
'string': 'Interface',
'type': 'selection'}
>>> #
Let’s examine the 'admin'
user in details.
>>> model('res.users').count()
1
>>> admin_user = model('res.users').browse(1)
>>> admin_user.groups_id
<RecordList 'res.groups,[1, 2, 3]'>
>>> admin_user.groups_id.name
['Access Rights', 'Configuration', 'Employee']
>>> admin_user.groups_id.full_name
['Administration / Access Rights',
'Administration / Configuration',
'Human Resources / Employee']
>>> admin_user.perm_read()
{'create_date': False,
'create_uid': False,
'id': 1,
'write_date': '2012-09-01 09:01:36.631090',
'write_uid': [1, 'Administrator'],
'xmlid': 'base.user_admin'}
Create a new user¶
Now we want a non-admin user to continue the exploration.
Let’s create Joe
.
>>> model('res.users').create({'login': 'joe'})
Fault: Integrity Error
The operation cannot be completed, probably due to the following:
- deletion: you may be trying to delete a record while other records still reference it
- creation/update: a mandatory field is not correctly set
[object with reference: name - name]
>>> #
It seems we’ve forgotten some mandatory data. Let’s give him a name
.
>>> model('res.users').create({'login': 'joe', 'name': 'Joe'})
<Record 'res.users,3'>
>>> joe_user = _
>>> joe_user.groups_id.full_name
['Human Resources / Employee', 'Partner Manager']
The user Joe
does not have a password: we cannot login as joe
.
We set a password for Joe
and we try again.
>>> client.login('joe')
Password for 'joe':
Error: Invalid username or password
>>> client.user
'admin'
>>> joe_user.password = 'bar'
>>> client.login('joe')
Logged in as 'joe'
>>> client.user
'joe'
>>> #
Success!
Explore the model¶
We keep connected as user Joe
and we explore the world around us.
>>> client.user
'joe'
>>> all_models = sorted(models().values(), key=str)
>>> len(all_models)
92
Among these 92 objects, some of them are read-only
, others are
read-write
. We can also filter the non-empty
models.
>>> # Read-only models
>>> len([m for m in all_models if not m.access('write')])
44
>>> #
>>> # Writable but cannot delete
>>> [m for m in all_models if m.access('write') and not m.access('unlink')]
[<Model 'ir.property'>]
>>> #
>>> # Unreadable models
>>> [m for m in all_models if not m.access('read')]
[<Model 'ir.actions.todo'>,
<Model 'ir.actions.todo.category'>,
<Model 'res.payterm'>]
>>> #
>>> # Now print the number of entries in all (readable) models
>>> for m in all_models:
... mcount = m.access() and m.count()
... if not mcount:
... continue
... print('%4d %s' % (mcount, m))
...
81 <Model 'ir.actions.act_window'>
14 <Model 'ir.actions.act_window.view'>
85 <Model 'ir.actions.act_window_close'>
85 <Model 'ir.actions.actions'>
4 <Model 'ir.actions.report.xml'>
3 <Model 'ir.config_parameter'>
2 <Model 'ir.cron'>
1 <Model 'ir.mail_server'>
92 <Model 'ir.model'>
126 <Model 'ir.model.access'>
1941 <Model 'ir.model.data'>
658 <Model 'ir.model.fields'>
32 <Model 'ir.module.category'>
207 <Model 'ir.module.module'>
432 <Model 'ir.module.module.dependency'>
8 <Model 'ir.rule'>
63 <Model 'ir.ui.menu'>
185 <Model 'ir.ui.view'>
1 <Model 'ir.ui.view_sc'>
72 <Model 'ir.values'>
1 <Model 'res.bank'>
1 <Model 'res.company'>
253 <Model 'res.country'>
51 <Model 'res.country.state'>
48 <Model 'res.currency'>
49 <Model 'res.currency.rate'>
9 <Model 'res.groups'>
1 <Model 'res.lang'>
1 <Model 'res.partner'>
1 <Model 'res.partner.address'>
1 <Model 'res.partner.bank.type'>
1 <Model 'res.partner.bank.type.field'>
5 <Model 'res.partner.title'>
1 <Model 'res.request.link'>
2 <Model 'res.users'>
6 <Model 'res.widget'>
1 <Model 'res.widget.user'>
>>> #
>>> # Show the content of a model
>>> config_params = model('ir.config_parameter').browse([], limit=None)
>>> config_params.read()
[{'id': 1, 'key': 'web.base.url', 'value': 'http://localhost:8069'},
{'id': 2, 'key': 'database.create_date', 'value': '2012-09-01 09:01:12'},
{'id': 3,
'key': 'database.uuid',
'value': '52fc9630-f49e-2222-e622-08002763afeb'}]
Browse the records¶
Query the "res.country"
model:
>>> model('res.country').keys()
['address_format', 'code', 'name']
>>> model('res.country').browse(['name like public'])
<RecordList 'res.country,[41, 42, 57, 62, 116, 144]'>
>>> model('res.country').browse(['name like public']).name
['Central African Republic',
'Congo, Democratic Republic of the',
'Czech Republic',
'Dominican Republic',
'Kyrgyz Republic (Kyrgyzstan)',
'Macedonia, the former Yugoslav Republic of']
>>> model('res.country').browse(['code > Y'], order='code ASC').read('code name')
[{'code': 'YE', 'id': 247, 'name': 'Yemen'},
{'code': 'YT', 'id': 248, 'name': 'Mayotte'},
{'code': 'YU', 'id': 249, 'name': 'Yugoslavia'},
{'code': 'ZA', 'id': 250, 'name': 'South Africa'},
{'code': 'ZM', 'id': 251, 'name': 'Zambia'},
{'code': 'ZR', 'id': 252, 'name': 'Zaire'},
{'code': 'ZW', 'id': 253, 'name': 'Zimbabwe'}]
>>> #
… the tutorial is done.
Jump to the ERPpeek API for further details.
Developer’s notes¶
Source code¶
- Source code and issue tracker on GitHub.
- Continuous tests against Python 2.7 through 3.7 and PyPy, on Travis-CI platform.
Third-party integration¶
This module can be used with other Python libraries to achieve more complex tasks.
For example:
- write unit tests using the standard unittest framework.
- write BDD tests using the Gherkin language, and a library like Behave.
- build an interface for Odoo, using a framework like Flask (HTML, JSON, SOAP, …).
Changes¶
1.7.1 (2018-12-05)¶
- Add support for the JSON-RPC protocol. It is enabled if the
--server
argument contains the full path to the/jsonrpc
endpoint. As an alternative, you can specify theprotocol
in the configuration file. - Change the return value of
Model.browse()
method if search domain is an empty list. It returns an emptyRecordList
except if some other argument is provided (e.g.all_users = model('res.users').browse([], limit=None)
). Compatibility tip: you can restore the old behavior withModel._browse_compat = True
. - Change the return value of
Client.read()
andModel.read()
methods if search domain is an empty list: it returnsFalse
. - Improve error formatting for recent Odoo versions, in interactive mode.
- Refactor the construction of
Service
proxies. - Drop compatibility with Python 2.6.
1.7 (2018-11-22)¶
- Fully support Odoo 10 and Odoo 11.
- New method
Client.clone_database
based onClient.db.duplicate_database
. - Optional
login
andcountry_code
arguments forClient.create_database
in Odoo 9+. - Use the
context
for thesearch
methods. - Service
Client._report
is removed in Odoo 11. MethodsClient.report
,Client.report_get
andClient.render_report
are removed too. - More robust Python 2 detection logic.
1.6.3 (2015-12-30)¶
- Do not parse long integers which overflow in XML-RPC.
1.6.2 (2015-09-17)¶
- Add an optional
transport
argument to theClient
constructor. This is useful for tweaking the SSL context or adding an optional timeout parameter. - Implement
==
comparison forRecordList
instances. - Uninstall dependent add-ons in a single call.
- Do not install/uninstall add-ons if other actions are pending.
- Do not hang when the
Client
constructor receives invalid arguments. - Fix
str(record)
andprint(record)
with non-ASCII names.
1.6.1 (2014-11-12)¶
- Support using
--env
and--user
together to connect with a different user. - Adapt for Odoo 8.0 after change
cc4fba6
on October 2014. - Do not interpret digits with leading
0
as octal in search domain.
1.6 (2014-09-23)¶
- Compatible with Odoo 8.0.
- New attribute
Client.context
to set the default context for high-levelModel
andRecord
methods. - Use blocking RPC call in
Client.create_database
. Asynchronous method is removed in Odoo. - Return the interactive namespace with
main(interact=False)
. It helps to integrate with third-party libraries, such as IPython. - Remove a duplicate
Logged in as ...
line in interactive mode. - Remove the
search+name_get
undocumented feature which has wrong behavior when applied to an emptyRecordList
. - Do not prevent login if access to
Client.db.list()
is denied.
1.6b1 (2014-06-09)¶
- When a function or a method fails, raise an
erppeek.Error
instead of printing a message and returningNone
. - Switch to local mode when the command line argument points at the
server configuration, like
-c path/to/openerp-server.conf
. - Local mode compatible with Odoo trunk: support both the old and the new API.
- Use shell-like parsing for
options =
setting in local mode. - Function
start_openerp_services
is replaced withstart_odoo_services
: it is still compatible with OpenERP 6.1 and 7 and it accepts a list of options in the first argument, similar tosys.argv[1:]
. - Search domains require square brackets. Usage without square brackets
was deprecated since 0.5, with
UserWarning
alerts. - Implement addition of
RecordList
of the same model. - Drop compatibility with Python 2.5.
1.5.3 (2014-05-26)¶
- Change command line output to CSV format.
- Translate command line output according to LANG environment variable.
- Pretty print the list of modules.
- Do not report
Module(s) not found
when trying to install a module already installed.
1.5.2 (2014-04-12)¶
- Return an appropriate error message when the client is not connected.
- Two similar
Record
from different connections do not compare equal. - Set the
PGAPPNAME
used for the PostgreSQL connection, in local mode. - Close PostgreSQL connections on exit, in local mode.
- Implement the context manager protocol.
1.5.1 (2014-03-11)¶
- When switching to a different environment, with
Client.connect
, invalidate the previous connection to avoid mistakes (interactive mode). - Avoid cluttering the globals in interactive mode.
- Close socket to avoid
ResourceWarning
on Python 3. - The
get_pool
helper is only available in interactive mode and if the client is connected locally using theopenerp
package. - Clear the last exception before entering interactive mode, only needed on Python 2.
- Fix the
searchargs
domain parser for compatibility with Python 3.4.
1.5 (2014-03-10)¶
- Advertize the
Model
andRecord
paradigm in theusage
printed in interactive mode: it’s far more easier to use, and available since 1.0. - In interactive mode, only inject four global names:
client
,models
,model
anddo
. Other methods are available onModel
andClient
instances (read
search
count
keys
fields
access
…). - Always clear the
Record
cache when an arbitrary method is called on thisRecord
. - Implement
==
comparison forRecord
instances. - New computed attributes
Record._external_id
andRecordList._external_id
, and new methodModel._get_external_ids(ids=None)
. - Better parsing of dates in search terms.
- Reject invalid
==
operator in search terms. - Now the
str(...)
of aRecord
is always retrieved withname_get
. Previously, the output was sometimes inconsistent. - Fix
TypeError
when browsing duplicate ids. - Fix error with
Model.get(['field = value'], context={...})
. - Workaround an issue with some models: always pass a list of ids
to
read
. - Test the behaviour when
read
is called with aFalse
id: it happens when browsing aRecordList
for example.
1.4.5 (2013-03-20)¶
- Extend
Model.get
to retrieve a record byxml_id
. - Fix AttributeError when reading a mix of valid and invalid records.
- Fix
dir()
onRecord
andRecordList
to return all declared fields, and do not reportid
field twice. - Fix a crash with built-in OS X readline on Python 2.5 or 2.6.
1.4.4 (2013-03-05)¶
- Remove deprecated
Record.client
. - Fix compatibility with Python 3.
- Add optional argument
check
to theClient.model
method to bypass the verification in some cases, used to speed up the read methods. - Do not crash when mixing non-existing and existing records: return
always
False
for non-existing records.
1.4.3 (2013-01-10)¶
- Compatible with OpenERP 7.
- Set the database name as thread attribute to print it in the log file (local mode only).
- Do not try to access private methods through RPC when resolving
attributes of the
Client
or anyRecord
orRecordList
.
1.4.2 (2012-12-19)¶
- Add the
get_pool
helper when connected using theopenerp
library. - Remove the leading slash on the
server
option, if present. - Do not try to access private methods through RPC when reading attributes
of the
model(...)
.
1.4.1 (2012-10-05)¶
- Fix reading
many2one
attribute onRecordList
object in local mode. - Fix occasional issue on login when switching database on the same server.
- Optimization: do not propagate the call to
RecordList.write
orRecordList.unlink
if the list is empty. - Clear the
Record
cache onRecord._send
. - Expose the method
Record.refresh
to clear the local cache.
1.4 (2012-10-01)¶
- New: direct connection to a local server using the
openerp
library. Usescheme = local
andoptions = -c /path/to/openerp-server.conf
in the configuration.
1.3.1 (2012-09-28)¶
- Fix method
Record._send
.
1.3 (2012-09-27)¶
- Implement exception chaining in
format_exception
to print the original traceback. - Return a list of
Record
objects when reading thereference
field of aRecordList
object. - Fix reading attributes on
RecordList
with holes or gaps. - Accessing an empty
one2many
ormany2many
attribute on aRecord
returns aRecordList
. - New method
Model.get
to retrieve a singleRecord
. It raises aValueError
if multiple records are found. - New method
Record._send
to send a workflow signal.
1.2.2 (2012-09-24)¶
- Accept
Record
andRecordList
attribute values when writing or creating records. - Improve the methods
write
andcreate
ofRecord
andRecordList
objects to manageone2many
andmany2many
fields. - Return a
Record
when reading areference
field. Implement thecreate
andwrite
methods for these fields. - Remove undocumented alias
Record.update
.
1.2.1 (2012-09-21)¶
- Add the special operators
=ilike
,=ilike
,=?
and fix parsing of inequality operators>=
and<=
. - Fix the
RecordList.id
attribute, and deprecateRecordList._ids
. - Deprecate the
Record.client
attribute: useRecord._model.client
. - Accessing an empty
many2one
attribute on aRecordList
now returns aRecordList
. - Fix
TypeError
when browsing non-existent records.
1.2 (2012-09-19)¶
- Catch some malformed search domains before sending the RPC request.
- Preserve dictionary response when calling non standard
Record
methods. - Expose the helper
format_exception
which formats the errors received through XML-RPC. - Support XML-RPC through HTTPS with
scheme = https
in theerppeek.ini
configuration file. - Print an error message when
client.upgrade(...)
does not find any module to upgrade.
1.1 (2012-09-04)¶
- When using arbitrary methods on
Record
, wrap theid
in a list[id]
. It fixes a recurring issue with poorly tested methods. - Do not read all records if the
RecordList
is empty. - Fix the bad behaviour when switching to a different database.
- Order the results when using
read
method withorder=
argument. - Reading attributes of the sequence
<RecordList 'sea.fish,[2, 1, 2]'>
will return an ordered sequence of three items. Previously it used to return an unordered sequence of two items. - Accept the
%(...)s
formatting for the fields parameter of theRecord.read
and theRecordList.read
methods too. - Add a tutorial to the documentation.
1.0 (2012-08-29)¶
- Add the test suite for Python 2 and Python 3.
- Implement
len()
forRecordList
objects. - Connect to the server even if the database is missing.
- Expose the method
Client.db.get_progress
. - New method
Client.create_database
which wraps togetherClient.db.create
andClient.db.get_progress
. - Save the readline history in
~/.erppeek_history
, only if the file already exists. - Enable auto-completion using
rlcompleter
standard module. - Raise an
AttributeError
when assigning to a missing or read-only attribute.
0.11 (2012-08-24)¶
- Enhance the
Model.browse()
method to accept the same keyword arguments as theClient.search()
method. - Fix the verbose level on
Client.connect()
. - Fix the
Record.copy()
method. - Fix the
Record.perm_read()
method (workaround an OpenERP bug when dealing with single ids). - Drop the
--search
argument, because the search terms can be passed as positional arguments after the options. Explain it in the description. - Fix the shell command. Request the password interactively if it’s not in the options and not in the configuration file.
0.10 (2012-08-23)¶
- Add the
--verbose
switch to log the XML-RPC messages. Lines are truncated at 79 chars. Use-vv
or-vvv
to truncate at 179 or 9999 chars respectively. - Removed the
--write
switch because it’s not really useful. UseRecord.write()
orclient.write()
for example. - Stop raising RuntimeError when calling
Client.model(name)
. Simply print the message if the name does not match. - Fix
RecordList.read()
andRecord.read()
methods to accept the same diversity offields
arguments as theClient.read()
method. RecordList.read()
andRecord.read()
return instances ofRecordList
andRecord
for relational fields.- Optimize: store the name of the
Record
when a relational field is accessed. - Fix message wording on module install or upgrade.
0.9.2 (2012-08-22)¶
- Fix
Record.write()
andRecord.unlink()
methods. - Fix the caching of the
Model
keys and fields and theRecord
name.
0.9.1 (2012-08-22)¶
- Fix
client.model()
method. Addmodels()
to theglobals()
in interactive mode.
0.9 (2012-08-22)¶
- Add the Active Record pattern for convenience. New classes
Model
,RecordList
andRecord
. TheClient.model()
method now returns a singleModel
instance. These models can be reached using camel case attribute too. Example:client.model('res.company')
andclient.ResCompany
return the sameModel
. - Refresh the list of modules before install or upgrade.
- List all modules which have
state not in ('uninstalled', 'uninstallable')
when callingclient.modules(installed=True)
. - Add documentation.
0.8 (2012-04-24)¶
- Fix
help(client)
andrepr(...)
. - Add basic safeguards for argument types.
0.7 (2012-04-04)¶
- Fix RuntimeError on connection.
0.6 (2012-04-03)¶
- Support Python 3.
- Return Client method instead of function when calling
client.write
or similar. - Fix the case where
read()
is called with a single id.
0.5 (2012-03-29)¶
- Implement
Client.__getattr__
special attribute to call any object method, likeclient.write(obj, values)
. This is somewhat redundant withclient.execute(obj, 'write', values)
and its interactive aliasdo(obj, 'write', values)
. - Add
--write
switch to enable unsafe helpers:write
,create
,copy
andunlink
. - Tolerate domain without square brackets, but show a warning.
- Add long options
--search
for-s
,--interact
for-i
.
0.4 (2012-03-28)¶
- Workaround for
sys.excepthook
ignored, related to a Python issue.
0.3 (2012-03-26)¶
- Add
--config
and--version
switches. - Improve documentation with session examples.
- Move the project from Launchpad to GitHub.
0.2 (2012-03-24)¶
- Allow to switch user or database: methods
client.login
andclient.connect
. - Allow
context=
keyword argument. - Add
access(...)
method. - Add
%(...)s
formatting for the fields parameter of theread(...)
method. - Refactor the interactive mode.
- Many improvements.
- Publish on PyPI.
0.1 (2012-03-14)¶
- Initial release.
- Online documentation: http://erppeek.readthedocs.org/
- Source code and issue tracker: https://github.com/tinyerp/erppeek