Skip to content

Commit 1478a18

Browse files
authored
Merge pull request #129 from drbergman/deprecate-kwargs
deprecate kwargs in connectedComponents
2 parents acc8a0b + 38826a5 commit 1478a18

25 files changed

+414
-129
lines changed

.github/workflows/CI.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ jobs:
113113
PCVCT_PUBLIC_REPO_AUTH: ${{ secrets.PUBLIC_REPO_AUTH }}
114114

115115
- uses: julia-actions/julia-processcoverage@v1
116+
with:
117+
directories: src,deps
116118

117119
- uses: codecov/codecov-action@v5
118120
with:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ test.jl
44
*.db
55
.vscode
66
studio_debug.log
7+
/temp
78

89
# from PkgTemplate.jl
910
*.jl.*.cov

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ LazyGrids = "7031d0ef-c40d-4431-b2f8-61a8d2f650db"
2020
LightXML = "9c8b4983-aa76-5018-a973-4c85ecc9e179"
2121
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2222
MAT = "23992714-dd62-5051-b70f-ba57cb901cac"
23+
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
2324
MetaGraphsNext = "fa8bd995-216d-47f1-8a91-f3b68fbeb377"
2425
PairCorrelationFunction = "1da3c5ec-5de6-497d-83f1-8bbf7fdc92ec"
2526
Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
@@ -52,6 +53,7 @@ LazyGrids = "1"
5253
LightXML = "0.9"
5354
LinearAlgebra = "1.10 - 1"
5455
MAT = "0.10"
56+
MacroTools = "0.5.16"
5557
MetaGraphsNext = "0.7.2"
5658
PairCorrelationFunction = "0.0.11"
5759
Parameters = "0.12"

codecov.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
ignore:
2-
- "src/public.jl"
3-
- "src/up.jl"
2+
- "src/up.jl"

