From d2f3982e831b2be3091db3d2ed9b765afc0cd6ab Mon Sep 17 00:00:00 2001
From: Peter Deffebach
Date: Fri, 28 Jun 2024 20:26:26 -0400
Subject: [PATCH] progress
---
src/parsing.jl | 35 +++++++++++++++++++++++------------
test/keyword_arguments.jl | 24 ++++++++++++++++++++++++
2 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/src/parsing.jl b/src/parsing.jl
index 00bff676..e2da6852 100644
--- a/src/parsing.jl
+++ b/src/parsing.jl
@@ -499,22 +499,35 @@ end
function get_df_args_kwargs(x, args...; wrap_byrow = false)
kw = []
+ # x is normally a data frame. But if the call looks like
+ # transform(df, :x = 1; copycols = false)
+ # then x is actually Expr(:parameters, Expr(:kw, :copycole, false))
+ # When this happens, we assign x to the data frame, use only
+ # the rest of the args, and keep trask of the keyword argument.
if x isa Expr && x.head === :parameters
append!(kw, x.args)
x = first(args)
args = args[2:end]
end
- transforms, outer_flags, kw = create_args_vector!(kw, args...; wrap_byrow = wrap_byrow)
+ if args isa Tuple
+ blockarg = Expr(:block, args...)
+ else
+ blockarg = args
+ end
- return (x, transforms, outer_flags, kw)
-end
+ # create_args_vector! has an exclamation point because
+ # we modify the keyword arguments kw
+ transforms, outer_flags, kw = create_args_vector!(kw, blockarg; wrap_byrow = wrap_byrow)
-function create_args_vector!(kw, args...; wrap_byrow::Bool=false)
- create_args_vector!(kw, Expr(:block, args...); wrap_byrow = wrap_byrow)
+ return (x, transforms, outer_flags, kw)
end
function get_kw_from_macro_call(e::Expr)
+ if length(e.args) != 3
+ throw(ArgumentError("Invalid @kwarg expression"))
+ end
+
nv = e.args[3]
return nv
@@ -532,8 +545,6 @@ the block as an array. If a simple expression,
wrap the expression in a one-element vector.
"""
function create_args_vector!(kw, arg; wrap_byrow::Bool=false)
- # TODO: Pass vector of keyword arguments to this function
- # and modify by detecting presence of `@kwarg`.
arg, outer_flags = extract_macro_flags(MacroTools.unblock(arg))
if wrap_byrow
@@ -549,16 +560,16 @@ function create_args_vector!(kw, arg; wrap_byrow::Bool=false)
if arg isa Expr && arg.head == :block && !outer_flags[ASTABLE_SYM][]
x = MacroTools.rmlines(arg).args
transforms = []
- seen_kw = !isempty(kw)
+ seen_kw_macro = false
for xi in x
if is_macro_head(xi, "@kwarg")
- if seen_kw
- throw(ArgumentError("@kwarg calls must be at end of block"))
- end
kw_item = get_kw_from_macro_call(xi)
push!(kw, kw_item)
- seen_kw = true
+ seen_kw_macro = true
else
+ if seen_kw_macro
+ throw(ArgumentError("@kwarg calls must be at end of block"))
+ end
push!(transforms, xi)
end
end
diff --git a/test/keyword_arguments.jl b/test/keyword_arguments.jl
index 2d7dd149..0c3116eb 100644
--- a/test/keyword_arguments.jl
+++ b/test/keyword_arguments.jl
@@ -401,4 +401,28 @@ end
@test df2 == correct
end
+@testset "Multiple arguments #399" begin
+ correct = df[df.a .== 1, :]
+ correct_view = view(df, df.a .== 1, :)
+
+ df2 = @subset(df, :a .== 1, :b .== 3; view = true)
+ @test df2 ≈ correct_view
+
+ @test_throws ArgumentError @subset(df, :a .== 1, :b .== 3; skipmissing = false)
+ @test_throws ArgumentError @subset(df, :a .== 1, :b .== 3; skipmissing = false, view = true)
+
+ correct = transform(df, :a => ByRow(t -> t + 1) => :y, :b => ByRow(t -> t + 2) => :z)
+ df2 = @rtransform(df, :y = :a + 1, :z = :b + 2; copycols = false)
+ @test df2 ≅ correct
+ @test df.a === df2.a
+
+ correct = DataFrame(b_mean = [3.5, 5.0], b_first = [3, 5])
+ df2 = @combine(gd, :b_mean = mean(skipmissing(:b)), :b_first = first(:b); keepkeys = false)
+ @test df2 ≅ correct
+end
+
+@testset "@kwarg errors" begin
+
+end
+
end # module
\ No newline at end of file