Skip to content

Commit

Permalink
Merge pull request #15 from inbo/first_functions
Browse files Browse the repository at this point in the history
Add first functions to support reading Camtrap DP
  • Loading branch information
peterdesmet authored Mar 14, 2024
2 parents b92a901 + 9ecceb0 commit 4316ffb
Show file tree
Hide file tree
Showing 14 changed files with 304 additions and 5 deletions.
Binary file removed .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
^LICENSE\.md$
^\.github$
^README\.Rmd$
^_pkgdown\.yml$
^docs$
^pkgdown$
48 changes: 48 additions & 0 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
release:
types: [published]
workflow_dispatch:

name: pkgdown

jobs:
pkgdown:
runs-on: ubuntu-latest
# Only restrict concurrency for non-PR jobs
concurrency:
group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::pkgdown, local::.
needs: website

- name: Build site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}

- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/[email protected]
with:
clean: false
branch: gh-pages
folder: docs
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ po/*~
# RStudio Connect folder
rsconnect/
.Rproj.user

# Mac OS
.DS_Store
13 changes: 10 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,25 @@ Package: camtrapdp
Title: Read and Convert Camera Trap Data Packages (Camtrap DP)
Version: 0.0.0.9000
Authors@R: c(
person("Peter", "Desmet", email = "[email protected]",
role = c("aut", "cre"), comment = c(ORCID = "0000-0002-8442-8025")),
person("Damiano", "Oldoni", email = "[email protected]",
role = c("aut", "cre"), comment = c(ORCID = "0000-0003-3445-7562")),
role = "aut", comment = c(ORCID = "0000-0003-3445-7562")),
person("Research Institute for Nature and Forest (INBO)",
role = "cph", comment = "https://www.vlaanderen.be/inbo/en-gb/"),
person("LifeWatch Belgium",
role = "fnd", comment = "https://lifewatch.be")
)
Description: What the package does (one paragraph).
License: MIT + file LICENSE
URL: https://github.com/inbo/camtrapdp, https://inbo.github.io/camtrapdp/
BugReports: https://github.com/inbo/camtrapdp/issues
Imports:
cli,
frictionless
Suggests:
testthat (>= 3.0.0)
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.0
Suggests:
testthat (>= 3.0.0)
Config/testthat/edition: 3
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# Generated by roxygen2: do not edit by hand

export(read_camtrap_dp)
export(version)
28 changes: 28 additions & 0 deletions R/convert.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#' Convert a Camera Trap Data Package
#'
#' Converts a Camera Trap Data Package object that uses an older version of
#' the Camtrap DP standard to a newer version.
#'
#' @inheritParams version
#' @param convert_to Version to convert to.
#' @return Converted Camera Trap Data Package object.
#' @noRd
convert <- function(x, convert_to = "1.0") {
# Convert until the version number matches the expected version
while(version(x) != convert_to) {
x <- switch(
version(x),
"0.1.6" = convert_0.1.6_to_1.0(x),
"1.0" = x
)
}
x
}

#' Convert a Camtrap DP 0.1.6 to 1.0
#' @noRd
convert_0.1.6_to_1.0 <- function(x) {
# TODO: conversion steps for 0.1.6
attr(x, "version") <- "1.0"
x
}
41 changes: 41 additions & 0 deletions R/read_camtrap_dp.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#' Read a Camera Trap Data Package
#'
#' Reads files from a [Camera Trap Data Package (Camtrap DP)](
#' https://camtrap-dp.tdwg.org) into memory.
#'
#' @param file Path or URL to a `datapackage.json` file.
#' @return Camera Trap Data Package object.
#' @export
read_camtrap_dp <- function(file) {
# Read datapackage.json
package <- frictionless::read_package(file)

# Check version
version <- version(package)
supported_versions <- c("1.0")
if (!version %in% supported_versions) {
cli::cli_abort(
c(
"{.val {version}} is not a supported Camtrap DP version.",
"i" = "Supported version{?s}: {.val {supported_versions}}."
),
class = "camtrapdp_error_unsupported_version"
)
}

# Create camtrapdp object
x <- package
class(x) <- c("camtrapdp", class(x))
attr(x, "version") <- version

# Read and attach csv data
x$data$deployments <-
frictionless::read_resource(package, "deployments")
x$data$media <-
frictionless::read_resource(package, "media")
x$data$observations <-
frictionless::read_resource(package, "observations")

# Convert
convert(x, convert_to = "1.0")
}
44 changes: 44 additions & 0 deletions R/version.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#' Get Camtrap DP version
#'
#' Extracts the version number used by a Camera Trap Data Package object.
#' This version number indicates what version of the [Camtrap DP standard](
#' https://camtrap-dp.tdwg.org) was used.
#'
#' The version number is derived as follows:
#' 1. The `version` attribute, if defined.
#' 2. A version number contained in `x$profile`, which is expected to
#' contain the URL to the used Camtrap DP standard.
#' 3. `x$profile` in its entirety (can be `NULL`).
#'
#' @param x Camera Trap Data Package object, as returned by
#' `read_camtrap_dp()`.
#' Also works on a Frictionless Data Package, as returned by
#' `frictionless::read_package()`.
#' @return Camtrap DP version number (e.g. `1.0`).
#' @export
version <- function(x) {
# Get version from attribute
attr_version <- attr(x, "version")
if (!is.null(attr_version)) {
return(attr_version)
}

# Get version from profile
profile <- x$profile
if (is.null(profile)) {
return(NA)
}

# Find pattern "camtrap-dp/<version>/" in e.g.
# https://raw.githubusercontent.com/tdwg/camtrap-dp/1.0/camtrap-dp-profile.json
pattern <- "camtrap-dp\\/([0-9A-Za-z]|\\.|-)+\\/"
match <- grep(pattern, profile)
if (length(match) > 0) {
extracted_version <- regmatches(profile, regexpr(pattern, profile))
extracted_version <- sub("camtrap-dp/", "", extracted_version, fixed = TRUE)
extracted_version <- sub("/", "", extracted_version, fixed = TRUE)
extracted_version
} else {
profile
}
}
4 changes: 4 additions & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
url: https://inbo.github.io/camtrapdp/
template:
bootstrap: 5

17 changes: 17 additions & 0 deletions man/read_camtrap_dp.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions man/version.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 39 additions & 2 deletions tests/testthat/test-read_camtrap_dp.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
test_that("multiplication works", {
expect_equal(2 * 2, 4)
test_that("read_camtrap_dp() reads a Camtrap DP", {
skip_if_offline()
file <-
"https://raw.githubusercontent.com/tdwg/camtrap-dp/1.0/example/datapackage.json"
expect_no_error(read_camtrap_dp(file))

# TODO: add more tests on returned object
})

test_that("read_camtrap_dp() returns error on unsupported Camtrap DP version", {
skip_if_offline()

# Unsupported version
camtrap_dp_1.0_rc.1 <-
"https://raw.githubusercontent.com/tdwg/camtrap-dp/1.0-rc.1/example/datapackage.json"
expect_error(
read_camtrap_dp(camtrap_dp_1.0_rc.1),
class = "camtrapdp_error_unsupported_version"
)
expect_error(
read_camtrap_dp(camtrap_dp_1.0_rc.1),
regexp = "\"1.0-rc.1\" is not a supported Camtrap DP version.",
fixed = TRUE
)

# Not a Camtrap DP
o_assen <- "https://zenodo.org/records/10053903/files/datapackage.json"
expect_error(
read_camtrap_dp(o_assen),
class = "camtrapdp_error_unsupported_version"
)
})

test_that("read_camtrap_dp() does not convert 1.0", {
skip_if_offline()
camtrap_dp_1.0 <-
"https://raw.githubusercontent.com/tdwg/camtrap-dp/1.0/example/datapackage.json"
x <- read_camtrap_dp(camtrap_dp_1.0)
expect_identical(version(x), "1.0")
})
35 changes: 35 additions & 0 deletions tests/testthat/test-version.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
test_that("version() extracts version from attribute", {
x <- list()
attr(x, "version") <- "1.0"
expect_identical(version(x), "1.0")
})

test_that("version() extracts version from x$profile on match", {
x <- list()
x$profile <- "https://raw.githubusercontent.com/tdwg/camtrap-dp/1.0/camtrap-dp-profile.json"
expect_identical(version(x), "1.0")
x$profile <- "https://rs.gbif.org/sandbox/data-packages/camtrap-dp/1.0/profile/camtrap-dp-profile.json"
expect_identical(version(x), "1.0")
x$profile <- "foo/camtrap-dp/2/foo"
expect_identical(version(x), "2")
x$profile <- "foo/camtrap-dp/2.30/foo"
expect_identical(version(x), "2.30")
x$profile <- "foo/camtrap-dp/2.30.5/foo"
expect_identical(version(x), "2.30.5")
x$profile <- "foo/camtrap-dp/1.0-rc.1/foo"
expect_identical(version(x), "1.0-rc.1")
})

test_that("version() returns x$profile when no match is found", {
x <- list()
x$profile <- NULL
expect_identical(version(x), NA)
x$profile <- NA
expect_identical(version(x), NA)
x$profile <- 1
expect_identical(version(x), 1)
x$profile <- "tabular-data-package"
expect_identical(version(x), "tabular-data-package")
x$profile <- "foo/2.30/foo" # Must contain camtrap-dp/<version>
expect_identical(version(x), "foo/2.30/foo")
})

0 comments on commit 4316ffb

Please sign in to comment.