Julia. Par oĂč commencer le projet? ...


TrĂšs souvent, lors de la rĂ©solution de problĂšmes d'analyse et de prĂ©paration de donnĂ©es, des scripts uniques sont Ă©crits, dont le support et le dĂ©veloppement ne sont pas fournis du tout. Cette approche a le droit d'exister, notamment dans la communautĂ© Ă©tudiante. Cependant, lorsque plusieurs personnes travaillent avec le code ou si le code doit ĂȘtre conservĂ© pendant plus d'une journĂ©e de travail, l'option d'organiser le travail sous la forme d'un tas de fichiers n'est pas acceptable.
Par conséquent, aujourd'hui, nous allons parler d'un sujet aussi important que la création d'un projet à partir de zéro dans la langue Julia, comment le remplir et quels outils technologiques existent pour soutenir le développement.


Projet


Comme dĂ©jĂ  mentionnĂ©, les scripts Ă  usage unique ou les ordinateurs portables Jupyter ont le droit d'exister sur le bureau d'une seule personne, en particulier lorsque le langage de programmation est utilisĂ© comme une calculatrice avancĂ©e. Mais cette approche est totalement inadaptĂ©e au dĂ©veloppement de projets qui devraient ĂȘtre dĂ©veloppĂ©s et exploitĂ©s pendant des annĂ©es. Et, bien sĂ»r, Julia, en tant que plate-forme technologique, dispose d'outils qui offrent aux dĂ©veloppeurs cette opportunitĂ©.


Pour commencer, quelques points généraux. Julia dispose d'un module Pkg pour la gestion des packages. Toute bibliothÚque Julia est un module. Si le module n'est pas inclus dans le kit de base Julia, il est émis dans un package séparé. Pour chaque package, il existe un fichier projet Project.toml , qui contient une description du projet et sa dépendance vis-à-vis des autres packages. Il existe un deuxiÚme fichier - Manifest.toml , qui, contrairement à Project.toml , est généré automatiquement et contient une liste de toutes les dépendances nécessaires avec les numéros de version des packages. Le format de fichier Toml est Tom's Obvious, Minimal Language .


RÚgles de dénomination des packages


Selon la documentation , le nom du package peut ĂȘtre composĂ© de lettres et de chiffres latins. Et ce nom doit ĂȘtre choisi de telle maniĂšre qu'il soit clair pour la plupart des utilisateurs de Julia, et pas seulement pour les experts dans un domaine restreint.


  • Le jargon et les contractions controversĂ©es utilisĂ©s diffĂ©remment dans diffĂ©rents domaines doivent ĂȘtre Ă©vitĂ©s.
  • N'utilisez pas le mot Julia dans le nom du package.
  • Les packages qui fournissent certaines fonctions ainsi que les nouveaux types qui y sont dĂ©clarĂ©s doivent ĂȘtre nommĂ©s au pluriel.
    ◩ DataFrames fournit un type DataFrame.
    ◩ BloomFilters fournit le type BloomFilter.
    ◩ Dans le mĂȘme temps, JuliaParser ne fournit pas de nouveau type et la nouvelle fonctionnalitĂ© est la fonction JuliaParser.parse ().
  • La transparence et l'intelligibilitĂ© en utilisant le nom complet doivent ĂȘtre prĂ©fĂ©rĂ©es Ă  l'abrĂ©viation. RandomMatrices moins ambigu que RndMat ou RMT .
  • Le nom peut correspondre aux spĂ©cificitĂ©s du domaine. Exemples:
    ◩ Julia n'a pas ses propres packages de dessin graphique. Au lieu de cela, il existe des packages Gadfly , PyPlot , Winston , etc., chacun implĂ©mentant sa propre approche et mĂ©thodologie d'utilisation.
    ◩ En mĂȘme temps, SortingAlgorithms fournit une interface complĂšte pour l'utilisation d'algorithmes de tri.
  • Dans les cas oĂč les packages sont un wrapper sur certaines bibliothĂšques tierces, ils conservent le nom de cette bibliothĂšque. Exemples:
    ◩ CPLEX.jl est un wrapper sur la bibliothùque CPLEX .
    ◩ MATLAB.jl fournit une interface pour activer MATLAB partir de Julia.

