From d50b0500d4bf28c2f1891c137415f4540df80898 Mon Sep 17 00:00:00 2001 From: GenaRazmakhnin Date: Sun, 8 Oct 2023 20:20:02 +0200 Subject: [PATCH] python generator: alfa --- src/python-generator/base.clj | 79 +++++++++++++++++++++++++++++++ src/python-generator/exporter.clj | 13 +++-- src/python-generator/helpers.clj | 40 ++++++---------- src/python-generator/index.clj | 70 +++++++++------------------ 4 files changed, 122 insertions(+), 80 deletions(-) create mode 100644 src/python-generator/base.clj diff --git a/src/python-generator/base.clj b/src/python-generator/base.clj new file mode 100644 index 0000000..27de46c --- /dev/null +++ b/src/python-generator/base.clj @@ -0,0 +1,79 @@ +(ns python-generator.base + (:require + [python-generator.extractor :as extractors] + [python-generator.helpers :as helpers] + [cheshire.core] + [clojure.string :as str]) + (:gen-class)) + +(defn save-to [directory, filename] + (fn [text] (helpers/write-to-file directory, filename, text))) + +(defn push-to-end [string1, string2] (str string2, string1)) + +(defn combine-base-file [definition, data] + (-> (str "\nclass " (helpers/get-resource-name (:type definition)) "(BaseModel)" ":\n") + (str (clojure.string/join "\n" (:elements data)) "\n"))) + +(defn combine-file [definition, data] + (-> #_(str (helpers/add-element-import (filter boolean (:imports-element data)))) + #_(str (helpers/add-backbone-element-import (filter boolean (:imports-backbone-element data)))) + #_(push-to-end (str "if TYPE_CHECKING:\n\t\"import typings\"\n")) + #_(str "else:\n\t\"import typings\"\n") + #_((typechecking-ignore-runtime (ignore (filter boolean (:imports data))))) + #_((if (= (helpers/get-resource-name (:base definition)) "DomainResource") (fn [string] (str string "from resource.index import DomainResource\n\n")) str)) + #_((if (= (helpers/get-resource-name (:base definition)) "Resource") (fn [string] (str string "from base.resource import Resource\n\n")) str)) + #_((if (= (helpers/get-resource-name (:base definition)) "BackboneElement") (fn [string] (str string "from element.index import BackboneElement\nfrom base.index import Element\n\n")) str)) + #_((if (= (helpers/get-resource-name (:base definition)) "Element") (fn [string] (str string "from base.index import Element\n\n")) str)) + (str "\nclass " (helpers/get-resource-name (:type definition)) (helpers/get-parent (:base definition)) ":\n") + (str (clojure.string/join "\n" (:elements data)) "\n"))) + +(defn compile-single-class [] + (fn [definition] + (->> (helpers/elements-to-vector definition) + (helpers/get-typings-and-imports (or (:required definition) [])) + (combine-file definition)))) + +(defn compile-single-base-class [] + (fn [definition] + (->> (helpers/elements-to-vector definition) + (helpers/get-typings-and-imports (or (:required definition) [])) + (combine-base-file definition)))) + +(defn compile-bases [] + (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") + (extractors/filter-base) + (map (compile-single-base-class)) + (str/join))) + +(defn compile-elements [] + (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") + (extractors/filter-element) + (map (compile-single-class)) + (str/join))) + +(defn compile-backbone-elements [] + (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") + (extractors/filter-backbone-element) + (map (compile-single-class)) + (str/join))) + +(defn compile-resources [] + (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") + (extractors/filter-resource) + (map (compile-single-class)) + (str/join))) + + +(defn root-compiler [] + (->> (str (compile-resources)) + (str (compile-backbone-elements)) + (str (compile-elements)) + (str (compile-bases)) + (str "from pydantic import BaseModel\n\n") + (str "from typing import Optional\n") + (str "from __future__ import annotations\n") + ((save-to "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/base" "__init__")))) + +(root-compiler) + diff --git a/src/python-generator/exporter.clj b/src/python-generator/exporter.clj index d2973fd..14a2188 100644 --- a/src/python-generator/exporter.clj +++ b/src/python-generator/exporter.clj @@ -41,15 +41,14 @@ (helpers/write-to-file "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/backbone", "index"))) (defn domain-index [] - (helpers/write-to-file "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/domain", "__init__", "") (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") (extractors/filter-domain-resource) - (map (fn [definition] (str "from domain." (clojure.string/lower-case (helpers/get-resource-name (:type definition))) " import " (helpers/get-resource-name (:type definition)) "\n"))) + (map (fn [definition] (str "from resources." (clojure.string/lower-case (helpers/get-resource-name (:type definition))) " import " (helpers/get-resource-name (:type definition)) "\n"))) (clojure.string/join) - (helpers/write-to-file "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/domain", "index"))) + (helpers/write-to-file "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/resources", "__init__"))) -(base-index) -(element-index) -(resource-index) -(backbone-index) +;; (base-index) +;; (element-index) +;; (resource-index) +;; (backbone-index) (domain-index) diff --git a/src/python-generator/helpers.clj b/src/python-generator/helpers.clj index 35d6e12..075d8c5 100644 --- a/src/python-generator/helpers.clj +++ b/src/python-generator/helpers.clj @@ -11,6 +11,9 @@ (def backbone-elements #{"Population" "Timing" "MarketingStatus" "SubstanceAmount" "ProductShelfLife" "ProdCharacteristic" "Dosage" "ElementDefinition"}) (def primitives-string #{"dateTime" "xhtml" "Distance" "time" "date" "string" "uuid" "oid" "id" "Dosage" "Duration" "instant" "Count" "decimal" "code" "base64Binary" "unsignedInt" "url" "markdown" "uri" "positiveInt" "canonical" "Age" "Timing"}) +(defn uppercase-first-letter [string] + (str (str/upper-case (first string)) (subs string 1))) + (defn escape-keyword [word] (if (.contains #{"class", "global", "for", "import"} word) (str word "_") word)) @@ -26,23 +29,23 @@ (defn get-resource-name [reference] (last (str/split (str reference) #"/"))) -(defn get-type [type] +(defn get-type [name type] (cond + (= type "BackboneElement") (uppercase-first-letter name) (= type "boolean") "bool" (= type "integer") "int" (= type "") "str" (.contains primitives-string type) "str" :else (or type "str"))) -(defn derive-basic-type [type] - (-> (get-resource-name type) - (get-type))) +(defn derive-basic-type [name element] + (get-type name (get-resource-name (:type element)))) (defn append-default-none [string] (str string " = None")) (defn append-default-vector [string] (str string " = []")) -(defn transform-element [element required] - (->> (derive-basic-type (:type element)) +(defn transform-element [name element required] + (->> (derive-basic-type name element) ((if (:array element) wrap-vector str)) ((if (and (not required) (not (:array element))) wrap-optional str)) ((if (and (not required) (not (:array element))) append-default-none str)) @@ -52,36 +55,21 @@ (->> (seq (:elements definition)) (filter (fn [[_, v]] (not (contains? v :choices)))))) -(defn transform-element-to-type [definition] - (fn [[k, v]] (str "\t" (escape-keyword (name k)) ": " (transform-element v (.contains (or (:required definition) []) (name k)))))) - (defn get-parent [base-reference] (->> (get-resource-name base-reference) (string-interpolation "(" ")"))) (defn collect-types [required, [k, v]] - (str "\t" (escape-keyword (name k)) ": " (transform-element v (.contains required (name k))))) - -(defn collect-imports [[_, v]] - (let [type (derive-basic-type (:type v))] - (if (.contains elements type) type nil))) - -(defn collect-backbone-imports [[_, v]] - (let [type (derive-basic-type (:type v))] - (if (.contains backbone-elements type) type nil))) - -(defn add-element-import [data] - (clojure.string/join (map (fn [item] (str "from element.index import " item "\n")), data))) + (str "\t" (escape-keyword (name k)) ": " (transform-element (name k) v (.contains required (name k))))) -(defn add-backbone-element-import [data] - (clojure.string/join (map (fn [item] (str "from backbone.index import " item "\n")), data))) +(defn resolve-backbone-elements [[k, v]] + (if (= (get-resource-name (:type v)) "BackboneElement") (vector k, v) (vector))) (defn get-typings-and-imports [required, data] (reduce (fn [acc, item] (hash-map :elements (conj (:elements acc) (collect-types required item)) - :imports-element (conj (:imports-element acc) (collect-imports item)) - :imports-backbone-element (conj (:imports-backbone-element acc) (collect-backbone-imports item)))) - (hash-map :elements [] :imports-element [] :imports-backbone-element []) data)) + :backbone-elements (conj (:backbone-elements acc) (resolve-backbone-elements item)))) + (hash-map :elements [] :backbone-elements []) data)) (defn parse-ndjson-gz [path] (with-open [rdr (-> path diff --git a/src/python-generator/index.clj b/src/python-generator/index.clj index d19adfe..ec63a4e 100644 --- a/src/python-generator/index.clj +++ b/src/python-generator/index.clj @@ -1,73 +1,49 @@ (ns python-generator.index (:require - [python-generator.extractor :as extractors] - [python-generator.helpers :as helpers] [cheshire.core] - [clojure.string :as str]) + [clojure.string :as str] + [python-generator.extractor :as extractors] + [python-generator.helpers :as helpers]) (:gen-class)) (defn save-to [directory, filename] (fn [text] (helpers/write-to-file directory, filename, text))) -(defn push-to-end [string1, string2] (str string2, string1)) +(defn compile-single-backbone [definition, data] + (->> #_(str "class " (helpers/get-resource-name (:type definition)) (helpers/get-parent (:base definition)) ":\n") + (str (clojure.string/join "\n" (:elements data)) "\n\n"))) -(defn ignore [data] - (clojure.string/join (map (fn [item] (str "\t" item " = Any\n")), data))) +(defn compile-backbone [definition] + (->> (helpers/elements-to-vector definition) + (helpers/get-typings-and-imports (or (:required definition) [])) + (compile-single-backbone definition))) -(defn typechecking-ignore-runtime [string] - (fn [inner_string] (str inner_string string "\n"))) +(defn test [data] + (->> (filter (fn [item] (> (count item) 0)) (:backbone-elements data)) + (map (fn [[k, v]] + (->> (str (compile-backbone v)) + (str "class " (helpers/uppercase-first-letter (name k)) "(BackboneElement):\n")))) + (str/join))) (defn combine-file [definition, data] - (-> (str (helpers/add-element-import (filter boolean (:imports-element data)))) - (str (helpers/add-backbone-element-import (filter boolean (:imports-backbone-element data)))) - #_(push-to-end (str "if TYPE_CHECKING:\n\t\"import typings\"\n")) - (push-to-end (str "from typing import TYPE_CHECKING, Optional, Any\n\n")) - #_(push-to-end (str "from __future__ import annotations\n")) - #_(str "else:\n\t\"import typings\"\n") - #_((typechecking-ignore-runtime (ignore (filter boolean (:imports data))))) - ((if (= (helpers/get-resource-name (:base definition)) "DomainResource") (fn [string] (str string "from resource.index import DomainResource\n\n")) str)) - ((if (= (helpers/get-resource-name (:base definition)) "Resource") (fn [string] (str string "from base.resource import Resource\n\n")) str)) - ((if (= (helpers/get-resource-name (:base definition)) "BackboneElement") (fn [string] (str string "from element.index import BackboneElement\nfrom base.index import Element\n\n")) str)) - ((if (= (helpers/get-resource-name (:base definition)) "Element") (fn [string] (str string "from base.index import Element\n\n")) str)) - (str "\nclass " (helpers/get-resource-name (:type definition)) "Origin" (helpers/get-parent (:base definition)) ":\n") - (str (clojure.string/join "\n" (:elements data)) "\n\n"))) + (->> (str (clojure.string/join "\n" (:elements data)) "\n\n") + (str "class " (helpers/get-resource-name (:type definition)) (helpers/get-parent (:base definition)) ":\n") + (str (test data)) + (str "from base import *\n\n") + (str "from typing import Optional\n"))) (defn compile-single-class [directory] (fn [definition] (->> (helpers/elements-to-vector definition) (helpers/get-typings-and-imports (or (:required definition) [])) (combine-file definition) - (push-to-end (str "class " (helpers/get-resource-name (:type definition)) "(" (helpers/get-resource-name (:type definition)) "Origin)" ": pass\n")) + (str/join) ((save-to directory (str/lower-case (helpers/get-resource-name (:type definition)))))))) -(defn compile-bases [] - (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") - (extractors/filter-base) - (map (compile-single-class "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/base")))) - -(defn compile-elements [] - (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") - (extractors/filter-element) - (map (compile-single-class "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/element")))) - -(defn compile-backbone-elements [] - (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") - (extractors/filter-backbone-element) - (map (compile-single-class "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/backbone")))) - -(defn compile-resources [] - (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") - (extractors/filter-resource) - (map (compile-single-class "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/resource")))) - (defn compile-domains [] (->> (helpers/parse-ndjson-gz "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/fhir-schema/hl7.fhir.r4.core#4.0.1/package.ndjson.gz") (extractors/filter-domain-resource) - (helpers/side-effect-map (compile-single-class "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/domain")))) + (helpers/side-effect-map (compile-single-class "/Users/gena.razmakhnin/Documents/aidbox-sdk-js/test_dir/resources")))) -(compile-bases) -(compile-elements) -(compile-backbone-elements) -(compile-resources) (compile-domains)