Compare commits

...

9 Commits

15 changed files with 521 additions and 339 deletions

View File

@ -5,5 +5,5 @@ clean:
.PHONY: test
test:
hy2 hy_odoo/tests/test_xml_base.hy
hy2 hy_odoo/tests/test_odoo.hy
hy hy_odoo/tests/test_xml.hy
hy hy_odoo/tests/test_odoo.hy

View File

@ -1,19 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2020-2021 Fabien Bourgeois <fabien@yaltik.com>
# Copyright 2020-2022 Fabien Bourgeois <fabien@yaltik.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import hy
import odoo, xml_base, utils

View File

@ -1,18 +0,0 @@
;; -*- coding: utf-8 -*-
;;
;; Copyright 2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
; (require [hy-odoo.macros [general odoo test]])

View File

@ -1,43 +0,0 @@
;; -*- coding: utf-8 -*-
;;
;; Copyright 2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
" Hy General Macros "
(defmacro if-python2 [python2-form python3-form]
"If running on python2, execute python2-form, else, execute python3-form"
(import sys)
(if (< (get sys.version_info 0) 3)
python2-form
python3-form))
(defmacro ustr-cast [s]
"If python2, return unicode casting, else str casting"
(if-python2 `(unicode ~s) `(str ~s)))
(defmacro hydict [dic]
"Generate dict with mangled keys, from HyDict list"
(setv mangled-dic
(list
(map
(fn [pair]
(if (even? (nth pair 0))
(mangle (nth pair 1))
(nth pair 1)))
(enumerate dic))))
`{~@mangled-dic})

View File

@ -1,58 +0,0 @@
;; -*- coding: utf-8 -*-
;;
;; Copyright 2019-2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
" Odoo related macros "
(defmacro o-cmod [model-name] `(. cls env [~model-name]))
(defmacro o-mod [model-name] `(. self env [~model-name]))
(defmacro o-cref [ref-name] `((. cls env ref) ~ref-name))
(defmacro o-ref [ref-name] `((. self env ref) ~ref-name))
(defmacro hydm [hy-domain]
"Generate Odoo domain from Hy like tuple domain"
(setv op (second hy-domain)
field (mangle (nth hy-domain 2))
value (nth hy-domain 3))
`(, ~field ~op ~value))
; Odoo ORM macros
(defmacro/g! compute-fn [field dependencies body]
"Macro to make computed definition smoother"
(setv fname f"_compute_{(mangle field)}" descr f"Computes {field}"
dependencies (list (map mangle dependencies)))
(import [hy.models [HySymbol]])
`(with-decorator (.depends api ~@dependencies)
(defn ~(HySymbol fname) [self]
~descr
~body)))
(defmacro compute-field [fname body]
"Takes fname Symbol and body to create computed field"
(setv fn-name f"_compute_{(mangle fname)}")
`(setv ~fname (~@body :compute ~fn-name)))
; Backend macros
(defmacro __ [sentence] `((py "_") ~sentence))
(defmacro logger []
`(do
(import logging)
(setv _logger (.getLogger logging --name--))))
(defmacro pdb [] `(do (import [pdb [set-trace]]) (set-trace)))

22
hy_odoo/mgeneral.hy Normal file
View File

@ -0,0 +1,22 @@
;; Copyright 2021-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" Hy General Macros "
(defmacro instance? [type record] `(isinstance ~record ~type))
(defmacro hydict [dic]
"Generate dict with mangled keys, from HyDict list"
(setv mangled-dic
(list
(map
(fn [pair]
(if (even? (nth pair 0))
(hy.mangle (nth pair 1))
(nth pair 1)))
(enumerate dic))))
`{~@mangled-dic})

46
hy_odoo/modoo.hy Normal file
View File

@ -0,0 +1,46 @@
;; Copyright 2019-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" Odoo related macros "
(defmacro o-cmod [model-name] `(. cls env [~model-name]))
(defmacro o-mod [model-name] `(. self env [~model-name]))
(defmacro o-cref [ref-name] `((. cls env ref) ~ref-name))
(defmacro o-ref [ref-name] `((. self env ref) ~ref-name))
(defmacro hydm [hy-domain]
"Generate Odoo domain from Hy like tuple domain"
(setv op (second hy-domain)
field (hy.mangle (get hy-domain 2))
value (get hy-domain 3))
`#(~field ~op ~value))
; Odoo ORM macros
#_(defmacro/g! compute-fn [field dependencies body]
"Macro to make computed definition smoother"
(setv fname f"_compute_{(hy.mangle field)}" descr f"Computes {field}"
dependencies (list (map hy.mangle dependencies)))
(import hy.models [HySymbol]
`(defn [(.depends api ~@dependencies)] ~(HySymbol fname) [self]
~descr
~body)))
(defmacro compute-field [fname body]
"Takes fname Symbol and body to create computed field"
(setv fn-name f"_compute_{(hy.mangle fname)}")
`(setv ~fname (~@body :compute ~fn-name)))
; Backend macros
(defmacro __ [sentence] `((py "_") ~sentence))
(defmacro logger []
`(do
(import logging)
(setv _logger (.getLogger logging --name--))))
(defmacro pdb [] `(do (import [pdb [set-trace]]) (set-trace)))

View File

@ -1,24 +1,11 @@
;; -*- coding: utf-8 -*-
;; Copyright 2021-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; Copyright 2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" Hy Odoo Tests Helpers and Macros "
(require [hy-odoo.macros.general [if-python2]])
(defmacro o-assert-equal [left right] `(.assertEqual self ~left ~right))
(defmacro o-assert-list-equal [left right] `(.assertListEqual self ~left ~right))
(defmacro o-assert-dict-equal [left right] `(.assertDictEqual self ~left ~right))
@ -34,10 +21,7 @@
(defmacro o-assert-is-instance [left right] `(.assertIsInstance self ~left ~right))
(defmacro o-assert-not-is-instance [left right] `(.assertNotIsInstance self ~left ~right))
(defmacro o-assert-raises [Error] `(.assertRaises self ~Error))
(defmacro o-assert-raises-regex [Error regexp]
(if-python2
`(.assertRaisesRegexp self ~Error ~regexp)
`(.assertRaisesRegex self ~Error ~regexp)))
(defmacro o-assert-raises-regex [Error regexp] `(.assertRaisesRegex self ~Error ~regexp))
(defmacro odo-assert-raises [Error body]
"Macro to test Error with self.assertRaises and do block"

View File

@ -1,54 +1,45 @@
;; -*- coding: utf-8 -*-
;; Copyright 2019-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; Copyright 2019-2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" Odoo macros and helpers "
(require [hy-odoo.macros.general [if-python2]])
(import [os [path]]
[hy-odoo.xml_base [xmlroot xmln]])
(require hyrule.collections [assoc]
hy-odoo.mgeneral [instance?])
(import os [path]
hy-odoo.xml [xmlroot xmln])
; Global helpers
(defn strdm [hy-domain]
"Generate Odoo domain from Hy like tuple domain"
(do
(setv (, op field value) hy-domain
field (mangle field)
value (if (string? value) f"'{value}'" value))
(setv #(op field value) hy-domain
field (hy.mangle field)
value (when (string? value) f"'{value}'" value))
(return f"('{field}', '{op}', {value})")))
; XML helpers functions and macros
(defn odoo [children] (xmlroot (xmln "odoo" {} children)))
(defn odoo [children] (xmlroot {"tag" "odoo" "attrs" {} "children" children}))
(defn data [&rest args]
(defn data [#* args]
"Special data node, allow optional args on data tag"
(when (= (len args) 1) (setv args (.insert (list args) 0 {})))
(xmln "data" #*args))
(when (= (len args) 1) (do (setv args (list args))
(.insert args 0 {})))
(xmln "data" #* args))
; Aliases
(defn function [&rest args] (xmln "function" #*args))
(defn record [&rest args] (xmln "record" #*args))
(defn form [&rest args] (xmln "form" #*args))
(defn tree [&rest args] (xmln "tree" #*args))
(defn search [&rest args] (xmln "search" #*args))
(defn function [#* args] (xmln "function" #*args))
(defn record [#* args] (xmln "record" #*args))
(defn form [#* args] (xmln "form" #*args))
(defn tree [#* args] (xmln "tree" #*args))
(defn search [#* args] (xmln "search" #*args))
; Actions
(defn act-window [&rest args] (xmln "act_window" #*args))
(defn act-window [#* args] (xmln "act_window" #*args))
(defn act-window-model [model attrs]
" Build new act_window from model and args"
@ -79,7 +70,7 @@
(field {"name" "value" "eval" action})]))
; Menus
(defn menuitem [&rest args] (xmln "menuitem" #*args))
(defn menuitem [#* args] (xmln "menuitem" #*args))
(defn menuitem-model [model attrs]
" Build new menuitem from model and attrs"
@ -91,21 +82,21 @@
(menuitem cloned-attrs))
; Form aliases
(defn group [&rest args] (xmln "group" #*args))
(defn header [&rest args] (xmln "header" #*args))
(defn footer [&rest args] (xmln "footer" #*args))
(defn sheet [&rest args] (xmln "sheet" #*args))
(defn button [&rest args] (xmln "button" #*args))
(defn p [&rest args] (xmln "p" #*args))
(defn xpath [&rest args] (xmln "xpath" #*args))
(defn group [#* args] (xmln "group" #*args))
(defn header [#* args] (xmln "header" #*args))
(defn footer [#* args] (xmln "footer" #*args))
(defn sheet [#* args] (xmln "sheet" #*args))
(defn button [#* args] (xmln "button" #*args))
(defn p [#* args] (xmln "p" #*args))
(defn xpath [#* args] (xmln "xpath" #*args))
(defn attribute [name value] (xmln "attribute" {"name" name} [value]))
; Fields
(defn field [&rest args]
(defn field [#* args]
"Special field allowing mangling name attribute"
(setv attrs (nth args 0))
(setv attrs (get args 0))
(when (and (instance? dict attrs) (in "name" attrs))
(assoc attrs "name" (mangle (get attrs "name")))
(assoc attrs "name" (hy.mangle (get attrs "name")))
(setv args (list args))
(assoc args 0 attrs)
(setv args (tuple args)))
@ -114,10 +105,10 @@
(defn field-name [name] (field {"name" "name"} [name]))
(defn field-model [model] (field {"name" "model"} [model]))
(defn field-inherit [xmlid] (field {"name" "inherit_id" "ref" xmlid} []))
(defn field-arch [&rest args] (field {"name" "arch" "type" "xml"} #*args))
(defn field-arch [#* args] (field {"name" "arch" "type" "xml"} #*args))
; Search
(defn filter [&rest args] (xmln "filter" #*args))
(defn filter [#* args] (xmln "filter" #*args))
; Views
(defn view [xmlid children] (record {"id" xmlid "model" "ir.ui.view"} children))
@ -152,11 +143,11 @@
(defn modulehytopy [module-path hy-files]
"Transforms hy to py for translation purpose"
(import astor)
(import [os.path [dirname]]
[io [open :as iopen]]
[hy.lex [hy-parse]]
[hy.compiler [hy-compile]]
[hy.errors [filtered-hy-exceptions]])
(import os.path [dirname]
io [open :as iopen]
hy.lex [hy-parse]
hy.compiler [hy-compile]
hy.errors [filtered-hy-exceptions])
(defn hytopy [source path]
"Hy source to Py source"
@ -165,14 +156,12 @@
(.to-source (. astor code-gen) -ast))
(for [hy-file hy-files]
(setv hy-path (% "%s/%s.hy" (, (dirname module-path) hy-file))
(setv hy-path (% "%s/%s.hy" #((dirname module-path) hy-file))
hy-source (with [o (iopen hy-path "r" :encoding "utf-8")] (.read o))
output-path (.replace hy-path ".hy" ".py")
content ["# Generate from Hy AST, for Babel translation purpose only."
"# For real source code, please see and use HY source."
(hytopy hy-source hy-path)])
(if-python2
(.insert content 0 "# -*- coding: utf-8 -*-") (continue))
(setv output-py (.join "\n" content))
(with [f (iopen output-path "w")] (.write f output-py))))

282
hy_odoo/tests/test_odoo.hy Normal file
View File

@ -0,0 +1,282 @@
;; Copyright 2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" Odoo Helpers tests "
(require
hyrule.control [defmain]
hy-odoo.mtest *)
(import unittest
functools [partial]
xml.etree.ElementTree :as ET
hy-odoo.xml [XMLDictElement]
hy-odoo.odoo :as od)
(defclass TextOdooBase [(. unittest TestCase)]
"Odoo Helpers tests"
(defn test-odoo [self]
" Test odoo function "
(setv element (od.odoo []))
(o-assert-is-instance element (. ET Element))
(o-assert-equal (. element tag) "odoo"))
(defn test-data [self]
" Test data function "
(setv element (od.data []))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal element.tag "data")
(o-assert-equal element.attrs {})
(setv element (od.data {"one" "attribute"} []))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal element.tag "data")
(o-assert-equal element.attrs {"one" "attribute"}))
(defn test-aliases [self]
" Test simple aliases to xmln "
(setv element (od.record {"one" "attribute"} "A child"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal element.tag "record")
(o-assert-equal element.attrs {"one" "attribute"})
(o-assert-equal element.children ["A child"])
(setv element (od.tree))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal element.tag "tree"))
(defn test-act-window-model [self]
" Test act_window function "
(setv element (od.act_window_model "sample.model" {"view_type" "form"}))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal element.tag "act_window")
(o-assert-equal (get (. element attrs) "view_type") "form")
(o-assert-equal (get (. element attrs) "id") "sample_model_view_action")
(o-assert-equal (get (. element attrs) "res_model") "sample.model")
(o-assert-equal (get (. element attrs) "name") "Sample Model Action"))
(defn test-menunitem-model [self]
" Test menuitem function "
(setv element (od.menuitem-model "sample.model" {"groups" "base.user_employee"}))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "menuitem")
(o-assert-equal (get (. element attrs) "groups") "base.user_employee")
(o-assert-equal (get (. element attrs) "id") "sample_model_menu")
(o-assert-equal (get (. element attrs) "action") "sample_model_view_action"))
(defn test-attribute [self]
" Test attribute function "
(setv element (od.attribute "invisible" "1"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "attribute")
(o-assert-equal (get (. element attrs) "name") "invisible")
(o-assert-equal (. element children) ["1"]))
(defn test-fields [self]
" Test fields function "
(setv element (od.field {"one" "attribute"} "A child"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal element.tag "field")
(setv element (od.field-name "A name"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "field")
(o-assert-equal (get (. element attrs) "name") "name")
(o-assert-equal (. element children) ["A name"])
(setv element (od.field-model "sample.model"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "field")
(o-assert-equal (get (. element attrs) "name") "model")
(o-assert-equal (. element children) ["sample.model"])
(setv element (od.field-inherit "module.xml_view"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "field")
(o-assert-equal (get (. element attrs) "name") "inherit_id")
(o-assert-equal (get (. element attrs) "ref") "module.xml_view")
(o-assert-false (. element children))
(setv element (od.field-arch))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "field")
(o-assert-equal (get (. element attrs) "name") "arch")
(o-assert-equal (get (. element attrs) "type") "xml")
(o-assert-false (. element children)))
(defn test-view [self]
" Test view function "
(setv element (od.view "view_xmlid" []))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "record")
(o-assert-equal (get (. element attrs) "id") "view_xmlid")
(o-assert-equal (get (. element attrs) "model") "ir.ui.view")
(o-assert-false (. element children)))
(defn test-view-def [self]
" Test view def function "
(setv element (od.view_def "view_xmlid" "View" "sample.model" []))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "record")
(o-assert-equal (get (. element attrs) "id") "view_xmlid")
(o-assert-equal (get (. element attrs) "model") "ir.ui.view")
(o-assert-equal (len (. element children)) 3)
(setv child (get (. element children) 0))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "name")
(o-assert-equal (. child children) ["View"])
(setv child (get (. element children) 1))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "model")
(o-assert-equal (. child children) ["sample.model"])
(setv child (get (. element children) 2))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "arch")
(o-assert-equal (get (. child attrs) "type") "xml")
(o-assert-false (. child children)))
(defn test-view-new [self]
" Test view-new function "
(setv element (od.view-new "tree" "sample.model" []))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element.tag) "record")
(o-assert-equal (get (. element attrs) "id") "sample_model_view_tree")
(o-assert-equal (get (. element attrs) "model") "ir.ui.view")
(o-assert-equal (len (. element children)) 3)
(setv child (get (. element children) 0))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "name")
(o-assert-equal (. child children) ["Sample Model Tree"])
(setv child (get (. element children) 1))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "model")
(o-assert-equal (. child children) ["sample.model"])
(setv child (get (. element children) 2))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "arch")
(o-assert-equal (get (. child attrs) "type") "xml")
(o-assert-false (. child children)))
(defn test_view_inherit [self]
" Test view_inherit function "
(setv element (od.view-inherit "odoo.addons.module" "sample.model" "parent.view" []))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "record")
(o-assert-equal (get (. element attrs) "id") "view_inherit_module")
(o-assert-equal (get (. element attrs) "model") "ir.ui.view")
(o-assert-equal (len (. element children)) 4)
(setv child (get (. element children) 0))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "name")
(o-assert-equal (. child children) ["Sample Model Adaptations"])
(setv child (get (. element children) 1))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "model")
(o-assert-equal (. child children) ["sample.model"])
(setv child (get (. element children) 2))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "inherit_id")
(o-assert-false (. child children))
(setv child (get (. element children) 3))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "arch")
(o-assert-equal (get (. child attrs) "type") "xml")
(o-assert-false (. child children)))
(defn test-actions-server-code [self]
" Test actions-server-code function "
(setv element (od.actions-server-code "sample.xmlid" "Code" "sample.model"
"record.do_something()"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "record")
(o-assert-equal (get (. element attrs) "id") "sample.xmlid")
(o-assert-equal (get (. element attrs) "model") "ir.actions.server")
(o-assert-equal (len (. element children)) 4)
(setv child (get (. element children) 0))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "name")
(o-assert-equal (. child children) ["Code"])
(setv child (get (. element children) 1))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "model_id")
(o-assert-equal (get (. child attrs) "ref") "sample.model")
(o-assert-false (. child children))
(setv child (get (. element children) 2))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "state")
(o-assert-equal (. child children) ["code"])
(setv child (get (. element children) 3))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "code")
(o-assert-equal (. child children) ["record.do_something()"]))
(defn test-client-action-multi [self]
" Test client_action_multi function "
(setv element (od.client-action-multi "sample.xmlid" "Multi" "sample.model" "sample.action"))
(o-assert-is-instance element XMLDictElement)
(o-assert-equal (. element tag) "record")
(o-assert-equal (get (. element attrs) "id") "sample.xmlid")
(o-assert-equal (get (. element attrs) "model") "ir.values")
(o-assert-equal (len (. element children)) 4)
(setv child (get (. element children) 0))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "name")
(o-assert-equal (. child children) ["Multi"])
(setv child (get (. element children) 1))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "key2")
(o-assert-equal (get (. child attrs) "eval") "'client_action_multi'")
(o-assert-false (. child children))
(setv child (get (. element children) 2))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "model")
(o-assert-equal (get (. child attrs) "eval") "'sample.model'")
(setv child (get (. element children) 3))
(o-assert-is-instance child XMLDictElement)
(o-assert-equal (. child tag) "field")
(o-assert-equal (get (. child attrs) "name") "value")
(o-assert-equal (get (. child attrs) "eval") "'ir.actions.server,%d'%sample.action")))
(defmain [] (.main unittest))

View File

@ -1,34 +1,26 @@
;; -*- coding: utf-8 -*-
;; Copyright 2019-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; Copyright 2019-2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
b" XML Helpers tests "
" XML Helpers tests "
(require
hyrule.control [defmain]
hy-odoo.mtest *)
(require [hy-odoo.macros.test [*]])
(import unittest
[functools [partial]]
[xml.etree.ElementTree :as ET]
[os [unlink]]
[hy-odoo.xml-base [XMLDictElement xmln xmlroot xmlchild xml-write]])
functools [partial]
xml.etree.ElementTree :as ET
os [unlink]
hy-odoo.xml [XMLDictElement xmln xmlroot xmlchild xml-write])
(defclass TextXMLBase [(. unittest TestCase)]
b"XML Helpers tests"
"XML Helpers tests"
(defn test-xmln [self]
b"Text xmln"
"Text xmln"
; XMLDictElement
(o-assert-is-instance (xmln) XMLDictElement)
; Tags
@ -54,7 +46,7 @@ b" XML Helpers tests "
(o-assert-is-instance element XMLDictElement))
(defn test-xmlchild [self]
b"Test xmlchild"
"Test xmlchild"
(setv parent (xmlroot {"tag" "root" "attrs" {} "children" []})
xmlc-par (partial xmlchild parent))
@ -68,33 +60,33 @@ b" XML Helpers tests "
(o-assert-equal (. parent text) "some text")
(xmlc-par[(xmln "t" {"a" "b"} [])])
(setv child (.next (.iter parent "t")))
(setv child (next (.iter parent "t")))
(o-assert-equal (. child tag) "t")
(o-assert-dict-equal (. child attrib) {"a" "b"})
(o-assert-list-equal (list child) [])
(xmlc-par [(xmln "t2" {1 2} [])])
(setv child (.next (.iter parent "t2")))
(setv child (next (.iter parent "t2")))
(o-assert-dict-equal (. child attrib) {"1" "2"})
(xmlc-par [(xmln "tchildren" {} [(xmln "subchild" {} [])])])
(setv child (.next (.iter parent "tchildren"))
(setv child (next (.iter parent "tchildren"))
subchildren (list child))
(o-assert-equal (len subchildren) 1)
(o-assert-equal (. (first subchildren) tag) "subchild"))
(o-assert-equal (. (get subchildren 0) tag) "subchild"))
(defn test-xmlroot [self]
b"Test xmlroot"
"Test xmlroot"
(setv root (xmlroot {"tag" "root" "attrs" {} "children" []}))
(o-assert-is-instance root (. ET Element))
(with [(o-assert-raises-regex TypeError "has no attribute")] (xmlroot False))
(with [(o-assert-raises-regex TypeError "is not subscriptable")] (xmlroot False))
(with [(o-assert-raises-regex KeyError "tag")] (xmlroot {}))
(with [(o-assert-raises-regex KeyError "attrs")] (xmlroot {"tag" "root"})))
(defn test-xml-write [self]
b"Test xml-write"
"Test xml-write"
(setv children [(xmln "child1" {"attr" "value"} [])
(xmln "child2" {} "Some text")]
@ -103,13 +95,13 @@ b" XML Helpers tests "
(o-assert-is-none (xmlw "/badpath"))
(o-assert-is-none (xmlw "/bad.ext"))
(xmlw --file--)
(setv filepath (.replace --file-- ".hy" "_views.xml"))
(xmlw __file__)
(setv filepath (.replace __file__ ".hy" "_views.xml"))
(with [output-file (open filepath "r")]
(setv output-xml (.read output-file))
(o-assert-in "<?xml version" output-xml)
(o-assert-in "<root>" output-xml)
(o-assert-in "<child1 attr=\"value\"/>" output-xml)
(o-assert-in "<child1 attr=\"value\" />" output-xml)
(o-assert-in "<child2>Some text</child2>" output-xml)
(unlink filepath))))

View File

@ -1,22 +1,13 @@
;; -*- coding: utf-8 -*-
;; Copyright 2021-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; Copyright 2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" Hy General Utils "
(require hyrule.collections [assoc])
(defn pick [keys record]
(reduce
(fn [acc key]

61
hy_odoo/xml.hy Normal file
View File

@ -0,0 +1,61 @@
;; Copyright 2019-2022 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at https://mozilla.org/MPL/2.0/.
" XML helpers and macros "
(require hy-odoo.mgeneral [instance?]
hy-odoo.modoo [pdb])
(import collections [namedtuple]
functools [partial]
os [path]
xml.etree.ElementTree :as ET)
;; Types
(setv XMLDictElement (namedtuple "XMLDictElement" ["tag" "attrs" "children"]))
;; Helpers
(defn xmlroot [tree]
"Special process for root XML Node"
(setv rootel (.Element ET (get tree "tag") (get tree "attrs")))
(when (in "children" tree)
(xmlchild rootel (get tree "children")))
(return rootel))
(defn xmlchild [parent children]
"Handling of children (ie non root) XML Nodes with/o text and subchildren
(recursive)"
(cond (instance? str children) (setv (. parent text) children)
(instance? XMLDictElement children)
(do
(setv attrs (dfor [k v] (.items (. children attrs)) [(str k) (str v)]))
(setv new-parent (.SubElement ET parent (. children tag) attrs)
subchildren (. children children))
(when subchildren) (xmlchild new-parent subchildren))
(instance? list children) (list( map (partial xmlchild parent) children))
True (raise (TypeError "Invalid arguments for xmlchild"))))
(defn xmln [[tag ""] [attrs {}] [children []]]
"XMLDictElement building from dict object, with defaults"
(when (instance? list attrs) (setv children attrs attrs {}))
(setv xmldictel (partial XMLDictElement tag attrs)
inst-str? (instance? str children))
(when inst-str? (return (xmldictel [children])))
(when (instance? list children) (return (xmldictel children)))
(raise (TypeError "Invalid arguments for xmln")))
(defn xml-write [filepath tree]
"Write XML file according to filepath and given tree"
(when (.endswith filepath ".hy")
(setv output-xml (.decode (.tostring ET
tree
:xml_declaration True
:encoding "utf-8") "utf-8")
output-path (.split (.abspath path filepath) "/")
(get output-path -1) (.replace (get output-path -1) ".hy" "_views.xml")
output-path (.join "/" output-path))
(with [output-file (open output-path "w")] (.write output-file output-xml))))

View File

@ -1,75 +0,0 @@
;; -*- coding: utf-8 -*-
;;
;; Copyright 2019-2021 Fabien Bourgeois <fabien@yaltik.com>
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
" XML helpers and macros "
(require [hy-odoo.macros.general [if-python2 ustr-cast]])
(require [hy-odoo.macros.odoo [pdb]])
(import [collections [namedtuple]]
[functools [partial]]
[os [path]]
[xml.etree.ElementTree :as ET])
;; Types
(setv XMLDictElement (namedtuple "XMLDictElement" ["tag" "attrs" "children"]))
;; Helpers
(defn xmlroot [tree]
"Special process for root XML Node"
(setv rootel (.Element ET (get tree "tag") (get tree "attrs")))
(when (in "children" tree)
(xmlchild rootel (get tree "children")))
(return rootel))
(defn xmlchild [parent children]
"Handling of children (ie non root) XML Nodes with/o text and subchildren
(recursive)"
(cond [(string? children) (setv (. parent text) children)]
[(instance? XMLDictElement children)
(do
(setv attrs (dfor [k v] (.items (. children attrs)) [(ustr-cast k) (ustr-cast v)]))
(setv new-parent (.SubElement ET parent (. children tag) attrs)
subchildren (. children children))
(when subchildren) (xmlchild new-parent subchildren))]
[(instance? list children) (list( map (partial xmlchild parent) children))]
[True (raise (TypeError "Invalid arguments for xmlchild"))]))
(defn xmln [&optional [tag ""] [attrs {}] [children []]]
"XMLDictElement building from dict object, with defaults"
(when (instance? list attrs) (setv children attrs attrs {}))
(setv xmldictel (partial XMLDictElement tag attrs)
inst-str? (if-python2 (instance? unicode children) (instance? str children)))
(when inst-str? (return (xmldictel [children])))
(when (instance? list children) (return (xmldictel children)))
(raise (TypeError "Invalid arguments for xmln")))
(defn xml-write [filepath tree]
"Write XML file according to filepath and given tree"
(when (.endswith filepath ".hy")
(if-python2
(do
(import [xml.etree.ElementTree :as ET]
[xml.dom [minidom]])
(setv output-xml (.toprettyxml :indent " "
(.parseString minidom (.tostring ET tree)))))
(setv output-xml (.decode (.tostring ET tree) "utf-8")))
(setv output-path (.split (.abspath path filepath) "/")
(cut output-path -1) [(.replace (last output-path) ".hy" "_views.xml")]
output-path (.join "/" output-path))
(with [output-file (open output-path "w")] (.write output-file output-xml))))

View File

@ -1,13 +1,30 @@
from setuptools import setup, find_packages
from setuptools.command.install import install
class install(install):
""" From hyrule, thanks """
def run(self):
super().run()
import py_compile
import hy # for compile hooks
for path in set(self.get_outputs()):
if path.endswith(".hy"):
py_compile.compile(
path,
invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
)
setup(
name="hy_odoo",
version="0.7.0pre",
version="0.8.4",
packages=find_packages(),
package_data={
'hy_odoo': ['*.hy'],
},
install_requires=["hy==0.17.Y"],
setup_requires=["hy==0.24.*", "hyrule==0.2.*"],
install_requires=["hy==0.24.*", "hyrule==0.2.*"],
author="Fabien Bourgeois",
author_email="fabien@yaltik.com",
description="HY functions and macros for Odoo",
@ -17,8 +34,12 @@ setup(
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: MPL2 License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
]
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
],
cmdclass={'install': install}
)