Dans le mĂȘme temps, le nom du dĂ©pĂŽt git a gĂ©nĂ©ralement le suffixe «.jl».


Génération de packages


La façon la plus simple de crĂ©er un package est de le gĂ©nĂ©rer avec un gĂ©nĂ©rateur intĂ©grĂ© Ă  Julia. Pour ce faire, dans la console, vous devez aller dans le rĂ©pertoire dans lequel le package doit ĂȘtre crĂ©Ă©, puis exĂ©cuter julia et le mettre en mode de gestion de package:


 julia> ] 

La derniÚre étape consiste à démarrer le générateur de package en spécifiant le nom que nous voulons donner au package.


 (v1.2) pkg> generate HelloWorld 

En consĂ©quence, un nouveau rĂ©pertoire apparaĂźt dans le rĂ©pertoire courant correspondant au nom du package, dont la composition peut ĂȘtre vue Ă  l'aide de la commande tree (si elle est installĂ©e):


 shell> cd HelloWorld shell> tree . . ├── Project.toml └── src └── HelloWorld.jl 1 directory, 2 files 

Dans ce cas, nous voyons un ensemble de fichiers minimal mais insuffisant pour un projet bien conçu. Pour plus de détails, voir https://julialang.imtqy.com/Pkg.jl/v1/creating-packages/ .


Une autre façon de crĂ©er des packages est d' utiliser le gĂ©nĂ©rateur PkgTemplates.jl . Contrairement au gĂ©nĂ©rateur intĂ©grĂ©, il vous permet de gĂ©nĂ©rer immĂ©diatement un ensemble complet de fichiers de service pour l'entretien du package. Le seul inconvĂ©nient est qu'il doit ĂȘtre installĂ© en tant que package.


La procédure de création d'un package avec son aide est la suivante. Nous connectons un package:


 julia> using PkgTemplates 

