Skip to content

Commit 0c2198b

Browse files
committed
Merge enhancement into master
2 parents c759336 + f0e51ac commit 0c2198b

5 files changed

Lines changed: 148 additions & 10 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
tags: '*.*.*'
6+
release:
7+
types: [ published ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version:
15+
- '3.8'
16+
- '3.9'
17+
- '3.10'
18+
- '3.11'
19+
- '3.12'
20+
- '3.13'
21+
- '3.14'
22+
23+
steps:
24+
- uses: actions/checkout@v3
25+
26+
- name: Set up Python ${{ matrix.python-version }}
27+
uses: actions/setup-python@v4
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
31+
- name: Install dependencies
32+
run: |
33+
python -m pip install --upgrade pip
34+
python -m pip install -e . --extra-index-url https://source.md.land/python/
35+
python -m pip install pytest pytest-cov
36+
# pip install -e ".[test]"
37+
38+
- name: Run tests
39+
run: |
40+
# python -m pytest tests/ --cov=lib --cov-report=xml
41+
export PYTHONPATH="$(pwd -P)/lib:$PYTHONPATH"
42+
python -m pytest tests/unit/md/processor/processor.py --cov=lib --cov-report=term
43+
44+
# - name: Upload coverage to Codecov
45+
# uses: codecov/codecov-action@v3
46+
# if: matrix.python-version == '3.10'
47+
# with:
48+
# file: ./coverage.xml
49+
# fail_ci_if_error: true
50+
51+
security:
52+
runs-on: ubuntu-latest
53+
steps:
54+
- uses: actions/checkout@v3
55+
56+
- name: Set up Python
57+
uses: actions/setup-python@v4
58+
with:
59+
python-version: '3.10'
60+
61+
- name: Install safety
62+
run: pip install safety
63+
64+
- name: Check dependencies for vulnerabilities
65+
run: safety check --full-report
66+
67+
- name: Install bandit
68+
run: pip install bandit
69+
70+
- name: Static security analysis
71+
run: bandit -r lib/ -f json -o bandit-report.json --skip B101
72+
73+
type-check:
74+
runs-on: ubuntu-latest
75+
steps:
76+
- uses: actions/checkout@v3
77+
78+
- name: Set up Python
79+
uses: actions/setup-python@v4
80+
with:
81+
python-version: '3.10'
82+
83+
- name: Install mypy
84+
run: pip install mypy
85+
86+
- name: Install dependencies
87+
run: pip install -e . --extra-index-url https://source.md.land/python/
88+
89+
- name: Type checking
90+
run: |
91+
export PYTHONPATH="$(pwd -P)/lib:$PYTHONPATH"
92+
mypy lib/ --disable-error-code import-untyped
93+
94+
build:
95+
needs: [test, security, type-check]
96+
runs-on: ubuntu-latest
97+
98+
steps:
99+
- uses: actions/checkout@v3
100+
101+
- name: Set up Python
102+
uses: actions/setup-python@v4
103+
with:
104+
python-version: '3.10'
105+
106+
- name: Install build dependencies
107+
run: pip install build wheel
108+
109+
- name: Build wheel package
110+
run: python -m build --wheel
111+
112+
- name: List artifacts
113+
run: ls -la dist/
114+
115+
- name: Upload wheel to GitHub Releases
116+
uses: svenstaro/upload-release-action@v2
117+
with:
118+
repo_token: ${{ secrets.GITHUB_TOKEN }}
119+
file: dist/*.whl
120+
tag: ${{ github.ref }}
121+
overwrite: true
122+
file_glob: true

changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- add retry logic
1111

12+
## [1.1.0] — 2026-01-02
13+
### Added
14+
15+
- [x] feature: add generic typing for contracts and base implementation
16+
- [x] feature: add CI/CD github workflow configuration
1217

1318
## [1.0.0] - 2022-05-19
1419

1520
- Implementation initialization
1621

22+
[1.1.0]: https://github.com/md-py/md.processor/compare/1.0.0..1.1.0
1723
[1.0.0]: https://github.com/md-py/md.processor/releases/tag/1.0.0

docs/index.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,25 @@ if __name__ == '__main__':
105105
```
106106

107107
```python3
108-
if __name__ == '__main__':
108+
if __name__ == '__main__':
109109
# Use case #3: as same as #2 using `worker` concept
110110
worker = md.processor.Worker(
111111
provider=convert_image_task_provider,
112112
processor=convert_image_processor,
113113
)
114-
114+
115115
try:
116116
worker.run()
117117
except ConvertException as e:
118118
exit(1)
119119
```
120120

121+
## Thread safe provider
122+
123+
Python does not provide thread safe access to generators by default,
124+
in case when task provider is assumed to be shared and used in few threads,
125+
consider to wrap provider with thread safe provider from
126+
[md.processor.threading](../md.processor.threading/) component to prevent
127+
race-condition issue.
128+
121129
[architecture-overview]: _static/architecture.class-diagram.svg

lib/md/processor/_processor.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# Metadata
55
__author__ = 'https://md.land/md'
6-
__version__ = '1.0.0'
6+
__version__ = '1.1.0'
77
__all__ = (
88
# Metadata
99
'__author__',
@@ -21,6 +21,8 @@
2121
)
2222

2323

24+
T = typing.TypeVar('T', bound='TaskInterface')
25+
2426
# Exception
2527
class ProcessorException(RuntimeError):
2628
""" Component marker exception """
@@ -43,21 +45,21 @@ class TaskInterface:
4345
pass
4446

4547

46-
class ProviderInterface:
48+
class ProviderInterface(typing.Generic[T]):
4749
""" Provides task to process """
48-
def provide(self) -> typing.Iterator[TaskInterface]:
50+
def provide(self) -> typing.Iterator[T]:
4951
raise NotImplementedError
5052

5153

52-
class ProcessorInterface:
54+
class ProcessorInterface(typing.Generic[T]):
5355
""" Processes task """
54-
def process(self, task: TaskInterface) -> None:
56+
def process(self, task: T) -> None:
5557
raise NotImplementedError
5658

5759

5860
# Implementation
59-
class Worker: # nt: unit
60-
def __init__(self, provider: ProviderInterface, processor: ProcessorInterface) -> None:
61+
class Worker(typing.Generic[T]): # nt: unit
62+
def __init__(self, provider: ProviderInterface[T], processor: ProcessorInterface[T]) -> None:
6163
self._provider = provider
6264
self._processor = processor
6365

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
setuptools.setup(
88
name='md.processor',
9-
version='1.0.0',
9+
version='1.1.0',
1010
description='Common task processing contracts',
1111
long_description=long_description,
1212
long_description_content_type='text/markdown',

0 commit comments

Comments
 (0)