How to provide an explicit error/failure message in the Scala fastparse library? - scala

I'm using Li Haoyi's FastParse library. I have several situations where I'd like to provide explicit failure messages.
For example:
def courseRE[p: P]: P[Regex] =
P(CharIn("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.|*+[]()-^$").repX(1).!).map { re =>
try { re.r }
catch { case e => failure(s"Ill-formed regular expression: ${re}.") }
}
But there is (apparently) no failure function.
Any suggested work-arounds? Simply throwing an exception doesn't give any context information.

I haven't yet found a good solution. I don't like the solution proposed by #user2963757 because it loses all the information from the parser about what it was looking for, where it was looking, etc.
This is raised a number of times in the FastParse issues list on GitHub. See issue 213, issue 187, issue 243, and pull request 244. There are a few vague suggestions but as far as I can tell the pull request hasn't been acted on (as of 2023-02-09).
The best I've found so far is defining this in an accessible location:
// Fail with a message. See https://github.com/com-lihaoyi/fastparse/issues/213
// The message shows up as "Expected ..."; phrase it appropriately.
private def Fail[T](expected: String)(implicit ctx: P[_]): P[T] = {
val res = ctx.freshFailure()
if (ctx.verboseFailures) ctx.setMsg(ctx.index, () => expected)
res
}
To use it:
P(CharIn("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.|*+[]()-^$").repX(1).!).flatMap(re =>
Try(re.r)
.map(Pass(_))
.getOrElse(Fail("<Well-formed regular expression>"))
)
Trying to parse "^CS1[1345" yields
Expected <Well-formed regular expression>:1:10, found ""
Notice that the failure message has to be stated in terms of what was expected, not the actual problem. The actual error message thrown by the exception usually doesn't work well in this situation. I'm also not getting the fragment that it found.
Unfortunately, even this message is usually unavailable. For example, parsing a larger piece of my input results in
Expected (courseSpecDef | minUnits | xOf | courseSpec):1:14, found "^CS1[1345 "
I'd like to be able to surface the more exact error of "Unclosed character class" but seemingly can't.
By the way, I looked in the documentation, source code, and the sample parsers (PythonParse and ScalaParse) for examples of the use of the Fail parser. Can't find any. The only one is the one shown in the documentation, which doesn't compose with another parser.
If anyone has a better solution, I'd still love to hear it.

Related

org_scalajs_dom_raw_HTMLDocument(...).createRange is not a function

