Skip to content

Commit

Permalink
Various updates (#9)
Browse files Browse the repository at this point in the history
* skip markdown files that don't have jupytext header

* Add <COGSTUB> feature

* add pypi-publishing workflow

* add straggler

* cleanup readme
  • Loading branch information
rsokl authored Feb 28, 2022
1 parent cc5a527 commit d8f1e41
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 16 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/pypi_publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

name: Upload Python Package

on:
release:
types: [created]

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ By default, existing notebooks will not be overwritten. Specifying `--force` or


## Forms of Delimiters
Any instructor-only markdown file should be properly delimited. To delimit blocks of Python code, use:
Any instructor-only markdown file should be properly delimited. To delimit blocks of Python code, use `<COGINST>`:
````
```python
# set-up code here
Expand All @@ -77,7 +77,7 @@ Running Cogbooks will then yield:
# STUDENT CODE HERE
```

Alternatively, to remove single lines of code, use:
Alternatively, to remove single lines of code, use `<COGLINE>`:
````
```python
# set-up code here
Expand All @@ -90,6 +90,19 @@ Applying Cogbooks will again result in:
# STUDENT CODE HERE
```

To leave a "stubbed" assignment expression, one can use `<COGSTUB>` to the right of an assignment (i.e. an expression using `=`):

````
```python
x = 33.1 # <COGSTUB> compute `x`
```
````
Applying Cogbooks will leave behind a "stub" for that assignment:

```python
x = # compute `x`
```


In markdown, use:
```markdown
Expand Down
22 changes: 20 additions & 2 deletions src/cogbooks/_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

from jupytext.cli import jupytext

JUPYTEXT_HEADER = """---
jupyter:
jupytext:"""

def strip_text(text: str) -> str:
"""
Expand Down Expand Up @@ -37,7 +40,15 @@ def strip_text(text: str) -> str:

# Remove single lines from code (with `<COGLINE>` addendum), preserving whitespace
# and replace with a STUDENT CODE HERE comment
return re.sub(r"\S(?<!\s)(.*?)<COGLINE>", "# STUDENT CODE HERE", stu_notebook)
stu_notebook = re.sub(r"\S(?<!\s)(.*?)<COGLINE>", "# STUDENT CODE HERE", stu_notebook)

# Replace expression to the right of a `=` and left of `<COGSTUB>` with a comment.
# z = 1 # <COGSTUB> compute `z`
# z = # compute `z`
stu_notebook = re.sub(r"=.\S(?<!\s)(.*?)<COGSTUB>", "= #", stu_notebook)

return stu_notebook



def make_student_files(path: Path, outdir: Path, force: bool) -> bool:
Expand All @@ -62,7 +73,14 @@ def make_student_files(path: Path, outdir: Path, force: bool) -> bool:

if path.is_file() and path.suffix == ".md" and path.stem != "README":
with path.open(mode="r") as f:
student_notebook_text = strip_text(f.read())
file_contents = f.read()

if not file_contents.startswith(JUPYTEXT_HEADER):
print(path.name + " is not a jupytext-formatted markdown file")
return False

student_notebook_text = strip_text(file_contents)
del file_contents

student_markdown_path = outdir / (path.stem + "_STUDENT.md")
student_notebook_path = student_markdown_path.parent / (
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def cleandir() -> str:
os.mkdir('test_files')
dest = Path.cwd() / 'test_files'
shutil.copy(data_dir / 'test.md', dest)
shutil.copy(data_dir / 'not_jupytext.md', dest)
shutil.copy(data_dir / 'test_STUDENT.ipynb', dest)
yield tmpdirname
os.chdir(old_dir)
1 change: 1 addition & 0 deletions tests/test_file_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def test_dir_ipynb_doesnt_exist():
assert not dest.exists()
os.system(f"cogbooks test_files")
assert dest.exists()
assert len(list((Path(".") / "test_files").glob("*.ipynb"))) == 1


@pytest.mark.usefixtures("cleandir")
Expand Down
1 change: 1 addition & 0 deletions tests/test_files/not_jupytext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Should not be parsed by Cogbooks
51 changes: 39 additions & 12 deletions tests/test_strip_text.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
from cogbooks import strip_text
from hypothesis import given
import hypothesis.strategies as st
from functools import wraps


def contains_cogbook_tag(text: str) -> bool:
return all(item not in text for item in ["<COGINST>", "</COGINST>", "<COGINST>", "</COGNOTE>", "<COGLINE>", "<COGSTUB>"])


def filtered_text(*arg, **kwargs):
return st.text(*arg, **kwargs).filter(contains_cogbook_tag)


@given(
pre_code_delim=st.characters(),
code_delim=st.characters(),
post_code_delim=st.characters(),
pre_md_delim=st.characters(),
md_delim=st.characters(),
post_md_delim=st.characters(),
pre_note_delim=st.characters(),
note_delim=st.characters(),
post_note_delim=st.characters(),
pre_line_delim=st.characters(),
line_delim=st.characters(blacklist_characters="\n"),
post_line_delim=st.characters(),
pre_code_delim=filtered_text(),
code_delim=filtered_text(),
post_code_delim=filtered_text(),
pre_md_delim=filtered_text(),
md_delim=filtered_text(),
post_md_delim=filtered_text(),
pre_note_delim=filtered_text(),
note_delim=filtered_text(),
post_note_delim=filtered_text(),
pre_line_delim=filtered_text(),
line_delim=filtered_text(st.characters(blacklist_characters="\n")),
post_line_delim=filtered_text(),
)
def test_combined_rand_text(
pre_code_delim,
Expand Down Expand Up @@ -72,6 +81,20 @@ def test_combined_rand_text(
assert strip_text(text) == filtered_text


text_strat = filtered_text().filter(lambda x: "=" not in x)


@given(pre=filtered_text().filter(lambda x: "=" not in x),
answer=filtered_text(alphabet="abc123", min_size=1).filter(lambda x: "=" not in x),
description=filtered_text().filter(lambda x: "=" not in x),
)
def test_cogstub(pre: str, answer: str, description: str):

original_text = f"{pre} = {answer} # <COGSTUB> {description}"
filtered_text = f"{pre} = # {description}"
assert strip_text(original_text) == filtered_text


def test_ex_ipynb():
text = """
<!-- #region -->
Expand Down Expand Up @@ -121,6 +144,8 @@ def test_ex_ipynb():
ax.set_xlabel("Frequency [1 / days]")
ax.set_yscale("log")
# </COGINST>
z = 1 # <COGSTUB> compute `z`
```
3.9 We want to smooth this stock market data. We can do this by "removing" the high-frequency coefficients of its Fourier spectrum. Try zeroing-out the top 90% high-frequency coefficients, and then perform an inverse FFT using these altered coefficients. Plot the "recovered" signal on top of a semi-transparent version of the original data (use the plot parameter `alpha=0.5`). Then repeat this, but with zeroing out the top 98% coefficients. In both of these cases, on what scale are the fluctuations being filtered out?
Expand Down Expand Up @@ -185,6 +210,8 @@ def test_ex_ipynb():
```python
# STUDENT CODE HERE
z = # compute `z`
```
3.9 We want to smooth this stock market data. We can do this by "removing" the high-frequency coefficients of its Fourier spectrum. Try zeroing-out the top 90% high-frequency coefficients, and then perform an inverse FFT using these altered coefficients. Plot the "recovered" signal on top of a semi-transparent version of the original data (use the plot parameter `alpha=0.5`). Then repeat this, but with zeroing out the top 98% coefficients. In both of these cases, on what scale are the fluctuations being filtered out?
Expand Down

0 comments on commit d8f1e41

Please sign in to comment.