diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000..2dd506d --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,9 @@ +# Devcontainer Configuration + +This folder contains configuration files required for Codespaces/devcontainers. +Please do not modify its contents unless you know what you are doing and there +is a specific change to the devcontainer configuration you need to make. + +If you believe you have a broken configuration or are unsure if you have the +latest version of the configuration, please follow the +[instructions to add codespaces to your project](https://docs.opensafely.org/getting-started/how-to/add-github-codespaces-to-your-project/). diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..978488f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,55 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/python +{ + "name": "OpenSAFELY", + "image": "ghcr.io/opensafely-core/research-template:v0", + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {} + }, + "postCreateCommand": "/bin/bash /opt/devcontainer/postCreate.sh ${containerWorkspaceFolder}", + "postAttachCommand": "/bin/bash /opt/devcontainer/postAttach.sh", + "forwardPorts": [ + 8787 + ], + "portsAttributes": { + "8787": { + "label": "RStudio IDE" + } + }, + // Configure tool-specific properties. + "customizations": { + "codespaces": { + "repositories": { + "opensafely/server-instructions": { + "permissions": { + "contents": "read" + } + } + } + }, + "vscode": { + "extensions": [ + "ms-python.python", + "ms-toolsai.jupyter", + "ms-toolsai.jupyter-renderers" + ], + "settings": { + "extensions.ignoreRecommendations": true, + "files.autoSave": "afterDelay", + "files.autoSaveDelay": 1000, + "git.autofetch": true, + "python.analysis.extraPaths": [".devcontainer/ehrql-main/"], + "python.defaultInterpreterPath": "/opt/venv/bin/python", + "python.terminal.activateEnvInCurrentTerminal": true, + "python.terminal.activateEnvironment": true, + "window.autoDetectColorScheme": true + } + } + }, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" + "remoteEnv": { + "MAX_WORKERS": "2" + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5d37250 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# ensure unix line endings on windows for files that need them. +*.sh eol=lf +codelists/* eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..27f4a0a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 + +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/setup.yaml b/.github/workflows/setup.yaml new file mode 100644 index 0000000..d433966 --- /dev/null +++ b/.github/workflows/setup.yaml @@ -0,0 +1,45 @@ +name: Setup repository +on: + workflow_dispatch: + push: + branches: [main] +permissions: + contents: write +jobs: + setup: + name: Initialise OpenSAFELY project. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Update README.md and remove action + shell: bash + run: | + export GITHUB_REPOSITORY_OWNER="$(echo $GITHUB_REPOSITORY | awk -F/ '{print $1}')" + export GITHUB_REPOSITORY_NAME="$(echo $GITHUB_REPOSITORY | awk -F/ '{print $2}')" + envsubst < README.md > tmp && mv tmp README.md + rm .github/workflows/setup.yaml + - name: Do not run on template repository + id: is_template + # The only way to trigger this to run when used as a template is on + # push to main. But that means it would also trigger when we push to + # the template repo itself, which we do not want. So, check if we are + # in a template repo + run: | + is_template=false + curl --silent -X GET \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.baptiste-preview+json" \ + https://api.github.com/repos/$GITHUB_REPOSITORY \ + | jq --exit-status '.is_template == false' || is_template=true + # output true/false so later actions can be skipped + echo "::set-output name=is_template::$is_template" + - name: Commit changes + # only actually commit the changes if this is not a template repo + if: steps.is_template.outputs.is_template == 'false' + run: | + # use the same author as the initial commit + git config user.email "$(git log -1 --pretty=format:'%ae')" + git config user.name "$(git log -1 --pretty=format:'%an')" + git add . + git commit --amend --no-edit + git push origin $GITHUB_REF --force diff --git a/.github/workflows/test_runner.yaml b/.github/workflows/test_runner.yaml new file mode 100644 index 0000000..a3f3dc4 --- /dev/null +++ b/.github/workflows/test_runner.yaml @@ -0,0 +1,17 @@ +name: Test that the project is runnable + +on: [push, workflow_dispatch] +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCKER_RO_TOKEN: ${{ secrets.DOCKER_RO_TOKEN }} + STATA_LICENSE: ${{ secrets.STATA_LICENSE }} + HONEYCOMB_API_KEY: ${{ secrets.HONEYCOMB_API_KEY }} +jobs: + test: + runs-on: ubuntu-latest + name: Test the project can run, using dummy data + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Test that the project is runnable + uses: opensafely-core/research-action@v2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c206cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*~ +model.log +*/input.csv +__pycache__ +.python-version +/output/* +metadata/* +venv/ +.DS_Store +.Rhistory +.Rproj.user/ +.devcontainer/ehrql-main/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a67970f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,25 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "OpenSAFELY run project", + "type": "shell", + "command": "opensafely run run_all -f", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "new", + "showReuseMessage": false, + "clear": true, + } + } + ] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..df56052 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) {{current_year}} {{organisation}} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..db682a6 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# ${GITHUB_REPOSITORY_NAME} + +[View on OpenSAFELY](https://jobs.opensafely.org/repo/https%253A%252F%252Fgithub.com%252Fopensafely%252F${GITHUB_REPOSITORY_NAME}) + +Details of the purpose and any published outputs from this project can be found at the link above. + +The contents of this repository MUST NOT be considered an accurate or valid representation of the study or its purpose. +This repository may reflect an incomplete or incorrect analysis with no further ongoing work. +The content has ONLY been made public to support the OpenSAFELY [open science and transparency principles](https://www.opensafely.org/about/#contributing-to-best-practice-around-open-science) and to support the sharing of re-usable code for other subsequent users. +No clinical, policy or safety conclusions must be drawn from the contents of this repository. + +# About the OpenSAFELY framework + +The OpenSAFELY framework is a Trusted Research Environment (TRE) for electronic +health records research in the NHS, with a focus on public accountability and +research quality. + +Read more at [OpenSAFELY.org](https://opensafely.org). + +# Licences +As standard, research projects have a MIT license. diff --git a/analysis/dataset_definition.py b/analysis/dataset_definition.py new file mode 100644 index 0000000..18824f6 --- /dev/null +++ b/analysis/dataset_definition.py @@ -0,0 +1,14 @@ +from ehrql import create_dataset +from ehrql.tables.tpp import patients, practice_registrations + +dataset = create_dataset() + +index_date = "2020-03-31" + +has_registration = practice_registrations.for_patient_on( + index_date +).exists_for_patient() + +dataset.define_population(has_registration) + +dataset.sex = patients.sex diff --git a/codelists/codelists.json b/codelists/codelists.json new file mode 100644 index 0000000..5cc232f --- /dev/null +++ b/codelists/codelists.json @@ -0,0 +1,3 @@ +{ + "files": {} +} \ No newline at end of file diff --git a/codelists/codelists.txt b/codelists/codelists.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docs/.gitkeep @@ -0,0 +1 @@ + diff --git a/logs/.gitkeep b/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/output/.gitkeep b/output/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/project.yaml b/project.yaml new file mode 100644 index 0000000..0aadb83 --- /dev/null +++ b/project.yaml @@ -0,0 +1,12 @@ +version: '3.0' + +# Ignore this`expectation` block. It is required but not used, and will be removed in future versions. +expectations: + population_size: 1000 + +actions: + generate_dataset: + run: ehrql:v1 generate-dataset analysis/dataset_definition.py --output output/dataset.csv.gz + outputs: + highly_sensitive: + dataset: output/dataset.csv.gz