deps/DeprecateKeywords.jl

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
module DeprecateKeywords
2+
3+
using MacroTools
4+
5+
"""
6+
@depkws [force=false] def
7+
8+
Macro to deprecate keyword arguments. Use by wrapping a function signature,
9+
while using `@deprecate(old_kw, new_kw)` within the function signature to deprecate.
10+
11+
# Examples
12+
13+
```julia
14+
@depkws function f(; a=2, @deprecate(b, a))
15+
a
16+
end
17+
```
18+
19+
```julia
20+
# force the deprecation warning to be emitted
21+
@depkws force=true function f(; a=2, @deprecate(b, a))
22+
a
23+
end
24+
```
25+
"""
26+
macro depkws(args...)
27+
options = parse_options(args[1:end-1])
28+
return esc(_depkws(args[end], options))
29+
end
30+
31+
function parse_options(args)
32+
options = default_options()
33+
for arg in args
34+
if isa(arg, Expr) && arg.head == :(=)
35+
@assert arg.args[1] keys(options) "Unknown option: $(arg.args[1])"
36+
options[arg.args[1]] = arg.args[2]
37+
else
38+
error("Invalid option: $arg")
39+
end
40+
end
41+
return options
42+
end
43+
44+
function default_options()
45+
return Dict{Symbol, Any}(:force => false)
46+
end
47+
48+
abstract type DeprecatedDefault end
49+
50+
function _depkws(def, options)
51+
sdef = splitdef(def)
52+
func_symbol = Expr(:quote, sdef[:name]) # Double quote for expansion
53+
54+
new_symbols = Symbol[]
55+
deprecated_symbols = Symbol[]
56+
kwargs_to_remove = Int[]
57+
for (i, param) in enumerate(sdef[:kwargs])
58+
isa(param, Symbol) && continue
59+
# Look for @deprecated macro:
60+
if param.head == :macrocall && param.args[1] == Symbol("@deprecate")
61+
# e.g., params.args[2] is the line number
62+
deprecated_symbol = param.args[end-1]
63+
new_symbol = param.args[end]
64+
if !isa(new_symbol, Symbol)
65+
# Remove line numbers nodes:
66+
clean_param = deepcopy(param)
67+
filter!(x -> !isa(x, LineNumberNode), clean_param.args)
68+
error(
69+
"The expression\n $(clean_param)\ndoes not appear to be two symbols in a `@deprecate`. This can happen if you use `@deprecate` in a function " *
70+
"definition without " *
71+
"parentheses, such as `f(; @deprecate a b, c=2)`. Instead, you should write `f(; (@deprecate a b), c=2)` or alternatively " *
72+
"`f(; @deprecate(a, b), c=2)`.)"
73+
)
74+
end
75+
push!(deprecated_symbols, deprecated_symbol)
76+
push!(new_symbols, new_symbol)
77+
push!(kwargs_to_remove, i)
78+
end
79+
end
80+
deleteat!(sdef[:kwargs], kwargs_to_remove)
81+
82+
# Add deprecated kws:
83+
for deprecated_symbol in deprecated_symbols
84+
pushfirst!(sdef[:kwargs], Expr(:kw, deprecated_symbol, DeprecatedDefault))
85+
end
86+
87+
symbol_mapping = Dict(new_symbols .=> deprecated_symbols)
88+
89+
# Update new symbols to use deprecated kws if passed:
90+
for (i, kw) in enumerate(sdef[:kwargs])
91+
no_default_type_assertion = !isa(kw, Symbol) && kw.head != :kw
92+
no_default_naked = isa(kw, Symbol)
93+
no_default = no_default_naked || no_default_type_assertion
94+
95+
(kw, type_assertion) = if no_default_type_assertion
96+
@assert kw.head == :(::)
97+
# Remove type assertion from keyword; we will
98+
# assert it later.
99+
kw.args
100+
else
101+
(kw, Nothing)
102+
end
103+
104+
new_kw, default = if no_default
105+
(kw, DeprecatedDefault)
106+
else
107+
(kw.args[1], kw.args[2])
108+
end
109+
110+
111+
_get_symbol(new_kw) in deprecated_symbols && continue
112+
!(_get_symbol(new_kw) in new_symbols) && continue
113+
114+
deprecated_symbol = symbol_mapping[_get_symbol(new_kw)]
115+
depwarn_string = "Keyword argument `$(deprecated_symbol)` is deprecated. Use `$(_get_symbol(new_kw))` instead."
116+
new_kwcall = quote
117+
if $deprecated_symbol !== $(DeprecatedDefault)
118+
Base.depwarn($depwarn_string, $func_symbol; force=$(options[:force]))
119+
$deprecated_symbol
120+
else
121+
$default
122+
end
123+
end
124+
sdef[:kwargs][i] = Expr(:kw, new_kw, new_kwcall)
125+
126+
if no_default_type_assertion
127+
pushfirst!(
128+
sdef[:body].args,
129+
Expr(:(::), _get_symbol(new_kw), type_assertion)
130+
)
131+
end
132+
133+
if no_default
134+
# Propagate UndefKeywordError
135+
pushfirst!(
136+
sdef[:body].args,
137+
Expr(:if,
138+
Expr(:call, :(===), _get_symbol(new_kw), DeprecatedDefault),
139+
Expr(:call, :throw,
140+
Expr(:call, :UndefKeywordError, QuoteNode(_get_symbol(new_kw)))
141+
)
142+
)
143+
)
144+
end
145+
end
146+
147+
return combinedef(sdef)
148+
end
149+
150+
# This is used to go from a::Int to a
151+
_get_symbol(e::Expr) = first(map(_get_symbol, e.args))
152+
_get_symbol(e::Symbol) = e
153+
154+
end

