Skip to content

Commit 1682ff1

Browse files
authored
chore: Replace Makefile with poethepoet task runner (#1678)
### Description Migrates from `Makefile` to [Poe the Poet](https://poethepoet.natn.io/) for task running. This is something I've wanted to do for a long time - having a more Pythonic solution than `Makefile`, that keeps all project configuration in `pyproject.toml`, similar to how `npm` scripts work in `package.json`. ### Motivation - Consistency across technologies – The company primarily works with JS/TS, and Poe the Poet is conceptually the closest equivalent to how this is handled there via npm scripts. - Cross-platform compatibility – Makefiles can cause issues on Windows (shell differences, GNU tooling, quoting, ...), whereas Poe the Poet is a pure Python solution that works everywhere Python works. - Single source of configuration – Over time, we have consolidated the configuration of most tools (linter, type checker, formatter, pytest, …) into a single file (`pyproject.toml`), which is also a long-term trend in the Python ecosystem. Moving task definitions into Poe the Poet within `pyproject.toml` is a natural next step in this direction. - Being Pythonic – Poe the Poet is a Python-native tool designed specifically for running tasks in Python projects. Makefile, on the other hand, is a general, historically Unix-centric tool originally intended for building and linking C/C++ software 😄. Meaning it is definitely a less natural fit for pure Python projects. The presence of a Makefile in a Python open-source library is, at the very least, surprising 😄. ### Changes - Remove `Makefile`. - Add `poethepoet` as a dev dependency. - Add `[tool.poe.tasks]` section in `pyproject.toml` with all tasks. - Update `CONTRIBUTING.md` with new commands and `poe` documentation. - Update GitHub workflows to use `uv run poe` commands. - Update `.pre-commit-config.yaml` to use `poe` tasks. ### Usage Tasks are now run with `uv run poe <task>` (or just `poe <task>` if you have venv actived): ```sh uv run poe install-dev uv run poe lint uv run poe format uv run poe type-check uv run poe unit-tests uv run poe check-code uv run poe build-docs uv run poe run-docs ```
1 parent 42947c8 commit 1682ff1

File tree

8 files changed

+113
-110
lines changed

8 files changed

+113
-110
lines changed

.github/workflows/_release_docs.yaml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,10 @@ jobs:
5050
python-version: ${{ env.PYTHON_VERSION }}
5151

5252
- name: Install Python dependencies
53-
run: make install-dev
54-
55-
- name: Build generated API reference
56-
run: make build-api-reference
53+
run: uv run poe install-dev
5754

5855
- name: Build Docusaurus docs
59-
run: make build-docs
56+
run: uv run poe build-docs
6057
env:
6158
APIFY_SIGNING_TOKEN: ${{ secrets.APIFY_SIGNING_TOKEN }}
6259
SEGMENT_TOKEN: ${{ secrets.SEGMENT_TOKEN }}

.github/workflows/on_schedule_tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ jobs:
5757

5858
# Sync the project, but no need to install the browsers into the test runner environment.
5959
- name: Install Python dependencies
60-
run: make install-sync
60+
run: uv run poe install-sync
6161

6262
- name: Run templates end-to-end tests
63-
run: make e2e-templates-tests args="-m ${{ matrix.http-client }} and ${{ matrix.crawler-type }} and ${{ matrix.package-manager }}"
63+
run: uv run poe e2e-templates-tests -- -m "${{ matrix.http-client }} and ${{ matrix.crawler-type }} and ${{ matrix.package-manager }}"
6464
env:
6565
APIFY_TEST_USER_API_TOKEN: ${{ secrets.APIFY_TEST_USER_API_TOKEN }}

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ repos:
33
hooks:
44
- id: lint-check
55
name: Lint check
6-
entry: make lint
6+
entry: uv run poe lint
77
language: system
88
pass_filenames: false
99

1010
- id: type-check
1111
name: Type check
12-
entry: make type-check
12+
entry: uv run poe type-check
1313
language: system
1414
pass_filenames: false

CONTRIBUTING.md

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,40 @@ For local development, it is required to have Python 3.10 (or a later version) i
88

99
We use [uv](https://docs.astral.sh/uv/) for project management. Install it and set up your IDE accordingly.
1010

11+
We use [Poe the Poet](https://poethepoet.natn.io/) as a task runner, similar to npm scripts in `package.json`.
12+
All tasks are defined in `pyproject.toml` under `[tool.poe.tasks]` and can be run with `uv run poe <task>`.
13+
14+
### Available tasks
15+
16+
| Task | Description |
17+
| ---- | ----------- |
18+
| `install-dev` | Install development dependencies |
19+
| `check-code` | Run lint, type-check, and unit-tests |
20+
| `lint` | Run linter |
21+
| `format` | Fix lint issues and format code |
22+
| `type-check` | Run type checker |
23+
| `unit-tests` | Run unit tests |
24+
| `unit-tests-cov` | Run unit tests with coverage |
25+
| `e2e-templates-tests` | Run end-to-end template tests |
26+
| `build-docs` | Build documentation website |
27+
| `run-docs` | Run documentation website locally |
28+
| `build` | Build package |
29+
| `clean` | Remove build artifacts and clean caches |
30+
1131
## Dependencies
1232

1333
To install this package and its development dependencies, run:
1434

1535
```sh
16-
make install-dev
36+
uv run poe install-dev
1737
```
1838

1939
## Code checking
2040

2141
To execute all code checking tools together, run:
2242

2343
```sh
24-
make check-code
44+
uv run poe check-code
2545
```
2646

2747
### Linting
@@ -31,7 +51,7 @@ We utilize [ruff](https://docs.astral.sh/ruff/) for linting, which analyzes code
3151
To run linting:
3252

3353
```sh
34-
make lint
54+
uv run poe lint
3555
```
3656

3757
### Formatting
@@ -41,7 +61,7 @@ Our automated code formatting also leverages [ruff](https://docs.astral.sh/ruff/
4161
To run formatting:
4262

4363
```sh
44-
make format
64+
uv run poe format
4565
```
4666

4767
### Type checking
@@ -51,51 +71,48 @@ Type checking is handled by [ty](https://docs.astral.sh/ty/), verifying code aga
5171
To run type checking:
5272

5373
```sh
54-
make type-check
74+
uv run poe type-check
5575
```
5676

5777
### Unit tests
5878

59-
We employ pytest as our testing framework, equipped with various plugins. Check pyproject.toml for configuration details and installed plugins.
60-
6179
We use [pytest](https://docs.pytest.org/) as a testing framework with many plugins. Check `pyproject.toml` for configuration details and installed plugins.
6280

6381
To run unit tests:
6482

6583
```sh
66-
make unit-tests
84+
uv run poe unit-tests
6785
```
6886

69-
To run unit tests with HTML coverage report:
87+
To run unit tests with coverage report:
7088

7189
```sh
72-
make unit-tests-cov
90+
uv run poe unit-tests-cov
7391
```
7492

7593
## End-to-end tests
7694

77-
Pre-requisites for running end-to-end tests:
78-
- [apify-cli](https://docs.apify.com/cli/docs/installation) correctly installed
79-
- `apify-cli` available in `PATH` environment variable
80-
- Your [apify token](https://docs.apify.com/platform/integrations/api#api-token) is available in `APIFY_TEST_USER_API_TOKEN` environment variable
95+
Prerequisites:
8196

97+
- [apify-cli](https://docs.apify.com/cli/docs/installation) installed and available in `PATH`
98+
- Set `APIFY_TEST_USER_API_TOKEN` to your [Apify API token](https://docs.apify.com/platform/integrations/api#api-token)
8299

83100
To run end-to-end tests:
84101

85102
```sh
86-
make e2e-templates-tests
103+
uv run poe e2e-templates-tests
87104
```
88105

89106
## Documentation
90107

91108
We follow the [Google docstring format](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) for code documentation. All user-facing classes and functions must be documented. Documentation standards are enforced using [Ruff](https://docs.astral.sh/ruff/).
92109

93-
Our API documentation is generated from these docstrings using [pydoc-markdown](https://pypi.org/project/pydoc-markdown/) with custom post-processing. Additional content is provided through markdown files in the `docs/` directory. The final documentation is rendered using [Docusaurus](https://docusaurus.io/) and published to GitHub pages.
110+
Our API documentation is generated from these docstrings using [pydoc-markdown](https://pypi.org/project/pydoc-markdown/) with custom post-processing. Additional content is provided through markdown files in the `docs/` directory. The final documentation is rendered using [Docusaurus](https://docusaurus.io/) and published to GitHub Pages.
94111

95112
To run the documentation locally, ensure you have `Node.js` 20+ installed, then run:
96113

97114
```sh
98-
make run-docs
115+
uv run poe run-docs
99116
```
100117

101118
## Release process
@@ -120,14 +137,14 @@ name = "crawlee"
120137
version = "x.z.y"
121138
```
122139

123-
4. Generate the distribution archives for the package:
140+
4. Build the package:
124141

125-
```shell
126-
uv build
142+
```sh
143+
uv run poe build
127144
```
128145

129-
5. Set up the PyPI API token for authentication and upload the package to PyPI:
146+
5. Upload to PyPI:
130147

131-
```shell
148+
```sh
132149
uv publish --token YOUR_API_TOKEN
133150
```

Makefile

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

pyproject.toml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ dev = [
102102
"build<2.0.0", # For e2e tests.
103103
"dycw-pytest-only<3.0.0",
104104
"fakeredis[probabilistic,json,lua]<3.0.0",
105+
"poethepoet<1.0.0",
105106
"pre-commit<5.0.0",
106107
"proxy-py<3.0.0",
107108
"pydoc-markdown<5.0.0",
@@ -255,3 +256,44 @@ exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:", "assert_never()"]
255256

256257
[tool.ipdb]
257258
context = 7
259+
260+
# Run tasks with: uv run poe <task>
261+
[tool.poe.tasks]
262+
clean = "rm -rf .coverage .pytest_cache .ruff_cache .ty_cache .uv-cache build coverage-unit.xml dist htmlcov website/.docusaurus website/.yarn website/module_shortcuts.json website/node_modules "
263+
install-sync = "uv sync --all-extras"
264+
build = "uv build --verbose"
265+
publish-to-pypi = "uv publish --verbose --token ${APIFY_PYPI_TOKEN_CRAWLEE}"
266+
type-check = "uv run ty check"
267+
check-code = ["lint", "type-check", "unit-tests"]
268+
269+
[tool.poe.tasks.install-dev]
270+
shell = "uv sync --all-extras && uv run pre-commit install && uv run playwright install"
271+
272+
[tool.poe.tasks.lint]
273+
shell = "uv run ruff format --check && uv run ruff check"
274+
275+
[tool.poe.tasks.format]
276+
shell = "uv run ruff check --fix && uv run ruff format"
277+
278+
[tool.poe.tasks.unit-tests]
279+
shell = """
280+
uv run pytest --numprocesses=1 --verbose -m "run_alone" tests/unit && \
281+
uv run pytest --numprocesses=auto --verbose -m "not run_alone" tests/unit
282+
"""
283+
284+
[tool.poe.tasks.unit-tests-cov]
285+
shell = """
286+
uv run pytest --numprocesses=1 --verbose -m "run_alone" --cov=src/crawlee --cov-report=xml:coverage-unit.xml tests/unit && \
287+
uv run pytest --numprocesses=auto --verbose -m "not run_alone" --cov=src/crawlee --cov-report=xml:coverage-unit.xml --cov-append tests/unit
288+
"""
289+
290+
[tool.poe.tasks.e2e-templates-tests]
291+
cmd = "uv run pytest --numprocesses=${E2E_TESTS_CONCURRENCY:-1} --verbose tests/e2e/project_template --timeout=600"
292+
293+
[tool.poe.tasks.build-docs]
294+
shell = "./build_api_reference.sh && corepack enable && yarn && yarn build"
295+
cwd = "website"
296+
297+
[tool.poe.tasks.run-docs]
298+
shell = "./build_api_reference.sh && corepack enable && yarn && yarn start"
299+
cwd = "website"

tests/unit/crawlers/_playwright/test_playwright_crawler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None:
234234
assert 'headless' not in headers['user-agent'].lower()
235235

236236

237+
@pytest.mark.flaky(reruns=3, reason='Test is flaky.')
237238
async def test_firefox_headless_headers(header_network: dict, server_url: URL) -> None:
238239
browser_type: BrowserType = 'firefox'
239240
crawler = PlaywrightCrawler(headless=True, browser_type=browser_type)

uv.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)