How do you pass empty arguments in Cake v1? - cakebuild

According to the upgrade document it is no longer possible to ./build.sh arg= as of v1.0. Indeed, that produces:
Error: Expected an option value.
However it also doesn't work with arg=''. I could leave it off and rely on the default value, but that's hard to do from my Azure DevOps pipelines, which read like - script: ./build.sh --arg='$(arg1)' where arg1 is a variable defined elsewhere.
The problem is that the variable arg1 in my DevOps pipeline is defined externally and may or may not be empty.
The best I can think of is passing in at least a space like ./build.sh --arg='$(arg) ' (note the space at the end) and always checking for string.IsNullOrWhiteSpace and always Trimming, but that seems very hacky.
Is there a cleaner solution to pass a possibly empty variable from the command line? If not how can I rewrite my Azure DevOps YML to not pass the argument if it is empty?

TL;DR; Use a (space) instead of = if the value can be empty/null.
./build.sh --arg '$(arg1)'
Cake v1.0 supports using a space between the --argumentName and the value as an alternative for the = sign. For example:
dotnet cake empty-args.cake --arg1 --arg2
dotnet cake empty-args.cake --arg1 valueA --arg2
dotnet cake empty-args.cake --arg1 --arg2 valueB
dotnet cake empty-args.cake --arg1 valueA --arg2 valueB
With a sample Cake script like the below, it will output the following:
var arg1 = Argument<string>("arg1", null);
var arg2 = Argument<string>("arg2", null);
Information("arg1: {0}", arg1);
Information("arg2: {0}", arg2);
dotnet cake empty-args.cake --arg1 --arg2
arg1: [NULL]
arg2: [NULL]
dotnet cake empty-args.cake --arg1 --arg2
arg1: [NULL]
arg2: [NULL]
dotnet cake empty-args.cake --arg1 valueA --arg2
arg1: valueA
arg2: [NULL]
dotnet cake empty-args.cake --arg1 --arg2 valueB
arg1: [NULL]
arg2: valueB
dotnet cake empty-args.cake --arg1 valueA --arg2 valueB
arg1: valueA
arg2: valueB

One key difference with Cake 1.0 is that it beyond keyvalue arguments (--key=value), supports flags (--flag), and multiple arguments with the same name (--key=value1 --key=value2). Which allows for much more flexibility than before.
As no example script provided, my example will be emptyarg.cake looking like below
var arg = Argument<string>("arg", null);
Information("Arg: {0}", arg ?? "NULL");
dotnet cake .\emptyarg.cake will output Arg: NULL
dotnet cake .\emptyarg.cake --arg will output Arg: NULL
dotnet cake .\emptyarg.cake --arg=" " will output Arg:
If you want to treat all the above examples as an argument missing, you could create a reusable helper method.
public string ArgumentNotNullOrWhiteSpace(string key)
{
var value = Argument<string>(key, null);
return string.IsNullOrWhiteSpace(value)
? null
: value;
}
var arg = ArgumentNotNullOrWhiteSpace("arg");
Information("Arg: {0}", arg ?? "NULL");
Then output of
dotnet cake .\emptyarg.cake
dotnet cake .\emptyarg.cake --arg
dotnet cake .\emptyarg.cake --arg=hh
dotnet cake .\emptyarg.cake --arg=" "
will be
Arg: NULL
Arg: NULL
Arg: hh
Arg: NULL
and you can use ?? operator if you want some default value i.e.
var arg = ArgumentNotNullOrWhiteSpace("arg") ?? "default" and the output will be
Arg: default
Arg: default
Arg: hh
Arg: default

Related

pytest. Change default values of arguments of fixture

Hi I have a fixture with default arguments, like
pytest.fixture(scope='function', params =[{'arg1':value1}, {'arg2':Value2}])
def some_fixture(request):
if request.param['arg1'] == value1:
'do some actions'
if request.param['arg2'] ==value2:
'do some actions'
but now i see an error:
def some_fixture(request):
if request.param['arg1']
KeyError: arg1

How to pass fixture when parametrizing a test

I am trying to parametrize my test.
In the setup method which returns a list, I am calling a fixture (app_config).
Now, i want to call the setup so that the list can be used as a parameter values inside the test.
The problem i am running into is that i cannot pass app_config fixture when calling setup in the parametrize decorator.
def setup(app_config):
member = app_config.membership
output = app_config.plan_data
ls = list(zip(member, output))
return ls
#pytest.mark.parametrize('member, output', setup(app_config))
def test_concentric(app_config, member, output):
....
....
Is there an elegant way to pass setup method in the parametrize decorator or any other way to approach this?
Unfortunately, starting with pytest version 4, it has become impossible to call fixtures like regular functions.
https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly
https://github.com/pytest-dev/pytest/issues/3950
In your case I can recommend not using fixtures and switch to normal functions.
For example, it might look like this:
import pytest
def app_config():
membership = ['a', 'b', 'c']
plan_data = [1, 2, 3]
return {'membership': membership,
'plan_data': plan_data}
def setup_func(config_func):
data = config_func()
member = data['membership']
output = data['plan_data']
ls = list(zip(member, output))
return ls
#pytest.mark.parametrize('member, output', setup_func(app_config))
def test_concentric(member, output):
print(member, output)
....
NB! Avoid the setup() function/fixture name because it will conflict with pytest.runner's internals.