Nous créons un modÚle qui comprend une liste d'auteurs, une licence, les exigences pour Julia, une liste de plugins pour les systÚmes d'intégration continue (un exemple de la documentation pour PkgTemplates ):


 julia> t = Template(; user="myusername", #   github license="ISC", #   authors=["Chris de Graaf", "Invenia Technical Computing Corporation"], dir="~/code", # ,    julia_version=v"1.0", #   Julia plugins=[ #     TravisCI(), Codecov(), Coveralls(), AppVeyor(), GitHubPages(), CirrusCI(), ], ) 

Nous obtenons le modĂšle:


 Template: → User: myusername → Host: github.com → License: ISC (Chris de Graaf, Invenia Technical Computing Corporation 2018) → Package directory: ~/code → Minimum Julia version: v0.7 → SSH remote: No → Commit Manifest.toml: No → Plugins: ‱ AppVeyor: → Config file: Default → 0 gitignore entries ‱ Codecov: → Config file: None → 3 gitignore entries: "*.jl.cov", "*.jl.*.cov", "*.jl.mem" ‱ Coveralls: → Config file: None → 3 gitignore entries: "*.jl.cov", "*.jl.*.cov", "*.jl.mem" ‱ GitHubPages: → 0 asset files → 2 gitignore entries: "/docs/build/", "/docs/site/" ‱ TravisCI: → Config file: Default → 0 gitignore entries 

Maintenant, en utilisant ce modÚle, nous pouvons créer des packages simplement en spécifiant leur nom:


 julia> generate(t, "MyPkg1") 

Dans une version minimale, le modĂšle peut ressembler Ă  ceci:


 julia> t = Template(; user="rssdev10", authors=["rssdev10"]) Template: → User: rssdev10 → Host: github.com → License: MIT (rssdev10 2019) → Package directory: ~/.julia/dev → Minimum Julia version: v1.0 → SSH remote: No → Add packages to main environment: Yes → Commit Manifest.toml: No → Plugins: None 

Si nous créons un package nommé MyPkg2 à partir de ce modÚle:


 julia> generate(t, "MyPkg2") 

Ensuite, nous pouvons vérifier le résultat directement de Julia:


 julia> run(`git -C $(joinpath(t.dir, "MyPkg2")) ls-files`); .appveyor.yml .gitignore .travis.yml LICENSE Project.toml README.md REQUIRE docs/Manifest.toml docs/Project.toml docs/make.jl docs/src/index.md src/MyPkg2.jl test/runtests.jl 

Les champs suivants sont Ă  noter:


  • user="myusername" , est le nom de l'entrĂ©e d'enregistrement git.
  • dir - rĂ©pertoire pour le placement du code du package. S'il n'est pas spĂ©cifiĂ©, il sera crĂ©Ă© dans le rĂ©pertoire de dĂ©veloppement ~/.julia/dev . De plus, conformĂ©ment aux rĂšgles des systĂšmes de fichiers Unix, le ~/.julia est cachĂ©.

AprÚs avoir créé le projet, un ensemble suffisant de fichiers sera généré et un référentiel git sera créé. De plus, tous les fichiers générés seront ajoutés automatiquement à ce référentiel.


Emplacement de fichier typique dans un projet


Nous emprunterons une image avec une disposition typique des fichiers et de leur contenu Ă  https://en.wikibooks.org/wiki/Introducing_Julia/Modules_and_packages , mais nous allons l'Ă©tendre un peu:


 Calculus.jl/ #    Calculus deps/ #       docs/ #       src/ #    Calculus.jl #    —   . module Calculus #        ! import Base.ctranspose #     , export derivative, check_gradient, #      ... include("derivative.jl") #     include("check_derivative.jl") include("integrate.jl") import .Derivative end #   Calculus.jl derivative.jl #     - , module Derivative #    Calculus.jl export derivative function derivative() ... end 
 end check_derivative.jl #     , function check_derivative(f::...)#     ... # "include("check_derivative.jl")"  Calculus.jl end 
 integrate.jl #     , function adaptive_simpsons_inner(f::Funct#      Calculus.jl ... end ... symbolic.jl #     Calculus.jl export processExpr, BasicVariable, ...#       import Base.show, ... #     Base , type BasicVariable <: AbstractVariable# ...       ... end function process(x::Expr) ... end ... test/ #     Calculus runtests.jl #     using Calculus #    Calculus... using Test #   Base.Test... tests = ["finite_difference", ... #  -   ... for t in tests include("$(t).jl") # ...     end ... finite_difference.jl #    -   @test ... # ...      runtests.jl ... 

Nous ajoutons que le répertoire deps peut contenir les fichiers nécessaires au bon assemblage du package. Par exemple, deps/build.jl est un script qui s'exécute automatiquement lorsque le package est installé. Le script peut contenir n'importe quel code pour la préparation des données (télécharger un ensemble de données ou effectuer un prétraitement) ou d'autres programmes nécessaires au travail.


Il convient de noter qu'il ne peut y avoir qu'un seul module principal dans un projet. Autrement dit, dans l'exemple ci-dessus - Calculus . Cependant, dans le mĂȘme exemple, il existe un module imbriquĂ© Derivative qui se connecte via include . Faites attention Ă  cela. include inclut le fichier en tant que texte, et non en tant que module, ce qui se produit lors de l' using ou de l' import . Les deux derniĂšres fonctions incluent non seulement le module, mais obligent Julia Ă  le compiler en tant qu'entitĂ© distincte. De plus, Julia essaiera de trouver ce module dans les packages de dĂ©pendances et Ă©mettra un avertissement qu'il manque dans Project.toml . Par consĂ©quent, si notre tĂąche consiste Ă  crĂ©er un accĂšs hiĂ©rarchique aux fonctions, en les dĂ©limitant par des espaces de noms, nous incluons les fichiers via include et activons le module via un point, indiquant son affiliation locale. Soit:


 module Calculus include("derivative.jl") import .Derivative ... end 

La fonction derivative qui est exportée à partir du module Derivative sera disponible pour nous via Calculus.Derivative.derivative()


Fichier de projet Project.toml


Le fichier de projet est un fichier texte. Ses sections principales sont décrites dans la description https://julialang.imtqy.com/Pkg.jl/v1/toml-files/


Une fois le fichier gĂ©nĂ©rĂ©, tous les champs nĂ©cessaires y sont dĂ©jĂ  prĂ©sents. Cependant, vous devrez peut-ĂȘtre modifier une partie de la description, modifier la composition des packages, leurs versions et les dĂ©pendances spĂ©cifiques des diffĂ©rents systĂšmes d'exploitation ou configurations.


Les principaux domaines sont:


 name = "Example" uuid = "7876af07-990d-54b4-ab0e-23690620f79a" version = "1.2.5" 

name - le nom du package choisi selon les rĂšgles de nommage. uuid est un identifiant unifiĂ© qui peut ĂȘtre gĂ©nĂ©rĂ© par un gĂ©nĂ©rateur de package ou tout autre gĂ©nĂ©rateur uuid . version - numĂ©ro de version du package au format de trois nombres dĂ©cimaux sĂ©parĂ©s par des points. Ceci est conforme au format de Semantic Versioning 2.0.0 . Avant la version 1.0.0 dĂ©clarĂ©e, toute modification de l'interface du programme est possible. AprĂšs la sortie de cette version, le propriĂ©taire du package doit respecter les rĂšgles de compatibilitĂ©. Toute modification compatible doit ĂȘtre reflĂ©tĂ©e dans le numĂ©ro mineur (Ă  droite). Les modifications incompatibles doivent ĂȘtre accompagnĂ©es d'une modification du nombre Ă©levĂ©. Naturellement, il n'y a pas de contrĂŽle automatique sur la rĂšgle de versionnage, mais le non-respect de la rĂšgle entraĂźnera simplement le fait que les utilisateurs du package commenceront Ă  cesser massivement d'utiliser et Ă  migrer vers le package dont les auteurs se conformeront Ă  cette rĂšgle.


Toutes les dépendances de package sont présentées dans la section [deps] .


 [deps] Example = "7876af07-990d-54b4-ab0e-23690620f79a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 

Cette section contient une liste des dépendances directes de notre package. Les dépendances en cascade sont reflétées dans le fichier Manifest.toml , qui est automatiquement généré dans le répertoire du projet. Toutes les dépendances sont représentées par = paires = . Et, généralement, cette partie n'est pas remplie de mains. Pour cela, les fonctions du package Pkg sont fournies. Et, le plus souvent, cela se fait à partir de REPL , en le basculant en mode de gestion des packages - ] . Suivant - les opérations add , rm , st , etc., mais toujours dans le contexte du package actuel. Sinon, vous devez exécuter activate . .


Manifest.toml peut ĂȘtre enregistrĂ© dans le systĂšme de contrĂŽle de version git . Cette approche avec deux fichiers vous permet de fixer de maniĂšre rigide les packages dans l'arborescence de dĂ©pendances pendant le test du produit logiciel, aprĂšs quoi il est garanti que si notre package est dĂ©ployĂ© dans un nouvel emplacement, les mĂȘmes versions de packages tiers seront rĂ©pĂ©tĂ©es au mĂȘme endroit. Ou, Ă  l'inverse, en l'absence de Manifest.toml aurez la possibilitĂ© d'utiliser toutes les versions disponibles qui satisfont aux conditions de base.


La section [compat] vous permet de spécifier des versions spécifiques des packages dont nous avons besoin.


 [deps] Example = "7876af07-990d-54b4-ab0e-23690620f79a" [compat] Example = "1.2" julia = "1.1" 

Les packages sont identifiĂ©s par le nom prĂ©cĂ©demment utilisĂ© dans la section [compat] . julia indique la version de Julia elle-mĂȘme.


Lors de la spĂ©cification des versions, les rĂšgles rĂ©pertoriĂ©es dans https://julialang.imtqy.com/Pkg.jl/dev/compatibility/ s'appliquent. Cependant, les mĂȘmes rĂšgles sont spĂ©cifiĂ©es dans le versioning sĂ©mantique .


Il existe plusieurs rĂšgles de version. Par exemple:


 [compat] Example = "1.2, 2" 

signifie que toute version de la gamme [1.2.0, 3.0.0) convient, à l' 3.0.0 . Et cela est parfaitement cohérent avec une rÚgle plus simple:


 [compat] Example = "1.2" 

De plus, la simple spécification du numéro de version est une forme abrégée de "^1.2" . Un exemple de l'application qui ressemble à:


 [compat] PkgA = "^1.2.3" # [1.2.3, 2.0.0) PkgB = "^1.2" # [1.2.0, 2.0.0) PkgC = "^1" # [1.0.0, 2.0.0) PkgD = "^0.2.3" # [0.2.3, 0.3.0) PkgE = "^0.0.3" # [0.0.3, 0.0.4) PkgF = "^0.0" # [0.0.0, 0.1.0) PkgG = "^0" # [0.0.0, 1.0.0) 

Si nous devons spécifier des restrictions plus strictes, il est nécessaire d'utiliser un formulaire avec un tilde.


 [compat] PkgA = "~1.2.3" # [1.2.3, 1.3.0) PkgB = "~1.2" # [1.2.0, 1.3.0) PkgC = "~1" # [1.0.0, 2.0.0) PkgD = "~0.2.3" # [0.2.3, 0.3.0) PkgE = "~0.0.3" # [0.0.3, 0.0.4) PkgF = "~0.0" # [0.0.0, 0.1.0) PkgG = "~0" # [0.0.0, 1.0.0) 

Eh bien et, bien sûr, une indication de signes / inégalités égaux est disponible:


 [compat] PkgA = ">= 1.2.3" # [1.2.3, ∞) PkgB = "≄ 1.2.3" # [1.2.3, ∞) PkgC = "= 1.2.3" # [1.2.3, 1.2.3] PkgD = "< 1.2.3" # [0.0.0, 1.2.2] 

Il est possible de spécifier plusieurs options pour les dépendances dans la section [targets] . Traditionnellement, dans Julia avant la version 1.2, il était utilisé pour spécifier les dépendances pour l'utilisation du package et pour l'exécution des tests. Pour ce faire, des packages supplémentaires ont été spécifiés dans la section [extras] , et les configurations cibles avec des noms de packages ont été répertoriées dans [targets] .


 [extras] Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["Markdown", "Test"] 

À partir de Julia 1.2, il est recommandĂ© d'ajouter simplement un fichier de projet distinct pour les test/Project.toml .


Dépendances supplémentaires


Des dĂ©pendances supplĂ©mentaires peuvent ĂȘtre connectĂ©es via le deps/build.jl , cependant, le fichier Artifacts.toml est fourni dans la structure du projet Julia. La Pkg.Artifacts gestion de projet Pkg.Artifacts fournit des fonctions pour automatiser le chargement de dĂ©pendances supplĂ©mentaires. Un exemple d'un tel fichier:


 # Example Artifacts.toml file [socrates] git-tree-sha1 = "43563e7631a7eafae1f9f8d9d332e3de44ad7239" lazy = true [[socrates.download]] url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.gz" sha256 = "e65d2f13f2085f2c279830e863292312a72930fee5ba3c792b14c33ce5c5cc58" [[socrates.download]] url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.bz2" sha256 = "13fc17b97be41763b02cbb80e9d048302cec3bd3d446c2ed6e8210bddcd3ac76" [[c_simple]] arch = "x86_64" git-tree-sha1 = "4bdf4556050cb55b67b211d4e78009aaec378cbc" libc = "musl" os = "linux" [[c_simple.download]] sha256 = "411d6befd49942826ea1e59041bddf7dbb72fb871bb03165bf4e164b13ab5130" url = "https://github.com/JuliaBinaryWrappers/c_simple_jll.jl/releases/download/c_simple+v1.2.3+0/c_simple.v1.2.3.x86_64-linux-musl.tar.gz" [[c_simple]] arch = "x86_64" git-tree-sha1 = "51264dbc770cd38aeb15f93536c29dc38c727e4c" os = "macos" [[c_simple.download]] sha256 = "6c17d9e1dc95ba86ec7462637824afe7a25b8509cc51453f0eb86eda03ed4dc3" url = "https://github.com/JuliaBinaryWrappers/c_simple_jll.jl/releases/download/c_simple+v1.2.3+0/c_simple.v1.2.3.x86_64-apple-darwin14.tar.gz" [processed_output] git-tree-sha1 = "1c223e66f1a8e0fae1f9fcb9d3f2e3ce48a82200" 

Nous ne nous attarderons pas plus en détail, car la suite de la description dépend du cas d'utilisation spécifique. Les fonctions de bibliothÚque artifact_hash , download , create_artifact , bind_artifact . Voir la documentation https://julialang.imtqy.com/Pkg.jl/dev/artifacts/ pour plus de détails.


Implémentation et débogage du code principal


Bien sûr, nous spécifions explicitement ou implicitement le répertoire de développement lors de la création du package. Cependant, si nécessaire, nous pouvons le changer. Si le package a été généré par PkgTemplates avec des paramÚtres par défaut, recherchez-le dans le ~/.julia/dev . Malgré le fait que le répertoire soit caché, la transition vers celui-ci est possible via un lien direct dans le navigateur de fichiers. Pour MacOS dans le Finder, par exemple, cela se fait en appuyant sur Commande + Maj + G. Si le package est créé dans un autre répertoire, ouvrez-le simplement dans un éditeur de texte. Le meilleur éditeur pour travailler avec du code Julia est Atom et tout ce que le plugin uber-juno prend en charge. Dans ce cas, vous obtenez un éditeur de texte avec mise en forme automatique du code, une console REPL pour l'exécution interactive de code, la possibilité d'exécuter uniquement des fragments de code sélectionnés et d'afficher les résultats, y compris l'affichage de graphiques. Et aussi, un débogueur pas à pas. Bien que, nous devons admettre que pour le moment, il est assez lent, donc le mode de débogage actuel - nous pensons d'abord que nous voulons vérifier et mettre la sortie de débogage, puis nous exécutons le test pour le tester.


Il est recommandĂ© de regarder les modĂšles de conception courants pour les langages de programmation dynamiques . En outre, le livre "Patterns de conception pratique avec Julia 1.0. Tom Kwong" et un exemple de code pour cela . Et lors de la mise en Ɠuvre de programmes, vous devez tenir compte des recommandations sur le style de programmation Julia Style Guide .


Parmi les subtilitĂ©s du dĂ©bogage, le package Revise.jl peut ĂȘtre notĂ©. Son activation peut ĂȘtre dĂ©finie dans le fichier .julia/config/startup.jl uniquement pour le mode interactif, dans lequel REPL peut ĂȘtre exĂ©cutĂ© Ă  partir de l'Ă©diteur Atom. Revise vous permet de modifier le code de fonction dans notre package sans redĂ©marrer la session REPL, et chaque exĂ©cution en utilisant / import dans nos tests activera ces mises Ă  jour.


Pour un dĂ©veloppement efficace, il est recommandĂ© de dĂ©velopper en parallĂšle le code principal et les tests qui le testent. Cela vous permet d'implĂ©menter uniquement ce qui est vraiment nĂ©cessaire, car sinon, dans les tests, il y aura Ă©videmment des fonctions inutiles. Par consĂ©quent, ils doivent ĂȘtre supprimĂ©s. En substance, Julia n'offre rien de spĂ©cifique dans les principes de dĂ©veloppement. Cependant, l'accent est mis sur le dĂ©veloppement par le biais de tests unitaires, car Julia compile le code assez lentement et en mode de dĂ©bogage Ă©tape par Ă©tape, les performances sont trĂšs rĂ©duites. Autrement dit, cela dĂ©pend du dĂ©veloppement des tests, de leur organisation, de la rapiditĂ© avec laquelle le package en cours de dĂ©veloppement sera dĂ©boguĂ© et vĂ©rifiĂ©.


Les tests


Un emplacement de test typique est le répertoire de test. Le fichier test/runtests.jl est le point de départ de tous les tests.


En ce qui concerne l'exemple mentionné ci-dessus, la forme typique du fichier est:


 using Calculus #    Calculus  ... using Test #   Test... tests = ["finite_difference", "..."]#      -... for t in tests include("$(t).jl") #        end 

Il est recommandĂ© de dĂ©velopper des fichiers de tests spĂ©cifiques sur la base du regroupement des fonctions testĂ©es. Par exemple, dans le module de Calculus mentionnĂ©, divers algorithmes de calcul de dĂ©rivĂ©s, d'intĂ©grales, etc. peuvent ĂȘtre prĂ©sents, il sera logique de les tester avec diffĂ©rents tests situĂ©s dans diffĂ©rents fichiers.


Pour les tests unitaires, Julia fournit le module Test partir de l'ensemble de bibliothÚques de base. La macro @test est définie dans ce module, dont le but est de vérifier l'exactitude de l'instruction spécifiée. Exemples:


 julia> @test true Test Passed julia> @test [1, 2] + [2, 1] == [3, 3] Test Passed julia> @test π ≈ 3.14 atol=0.01 Test Passed 

Faites attention Ă  la forme complĂšte de l'opĂ©rateur de comparaison approximatif ≈ .


L'instruction vérifiant le choix de l'exception est @test_throws . Exemple - créez un tableau et accédez à l'index au-delà:


 julia> @test_throws BoundsError [1, 2, 3][4] Test Passed Thrown: BoundsError 

Une construction utile est @testset . Il vous permet de regrouper des instructions individuelles dans un test connecté de maniÚre logique. Par exemple:


 julia> @testset "trigonometric identities" begin Ξ = 2/3*π @test sin(-Ξ) ≈ -sin(Ξ) @test cos(-Ξ) ≈ cos(Ξ) @test sin(2Ξ) ≈ 2*sin(Ξ)*cos(Ξ) @test cos(2Ξ) ≈ cos(Ξ)^2 - sin(Ξ)^2 end; Test Summary: | Pass Total trigonometric identities | 4 4 

Pour chaque ensemble dĂ©clarĂ© via @testset , sa propre table de tests rĂ©ussis est formĂ©e. Les suites de tests peuvent ĂȘtre imbriquĂ©es. En cas de rĂ©ussite de leur passage, un tableau rĂ©capitulatif est Ă©mis, en cas d'Ă©chec - pour chaque groupe de tests ses propres statistiques seront Ă©mises.


 julia> @testset "Foo Tests" begin @testset "Animals" begin @testset "Felines" begin @test foo("cat") == 9 end @testset "Canines" begin @test foo("dog") == 9 end end @testset "Arrays" begin @test foo(zeros(2)) == 4 @test foo(fill(1.0, 4)) == 15 end end Arrays: Test Failed Expression: foo(fill(1.0, 4)) == 15 Evaluated: 16 == 15 [...] Test Summary: | Pass Fail Total Foo Tests | 3 1 4 Animals | 2 2 Arrays | 1 1 2 ERROR: Some tests did not pass: 3 passed, 1 failed, 0 errored, 0 broken. 

@test_broken , @test_skip .



. julia :


  --code-coverage={none|user|all}, --code-coverage Count executions of source lines (omitting setting is equivalent to "user") --code-coverage=tracefile.info Append coverage information to the LCOV tracefile (filename supports format tokens). --track-allocation={none|user|all}, --track-allocation Count bytes allocated by each source line (omitting setting is equivalent to "user") 

code-coverage — . ( ), . , . .cov . .
:


  - function vectorize(str::String) 96 tokens = str |> tokenizer |> wordpiece 48 text = ["[CLS]"; tokens; "[SEP]"] 48 token_indices = vocab(text) 48 segment_indices = [fill(1, length(tokens) + 2);] 48 sample = (tok = token_indices, segment = segment_indices) 48 bert_embedding = sample |> bert_model.embed 48 collect(sum(bert_embedding, dims=2)[:]) - end 

track-allocation — . , , , , .mem .


:


  - function vectorize(str::String) 0 tokens = str |> tokenizer |> wordpiece 6766790 text = ["[CLS]"; tokens; "[SEP]"] 0 token_indices = vocab(text) 11392 segment_indices = [fill(1, length(tokens) + 2);] 1536 sample = (tok = token_indices, segment = segment_indices) 0 bert_embedding = sample |> bert_model.embed 170496 collect(sum(bert_embedding, dims=2)[:]) - end 

, . , , , , . , . .


— :


 julia --project=@. --code-coverage --track-allocation test/runtests.jl 

— Profile.jl @profile . https://julialang.org/blog/2019/09/profilers . @noinline , . , fib fib_r .


 julia> @noinline function fib(n) return n > 1 ? fib_r(n - 1) + fib_r(n - 2) : 1 end julia> @noinline fib_r(n) = fib(n) julia> @time fib(40) 0.738735 seconds (3.16 k allocations: 176.626 KiB) 165580141 julia> using Profile julia> @profile fib(40) 165580141 julia> Profile.print(format=:flat, sortedby=:count) Count File Line Function 12 int.jl 52 - 14 int.jl 53 + 212 boot.jl 330 eval 5717 REPL[2] 1 fib_r 6028 REPL[1] 2 fib julia> count(==(0), Profile.fetch()) 585 

@profile fib(40) . Profile.print(format=:flat, sortedby=:count) . , , , fib_r fib , . , :


 julia> Profile.print(format=:tree) 260 REPL[1]:2; fib(::Int64) 112 REPL[1]:1; fib_r(::Int64) 212 task.jl:333; REPL.var"##26#27" 212 REPL.jl:118; macro expansion 212 REPL.jl:86; eval_user_input 212 boot.jl:330; eval ╎ 210 REPL[1]:2; fib ╎ 210 REPL[1]:1; fib_r ╎ 210 REPL[1]:2; fib ╎ 210 REPL[1]:1; fib_r ╎ 210 REPL[1]:2; fib ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ ╎ 210 REPL[1]:2; fib ... 

. PProf.jl, .



. https://github.com/vchuravy/PProf.jl .



doc . https://habr.com/ru/post/439442/
, , Julia .


Project.toml , . , , - , , .



, , . , — . :



, , . , , git clone, . PackageCompiler.jl . , , - .


C


- , , ( - , ), deps, deps/build.jl . . , , , . , , , , . , , build.jl , :


 #!/usr/bin/env julia --project=@. using Pkg Pkg.activate(".") Pkg.build() # Pkg.build(; verbose = true) for Julia 1.1 and up Pkg.test() # (coverage=true) 

. julia --project=@. Julia Project.toml . , — build.jl , executable . , julia --project=@. build.jl .


Pkg.activate(".") ( Project.toml ).


Pkg.build() , C-, . deps/build.jl , .


Pkg.test() . , -, , . -, , . coverage=true . , . build.jl .


, . , PkgTempletes . — Gitlab CI, Travis CI, GitHub , .


Conclusion


, , Julia. , , . , — , -, , . , .


Les références


Source: https://habr.com/ru/post/fr473290/


All Articles