2024 Clojure 状态调查中分享您的想法!

欢迎!请参阅关于页面以获取更多关于此工作的信息。

0
Spec by
此问题是在以下讨论的背景下检测到的 https://groups.google.com/d/msg/clojure/mIlKaOiujlo/tF71zZ2BCwAJ

以下是一个规格错误报告失败的示例,它看起来像这样

他使用了一个无效的ns形式

(ns foo (require [clojure.spec :as s])) ; 应该是 :require
 

规格报告的错误

在:[1] val:((require [clojure.spec :as s])) 在 [:args] 处失败:谓词:(cat :docstring (? string?) :attr-map (? map?) :clauses :clojure.core.specs/ns-clauses),  额外输入
:clojure.spec/args  (foo (require [clojure.spec :as s]))
  clojure.core/ex-info (core.clj:4725)


虽然错误在技术上是真的,但它没有显示用户如何/每个报告的s/cat的替代选项失败。

为了更好地理解为什么用户数据不正确,他应该确切知道规格尝试了什么以及它如何失败。

好的,s/alt是一个很好的例子,其中所有失败的替代选项都始终报告给用户。

已调查此问题,首先在现场实验中,然后在规格代码中。  最后,附带了类似s/alts的错误报告补丁。

已观察到spec为具有可选分支的cat的错误报告行为如下:

1. 如果cat在经过一个或多个可选分支后失败,则整个cat报告为失败。
2. 如果cat在经过一个或多个可选分支/和/随后的必需分支后失败,则只报告随后的必需分支,而对替代的任意分支不进行说明。

规则1解释了ns示例。
规则2可能严重违反用户的直观感觉


(s/explain (s/cat :maybe-num (s/? number?)
           ["3"])
        (较小地纠正版)


给出


在:[0] val:"3" 在 [:keyword] 处失败:谓词:keyword?


报告明显没有提及用户想要输入数字的意图。  相反,他相信他应该输入一个关键字。

解决方案

已编写一个简单的补丁,将op-explain改为以下行为:

- 报告s/cat中所尝试的每个替代选项。

它明显提高了报告的准确性,因为它清楚地展示了用户数据如何验证失败。


(ns foo (require [clojure.spec :as s])) ; 应该是 :require
 

现在给出了


ExceptionInfo 对clojure.core/ns的调用未符合规范
在:[1] val:((require [clojure.spec :as s])) 在 [:args :docstring] 处失败:谓词:string?
输入:[1] val:(require '[clojure.spec :as s]) 失败于:[:args :attr-map],谓词:map?
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-refer-clojure,失败在:[:args :clauses :refer-clojure :clause],谓词:#{:refer-clojure}
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-require,失败在:[:args :clauses :require :clause],谓词:#{:require}
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-import,失败在:[:args :clauses :import :clause],谓词:#{:import}
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-use,失败在:[:args :clauses :use :clause],谓词:#{:use}
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-refer,失败在:[:args :clauses :refer :clause],谓词:#{:refer}
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-load,失败在:[:args :clauses :load :clause],谓词:#{:load}
输入:[1 0] val:require 失败于 spec::clojure.core.specs/ns-gen-class,失败在:[:args :clauses :gen-class :clause],谓词:#{:gen-class}
:clojure.spec/args  (foo (require [clojure.spec :as s]))
  clojure.core/ex-info (core.clj:4725)


如果 explain-data 能够根据它们的 :path 长度对 ::s/problems 进行排序,那就更好了,这将把前两个意外选项推到最后。


(s/explain (s/cat :maybe-num (s/? number?)
           ["3"])
        (较小地纠正版)


现在给出了


输入:[0] val:"3" 失败于:[:maybe-num],谓词:number?
在:[0] val:"3" 在 [:keyword] 处失败:谓词:keyword?


虽然可以找到这类报告产生更多噪音的例子(如 defn),但根据上述原因,我认为这是正确的权衡。

- 我们程序员总是在出错时向用户索取最具体的信息 - 将同样的方法应用于 spec 错误报告是正确的。
- 在线错误报告器(s/*explain-out*)可以获得更多数据来生成更匹配用户意图的狭窄报告。

7 答案

0
by
_评论由:visibletrap_ 发布

我将在这里提出一个稍有不同的问题,因为它我认为它有相同的原因。

它应具体说明 fspec 的 :ret 已缺失,但它说失败在 :args。


(require '[clojure.spec :as s])
(require '[clojure.spec.test :as st])

(defn x [f] (f 1))

(s/fdef x
  :args (s/cat :f (s/fspec :args (s/cat :i int?))))

(st/instrument `x)

(x (fn [a] a))



主线程中发生异常 clojure.lang.ExceptionInfo:调用 #'user/x 未符合 spec
输入:[0] val:(#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]) 失败于:[:args],谓词:((cat :f (fspec :args (cat :i int?))),  额外输入
:clojure.spec/args  (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"])
:clojure.spec/failure  :instrument
:clojure.spec.test/caller  {:file "debug.clj", :line 16, :var-scope user/eval20}
 {:clojure.spec/problems [{:path [:args], :reason "Extra input", :pred ((cat :f (fspec :args (cat :i int?)))), :val (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]), :via [], :in [0]}], :clojure.spec/args (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]), :clojure.spec/failure :instrument,
...
0
by

评论由:lgs32a 发布

@alexmiller:在发布1.9版本之前决定此事如何,因为这在很大程度上改善了错误信息。自从在小组讨论中首先讨论之后,还有更多的报告称,这些错误信息不够直观,但它将修复这些问题。与此相关的是,按路径长度排序说明,如上所示(目前还没有相应的任务)。
请征询Rich的看法。

0

评论由:gshayban发表

关于规范的工作正在进行中,并且在一个独立的git仓库中进行,不受Clojure 1.9发布的影响。我们将能够独立于Clojure更新spec依赖,并最终获得修复。

0

评论由:lgs32a 发布

这影响了Clojure的编译时错误信息,而不仅仅是spec的opt-in部分。这部分编译器错误报告是损坏的,不应用与主要发布版本一起发布。在这方面,spec是一个独立的依赖还是不是真的不重要。

另外,等待spec稳定版本的用户并不一定会更新他们的spec依赖。

0

评论由:lgs32a 发布

AFAIK,更好的错误报告是Spec成为1.9的依赖的唯一原因。-请重新考虑。

0

评论由:alexmiller发表

我不知道这是在1.9之前还是之后被考虑的。根据我所了解的,这似乎是合理的。

按路径长度排序确实有一个CLJ-2063任务,它在5月份得到应用并在spec.alpha 0.1.109中发布。

0
参考:https://clojure.atlassian.net/browse/CLJ-2013(由lgs32a报告)
...