Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,62 @@ concurrency:
cancel-in-progress: true

jobs:

format:
name: "Check formatting"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# [[[cog cog.include("./steps/checkout.yml") ]]]
- name: "Check out the repo"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
# [[[end]]]

# [[[cog cog.include("./steps/ruff.yml") ]]]
- uses: astral-sh/ruff-action@eaf0ecdd668ceea36159ff9d91882c9795d89b49 # v3.4.0
# [[[end]]]
with:
args: 'format --check'
args: "format --check"

lint:
name: "Lint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# [[[cog cog.include("./steps/checkout.yml") ]]]
- name: "Check out the repo"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
# [[[end]]]

# [[[cog cog.include("./steps/ruff.yml") ]]]
- uses: astral-sh/ruff-action@eaf0ecdd668ceea36159ff9d91882c9795d89b49 # v3.4.0
# [[[end]]]

# [[[cog cog.include("./steps/setup-python.yml") ]]]
- name: "Set up Python"
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
# [[[end]]]
with:
python-version: "3.13"

# [[[cog cog.include("./steps/install-dependencies.yml") ]]]
- name: "Install dependencies"
run: |
python -m pip install -r requirements.pip

# [[[end]]]
- name: "Check the docs are up-to-date"
run: |
make lintdoc

- name: "Check that this file is up-to-date"
run: |
python -m cogapp -r --check --diff .github/workflows/ci.yml
if [ $? -ne 0 ]; then
echo 'Docs need to be updated: `python -m cogapp -r .github/workflows/ci.yml`';
exit 1;
fi

tests:
name: "Python ${{ matrix.python }} on ${{ matrix.os }}"
runs-on: "${{ matrix.os }}-${{ matrix.os-version || 'latest' }}"
Expand Down Expand Up @@ -79,20 +99,25 @@ jobs:
os-version: "13"

steps:
# [[[cog cog.include("./steps/checkout.yml") ]]]
- name: "Check out the repo"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
# [[[end]]]

# [[[cog cog.include("./steps/setup-python.yml") ]]]
- name: "Set up Python"
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
# [[[end]]]
with:
python-version: "${{ matrix.python }}"

# [[[cog cog.include("./steps/install-dependencies.yml") ]]]
- name: "Install dependencies"
run: |
python -m pip install -r requirements.pip

# [[[end]]]
- name: "Run tox for ${{ matrix.python }}"
run: |
python -m tox
Expand All @@ -111,21 +136,26 @@ jobs:
runs-on: ubuntu-latest

steps:
# [[[cog cog.include("./steps/checkout.yml") ]]]
- name: "Check out the repo"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: "0"
persist-credentials: false
# [[[end]]]
fetch-depth: "0"

# [[[cog cog.include("./steps/setup-python.yml") ]]]
- name: "Set up Python"
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
# [[[end]]]
with:
python-version: "3.9"

# [[[cog cog.include("./steps/install-dependencies.yml") ]]]
- name: "Install dependencies"
run: |
python -m pip install -r requirements.pip

# [[[end]]]
- name: "Download coverage data"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/steps/checkout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- name: "Check out the repo"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
3 changes: 3 additions & 0 deletions .github/workflows/steps/install-dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- name: "Install dependencies"
run: |
python -m pip install -r requirements.pip
1 change: 1 addition & 0 deletions .github/workflows/steps/ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- uses: astral-sh/ruff-action@eaf0ecdd668ceea36159ff9d91882c9795d89b49 # v3.4.0
2 changes: 2 additions & 0 deletions .github/workflows/steps/setup-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- name: "Set up Python"
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Daniel Murdin
Doug Hellmann
Hugh Perkins
Jean-François Giraud
Joshua Cannon
Panayiotis Gavriil
Petr Gladkiy
Phil Kirkpatrick
Expand Down
13 changes: 11 additions & 2 deletions cogapp/cogapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io
import linecache
import os
import os.path
import re
import shlex
import sys
Expand Down Expand Up @@ -111,10 +112,11 @@ class CogCheckFailed(CogError):
class CogGenerator(Redirectable):
"""A generator pulled from a source file."""

def __init__(self, options=None):
def __init__(self, filename, options=None):
super().__init__()
self.markers = []
self.lines = []
self.filename = filename
self.options = options or CogOptions()

def parse_marker(self, line):
Expand Down Expand Up @@ -152,6 +154,7 @@ def evaluate(self, cog, globals, fname):
cog.cogmodule.msg = self.msg
cog.cogmodule.out = self.out
cog.cogmodule.outl = self.outl
cog.cogmodule.include = self.include
cog.cogmodule.error = self.error

real_stdout = sys.stdout
Expand Down Expand Up @@ -205,6 +208,12 @@ def outl(self, sOut="", **kw):
self.out(sOut, **kw)
self.out("\n")

def include(self, filepath, **kw):
"""The cog.include function."""
parent_dir = os.path.dirname(self.filename)
with open(os.path.join(parent_dir, filepath), "r") as f:
self.out(f.read(), **kw)

def error(self, msg="Error raised by cog generator."):
"""The cog.error function.

Expand Down Expand Up @@ -466,7 +475,7 @@ def process_file(self, file_in, file_out, fname=None, globals=None):
file_out.write(line)

# `line` is the begin spec
gen = CogGenerator(options=self.options)
gen = CogGenerator(filename=file_name_in, options=self.options)
gen.set_output(stdout=self.stdout)
gen.parse_marker(line)
first_line_num = file_in.linenumber()
Expand Down
54 changes: 54 additions & 0 deletions cogapp/test_cogapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,60 @@ def test_change_dir(self):
output = self.output.getvalue()
self.assertIn("(changed)", output)

def test_cog_include(self):
d = {
"coglet": "World!",
"sub": {
"coglet": "Hello!",
"test.cog": """\
//[[[cog
cog.include("coglet")
cog.include("./coglet")
cog.include("../coglet")
//]]]
//[[[end]]]
""",
"test.out": """\
//[[[cog
cog.include("coglet")
cog.include("./coglet")
cog.include("../coglet")
//]]]
Hello!
Hello!
World!
//[[[end]]]
""",
},
}

make_files(d)
self.cog.callable_main(["argv0", "-r", "sub/test.cog"])
self.assertFilesSame("sub/test.cog", "sub/test.out")
output = self.output.getvalue()
self.assertIn("(changed)", output)

def test_cog_include_with_stdin(self):
d = {"coglet": "Hello World!"}
make_files(d)
stdin = io.StringIO("--[[[cog cog.include('coglet') ]]]\n--[[[end]]]\n")

def restore_stdin(old_stdin):
sys.stdin = old_stdin

self.addCleanup(restore_stdin, sys.stdin)
sys.stdin = stdin

stderr = io.StringIO()
self.cog.set_output(stderr=stderr)
self.cog.callable_main(["argv0", "-"])
output = self.output.getvalue()
outerr = stderr.getvalue()
self.assertEqual(
output, "--[[[cog cog.include('coglet') ]]]\nHello World!\n--[[[end]]]\n"
)
self.assertEqual(outerr, "")


class CogTestLineEndings(TestCaseWithTempDir):
"""Tests for -U option (force LF line-endings in output)."""
Expand Down
4 changes: 4 additions & 0 deletions docs/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ The module contents are:
**cog.outl**
Same as **cog.out**, but adds a trailing newline.

**cog.include(filepath=, **kwargs)**
Outputs the contents of the file at filepath (relative to the current file's directory).
(Keyword-arguments forwarded to **cog.out**)

**cog.msg** `(msg)`
Prints `msg` to stdout with a "Message: " prefix.

Expand Down