docs/src/lib/deprecate_keywords.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
```@meta
2+
CollapsedDocStrings = true
3+
```
4+
5+
# Deprecate Keywords
6+
7+
A light edit of the [DeprecateKeywords.jl](https://github.com/MilesCranmer/DeprecateKeywords.jl) package to enable the deprecation warnings for users.
8+
9+
## Public API
10+
```@autodocs
11+
Modules = [pcvct.DeprecateKeywords]
12+
Pages = ["DeprecateKeywords.jl"]
13+
Private = false
14+
```
15+
16+
## Private API
17+
```@autodocs
18+
Modules = [pcvct.DeprecateKeywords]
19+
Pages = ["DeprecateKeywords.jl"]
20+
Public = false
21+
```

docs/src/man/covariations.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ using pcvct
4444
timing_1_path = configPath("user_parameters", "event_1_time")
4545
timing_2_path = configPath("user_parameters", "event_2_time")
4646
dv1 = UniformDistributedVariation(timing_1_path, 100.0, 200.0)
47-
flip = true
48-
dv2 = UniformDistributedVariation(timing_2_path, 100.0, 200.0, flip)
47+
dv2 = UniformDistributedVariation(timing_2_path, 100.0, 200.0; flip=true)
4948
covariation = CoVariation(dv1, dv2)
5049
cdf = 0.1
5150
pcvct.variationValues.(covariation.variations, cdf) # pcvct internal for getting values for an ElementaryVariation

src/analysis/graphs.jl

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using Graphs, MetaGraphsNext
22

3+
include(joinpath(@__DIR__, "..", "..", "deps", "DeprecateKeywords.jl"))
4+
import .DeprecateKeywords: @depkws
5+
36
export connectedComponents
47

58
"""
@@ -34,25 +37,15 @@ For each key, the value is a list of connected components in the graph.
3437
Each component is represented as a vector of vertex labels.
3538
As of this writing, the vertex labels are the simple `AgentID` class that wraps the cell ID.
3639
"""
37-
function connectedComponents(snapshot::PhysiCellSnapshot, graph::Symbol=:neighbors; include_cell_type_names=:all_in_one, exclude_cell_type_names=String[], include_dead::Bool=false,
38-
include_cell_types=nothing, exclude_cell_types=nothing)
40+
@depkws force=true function connectedComponents(snapshot::PhysiCellSnapshot, graph::Symbol=:neighbors; include_cell_type_names=:all_in_one, exclude_cell_type_names=String[], include_dead::Bool=false,
41+
@deprecate(include_cell_types, include_cell_type_names), @deprecate(exclude_cell_types, exclude_cell_type_names))
3942
is_all_in_one = include_cell_type_names == :all_in_one
4043
cell_type_to_name_dict = cellTypeToNameDict(snapshot)
4144
cell_type_names = values(cell_type_to_name_dict) |> collect
4245

43-
if !isnothing(include_cell_types)
44-
@assert include_cell_type_names == :all_in_one "Do not use both `include_cell_types` and `include_cell_type_names` as keyword arguments. Use `include_cell_type_names` instead."
45-
Base.depwarn("`include_cell_types` is deprecated as a keyword. Use `include_cell_type_names` instead.", :connectedComponents, force=true)
46-
include_cell_type_names = include_cell_types
47-
end
4846
include_cell_type_names = processIncludeCellTypes(include_cell_type_names, cell_type_names)
49-
50-
if !isnothing(exclude_cell_types)
51-
@assert exclude_cell_type_names == String[] "Do not use both `exclude_cell_types` and `exclude_cell_type_names` as keyword arguments. Use `exclude_cell_type_names` instead."
52-
Base.depwarn("`exclude_cell_types` is deprecated as a keyword. Use `exclude_cell_type_names` instead.", :connectedComponents, force=true)
53-
exclude_cell_type_names = exclude_cell_types
54-
end
5547
exclude_cell_type_names = processExcludeCellTypes(exclude_cell_type_names)
48+
5649
loadGraph!(snapshot, graph)
5750
if is_all_in_one
5851
G = getfield(snapshot, graph) |> deepcopy

src/analysis/substrate.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ asts = pcvct.AverageSubstrateTimeSeries(1) # Load average substrate time series
7777
asts.time # Get the time points
7878
asts["time"] # alternative way to get the time points
7979
asts["oxygen"] # Get the oxygen concentration over time
80+
```
8081
"""
8182
struct AverageSubstrateTimeSeries
8283
simulation_id::Int

src/configuration.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ function rulePath(cell_definition::AbstractString, behavior::AbstractString, pat
998998
end
999999

10001000
"""
1001-
icCellsPath(cell_definition::AbstractString, patch_type::AbstractString, patch_id, path_elements::Vararg{<:Union{Integer,AbstractString}})
1001+
icCellsPath(cell_definition::AbstractString, patch_type::AbstractString, patch_id, path_elements::Vararg{Union{Integer,AbstractString}})
10021002
10031003
Return the XML path to the IC cell patch for the given cell type, patch type, and patch ID.
10041004
The remaining arguments are either just the tag for the patch parameter or the carveout patch type, ID, and tag.
@@ -1024,7 +1024,7 @@ julia> icCellsPath("default", "annulus", 1, "rectangle", 1, "width")
10241024
"width"
10251025
```
10261026
"""
1027-
function icCellsPath(cell_definition::AbstractString, patch_type::AbstractString, patch_id, path_elements::Vararg{<:Union{Integer,AbstractString}})
1027+
function icCellsPath(cell_definition::AbstractString, patch_type::AbstractString, patch_id, path_elements::Vararg{Union{Integer,AbstractString}})
10281028
supported_patch_types = PhysiCellCellCreator.supportedPatchTypes()
10291029
@assert patch_type in supported_patch_types "IC Cell patch_type must be one of the available patch types, i.e., in $(supported_patch_types). Got $(patch_type)"
10301030
xml_path = ["cell_patches:name:$(cell_definition)"; "patch_collection:type:$(patch_type)"; "patch:ID:$(patch_id)"]

0 commit comments

Comments
 (0)