Is there a way to get the exit code of an earlier piped Scala Process (#|)?

I'm trying to pipe commands using scala's sys.process library, but I noticed that #| will return the exit code of the final process. I'm having commands earlier in the pipe fail, but the exit code of the final command is 0 as it didn't error out.
I was wondering if scala has a way to check/retrieve if previous commands in the pipe (#|) failed.
import scala.sys.process._
val p1 = ("false" #| "true").run()
assert(p1.exitValue == 1)
Bash has set -o pipefail that will pass the non-zero exit-code of a pipe, but it just seems a bit "hacky":
val p2 = Seq("/bin/bash", "-c", "set -o pipefail && false | true").run()
assert(p2.exitValue == 1)
I was hoping there might be a better way.
Thanks, I appreciate any help :)
!! operator throws an exception on non-zero exit code, so perhaps it can be used to pass output of one process to the input stream of another via #< operator only on success. If we define a custom operator #|< like so
implicit class Pipefail[T](p1: T) {
def #|<(p2: T)(implicit ev: T => ProcessBuilder): ProcessBuilder =
Try(p1.!!).map(result => (p2 #< new ByteArrayInputStream(result.getBytes))).get
}
then we could call it with
("false" #|< "true").run
which should throw
java.lang.RuntimeException: Nonzero exit value: 1
whilst
("echo Beam Me Up, Scotty" #|< "tr a-z A-Z" #|< "grep -o SCOTTY" ).run
should output uppercase SCOTTY. This will use stringToProcess implicit conversion, so remember to import scala.sys.process._

Dynamically add CLI arguments in pytest tests

I'd like to run specific tests in pytest with dynamically added CLI arguments, i.e:
class TestHyperML:
def some_test(self):
# Setup some CLI argument such as --some_arg 3 -- some_other_arg 12
my_class = SomeClass()
class SomeClass:
def parse_cli_arguments(self):
# here I want to fetch my arguments in sys.argv.
parameters = {}
name = None
for x in sys.argv[1:]:
if name:
parameters[name] = {'default': ast.literal_eval(x)}
name = None
elif x.startswith('-'):
name = x.lstrip('-')
return parameters
I understand there is a way to do that programatically by running pytest test_something.py --somearg, but I would like to do that programatically from inside the test.
Is it possible ? Thanks !
Thanks to answers posted above, and similar SO questions, here is the solution that I used:
import mock
def test_parsing_cli_arguments(self):
args = 'main.py --my_param 1e-07 --my_other_param 2'.split()
with mock.patch('sys.argv', args):
parser = ConfigParser("config.yaml")
# Inside parser, sys.argv will contain the arguments set here.

Calling methods with parameters without using parentheses

I am using the following implicit class in order to call a function which would otherwise take parameters without having to write the parameters in brackets:
scala> implicit class Print(string: String) {
| def echo: Unit = Console.println(string)
| }
defined class Print
scala> "Hello world" echo
Hello world
However while this works, I don't really like how it looks and my goal is to get the method call in front of the input variable as I think it reads better.
Is there any simple way, without relying on external libraries, to be able to call a method before supplying the parameters and without needing brackets? Implicit classes are what I've been using so far but that doesn't have to be the final solution.
What I would like to type instead of "Hello world" echo:
scala> echo "Hello world"
Alternatives I have tried:
Object with apply method
Requires parentheses
object echo {
def apply(string: String): Unit = Console.println(string)
}
echo "Hello world" // Error: ';' or newline expected
extending Dynamic [see here]
Doesn't seem to work in my version of Scala
Special characters [see here]
Looks ugly and not what I am looking for
Scalaz [see here]
Looks to do basically what my implicit class solution does, and I don't want any external dependencies.
EDIT
This answer has been pointed to as a potential solution, but again it doesn't address my issue as it relies on Dynamic to achieve a solution. As previously mentioned, Dynamic does not solve my problem for a couple of reasons:
It behaves funnily
If you define a val and try to println that val, it gives you back the val's name and not its value (as pointed out by #metaphori):
object println extends Dynamic {
def typed[T] = asInstanceOf[T]
def selectDynamic(name: String) = Console.println(name)
}
val x = "hello"
println x // prints: x
The specific example linked to did not work when I tried to recreate it - it still gave the ';' or newline expected error
If I just misunderstood how to implement it then I would appreciate a scalafiddle demonstrating that this solution solves my problem and will happily concede that this question is a duplicate of the previously mentioned answer, but until then I do contest it.
AFAIK only way to do something similar to what you want is extending Dynamic like this:
object println extends Dynamic {
def typed[T] = asInstanceOf[T]
def selectDynamic(name: String) = Console.println(name)
}
and using it with:
println `Hello World`
edit: of course you need to enable related features either by adding compiler parameters -language:postfixOps and -language:dynamics or by importing scala.language.dynamics and scala.language.postfixOps
You cannot achieve
echo "str"
since Scala is not e.g. Ruby: it syntactically requires that function invocations use parentheses.
It is not a matter of semantics or how things are implemented or what techniques are used: here is the parser that complains.
The point is that x y is actually interpreted as x.y, which means that y must be a method.
Refer to the Scala Language Specification, section 6.6 Function Applications:
SimpleExpr ::= SimpleExpr1 ArgumentExprs
ArgumentExprs ::= ‘(’ [Exprs] ‘)’
| ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’
| [nl] BlockExpr
Exprs ::= Expr {‘,’ Expr}
I do not like the trick of #hüseyin-zengin since it leverages dynamic method invocations, and also does not work as expected:
val x = "hello"
println x // prints: x
To partially achieve what you like you need to use infix operator notation
object run { def echo(s: String) = println(s) }
run echo "hello" // OK
run.echo "hello" // error: ';' expected but string literal found.
You may also use a symbol to reduce "typing" overhead (though may be perceived weirdly):
object > { def echo(s: String) = println(s) }
> echo "hello" // OK