Skip to content

Commit e96aaaf

Browse files
authored
Merge pull request #1 from stefmolin/env-check-workflow
Add env check workflow with GitHub Actions
2 parents 8df8b56 + 90dd486 commit e96aaaf

File tree

9 files changed

+247
-57
lines changed

9 files changed

+247
-57
lines changed

.github/workflows/env-checks.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# This workflow builds the workshop environment on Mac, Linux, and Windows for
2+
# multiple versions of Python to confirm it can be properly installed.
3+
#
4+
# Author: Stefanie Molin
5+
6+
name: Env Build
7+
8+
# Controls when the workflow will run
9+
on:
10+
# Triggers the workflow on push events
11+
push:
12+
branches: [ "main" ]
13+
14+
# Trigger on pull request always (note the trailing colon)
15+
pull_request:
16+
17+
# Allows you to run this workflow manually from the Actions tab
18+
workflow_dispatch:
19+
20+
# Run this every month
21+
schedule:
22+
- cron: "44 22 11 * *"
23+
24+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
25+
jobs:
26+
# This workflow contains a single job called "build"
27+
build:
28+
name: Python ${{ matrix.python-version }}, ${{ matrix.os }}
29+
30+
# The type of runner that the job will run on
31+
runs-on: ${{ matrix.os }}
32+
33+
defaults:
34+
run:
35+
shell: bash -el {0}
36+
37+
strategy:
38+
fail-fast: false
39+
matrix:
40+
os: [macos-latest, ubuntu-latest, windows-latest]
41+
python-version: ["3.8", "3.9", "3.10"]
42+
43+
# Steps represent a sequence of tasks that will be executed as part of the job
44+
steps:
45+
# checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
46+
- uses: actions/checkout@v3
47+
48+
# remove the Python version from the file for testing
49+
- name: strip hardcoded Python version from environment for testing
50+
run: |
51+
if [[ ${{ matrix.os }} == "macos"* ]]; then
52+
sed -i '' -e '/- python/d' environment.yml;
53+
else
54+
sed -i -e '/- python/d' environment.yml;
55+
fi;
56+
57+
# create the conda env
58+
- uses: conda-incubator/setup-miniconda@v2
59+
with:
60+
python-version: ${{ matrix.python-version }}
61+
auto-update-conda: true
62+
miniforge-variant: Mambaforge
63+
use-mamba: true
64+
channel-priority: true
65+
activate-environment: pandas_workshop
66+
environment-file: environment.yml
67+
68+
- name: conda diagnostics
69+
run: |
70+
conda info
71+
conda list
72+
conda config --show-sources
73+
conda config --show
74+
printenv | sort
75+
76+
- name: verify install
77+
run: cd notebooks && python check_env.py
78+

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Pandas Workshop
22

