-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Specification for generators/ directory. #2
Conversation
Thanks for the thorough review @eldering! Resolved most of the easy fixes. Btw, is there a way to respond in bulk, like for reviews? -> Oh found it: should have gone to the |
d: stdout.py d | ||
# This is forbidden because data: dictionaries may not appear within data: lists. | ||
#data: | ||
# c: stdout.py c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still confused... :-/
This commented out data
key is nested under the testgroup
key in the YAML, right? Then isn't it simply disallowed because you can't have the same data
key twice in the dictionary testgroup
?
- f: stdout.py f | ||
- g: stdout.py g | ||
- h: stdout.py h | ||
- i: stdout.py i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to have two different variables? One that refers to the base file path (like {name}
currently does) and that should be used for file operations, e.g. when passing it to a visualizer script as argument, so that that can write to {name}.jpg
, and one that can be used as a name to put in descriptions, for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fredrik asked me to leave some review comments.
Note that in the current state we can't use this for the Swedish IOI organization:
- we need testgroup/testcase reuse
- specifying testdata.yaml files by hand is too verbose and error-prone. Could fix this using some validation tool, but it doesn't help with verbosity, and we'd prefer to not introduce more tooling. Some kind of plugin system?
Both these points could be solved backwards compatibly, however.
|
||
* `<generator_name>` must either be a program (file/directory) in `generators/` or else a key in the top level `generators` dictionary. | ||
* The generator will be invoked with `<arguments>`. | ||
Arguments are separated by white space (space, tab, newline). Quoting white space is not supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? If we want this in the future, let's make it an error to include a "
char
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? -> mostly because it's quite hard to do correctly. The easiest way to 'spec' this is by saying 'you'll get whatever the output of python shlex.shlex
gives you', but that's not really that great of a spec.
Just saying 'shell style quoting' is also severely under specified sadly.
I'd be ok with disallowing '
and "
for now.
Generators are used to generate test cases. | ||
They are provided in the `generators/` directory together with the file | ||
`generators/generators.yaml` which specifies how to invoke the generators to generate the test cases. | ||
This directory must adhere to the [**Generators specification**](./generators) . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some legacy problems that have generators/ directories that don't adhere to it. Should we say that a directory without generators.yaml is ignored? (but that tools MAY warn about it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right; the intention is that the presence of generators/generators.yaml
enabled this spec, so that should be more clear
|
||
# Unknown keys are allowed inside directory dictionaries for tooling-specific | ||
# extensions. This includes both the global scope and explicit directories with type: directory. | ||
unknown_key: tool_specific_config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an explicit prefix reserved for extensions would make it possible to add things to the spec in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good idea. Happy to guarantee that keys prefixed with e.g. .
or _
(so .my_key
or _my_key
) are reserved for extensions.
# will determine the required number of digits to use and numbers will be | ||
# zero-padded accordingly, using a dash as separator from the given name (when | ||
# the given name is not empty). All items in a given dictionary will get the | ||
# same number. Use a list of 1-item dictionaries for incremental numbering. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just require that the list has size 1? I don't see a use-case for larger sizes, but I can see it hiding mistakes and making tooling more complex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I can live with that.
- a: stdout.py a | ||
b: stdout.py b | ||
- testgroup: | ||
type: directory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this implicit if there exists a data
key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is a complicated point. The answer in the current setup is no, because testcase: generator.py
is equivalent to:
testcase:
type: testcase
data: generator.py
this allows for per-testcase customization of solution and visualizer, although that's super rare in practice of course
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we rename data
to something else for testcases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad: yes, we're actually using input
instead of data
already for testcases.
There probably is/was a reason for having type:
in the first place, but I don't remember it anymore.
One case where it does matter is to distinguish an empty directory object from an empty testcase object. But we could say that directories must always have a data
key in them, which may be an empty list/dictionary.
A **Generator** takes one of the following four types/forms: | ||
|
||
1. Null / empty | ||
* An empty generator means that the testcase is a manual case and must not be modified or deleted by generator tooling. The corresponding `.in` file must be present in the `data/` directory. The corresponding `.ans` may be present, but may also be generated once from a given solution. Note that this form is discouraged. Prefer specifying a path to a `.in` file as below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the existence of this form means that if a file exists in data/ but isn't mentioned in generators.yaml (e.g. because of a git pull
in a repo where test data isn't checked in) and we run the command to regenerate test data, we can't delete it directly but need to prompt the user. Unless:
- we have tooling keep additional state (it would be nice to document how we expect tooling to work!)
- we add some (per-directory?) key saying whether this feature is in use
- we remove this feature
I don't see a strong use-case for it within secret/; it adds complexity and splits testdata across two directories. I see a weak use-case for it within sample/, since that consists solely of manual testdata, and deduplicating that testdata would make for e.g. slightly smaller version control diffs.
Documenting why we have it, and what best practices are, would be good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current state is that all testcases must be mentioned in generators.yaml.
However, I find that in practice during development, the easiest way to play with manual testcases is to just put them in data/secret, so BAPCtools does support this. It does complicate things quite a bit though and cleaning up spurious generated files is tricky indeed.
I also added --add-manual
and --move-manual
flags to my bt generate
command to easily update the generators.yaml to match the files in the directory, but i don't like requiring running that every time you want to test a submissions.
'3': manual_cases/sample/3.in | ||
# Every testcase present in the directory must be listed. | ||
# TOOLING: may still allow unlisted testcases and warn about them. | ||
#'4': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sample files for interactive problems use .interaction. How do we support that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the manual_cases/sample/3.in
example would copy over all of (e.g.) 3.in
, 3.ans
, 3.png
, and 3.interaction
, so this works fine.
A generator can generate the .interaction
file along the .in
file if you'd want this by taking the {name}
argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that interactive problems use only .interaction, there's no .in file. So it needs some additional spec text/implementation logic.
range: 0 25 | ||
grader_flags: min | ||
|
||
# To enable automatic numbering of testcases, data: may also contain a list of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basing automatic numbering only on whether there are - prefixes seems very easy to screw up as an author. Can we add that tooling SHOULD warn if it sees non-automatically numbered testcases that don't start with numbers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd prefer not to do this. in BAPC we 'traditionally' don't number testcases, and if we do, it's only at the very end.
Personally I find that numbering during development is rather annoying because inserting in the middle renumbers everything.
Also, detecting whether all cases start with (consecutive? zero padded?) numbers is messy.
But tooling is free to still warn about this if it's up to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's annoying. I guess the downside of making a mistake here is small enough that I'll just drop this issue. Short comments though:
(zero padded?)
Detecting missing zero-padding would be nice, and in fact problemtools already does that for names of testdata groups (grep for natural_sort_le). But that's a quality of implementation issue and not something an implementation would be required to do.
But tooling is free to still warn about this if it's up to me
Perhaps as a tooling option that we can stick in contest repo's git root... but by default I don't think tooling should have different opinions on what patterns to warn about.
Quick reply; will get into details later this week.
Thanks! Good feedback for such a quick look!
We are aware. We did discuss extensively at some point about this and we have ideas, but since it's not used in ICPC style problems, it's hard to know what we're designing for without your involvement.
Hmm, you're generating testdata.yaml currently? I'd be perfectly happy to allow
Jup, that's the plan :) |
Yes. We generate testdata.yaml files like the following: /data/testdata.yaml: on_reject: continue
range: 0 100 # where 100 = sum of scores
grader_flags: ignore_sample /data/sample/testdata.yaml: on_reject: continue
range: 0 0
accept_score: 0
grader_flags: first_error
input_validator_flags: n=100 m=100 # user-provided flags /data/secret/testdata.yaml: on_reject: continue
range: 0 100 # sum of scores
grader_flags: first_error accept_if_any_accepted /data/secret/*/testdata.yaml: on_reject: break
accept_score: 17 # user-provided
range: 0 17 # same as accept_score
grader_flags: min
input_validator_flags: n=100000 m=100000 # user-provided flags, different for each group
|
Is there any informed speculation (say, by @simonlindholm or @RagnarGrootKoerkamp) about how to allow the inclusion of the testcases of one testgroup into another? The group group3 12
include_group group1
tc other_testcase which includes all the testcases generated for I find this incredibly useful, in particular the inclusion of entire groups. I can see that both |
extending generators.yaml for this sounds reasonable. Since we don't use testdata groups in BAPC/NWERC this hasn't really come up so far, but I think it should be OK to add this. |
@RagnarGrootKoerkamp : was the If so, part of a reject-greedy: # another testgroup
testdata.yaml:
accept_score: 12
data:
- m: stdout.py m # m belongs only to reject-greedy
include:
- hard_cases_group # include all testcases of hard_cases_group
- 13_no_visualizer # also include another test case Is this what you had in mind? The semantics of Maybe specified like this: directory :: {
type: "directory"
file_config
"testdata.yaml"?: {
...
}
data?: data_dict | [...data_dict]
include?: string | [...string]
generator_reserved
...
} ( Issues to clarify:
But there may be many aspects I haven’t thought about. Please help. |
We decided that this will not be part of the problem package format spec. Instead, the documentation and specification of this will move into the BAPCtools repo. |
Moved the example
generators.yaml
here, and made the spec we had written in the BAPCtools repo a bit nicer.Specification: https://ragnargrootkoerkamp.nl/problem-package-format/generators/spec/generators.html
Updated this a bit, so PTAL. I made it a list of lists instead of a table for the
Directory
object since tables will make the description a bit too small I think.Commented examples: https://ragnargrootkoerkamp.nl/problem-package-format/generators/examples/generators.yaml.html
This is unchanged from what we discussed in our meetings.
Description in main text: https://ragnargrootkoerkamp.nl/problem-package-format/generators/spec/problem_package_format#generators
@niemela @eldering @nickygerritsen @deboer-tim @clevengr (Not sure what the current membership status is here, so to be sure.)
FYI: @SuprDewd