Change CI to GitHub actions

Use copier template from oca/oca-addons-repo-template

Target Python3.8

Apply linting

Fix a missing call to super
This commit is contained in:
Yannick Payot
2023-05-24 16:09:11 +02:00
parent dc83bd74b3
commit 9ca3f6a710
83 changed files with 1714 additions and 912 deletions
+15 -17
View File
@@ -2,20 +2,18 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{'name': 'Attachments on Swift storage',
'summary': 'Store assets and attachments on a Swift compatible object store',
'version': "14.0.1.0.0",
'author': 'Camptocamp,Odoo Community Association (OCA)',
'license': 'AGPL-3',
'category': 'Knowledge Management',
'depends': ['base_attachment_object_storage'],
'external_dependencies': {
'python': ['swiftclient',
'keystoneclient',
'keystoneauth1',
],
},
'website': 'https://www.camptocamp.com',
'data': [],
'installable': True,
}
{
"name": "Attachments on Swift storage",
"summary": "Store assets and attachments on a Swift compatible object store",
"version": "14.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Knowledge Management",
"depends": ["base_attachment_object_storage"],
"external_dependencies": {
"python": ["swiftclient", "keystoneclient", "keystoneauth1"],
},
"website": "https://github.com/camptocamp/odoo-cloud-platform",
"data": [],
"installable": True,
}
+44 -45
View File
@@ -4,17 +4,18 @@
import logging
import os
from ..swift_uri import SwiftUri
from odoo import api, exceptions, models, _
from odoo import _, api, exceptions, models
from ..swift_uri import SwiftUri
_logger = logging.getLogger(__name__)
try:
import swiftclient
import keystoneauth1
import keystoneauth1.identity
import keystoneauth1.session
import swiftclient
from swiftclient.exceptions import ClientException
except ImportError:
swiftclient = None
@@ -48,8 +49,9 @@ class SwiftSessionStore(object):
def _get_key(self, auth_url, username, password, project_name):
return (auth_url, username, password, project_name)
def get_session(self, auth_url=None, username=None, password=None,
project_name=None):
def get_session(
self, auth_url=None, username=None, password=None, project_name=None
):
key = self._get_key(auth_url, username, password, project_name)
session = self._sessions.get(key)
if not session:
@@ -58,8 +60,8 @@ class SwiftSessionStore(object):
password=password,
project_name=project_name,
auth_url=auth_url,
project_domain_id='default',
user_domain_id='default',
project_domain_id="default",
user_domain_id="default",
)
session = keystoneauth1.session.Session(
auth=auth,
@@ -73,36 +75,38 @@ swift_session_store = SwiftSessionStore()
class IrAttachment(models.Model):
_inherit = 'ir.attachment'
_inherit = "ir.attachment"
def _get_stores(self):
l = ['swift']
l += super()._get_stores()
return l
stores = ["swift"]
stores += super()._get_stores()
return stores
@api.model
def _get_swift_connection(self):
""" Returns a connection object for the Swift object store """
host = os.environ.get('SWIFT_AUTH_URL')
account = os.environ.get('SWIFT_ACCOUNT')
password = os.environ.get('SWIFT_PASSWORD')
project_name = os.environ.get('SWIFT_PROJECT_NAME')
if not project_name and os.environ.get('SWIFT_TENANT_NAME'):
project_name = os.environ['SWIFT_TENANT_NAME']
"""Returns a connection object for the Swift object store"""
host = os.environ.get("SWIFT_AUTH_URL")
account = os.environ.get("SWIFT_ACCOUNT")
password = os.environ.get("SWIFT_PASSWORD")
project_name = os.environ.get("SWIFT_PROJECT_NAME")
if not project_name and os.environ.get("SWIFT_TENANT_NAME"):
project_name = os.environ["SWIFT_TENANT_NAME"]
_logger.warning(
"SWIFT_TENANT_NAME is deprecated and "
"must be replaced by SWIFT_PROJECT_NAME"
)
region = os.environ.get('SWIFT_REGION_NAME')
region = os.environ.get("SWIFT_REGION_NAME")
os_options = {}
if region:
os_options['region_name'] = region
os_options["region_name"] = region
if not (host and account and password and project_name):
raise exceptions.UserError(_(
"Problem connecting to Swift store, are the env variables "
"(SWIFT_AUTH_URL, SWIFT_ACCOUNT, SWIFT_PASSWORD, "
"SWIFT_TENANT_NAME) properly set?"
))
raise exceptions.UserError(
_(
"Problem connecting to Swift store, are the env variables "
"(SWIFT_AUTH_URL, SWIFT_ACCOUNT, SWIFT_PASSWORD, "
"SWIFT_TENANT_NAME) properly set?"
)
)
try:
session = swift_session_store.get_session(
username=account,
@@ -115,13 +119,13 @@ class IrAttachment(models.Model):
os_options=os_options,
)
except ClientException:
_logger.exception('Error connecting to Swift object store')
raise exceptions.UserError(_('Error on Swift connection'))
_logger.exception("Error connecting to Swift object store")
raise exceptions.UserError(_("Error on Swift connection"))
return conn
@api.model
def _store_file_read(self, fname):
if fname.startswith('swift://'):
if fname.startswith("swift://"):
swifturi = SwiftUri(fname)
try:
conn = self._get_swift_connection()
@@ -129,31 +133,27 @@ class IrAttachment(models.Model):
_logger.exception(
"error reading attachment '%s' from object storage", fname
)
return ''
return ""
try:
resp, read = conn.get_object(
swifturi.container(),
swifturi.item()
)
resp, read = conn.get_object(swifturi.container(), swifturi.item())
except ClientException:
read = ''
_logger.exception(
'Error reading object from Swift object store')
read = ""
_logger.exception("Error reading object from Swift object store")
return read
else:
return super()._store_file_read(fname)
def _store_file_write(self, key, bin_data):
if self._storage() == 'swift':
container = os.environ.get('SWIFT_WRITE_CONTAINER')
if self._storage() == "swift":
container = os.environ.get("SWIFT_WRITE_CONTAINER")
conn = self._get_swift_connection()
conn.put_container(container)
filename = 'swift://{}/{}'.format(container, key)
filename = "swift://{}/{}".format(container, key)
try:
conn.put_object(container, key, bin_data)
except ClientException:
_logger.exception('Error writing to Swift object store')
raise exceptions.UserError(_('Error writing to Swift'))
_logger.exception("Error writing to Swift object store")
raise exceptions.UserError(_("Error writing to Swift"))
else:
_super = super()
filename = _super._store_file_write(key, bin_data)
@@ -161,18 +161,17 @@ class IrAttachment(models.Model):
@api.model
def _store_file_delete(self, fname):
if fname.startswith('swift://'):
if fname.startswith("swift://"):
swifturi = SwiftUri(fname)
container = swifturi.container()
# delete the file only if it is on the current configured bucket
# otherwise, we might delete files used on a different environment
if container == os.environ.get('SWIFT_WRITE_CONTAINER'):
if container == os.environ.get("SWIFT_WRITE_CONTAINER"):
conn = self._get_swift_connection()
try:
conn.delete_object(container, swifturi.item())
except ClientException:
_logger.exception(
_('Error deleting an object on the Swift store'))
_logger.exception(_("Error deleting an object on the Swift store"))
# we ignore the error, file will stay on the object
# storage but won't disrupt the process
else:
+1 -2
View File
@@ -6,8 +6,7 @@ import re
class SwiftUri(object):
_url_re = re.compile("^swift:///*([^/]*)/?(.*)",
re.IGNORECASE | re.UNICODE)
_url_re = re.compile("^swift:///*([^/]*)/?(.*)", re.IGNORECASE | re.UNICODE)
def __init__(self, uri):
match = self._url_re.match(uri)
-1
View File
@@ -1,2 +1 @@
from . import test_mock_swift_api
+56 -57
View File
@@ -2,30 +2,27 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import base64
import mock
import os
import keystoneauth1
import mock
from mock import patch
import keystoneauth1
from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment
from odoo.addons.attachment_swift.models.ir_attachment import SwiftSessionStore
from odoo.addons.attachment_swift.swift_uri import SwiftUri
from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment
class TestAttachmentSwift(TestIrAttachment):
def setup(self):
super().setUp()
self.env['ir.config_parameter'].set_param('ir_attachment.location',
'swift')
self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift")
def test_session_store_get_session(self):
auth_url = 'auth_url'
username = 'username'
password = 'password'
project_name = 'project_name'
auth_url = "auth_url"
username = "username"
password = "password"
project_name = "project_name"
store = SwiftSessionStore()
session = store.get_session(
auth_url=auth_url,
@@ -34,10 +31,12 @@ class TestAttachmentSwift(TestIrAttachment):
project_name=project_name,
)
self.assertEqual(session.auth.auth_url, auth_url)
self.assertEqual(session.auth.get_cache_id_elements().get(
'password_username'), username)
self.assertEqual(session.auth.get_cache_id_elements().get(
'password_password'), password)
self.assertEqual(
session.auth.get_cache_id_elements().get("password_username"), username
)
self.assertEqual(
session.auth.get_cache_id_elements().get("password_password"), password
)
self.assertEqual(session.auth.project_name, project_name)
# get the same session on a second call
@@ -48,73 +47,73 @@ class TestAttachmentSwift(TestIrAttachment):
password=password,
project_name=project_name,
),
session
session,
)
@patch('swiftclient.client')
@patch("swiftclient.client")
def test_connection(self, mock_swift_client):
""" Test the connection to the store"""
os.environ['SWIFT_AUTH_URL'] = 'auth_url'
os.environ['SWIFT_ACCOUNT'] = 'account'
os.environ['SWIFT_PASSWORD'] = 'password'
os.environ['SWIFT_PROJECT_NAME'] = 'project_name'
os.environ['SWIFT_REGION_NAME'] = 'NOWHERE'
"""Test the connection to the store"""
os.environ["SWIFT_AUTH_URL"] = "auth_url"
os.environ["SWIFT_ACCOUNT"] = "account"
os.environ["SWIFT_PASSWORD"] = "password"
os.environ["SWIFT_PROJECT_NAME"] = "project_name"
os.environ["SWIFT_REGION_NAME"] = "NOWHERE"
attachment = self.Attachment
attachment._get_swift_connection()
mock_swift_client.Connection.assert_called_once_with(
session=mock.ANY,
os_options={'region_name': os.environ.get('SWIFT_REGION_NAME')},
os_options={"region_name": os.environ.get("SWIFT_REGION_NAME")},
)
__, kwargs = mock_swift_client.Connection.call_args
session = kwargs['session']
session = kwargs["session"]
self.assertTrue(isinstance(session, keystoneauth1.session.Session))
self.assertEqual(session.auth.auth_url, os.environ['SWIFT_AUTH_URL'])
self.assertEqual(session.auth.get_cache_id_elements().get(
'password_username'), os.environ['SWIFT_ACCOUNT'])
self.assertEqual(session.auth.get_cache_id_elements().get(
'password_password'), os.environ['SWIFT_PASSWORD'])
self.assertEqual(session.auth.project_name,
os.environ['SWIFT_PROJECT_NAME'])
self.assertEqual(session.auth.auth_url, os.environ["SWIFT_AUTH_URL"])
self.assertEqual(
session.auth.get_cache_id_elements().get("password_username"),
os.environ["SWIFT_ACCOUNT"],
)
self.assertEqual(
session.auth.get_cache_id_elements().get("password_password"),
os.environ["SWIFT_PASSWORD"],
)
self.assertEqual(session.auth.project_name, os.environ["SWIFT_PROJECT_NAME"])
def test_store_file_on_swift(self):
"""
Test writing a file
Test writing a file
"""
(self.env['ir.config_parameter'].
set_param('ir_attachment.location', 'swift'))
os.environ['SWIFT_AUTH_URL'] = 'auth_url'
os.environ['SWIFT_ACCOUNT'] = 'account'
os.environ['SWIFT_PASSWORD'] = 'password'
os.environ['SWIFT_PROJECT_NAME'] = 'project_name'
os.environ['SWIFT_WRITE_CONTAINER'] = 'my_container'
container = os.environ.get('SWIFT_WRITE_CONTAINER')
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
os.environ["SWIFT_AUTH_URL"] = "auth_url"
os.environ["SWIFT_ACCOUNT"] = "account"
os.environ["SWIFT_PASSWORD"] = "password"
os.environ["SWIFT_PROJECT_NAME"] = "project_name"
os.environ["SWIFT_WRITE_CONTAINER"] = "my_container"
container = os.environ.get("SWIFT_WRITE_CONTAINER")
attachment = self.Attachment
bin_data = base64.b64decode(self.blob1_b64)
with patch('swiftclient.client.Connection') as MockConnection:
with patch("swiftclient.client.Connection") as MockConnection:
conn = MockConnection.return_value
attachment.create({'name': 'a5', 'datas': self.blob1_b64})
attachment.create({"name": "a5", "datas": self.blob1_b64})
conn.put_object.assert_called_with(
container,
attachment._compute_checksum(bin_data),
bin_data)
container, attachment._compute_checksum(bin_data), bin_data
)
def test_delete_file_on_swift(self):
"""
Test deleting a file
Test deleting a file
"""
(self.env['ir.config_parameter'].
set_param('ir_attachment.location', 'swift'))
os.environ['SWIFT_AUTH_URL'] = 'auth_url'
os.environ['SWIFT_ACCOUNT'] = 'account'
os.environ['SWIFT_PASSWORD'] = 'password'
os.environ['SWIFT_PROJECT_NAME'] = 'project_name'
os.environ['SWIFT_WRITE_CONTAINER'] = 'my_container'
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
os.environ["SWIFT_AUTH_URL"] = "auth_url"
os.environ["SWIFT_ACCOUNT"] = "account"
os.environ["SWIFT_PASSWORD"] = "password"
os.environ["SWIFT_PROJECT_NAME"] = "project_name"
os.environ["SWIFT_WRITE_CONTAINER"] = "my_container"
attachment = self.Attachment
container = os.environ.get('SWIFT_WRITE_CONTAINER')
with patch('swiftclient.client.Connection') as MockConnection:
container = os.environ.get("SWIFT_WRITE_CONTAINER")
with patch("swiftclient.client.Connection") as MockConnection:
conn = MockConnection.return_value
a5 = attachment.create({'name': 'a5', 'datas': self.blob1_b64})
a5 = attachment.create({"name": "a5", "datas": self.blob1_b64})
uri = SwiftUri(a5.store_fname)
a5.unlink()
conn.delete_object.assert_called_with(container, uri.item())
+12 -13
View File
@@ -1,10 +1,12 @@
# Copyright 2017-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment
from ..swift_uri import SwiftUri
from swiftclient.exceptions import ClientException
from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment
from ..swift_uri import SwiftUri
class TestAttachmentSwift(TestIrAttachment):
"""
@@ -13,27 +15,24 @@ class TestAttachmentSwift(TestIrAttachment):
def setup(self):
super().setUp()
self.env['ir.config_parameter'].set_param('ir_attachment.location',
'swift')
self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift")
def test_connection(self):
""" Test the connection to the Swift object store """
"""Test the connection to the Swift object store"""
conn = self.Attachment._get_swift_connection()
self.assertNotEqual(conn, False)
def test_store_file_on_swift(self):
""" Test writing a file and then reading it """
(self.env['ir.config_parameter'].
set_param('ir_attachment.location', 'swift'))
a5 = self.Attachment.create({'name': 'a5', 'datas': self.blob1_b64})
"""Test writing a file and then reading it"""
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
a5 = self.Attachment.create({"name": "a5", "datas": self.blob1_b64})
a5bis = self.Attachment.browse(a5.id)[0]
self.assertEqual(a5.datas, a5bis.datas)
def test_delete_file_on_swift(self):
""" Create a file and then test the deletion """
(self.env['ir.config_parameter'].
set_param('ir_attachment.location', 'swift'))
a5 = self.Attachment.create({'name': 'a5', 'datas': self.blob1_b64})
"""Create a file and then test the deletion"""
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
a5 = self.Attachment.create({"name": "a5", "datas": self.blob1_b64})
uri = SwiftUri(a5.store_fname)
con = self.Attachment._get_swift_connection()
con.get_object(uri.container(), uri.item())