Skip to content

Commit 4e64019

Browse files
committed
Prepare npi 0.3.0 CRAN release
1 parent 16e3016 commit 4e64019

6 files changed

Lines changed: 153 additions & 49 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: npi
22
Title: Access the U.S. National Provider Identifier Registry API
3-
Version: 0.2.0.9000
3+
Version: 0.3.0
44
Authors@R: c(
55
person("Frank", "Farach", , "frank.farach@gmail.com",
66
role = c("cre", "aut", "cph"),
@@ -11,10 +11,6 @@ Authors@R: c(
1111
person(c("Emily", "C."), "Zabor", , "zabore2@ccf.org", role = "rev",
1212
comment = c(ORCID = "0000-0002-1402-4498"))
1313
)
14-
Author: Frank Farach [aut, cre, cph],
15-
Sam Parmar [ctb],
16-
Matthias Grenié [rev],
17-
Emily C. Zabor [rev]
1814
Maintainer: Frank Farach <frank.farach@gmail.com>
1915
Description: Access the United States National Provider Identifier
2016
Registry API <https://npiregistry.cms.hhs.gov/api/>. Obtain and transform

NEWS.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
# npi (development version)
1+
# npi 0.3.0 (2026-07-01)
22

33
## MINOR IMPROVEMENTS
44

55
* `npi_search()` now normalizes `address_purpose` values to API constants and accepts case-insensitive input.
66
* `npi_is_valid()` now supports vector inputs and returns logical vectors.
77
* `npi_search()` returns a typed empty `npi_results` object when no records are found.
88

9+
## BUG FIXES
10+
11+
* `npi_summarize()` now preserves input rows when NPI records have empty or missing nested address or taxonomy data.
12+
* Updated the package CITATION file to use `bibentry()` instead of the deprecated `citEntry()` format.
13+
914
## DOCUMENTATION FIXES
1015

1116
* Clarified `npi_summarize()` taxonomy fallback behavior when no primary taxonomy is marked.

R/npi_results_s3.R

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,29 @@ validate_npi_results <- function(x, ...) {
8383
}
8484

8585

86+
empty_npi_summary <- function() {
87+
tibble::tibble(
88+
npi = integer(),
89+
name = character(),
90+
enumeration_type = character(),
91+
primary_practice_address = character(),
92+
phone = character(),
93+
primary_taxonomy = character()
94+
)
95+
}
96+
97+
98+
add_missing_columns <- function(df, columns, default = NA_character_) {
99+
for (column in columns) {
100+
if (!column %in% names(df)) {
101+
df[[column]] <- rep(default, nrow(df))
102+
}
103+
}
104+
105+
df
106+
}
107+
108+
86109

87110
#' Summary method for \code{npi_results} S3 object
88111
#'
@@ -112,39 +135,87 @@ validate_npi_results <- function(x, ...) {
112135
#' @importFrom rlang .data
113136
#' @export
114137
npi_summarize.npi_results <- function(object, ...) {
115-
basic <- get_list_col(object, "basic")
138+
validate_npi_results(object)
139+
140+
if (nrow(object) == 0L) {
141+
return(empty_npi_summary())
142+
}
143+
144+
basic <- get_list_col(object, "basic") %>%
145+
add_missing_columns(
146+
c(
147+
"basic_first_name", "basic_last_name",
148+
"basic_organization_name"
149+
)
150+
) %>%
151+
dplyr::group_by(.data$npi) %>%
152+
dplyr::slice_head(n = 1L) %>%
153+
dplyr::ungroup() %>%
154+
dplyr::select(
155+
.data$npi, .data$basic_first_name, .data$basic_last_name,
156+
.data$basic_organization_name
157+
)
158+
116159
address_loc <- get_list_col(object, "addresses") %>%
160+
add_missing_columns(
161+
c(
162+
"addresses_address_purpose", "addresses_address_1",
163+
"addresses_address_2", "addresses_city", "addresses_state",
164+
"addresses_postal_code", "addresses_telephone_number"
165+
)
166+
) %>%
117167
dplyr::filter(.data$addresses_address_purpose == "LOCATION") %>%
118168
dplyr::mutate(
119-
postal_code = hyphenate_full_zip(.data$addresses_postal_code)
169+
addresses_postal_code = hyphenate_full_zip(.data$addresses_postal_code)
120170
)
121171

172+
address_loc$primary_practice_address <- make_full_address(
173+
address_loc,
174+
"addresses_address_1",
175+
"addresses_address_2",
176+
"addresses_city",
177+
"addresses_state",
178+
"addresses_postal_code"
179+
)
180+
address_loc$phone <- address_loc$addresses_telephone_number
181+
182+
address_loc <- address_loc %>%
183+
dplyr::group_by(.data$npi) %>%
184+
dplyr::slice_head(n = 1L) %>%
185+
dplyr::ungroup() %>%
186+
dplyr::select(.data$npi, .data$primary_practice_address, .data$phone)
187+
122188
# Some NPI records have only one taxonomy row with primary == FALSE;
123189
# include these along with those where primary == TRUE
124190
tax_primary <- get_list_col(object, "taxonomies") %>%
191+
add_missing_columns("taxonomies_primary", default = FALSE) %>%
192+
add_missing_columns("taxonomies_desc") %>%
125193
dplyr::group_by(.data$npi) %>%
126-
dplyr::mutate(n_primary = sum(.data$taxonomies_primary == TRUE)) %>%
127-
dplyr::filter(.data$taxonomies_primary == TRUE | .data$n_primary == 0) %>%
128-
dplyr::slice_head()
194+
dplyr::mutate(n_primary = sum(.data$taxonomies_primary %in% TRUE)) %>%
195+
dplyr::filter(.data$taxonomies_primary %in% TRUE | .data$n_primary == 0L) %>%
196+
dplyr::slice_head(n = 1L) %>%
197+
dplyr::ungroup() %>%
198+
dplyr::transmute(
199+
npi = .data$npi,
200+
primary_taxonomy = .data$taxonomies_desc
201+
)
129202

130-
tibble::tibble(
131-
npi = object$npi,
132-
name = ifelse(object$enumeration_type == "Individual",
133-
paste(basic$basic_first_name, basic$basic_last_name),
134-
basic$basic_organization_name
135-
),
136-
enumeration_type = object$enumeration_type,
137-
primary_practice_address = address_loc %>%
138-
make_full_address(
139-
"addresses_address_1",
140-
"addresses_address_2",
141-
"addresses_city",
142-
"addresses_state",
143-
"addresses_postal_code"
144-
),
145-
phone = address_loc$addresses_telephone_number,
146-
primary_taxonomy = tax_primary$taxonomies_desc
147-
)
203+
object %>%
204+
dplyr::select(.data$npi, .data$enumeration_type) %>%
205+
dplyr::left_join(basic, by = "npi") %>%
206+
dplyr::mutate(
207+
name = ifelse(
208+
.data$enumeration_type == "Individual",
209+
stringr::str_c(.data$basic_first_name, " ", .data$basic_last_name),
210+
.data$basic_organization_name
211+
)
212+
) %>%
213+
dplyr::left_join(address_loc, by = "npi") %>%
214+
dplyr::left_join(tax_primary, by = "npi") %>%
215+
dplyr::select(
216+
.data$npi, .data$name, .data$enumeration_type,
217+
.data$primary_practice_address, .data$phone, .data$primary_taxonomy
218+
)
148219
}
149220

150221

cran-comments.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1-
## Resubmission
1+
# npi 0.3.0
22

3-
This is a resubmission. In this version I have:
3+
This update fixes current CRAN check failures for npi 0.2.0:
44

5-
* Added a web reference for the API in the description field of the DESCRIPTION
6-
file.
5+
* Fixed vignette rebuild errors caused by NPI records whose nested address data
6+
did not contain the expected location-address fields.
77

8-
* Added \value and an explanation of the structure and meaning of the output to
9-
pipe.Rd.
8+
* Updated the package CITATION file to use `bibentry()` instead of the
9+
deprecated `citEntry()` format.
1010

1111
## R CMD check results
1212

13-
0 errors | 0 warnings | 1 note
13+
Standard local check:
1414

15-
* This is a new release.
15+
0 errors | 0 warnings | 0 notes
16+
17+
`R CMD check --as-cran npi_0.3.0.tar.gz` reported 0 errors, 0 warnings, and
18+
2 notes in this local macOS environment:
19+
20+
* `unable to verify current time`
21+
22+
* HTML validation problems caused by `/usr/bin/tidy`, Apple Inc. build 4474
23+
from 2006, not recognizing HTML5 tags generated by R's help system.
24+
25+
## Reverse dependencies
26+
27+
There are no reverse dependencies on CRAN.

inst/CITATION

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
citHeader("To cite npi in publications, please use:")
22

3-
citEntry(
4-
entry = "Manual",
5-
title = "npi: Access the U.S. National Provider Identifier Registry API (Version 0.2.0)",
6-
author = as.person("Frank J Farach"),
7-
year = 2022,
8-
url = "https://github.com/ropensci/npi",
9-
doi = "10.5281/zenodo.6326729",
10-
textVersion = paste("Farach, F. J. (2022). npi: Access the U.S. National Provider Identifier Registry API (Version 0.2.0). https://github.com/ropensci/npi"
11-
)
12-
)
13-
143
bibentry(
154
bibtype = "Manual",
165
title = "{npi}: Access the U.S. National Provider Identifier Registry API",
176
author = person("Frank", "Farach", role = c("cre", "aut")),
187
url = "https://github.com/ropensci/npi",
198
year = 2022,
209
doi = "10.5281/zenodo.6326729",
21-
note = "R package version 0.2.0"
10+
note = paste("R package version", meta$Version)
2211
)

tests/testthat/test-api.R

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,34 @@ with_mock_api({
283283
expect_identical(names(npi_summarize(atl)), expect_names)
284284
})
285285
})
286+
287+
test_that("npi_summarize() handles empty results", {
288+
res <- npi_summarize(new_empty_npi_results())
289+
expect_types <- c("integer", rep("character", 5))
290+
expect_names <- c(
291+
"npi", "name", "enumeration_type",
292+
"primary_practice_address", "phone",
293+
"primary_taxonomy"
294+
)
295+
296+
checkmate::expect_tibble(res, types = expect_types, nrows = 0L)
297+
expect_identical(names(res), expect_names)
298+
})
299+
300+
test_that("npi_summarize() keeps rows aligned when nested data is missing", {
301+
data(npis)
302+
res <- npis[1:2, ]
303+
res$addresses[[1]] <- tibble::tibble()
304+
res$taxonomies[[1]] <- tibble::tibble()
305+
306+
summarized <- npi_summarize(res)
307+
308+
expect_identical(summarized$npi, res$npi)
309+
expect_true(is.na(summarized$primary_practice_address[1]))
310+
expect_true(is.na(summarized$phone[1]))
311+
expect_true(is.na(summarized$primary_taxonomy[1]))
312+
expect_equal(
313+
summarized$primary_practice_address[2],
314+
npi_summarize(npis[2, ])$primary_practice_address
315+
)
316+
})

0 commit comments

Comments
 (0)