3-
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/stefmolin/pandas-workshop/main?urlpath=lab) [![Nbviewer](https://img.shields.io/badge/render-nbviewer-lightgrey?logo=jupyter)](https://nbviewer.jupyter.org/github/stefmolin/pandas-workshop/tree/main/) ![GitHub repo size](https://img.shields.io/github/repo-size/stefmolin/pandas-workshop) [![View slides in browser](https://img.shields.io/badge/view-slides-orange?logo=github)](https://stefmolin.github.io/pandas-workshop/slides/html/workshop.slides.html#/)
3+
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/stefmolin/pandas-workshop/main?urlpath=lab) [![Nbviewer](https://img.shields.io/badge/render-nbviewer-lightgrey?logo=jupyter)](https://nbviewer.jupyter.org/github/stefmolin/pandas-workshop/tree/main/) [![Env Build Workflow Status](https://img.shields.io/github/actions/workflow/status/stefmolin/pandas-workshop/env-checks.yml?label=env%20build&logo=github&logoColor=white)](https://github.com/stefmolin/pandas-workshop/actions/workflows/env-checks.yml) ![GitHub repo size](https://img.shields.io/github/repo-size/stefmolin/pandas-workshop?logo=git&logoColor=white) [![View slides in browser](https://img.shields.io/badge/view-slides-orange?logo=reveal.js&logoColor=white)](https://stefmolin.github.io/pandas-workshop/slides/html/workshop.slides.html#/)
44

55
Working with data can be challenging: it often doesn’t come in the best format for analysis, and understanding it well enough to extract insights requires both time and the skills to filter, aggregate, reshape, and visualize it. This session will equip you with the knowledge you need to effectively use pandas – a powerful library for data analysis in Python – to make this process easier.
66

@@ -31,7 +31,7 @@ You should have basic knowledge of Python and be comfortable working in Jupyter
3131

3232
## Setup Instructions
3333

34-
0. Install Python >= version 3.8.0 and <= version 3.10.2 OR install [Anaconda](https://docs.anaconda.com/anaconda/install/)/[Miniconda](https://docs.conda.io/en/latest/miniconda.html). Note that Anaconda/Miniconda is recommended if you are working on a Windows machine and are not very comfortable with the command line. Alternatively, you can use [this](https://mybinder.org/v2/gh/stefmolin/pandas-workshop/main?urlpath=lab) Binder environment if you don't want to install anything on your machine.
34+
0. Install Python >= version 3.8.0 and < version 3.11 OR install [Anaconda](https://docs.anaconda.com/anaconda/install/)/[Miniconda](https://docs.conda.io/en/latest/miniconda.html). Note that Anaconda/Miniconda is recommended if you are working on a Windows machine and are not very comfortable with the command line. Alternatively, you can use [this](https://mybinder.org/v2/gh/stefmolin/pandas-workshop/main?urlpath=lab) Binder environment if you don't want to install anything on your machine.
3535
1. Fork this repository:
3636

3737
![location of fork button in GitHub](./images/fork_button.png)

environment.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name: pandas_workshop
22
channels:
33
- conda-forge
44
dependencies:
5-
- python=3.10.2
6-
- jupyterlab=3.3.0
5+
- python>=3.8.0,<=3.10.15
6+
- jupyterlab=3.5.2
77
- matplotlib=3.5.1
88
- numpy=1.22.3
99
- pandas=1.4.1

images/env_check.png

-489 KB
Loading

images/open_env_check_notebook.png

-552 KB
Loading

notebooks/0-check_your_env.ipynb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
"name": "stdout",
1818
"output_type": "stream",
1919
"text": [
20-
"Using Python in /Users/stefanie/miniconda3/envs/pandas_workshop:\n",
21-
"\u001b[42m[ OK ]\u001b[0m Python is version 3.10.2 | packaged by conda-forge | (main, Mar 8 2022, 15:57:32) [Clang 11.1.0 ]\n",
22-
"\n",
20+
"\u001b[42m[ OK ]\u001b[0m Python\n",
2321
"\u001b[42m[ OK ]\u001b[0m jupyterlab\n",
2422
"\u001b[42m[ OK ]\u001b[0m matplotlib\n",
2523
"\u001b[42m[ OK ]\u001b[0m numpy\n",
@@ -31,7 +29,7 @@
3129
}
3230
],
3331
"source": [
34-
"from utils import run_env_check\n",
32+
"from check_env import run_env_check\n",
3533
"run_env_check()"
3634
]
3735
},
@@ -59,7 +57,7 @@
5957
"name": "python",
6058
"nbconvert_exporter": "python",
6159
"pygments_lexer": "ipython3",
62-
"version": "3.10.2"
60+
"version": "3.10.8"
6361
}
6462
},
6563
"nbformat": 4,

notebooks/check_env.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
"""Check the setup for the workshop."""
2+
3+
from functools import partial
4+
from packaging.version import Version
5+
import importlib
6+
import json
7+
import os
8+
import sys
9+
import yaml
10+
11+
12+
def _print_version_ok(item):
13+
"""
14+
Print an OK message for version check.
15+
16+
Parameters
17+
----------
18+
item : str
19+
The item being inspected (package, tool, etc.).
20+
"""
21+
print('\x1b[42m[ OK ]\x1b[0m', '%s' % item)
22+
23+
def _print_version_failure(item, req_version, version, failures):
24+
"""
25+
Print a failure message for version check.
26+
27+
Parameters
28+
----------
29+
item : str
30+
The item being inspected (package, tool, etc.).
31+
req_version : str
32+
The required version.
33+
version : str
34+
The version currently installed.
35+
failures : list
36+
The list of items currently failing the environment check.
37+
"""
38+
failures.append(item)
39+
if version:
40+
msg = '%s version %s is required, but %s installed.'
41+
values = (item, req_version, version)
42+
else:
43+
msg = '%s is not installed.'
44+
values = item
45+
print('\x1b[41m[FAIL]\x1b[0m', msg % values)
46+
47+
def run_env_check(raise_exc=False):
48+
"""
49+
Check that the packages we need are installed and, if necessary,
50+
whether the Python version is correct.
51+
52+
Parameters
53+
----------
54+
raise_exc : bool, default ``False``
55+
Whether to raise an `Exception` if any of the packages doesn't
56+
match the requirements (used for GitHub Action).
57+
"""
58+
59+
failures = []
60+
_print_failure = partial(_print_version_failure, failures=failures)
61+
62+
# read in the environment file and process versions
63+
with open('../environment.yml', 'r') as file:
64+
env = yaml.safe_load(file)
65+
66+
requirements = {}
67+
for line in env['dependencies']:
68+
try:
69+
if '>=' in line:
70+
pkg, versions = line.split('>=')
71+
if ',<=' in versions:
72+
version = versions.split(',<=')
73+
else:
74+
version = [versions, None]
75+
else:
76+
pkg, version = line.split('=')
77+
except ValueError:
78+
pkg, version = line, None
79+
if '-' in pkg:
80+
continue
81+
requirements[pkg.split('::')[-1]] = version
82+
83+
# check the python version, if provided
84+
try:
85+
required_version = requirements.pop('python')
86+
python_version = sys.version_info
87+
base_python_version = Version(
88+
f'{python_version.major}.{python_version.minor}.{python_version.micro}'
89+
)
90+
if isinstance(required_version, list):
91+
min_version, max_version = (
92+
Version(version_str) for version_str in required_version
93+
)
94+
if (
95+
min_version > base_python_version
96+
or (
97+
max_version and base_python_version > max_version
98+
)
99+
):
100+
print(f'Using Python at {sys.prefix}:\n-> {sys.version}')
101+
_print_failure(
102+
'Python',
103+
f'>= {min_version}{f" and <= {max_version}" if max_version else ""}',
104+
base_python_version
105+
)
106+
else:
107+
_print_version_ok('Python')
108+
else:
109+
for component, value in zip(
110+
['major', 'minor', 'micro'], required_version.split('.')
111+
):
112+
if getattr(python_version, component) != int(value):
113+
print(f'Using Python at {sys.prefix}:\n-> {sys.version}')
114+
_print_failure(
115+
'Python',
116+
required_version,
117+
f'{python_version.major}.{python_version.minor}'
118+
)
119+
break
120+
else:
121+
_print_version_ok('Python')
122+
except KeyError:
123+
pass
124+
125+
for pkg, req_version in requirements.items():
126+
try:
127+
mod = importlib.import_module(pkg)
128+
if req_version:
129+
version = mod.__version__
130+
installed_version = Version(version).base_version
131+
if isinstance(req_version, list):
132+
min_version, max_version = req_version
133+
if (
134+
installed_version < Version(min_version).base_version
135+
or (
136+
max_version and
137+
installed_version > Version(max_version).base_version
138+
)
139+
):
140+
_print_failure(
141+
pkg,
142+
f'>= {min_version}{f" and <= {max_version}" if max_version else ""}',
143+
version
144+
)
145+
continue
146+
elif Version(version).base_version != Version(req_version).base_version:
147+
_print_failure(pkg, req_version, version)
148+
continue
149+
_print_version_ok(pkg)
150+
except ImportError:
151+
_print_failure(pkg, req_version, None)
152+
153+
if failures and raise_exc:
154+
raise Exception(
155+
'Environment failed inspection due to incorrect versions '
156+
f'of {len(failures)} item(s): {", ".join(failures)}.'
157+
)
158+
159+
if __name__ == '__main__':
160+
print(f'Using Python at {sys.prefix}:\n-> {sys.version}')
161+
run_env_check(raise_exc=True)

notebooks/utils.py

Lines changed: 0 additions & 47 deletions
This file was deleted.

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
jupyterlab==3.3.0
1+
jupyterlab==3.5.2
22
matplotlib==3.5.1
33
numpy==1.22.3
44
pandas==1.4.1

0 commit comments

Comments
 (0)