mediacatch 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mediacatch might be problematic. Click here for more details.

@@ -0,0 +1,34 @@
1
+ name: Quality Check
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ quality:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v3
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v4
21
+ with:
22
+ python-version: "3.10"
23
+ cache: "pip"
24
+ cache-dependency-path: pyproject.toml
25
+ - uses: actions/cache@v3
26
+ id: cache
27
+ with:
28
+ path: ${{ env.pythonLocation }}
29
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-check
30
+ - name: Install build dependencies
31
+ if: steps.cache.outputs.cache-hit != 'true'
32
+ run: pip install ".[dev]"
33
+ - name: Run library checks
34
+ run: ruff .
@@ -0,0 +1,33 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types:
6
+ - released
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v3
13
+ - name: Set up Python
14
+ uses: actions/setup-python@v4
15
+ with:
16
+ python-version: "3.10"
17
+ cache: "pip"
18
+ cache-dependency-path: pyproject.toml
19
+ - uses: actions/cache@v3
20
+ id: cache
21
+ with:
22
+ path: ${{ env.pythonLocation }}
23
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-publish
24
+ - name: Install build dependencies
25
+ if: steps.cache.outputs.cache-hit != 'true'
26
+ run: pip install --upgrade build hatchling pkginfo
27
+ - name: Build distribution
28
+ run: python -m build
29
+ - name: Publish
30
+ uses: pypa/gh-action-pypi-publish@v1.6.4
31
+ with:
32
+ password: ${{ secrets.PYPI_API_TOKEN }}
33
+ verbose: true
@@ -0,0 +1,34 @@
1
+ name: Unit Tests
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ quality:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v3
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v4
21
+ with:
22
+ python-version: "3.10"
23
+ cache: "pip"
24
+ cache-dependency-path: pyproject.toml
25
+ - uses: actions/cache@v3
26
+ id: cache
27
+ with:
28
+ path: ${{ env.pythonLocation }}
29
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test
30
+ - name: Install build dependencies
31
+ if: steps.cache.outputs.cache-hit != 'true'
32
+ run: pip install ".[test]"
33
+ - name: Run tests
34
+ run: pytest
@@ -0,0 +1,151 @@
1
+ data
2
+
3
+ # Byte-compiled / optimized / DLL files
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ pip-wheel-metadata/
26
+ share/python-wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .nox/
46
+ .coverage
47
+ .coverage.*
48
+ .cache
49
+ nosetests.xml
50
+ coverage.xml
51
+ *.cover
52
+ *.py,cover
53
+ .hypothesis/
54
+ .pytest_cache/
55
+
56
+ # Translations
57
+ *.mo
58
+ *.pot
59
+
60
+ # Django stuff:
61
+ *.log
62
+ local_settings.py
63
+ db.sqlite3
64
+ db.sqlite3-journal
65
+
66
+ # Flask stuff:
67
+ instance/
68
+ .webassets-cache
69
+
70
+ # Scrapy stuff:
71
+ .scrapy
72
+
73
+ # Sphinx documentation
74
+ docs/_build/
75
+
76
+ # PyBuilder
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ .python-version
88
+
89
+ # pipenv
90
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
91
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
92
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
93
+ # install all needed dependencies.
94
+ #Pipfile.lock
95
+
96
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
97
+ __pypackages__/
98
+
99
+ # Celery stuff
100
+ celerybeat-schedule
101
+ celerybeat.pid
102
+
103
+ # SageMath parsed files
104
+ *.sage.py
105
+
106
+ # Environments
107
+ .env
108
+ .venv
109
+ env/
110
+ venv/
111
+ ENV/
112
+ env.bak/
113
+ venv.bak/
114
+
115
+ # Spyder project settings
116
+ .spyderproject
117
+ .spyproject
118
+
119
+ # Rope project settings
120
+ .ropeproject
121
+
122
+ # mkdocs documentation
123
+ /site
124
+
125
+ # mypy
126
+ .mypy_cache/
127
+ .dmypy.json
128
+ dmypy.json
129
+
130
+ # Pyre type checker
131
+ .pyre/
132
+ .ruff_cache
133
+
134
+ ### VisualStudioCode ###
135
+ .vscode/*
136
+ .vscode/settings.json
137
+ .vscode/tasks.json
138
+ .vscode/launch.json
139
+ .vscode/extensions.json
140
+ .vscode/*.code-snippets
141
+
142
+ # Local History for Visual Studio Code
143
+ .history/
144
+
145
+ # Built Visual Studio Code Extensions
146
+ *.vsix
147
+
148
+ ### VisualStudioCode Patch ###
149
+ # Ignore all local history of files
150
+ .history
151
+ .ionide
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.3
2
+ Name: mediacatch
3
+ Version: 0.0.1
4
+ Summary: Python package for easily interfacing with MediaCatch APIs and data formats.
5
+ Project-URL: Documentation, https://github.com/mediacatch/mediacatch#readme
6
+ Project-URL: Issues, https://github.com/mediacatch/mediacatch/issues
7
+ Project-URL: Source, https://github.com/mediacatch/mediacatch
8
+ Author-email: Mathias Nielsen <mathias@mediacatch.io>, Frederik Haarslev <frederik@mediacatch.io>
9
+ License-Expression: MIT
10
+ Classifier: Framework :: FastAPI
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Topic :: Internet
16
+ Classifier: Topic :: Software Development
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: opencv-python-headless
22
+ Requires-Dist: pydantic
23
+ Requires-Dist: python-dotenv
24
+ Requires-Dist: requests
25
+ Provides-Extra: dev
26
+ Requires-Dist: black; extra == 'dev'
27
+ Requires-Dist: hatch; extra == 'dev'
28
+ Requires-Dist: isort; extra == 'dev'
29
+ Requires-Dist: mypy; extra == 'dev'
30
+ Requires-Dist: ruff; extra == 'dev'
31
+ Provides-Extra: docs
32
+ Requires-Dist: mkdocs; extra == 'docs'
33
+ Requires-Dist: mkdocs-autorefs; extra == 'docs'
34
+ Requires-Dist: mkdocs-material; extra == 'docs'
35
+ Requires-Dist: mkdocstrings; extra == 'docs'
36
+ Requires-Dist: mkdocstrings-python; extra == 'docs'
37
+ Provides-Extra: test
38
+ Requires-Dist: black; extra == 'test'
39
+ Requires-Dist: hatch; extra == 'test'
40
+ Requires-Dist: isort; extra == 'test'
41
+ Requires-Dist: mypy; extra == 'test'
42
+ Requires-Dist: pytest; extra == 'test'
43
+ Requires-Dist: ruff; extra == 'test'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # MediaCatch
47
+
48
+ Python package for easily interfacing with MediaCatch APIs and data formats.
49
+
50
+ ## Installation
51
+
52
+ TBD.
53
+
54
+ ## Getting Started
55
+
56
+ TBD.
@@ -0,0 +1,11 @@
1
+ # MediaCatch
2
+
3
+ Python package for easily interfacing with MediaCatch APIs and data formats.
4
+
5
+ ## Installation
6
+
7
+ TBD.
8
+
9
+ ## Getting Started
10
+
11
+ TBD.
@@ -0,0 +1,17 @@
1
+ import logging
2
+ import sys
3
+ import os
4
+
5
+ from dotenv import load_dotenv
6
+
7
+ logging.basicConfig(
8
+ format='[%(asctime)s][%(levelname)s][%(name)s] %(message)s',
9
+ datefmt='%d/%m/%Y-%H:%M:%S',
10
+ handlers=[logging.StreamHandler(sys.stdout)],
11
+ level=logging.INFO,
12
+ )
13
+
14
+ load_dotenv()
15
+ mediacatch_api_key = os.environ['MEDIACATCH-API-KEY']
16
+
17
+ __version__ = '0.0.1'
@@ -0,0 +1,13 @@
1
+ from abc import ABC, abstractmethod
2
+ from argparse import ArgumentParser
3
+
4
+
5
+ class BaseCLICommand(ABC):
6
+ @staticmethod
7
+ @abstractmethod
8
+ def register_subcommand(parser: ArgumentParser):
9
+ raise NotImplementedError()
10
+
11
+ @staticmethod
12
+ def run(self):
13
+ raise NotImplementedError()
@@ -0,0 +1,31 @@
1
+ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
2
+
3
+ from mediacatch.commands.vision import VisionCLI
4
+
5
+
6
+ def main():
7
+ parser = ArgumentParser(
8
+ prog='MediaCatch CLI tool',
9
+ usage='mediacatch <command> [<args>]',
10
+ description='MediaCatch CLI tool',
11
+ formatter_class=ArgumentDefaultsHelpFormatter,
12
+ )
13
+ commands_parser = parser.add_subparsers(help='mediacatch command helpers')
14
+
15
+ # Register commands
16
+ VisionCLI.register_subcommand(commands_parser)
17
+
18
+ # Let's go
19
+ args = parser.parse_args()
20
+
21
+ if not hasattr(args, 'func'):
22
+ parser.print_help()
23
+ exit(1)
24
+
25
+ # Run
26
+ service = args.func(args)
27
+ service.run()
28
+
29
+
30
+ if __name__ == '__main__':
31
+ main()
@@ -0,0 +1,157 @@
1
+ import json
2
+ import logging
3
+ from argparse import ArgumentParser
4
+ from pathlib import Path
5
+ from pprint import pprint
6
+
7
+ from mediacatch.commands import BaseCLICommand
8
+ from mediacatch.vision import upload, wait_for_result
9
+
10
+ logger = logging.getLogger('mediacatch.cli.vision')
11
+
12
+
13
+ def vision_cli_factory(args):
14
+ return VisionCLI(
15
+ file_path=args.file_path,
16
+ type=args.type,
17
+ save_result=args.save_result,
18
+ fps=args.fps,
19
+ tolerance=args.tolerance,
20
+ min_levensthein_ratio=args.min_levensthein_ratio,
21
+ min_bbox_iou=args.min_bbox_iou,
22
+ min_text_confidence=args.min_text_confidence,
23
+ max_text_confidence=args.max_text_confidence,
24
+ max_text_length=args.max_text_length,
25
+ moving_text_threshold=args.moving_text_threshold,
26
+ )
27
+
28
+
29
+ class VisionCLI(BaseCLICommand):
30
+ @staticmethod
31
+ def register_subcommand(parser: ArgumentParser):
32
+ vision_parser: ArgumentParser = parser.add_parser(
33
+ 'vision', help='CLI tool to run inference with MediaCatch Vision API'
34
+ )
35
+ vision_parser.add_argument(
36
+ 'file_path', type=str, help='Path to the file to run inference on'
37
+ )
38
+ vision_parser.add_argument(
39
+ 'type',
40
+ type=str,
41
+ choices=['ocr', 'face'],
42
+ help='Type of inference to run on the file',
43
+ )
44
+ vision_parser.add_argument(
45
+ '--save-result',
46
+ type=str,
47
+ default=None,
48
+ help='Save result to a file',
49
+ )
50
+ vision_parser.add_argument(
51
+ '--fps',
52
+ type=int,
53
+ default=None,
54
+ help='FPS for the OCR results',
55
+ )
56
+ vision_parser.add_argument(
57
+ '--tolerance',
58
+ type=int,
59
+ default=None,
60
+ help='Tolerance for the OCR results',
61
+ )
62
+ vision_parser.add_argument(
63
+ '--min-levensthein-ratio',
64
+ type=float,
65
+ default=None,
66
+ help='Minimum Levenshtein ratio for the OCR results',
67
+ )
68
+ vision_parser.add_argument(
69
+ '--min-bbox-iou',
70
+ type=float,
71
+ default=None,
72
+ help='Minimum bounding box IOU for the OCR results',
73
+ )
74
+ vision_parser.add_argument(
75
+ '--min-text-confidence',
76
+ type=float,
77
+ default=None,
78
+ help='Minimum text confidence for the OCR results',
79
+ )
80
+ vision_parser.add_argument(
81
+ '--max-text-confidence',
82
+ type=float,
83
+ default=None,
84
+ help='Maximum text confidence for the OCR results',
85
+ )
86
+ vision_parser.add_argument(
87
+ '--max-text-length',
88
+ type=int,
89
+ default=None,
90
+ help='Maximum text length for the OCR results',
91
+ )
92
+ vision_parser.add_argument(
93
+ '--moving-text-threshold',
94
+ type=int,
95
+ default=None,
96
+ help='Moving text threshold for the OCR results',
97
+ )
98
+ vision_parser.set_defaults(func=vision_cli_factory)
99
+
100
+ def __init__(
101
+ self,
102
+ file_path: str,
103
+ type: str,
104
+ save_result: str | None = None,
105
+ fps: int | None = None,
106
+ tolerance: int | None = None,
107
+ min_levensthein_ratio: float | None = None,
108
+ min_bbox_iou: float | None = None,
109
+ min_text_confidence: float | None = None,
110
+ max_text_confidence: float | None = None,
111
+ max_text_length: int | None = None,
112
+ moving_text_threshold: int | None = None,
113
+ ) -> None:
114
+ self.file_path = file_path
115
+ self.type = type
116
+ self.save_result = save_result
117
+ self.fps = fps
118
+ self.tolerance = tolerance
119
+ self.min_levensthein_ratio = min_levensthein_ratio
120
+ self.min_bbox_iou = min_bbox_iou
121
+ self.min_text_confidence = min_text_confidence
122
+ self.max_text_confidence = max_text_confidence
123
+ self.max_text_length = max_text_length
124
+ self.moving_text_threshold = moving_text_threshold
125
+
126
+ def run(self) -> None:
127
+ # Create extra parameters
128
+ extra = {}
129
+ for k, val in (
130
+ ('fps', self.fps),
131
+ ('tolerance', self.tolerance),
132
+ ('min_levensthein_ratio', self.min_levensthein_ratio),
133
+ ('min_bbox_iou', self.min_bbox_iou),
134
+ ('min_text_confidence', self.min_text_confidence),
135
+ ('max_text_confidence', self.max_text_confidence),
136
+ ('max_text_length', self.max_text_length),
137
+ ('moving_text_threshold', self.moving_text_threshold),
138
+ ):
139
+ if val is not None:
140
+ extra[k] = val
141
+
142
+ # Upload file to MediaCatch Vision API
143
+ file_id = upload(self.file_path, self.type, extra=extra)
144
+
145
+ # Wait for result
146
+ result = wait_for_result(file_id)
147
+ if not result:
148
+ logger.error('Failed to get result from MediaCatch Vision API')
149
+ return
150
+
151
+ logger.info('Results:')
152
+ pprint(result)
153
+
154
+ # Save result to a file
155
+ if self.save_result:
156
+ Path(self.save_result).write_text(json.dumps(result, indent=4))
157
+ logger.info(f'Result saved to {self.save_result}')
File without changes
@@ -0,0 +1,38 @@
1
+ import json
2
+ import os
3
+ import logging
4
+
5
+ import requests
6
+
7
+ logger = logging.getLogger('mediacatch.utils.general')
8
+
9
+
10
+ def get_data_from_url(url: str) -> dict:
11
+ """Get data from a URL.
12
+
13
+ Args:
14
+ url (str): The URL to get data from.
15
+
16
+ Returns:
17
+ dict: Data dictionary from url.
18
+ """
19
+ logger.info(f'Getting data from {url}')
20
+ response = requests.get(url)
21
+ assert response.status_code == 200, f'Failed to get data from {url}: {response}'
22
+ return response.json()
23
+
24
+
25
+ def load_data_from_json(json_file: str) -> dict:
26
+ """Load data from a JSON file.
27
+
28
+ Args:
29
+ json_file (str): JSON file with data.
30
+
31
+ Returns:
32
+ dict: Data dictionary from JSON file.
33
+ """
34
+ logger.info(f'Loading data from {json_file}')
35
+ assert os.path.isfile(json_file), f'File {json_file} does not exist'
36
+ with open(json_file, 'r') as f:
37
+ result = json.load(f)
38
+ return result
@@ -0,0 +1,2 @@
1
+ from mediacatch.vision.result import wait_for_result
2
+ from mediacatch.vision.upload import upload
@@ -0,0 +1,49 @@
1
+ import json
2
+ import logging
3
+ import time
4
+ from typing import Any
5
+
6
+ import requests
7
+
8
+ logger = logging.getLogger('mediacatch.vision.result')
9
+
10
+
11
+ def wait_for_result(
12
+ file_id: str,
13
+ url: str = 'https://api.mediacatch.io/vision',
14
+ timeout: int = 3600,
15
+ delay: int = 30,
16
+ ) -> dict[str, Any] | None:
17
+ """Wait for result from a URL.
18
+
19
+ Args:
20
+ file_id (str): The file ID to get the result from.
21
+ url (str): The URL to get the result from.
22
+ timeout (int, optional): Timeout for waiting in seconds. Defaults to 3600.
23
+ delay (int, optional): Delay between each request. Defaults to 5.
24
+
25
+ Returns:
26
+ dict[str, Any] | None: Dictionary with the result from the URL or None if failed.
27
+ """
28
+ result_url = f'{url}/result/{file_id}'
29
+ logger.info(f'Waiting for result from {result_url}')
30
+ start_time = time.time()
31
+ end_time = start_time + timeout
32
+ while time.time() < end_time:
33
+ try:
34
+ response = requests.get(result_url)
35
+ response.raise_for_status()
36
+ result = response.json()
37
+ elapsed_time = time.time() - start_time
38
+ logger.info(f'Got result from {result_url} in {elapsed_time:.2f} seconds')
39
+ return result
40
+
41
+ except (requests.RequestException, json.JSONDecodeError):
42
+ time.sleep(delay)
43
+
44
+ except Exception as e:
45
+ logger.error(f'Failed to get result from {result_url}: {e}')
46
+ return None
47
+
48
+ logger.error(f'Timeout waiting for result from {result_url}, give up')
49
+ return None
@@ -0,0 +1,57 @@
1
+ import json
2
+ import logging
3
+ from typing import Any, Literal
4
+
5
+ import requests
6
+
7
+ from mediacatch import mediacatch_api_key
8
+
9
+ logger = logging.getLogger('mediacatch.vision.upload')
10
+
11
+ headers = {
12
+ 'accept': 'application/json',
13
+ 'Content-Type': 'application/json',
14
+ 'X-API-KEY': f'{mediacatch_api_key}',
15
+ }
16
+
17
+
18
+ def upload(
19
+ fpath: str,
20
+ type: Literal['ocr', 'face'],
21
+ url: str = 'https://api.mediacatch.io/vision',
22
+ extra: dict[str, Any] = {},
23
+ ) -> str:
24
+ """Upload a file to MediaCatch Vision API.
25
+
26
+ Args:
27
+ fpath (str): File path.
28
+ type (Literal['ocr', 'face']): Type of inference to run on the file.
29
+ url (str, optional): URL to the vision API. Defaults to 'https://api.mediacatch.io/vision'.
30
+ extra (dict[str, Any], optional): Dictonary with extra parameters. Defaults to {}.
31
+
32
+ Returns:
33
+ str: File ID.
34
+ """
35
+ logger.info(f'Uploading file {fpath} to MediaCatch Vision API')
36
+
37
+ # Get presigned URL
38
+ data = {'filename': fpath, 'type': type, 'extra': extra}
39
+ response = requests.post(f'{url}/upload/', headers=headers, data=json.dumps(data))
40
+ assert (
41
+ response.status_code == 201
42
+ ), f'Failed to upload file {fpath} to MediaCatch Vision API: {response.text}'
43
+ response_data = response.json()
44
+ file_id = response_data['file_id']
45
+
46
+ # Upload file to storage
47
+ with open(fpath, 'rb') as f:
48
+ files = {'file': (response_data['fields']['key'], f)}
49
+ response = requests.post(response_data['url'], data=response_data['fields'], files=files)
50
+
51
+ # Mark file as uploaded
52
+ data = {'file_id': file_id}
53
+ response = requests.post(f'{url}/upload/complete/', headers=headers, data=json.dumps(data))
54
+ assert response.status_code == 200, f'Failed to mark file {fpath} as uploaded: {response}'
55
+
56
+ logger.info(f'File {fpath} uploaded with ID {file_id}')
57
+ return file_id
@@ -0,0 +1,140 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project.urls]
6
+ Documentation = "https://github.com/mediacatch/mediacatch#readme"
7
+ Issues = "https://github.com/mediacatch/mediacatch/issues"
8
+ Source = "https://github.com/mediacatch/mediacatch"
9
+
10
+ [tool.hatch.version]
11
+ path = "mediacatch/__init__.py"
12
+
13
+ [project]
14
+ name = "mediacatch"
15
+ description = "Python package for easily interfacing with MediaCatch APIs and data formats."
16
+ readme = "README.md"
17
+ requires-python = ">=3.10"
18
+ license = "MIT"
19
+ authors = [
20
+ { name = "Mathias Nielsen", email = "mathias@mediacatch.io" },
21
+ { name = "Frederik Haarslev", email = "frederik@mediacatch.io" },
22
+ ]
23
+ classifiers = [
24
+ "Topic :: Internet",
25
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Software Development :: Libraries",
28
+ "Topic :: Software Development",
29
+ "Framework :: FastAPI",
30
+ "Intended Audience :: Developers",
31
+ "License :: OSI Approved :: MIT License",
32
+ "Programming Language :: Python :: 3 :: Only",
33
+ "Programming Language :: Python :: 3.10",
34
+ ]
35
+ dynamic = ["version"]
36
+ scripts = { mediacatch = "mediacatch.commands.cli:main" }
37
+ dependencies = [
38
+ "requests",
39
+ "opencv-python-headless",
40
+ "pydantic",
41
+ "python-dotenv",
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ test = ["pytest", "ruff", "black", "isort", "mypy", "hatch"]
46
+ dev = ["ruff", "black", "isort", "mypy", "hatch"]
47
+ docs = [
48
+ "mkdocs",
49
+ "mkdocs-material",
50
+ "mkdocstrings",
51
+ "mkdocstrings-python",
52
+ "mkdocs-autorefs",
53
+ ]
54
+
55
+ [tool.ruff]
56
+ # Exclude a variety of commonly ignored directories.
57
+ exclude = [
58
+ ".bzr",
59
+ ".direnv",
60
+ ".eggs",
61
+ ".git",
62
+ ".git-rewrite",
63
+ ".hg",
64
+ ".ipynb_checkpoints",
65
+ ".mypy_cache",
66
+ ".nox",
67
+ ".pants.d",
68
+ ".pyenv",
69
+ ".pytest_cache",
70
+ ".pytype",
71
+ ".ruff_cache",
72
+ ".svn",
73
+ ".tox",
74
+ ".venv",
75
+ ".vscode",
76
+ "__pypackages__",
77
+ "_build",
78
+ "buck-out",
79
+ "build",
80
+ "dist",
81
+ "node_modules",
82
+ "site-packages",
83
+ "venv",
84
+ ]
85
+
86
+ # Same as Black.
87
+ line-length = 100
88
+ indent-width = 4
89
+
90
+ # Assume Python 3.10
91
+ target-version = "py310"
92
+
93
+ [tool.ruff.lint]
94
+ # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
95
+ # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
96
+ # McCabe complexity (`C901`) by default.
97
+ select = ["E4", "E7", "E9", "F"]
98
+ ignore = []
99
+
100
+ # Allow fix for all enabled rules (when `--fix`) is provided.
101
+ fixable = ["ALL"]
102
+ unfixable = []
103
+
104
+ # Allow unused variables when underscore-prefixed.
105
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
106
+
107
+ [tool.ruff.format]
108
+ # Like Black, use single quotes for strings.
109
+ quote-style = "single"
110
+
111
+ # Like Black, indent with spaces, rather than tabs.
112
+ indent-style = "space"
113
+
114
+ # Like Black, respect magic trailing commas.
115
+ skip-magic-trailing-comma = false
116
+
117
+ # Like Black, automatically detect the appropriate line ending.
118
+ line-ending = "auto"
119
+
120
+ # Enable auto-formatting of code examples in docstrings. Markdown,
121
+ # reStructuredText code/literal blocks and doctests are all supported.
122
+ #
123
+ # This is currently disabled by default, but it is planned for this
124
+ # to be opt-out in the future.
125
+ docstring-code-format = false
126
+
127
+ # Set the line length limit used when formatting code snippets in
128
+ # docstrings.
129
+ #
130
+ # This only has an effect when the `docstring-code-format` setting is
131
+ # enabled.
132
+ docstring-code-line-length = "dynamic"
133
+
134
+ [tool.ruff.per-file-ignores]
135
+ "__init__.py" = ["F401"]
136
+
137
+ [tool.pytest.ini_options]
138
+ addopts = "-ra"
139
+ testpaths = ["tests"]
140
+ pythonpath = ['.']
File without changes
@@ -0,0 +1,2 @@
1
+ def test_dummy():
2
+ assert True