I'm upgrading scalatags from 0.6.7 to 0.9.3 as part of upgrading scalaJS from 0.6.x to 1.4.0.
I got the following error in some of my tests:
scala.scalajs.js.JavaScriptException: TypeError: $m_Lorg_scalajs_dom_package$(...).document__Lorg_scalajs_dom_raw_HTMLDocument(...).createRange is not a function
Tracing the code, I believe it occurs while executing line 141 of the following scalatags code in `scalatags.JsDom:
I extracted just the createRange call into a separate test and got the same error. "creating range" was printed; "created range" was not and it produced the same exception as above.
createRange() is a native function.
Googling "createRange is not a function" yields a number of similar issues, all seem to be related to testing (but not with ScalaJS). Many of them indicate the "fix" is to monkey-patch document with your own version of createRange. Really?
I initially thought this was an issue with scalatags. Then I thought it's with the scalajs library. Now I'm thinking it's something with Node.js, although Google is not producing any smoking guns.
Suggestions on how to proceed? Try to monkey patch document?
Summary: jsdom appears to be missing the document.createRange function when using Node.js for testing. Others in other languages have similar problems.
The following monkey patch worked for me. After developing this, I noticed that Facade Types has a section on monkey typing.
Also, the library code that tickled this bug (scalatags) actually calls document.createRange().createContextualFragment(v). So I needed to provide something for that as well.
import scala.scalajs.js
import org.scalajs.dom.document
js.Dynamic.global.document.createRange = () ⇒
js.Dynamic.literal(
setStart = () => js.Dynamic.literal(),
setEnd = () => js.Dynamic.literal(),
commonAncestorContainer = js.Dynamic.literal(
nodeName = "BODY",
ownerDocument = document
),
createContextualFragment = (v: String) ⇒ {
val p = document.createElement("p")
p.appendChild(document.createTextNode(v))
}
)

Stop huge error output from testing-library

I love testing-library, have used it a lot in a React project, and I'm trying to use it in an Angular project now - but I've always struggled with the enormous error output, including the HTML text of the render. Not only is this not usually helpful (I couldn't find an element, here's the HTML where it isn't); but it gets truncated, often before the interesting line if you're running in debug mode.
I simply added it as a library alongside the standard Angular Karma+Jasmine setup.
I'm sure you could say the components I'm testing are too large if the HTML output causes my console window to spool for ages, but I have a lot of integration tests in Protractor, and they are SO SLOW :(.
I would say the best solution would be to use the configure method and pass a custom function for getElementError which does what you want.
You can read about configuration here: https://testing-library.com/docs/dom-testing-library/api-configuration
An example of this might look like:
configure({
getElementError: (message: string, container) => {
const error = new Error(message);
error.name = 'TestingLibraryElementError';
error.stack = null;
return error;
},
});
You can then put this in any single test file or use Jest's setupFiles or setupFilesAfterEnv config options to have it run globally.
I am assuming you running jest with rtl in your project.
I personally wouldn't turn it off as it's there to help us, but everyone has a way so if you have your reasons, then fair enough.
1. If you want to disable errors for a specific test, you can mock the console.error.
it('disable error example', () => {
const errorObject = console.error; //store the state of the object
console.error = jest.fn(); // mock the object
// code
//assertion (expect)
console.error = errorObject; // assign it back so you can use it in the next test
});
2. If you want to silence it for all the test, you could use the jest --silent CLI option. Check the docs
The above might even disable the DOM printing that is done by rtl, I am not sure as I haven't tried this, but if you look at the docs I linked, it says
"Prevent tests from printing messages through the console."
Now you almost certainly have everything disabled except the DOM recommendations if the above doesn't work. On that case you might look into react-testing-library's source code and find out what is used for those print statements. Is it a console.log? is it a console.warn? When you got that, just mock it out like option 1 above.
UPDATE
After some digging, I found out that all testing-library DOM printing is built on prettyDOM();
While prettyDOM() can't be disabled you can limit the number of lines to 0, and that would just give you the error message and three dots ... below the message.
Here is an example printout, I messed around with:
TestingLibraryElementError: Unable to find an element with the text: Hello ther. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
...
All you need to do is to pass in an environment variable before executing your test suite, so for example with an npm script it would look like:
DEBUG_PRINT_LIMIT=0 npm run test
Here is the doc
UPDATE 2:
As per the OP's FR on github this can also be achieved without injecting in a global variable to limit the PrettyDOM line output (in case if it's used elsewhere). The getElementError config option need to be changed:
dom-testing-library/src/config.js
// called when getBy* queries fail. (message, container) => Error
getElementError(message, container) {
const error = new Error(
[message, prettyDOM(container)].filter(Boolean).join('\n\n'),
)
error.name = 'TestingLibraryElementError'
return error
},
The callstack can also be removed
You can change how the message is built by setting the DOM testing library message building function with config. In my Angular project I added this to test.js:
configure({
getElementError: (message: string, container) => {
const error = new Error(message);
error.name = 'TestingLibraryElementError';
error.stack = null;
return error;
},
});
This was answered here: https://github.com/testing-library/dom-testing-library/issues/773 by https://github.com/wyze.

returning error message to front end Scala Play

I need to send an error status to the front end using Scala play. Ok is to say all is ok but which one is for error? Can this be done from any Scala method I created?
thanks
It can be done from any method, you just need to use correspondent Result. For the general server error it is InternalServerErrorlike
def index = Action {
InternalServerError("Some error happens")
}
You can find more results here: https://playframework.com/documentation/2.6.7/api/scala/index.html#play.api.mvc.Results
The examples are:
InsufficientStorage //507
Locked //423
You can also send your own state as simple as
new Status(500) //aka InternalServerError

Apache Camel File process is resulting in TypeConversion Error

I am using akka-camel to process files. My initial tests were working great, however when I started passing in actual xml files it is puking with type conversions.
Here is my consumer (very simple, but puking at msg.bodyAs[String]
class FileConsumer extends Consumer {
def endpointUri = "file:/data/input/actor"
val processor = context.actorOf(Props[Processor], "processor")
def receive = {
case msg: CamelMessage => {
println("Parent...received %s" format msg)
processor ! msg.bodyAs[String]
}
}
}
Error:
[ERROR] [04/27/2015 12:10:48.617] [ArdisSystem-akka.actor.default-dispatcher-5] [akka://ArdisSystem/user/$a] Error during type conversion from type: org.apache.camel.converter.stream.FileInputStreamCache to the required type: java.lang.String with value org.apache.camel.converter.stream.FileInputStreamCache#4611b35a due java.io.FileNotFoundException: /var/folders/dh/zfqvn9gn7cl6h63d3400y4zxp3xtzf/T/camel-tmp-807558/cos2920459202139947606.tmp (No such file or directory)
org.apache.camel.TypeConversionException: Error during type conversion from type: org.apache.camel.converter.stream.FileInputStreamCache to the required type: java.lang.String with value org.apache.camel.converter.stream.FileInputStreamCache#4611b35a due java.io.FileNotFoundException: /var/folders/dh/zfqvn9gn7cl6h63d3400y4zxp3xtzf/T/camel-tmp-807558/cos2920459202139947606.tmp (No such file or directory)
I am wondering if it has something to do with the actual contents of the xml. They are not big at all (roughly 70kb). I doubt I will be able to provide an actual example of the XML itself. Just baffled as to why something so small and being converted to a string is having issues. Other dummy example xml files have worked fine.
EDIT:
One of the suggestions I had was to enable StreamCache, which I did. However, it still doesn't seem to be working. As Ankush commented, the error is confusing. I am not sure if it actually is a Stream issue or if it really is a conversion problem.
http://camel.apache.org/stream-caching.html
Added the below
camel.context.setStreamCaching(true)
I was finally able to figure out the problem. The issue was not bad data, but the size of the files. To account for this, you need to add addtional settings to the camel context.
http://camel.apache.org/stream-caching.html
The settings I used are below. I will need to further research if I should just turn off the streamcache, but this is a start.
camel.context.getProperties.put(CachedOutputStream.THRESHOLD, "750000");
or turn off streamcache
camel.context.setStreamCaching(false)
Hope this helps someone else.
we were having same issue commenting the streamCaching() helped
from(IEricssonConstant.ROUTE_USAGE_DATA_INDIVIDUAL_PROCSESS)
//.streamCaching()
.split(new ZipSplitter()) .stopOnException()
.streaming()
.unmarshal().csv()
.process(new UsageDataCSVRequestProcessor())

GetExportedValues<MyType> returns nothing, I can see the parts

I have a strange MEF problem, I tested this in a test project and it all seems to work pretty well but for some reason not working in the real project
This is the exporting code
public void RegisterComponents()
{
_registrationBuilder = new RegistrationBuilder();
_registrationBuilder
.ForTypesDerivedFrom(typeof(MyType))
.SetCreationPolicy(CreationPolicy.NonShared)
.Export();
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyType).Assembly, _registrationBuilder));
var directoryCatalog = new DirectoryCatalog(PathToMyTypeDerived, _registrationBuilder);
catalog.Catalogs.Add(directoryCatalog);
_compositionContainer = new CompositionContainer(catalog);
_compositionContainer.ComposeParts();
var exports = _compositionContainer.GetExportedValues<MyType>();
Console.WriteLine("{0} exports in AppDomain {1}", exports.Count(), AppDomain.CurrentDomain.FriendlyName);
}
exports count is 0 :( Any ideas why?
IN the log file I have many of this
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'SomeOthertype' was ignored because it contains no exports.
Though I would think this is ok because I wasn' interested in exporting 'someOtherType'
UPDATE: I found this link but after debuging over it I am not wiser but maybe I m not following up properly.
Thanks for any pointers
Cheers
I just had the same problem and this article helped me a lot.
It describes different reasons why a resolve can fail. One of the more important ones is that the dependency of a dependency of the type you want to resolve is not registered.
What helped me a lot was the the trace output that gets written to the Output window when you debug your application. It describes exactly the reasons why a type couldn't be resolved.
Even with this output. you might need to dig a little bit, because I only got one level deep.
Example:
I wanted to resolve type A and I got a message like this:
System.ComponentModel.Composition Warning: 1 : The ComposablePartDefinition 'Namespace.A' has been rejected. The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced multiple composition errors, with 1 root causes. The root causes are provided below. Review the CompositionException.Errors property for more detailed information.
1) No exports were found that match the constraint:
ContractName Namespace.IB
RequiredTypeIdentity Namespace.IB
Resulting in: Cannot set import 'Namespace.A..ctor (Parameter="b", ContractName="namespace.IB")' on part 'Namespace A'.
Element: Namespace.A..ctor (Parameter="b", ContractName="Namespace.IB") --> Namespace.A --> AssemblyCatalog (Assembly="assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=...")
But I clearly saw a part for Namespace.IB. So, in the debugger, I tried to resolve that one. And I got another trace output. This time it told me that my implementation of Namespace.IB couldn't be resolved because for one of its imports there was a missing export, so basically the same message as above, just with different types. And this time, I didn't find a part for that missing import. Now I knew, which type was the real problem and figure out, why no registration happened for it.