-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpyproject.toml
More file actions
196 lines (185 loc) · 8.33 KB
/
Copy pathpyproject.toml
File metadata and controls
196 lines (185 loc) · 8.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
[project]
name = "dspace-client"
version = "0.1.0"
description = "Python client for DSpace REST API (v7, v8, v9)"
readme = "README.md"
requires-python = ">=3.11"
license = {text = "GPL-3.0-or-later"}
authors = [
{name = "Bram Luyten", email = "bram@atmire.com"}
]
keywords = ["dspace", "rest-api", "client", "repository"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"httpx[http2]>=0.27.0",
"orjson>=3.10.0",
"rich>=13.7.0",
"tenacity>=8.2.0",
"gitpython>=3.1.0", # For git operations
"python-dateutil>=2.8.0", # For date manipulation
"typer>=0.12.0", # For CLI tools
"defusedxml>=0.7.1",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0.0",
"pytest-asyncio>=0.23.0",
"respx>=0.21.0",
# Pinned to a minor series: ruff's formatter output can change between minor
# releases, and CI gates on `ruff format --check`. An unpinned formatter would
# let a new ruff release turn the build red without anyone changing code.
"ruff>=0.15.8,<0.16",
"mypy>=1.10.0",
"types-defusedxml>=0.7",
]
examples = [
"pyyaml>=6.0.1",
]
# Access load test example (examples/access_load_test). The human persona drives real
# headless Chromium via Playwright; the good-bot and bad-bot scenarios do not need it.
# After installing, run `playwright install chromium` once to fetch the browser binary.
loadtest = [
"playwright>=1.44",
]
[project.urls]
Homepage = "https://github.com/atmire/dspace-python-client"
Documentation = "https://github.com/atmire/dspace-python-client/blob/main/README.md"
Repository = "https://github.com/atmire/dspace-python-client"
"Bug Tracker" = "https://github.com/atmire/dspace-python-client/issues"
"DSpace REST Contract" = "https://github.com/DSpace/RestContract"
[project.scripts]
dspace-docs = "dspace_client.docs:cli_main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.sdist]
include = [
"/NOTICE",
"/THIRD_PARTY_LICENSES.md",
]
[tool.ruff]
target-version = "py311"
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "W", "C90", "I", "N", "UP", "YTT", "S", "BLE", "FBT", "A", "COM", "C4", "DTZ", "T10", "EM", "EXE", "FA", "ISC", "ICN", "G", "INP", "PIE", "T20", "PYI", "PT", "Q", "RSE", "RET", "SLF", "SLOT", "SIM", "TID", "TCH", "INT", "ARG", "PTH", "TD", "FIX", "ERA", "PD", "PGH", "PL", "TRY", "FLY", "NPY", "AIR", "PERF", "FURB", "LOG", "RUF"]
ignore = [
"S101", # assert - pytest uses it
"T201", # print - this project is CLI-first and prints on purpose
"S608",
"A003",
"COM812", # conflicts with the formatter
"ISC001", # conflicts with the formatter
# Exception-message rules. This codebase deliberately raises with long, actionable
# text (e.g. "use create_validated_client() instead of create_anonymous_client()"),
# which is better UX than the terse messages these rules push towards.
"TRY003", "EM101", "EM102",
# Boolean-trap rules. `success: bool = True` and friends are idiomatic here and
# appear throughout the public API; changing them would be a breaking change.
"FBT001", "FBT002", "FBT003",
# Complexity thresholds. Informative when read deliberately, but not worth gating on.
"C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915",
# `ruff format` owns line length. What it leaves over-length are strings, URLs and
# comments it will not split, so E501 only ever fires on things a human must accept.
"E501",
# The "magic values" here are HTTP status codes (200, 404, 429) and tuned algorithm
# thresholds in the concurrency controller. `status_code != 200` is clearer as a
# literal than behind a constant, and renaming them in auth/HTTP paths would be churn
# with real risk for no readability gain.
"PLR2004",
# Broad `except Exception` is deliberate at the boundaries this codebase has: the
# per-item batch handler (one bad item must not kill the run), the docs CLI, and
# version detection. Narrowing them would change behaviour against real repositories.
"BLE001",
# `return` inside `try` rather than an `else:` block. Purely stylistic.
"TRY300",
# Rewriting readable append-loops that build dict literals into comprehensions makes
# them harder to read for a micro-optimisation that never shows up here.
"PERF401",
# Unused arguments are part of published signatures (`should_ramp_down(metrics)`,
# `validate_before_call(...)`); renaming or dropping them would be a breaking change.
"ARG002", "ARG001",
# Moving imports into `if TYPE_CHECKING:` blocks. Marginal, and easy to get wrong in
# modules whose annotations are evaluated at runtime.
"TC001", "TC002", "TC003",
# Imports inside functions are deliberate here: breaking import cycles, keeping CLI
# startup fast, and importing optional extras only when a code path needs them.
"PLC0415",
# Arrows, en-dashes and check marks in console output are intentional, not typos.
"RUF001", "RUF002", "RUF003",
# git is invoked by name on purpose; it is a documented prerequisite and must come
# from the user's PATH rather than a hardcoded absolute path.
"S607",
]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
# Tests legitimately poke at private members, compare against literals, and carry
# dummy credentials. They are also not a package, by design.
# S314: the XML the tests parse is hardcoded fixture data, not untrusted input.
"tests/**" = [
"INP001", "SLF001", "PLR2004", "S105", "S106", "S107", "ARG001", "ARG002", "S314",
# Tests use the standard random module for pacing/desynchronisation checks; not crypto.
"S311",
# pytest style preferences that fight the existing suite's conventions.
"PT006", "PT018",
# Some tests put example directories on sys.path before importing from them, so
# their imports cannot all sit at the top of the file.
"E402",
]
# Examples are standalone scripts, not a package: they use demo credentials against
# throwaway instances and local naive timestamps for filenames and console output.
# S110/S112: several examples try a parse and fall through to the next strategy on
# failure (URL heuristics, ORCID extraction, skipping corrupt lines in a state file).
# That is the intended behaviour, and logging each miss would be pure noise.
"examples/**" = [
"INP001", "PLR2004", "S105", "S106", "DTZ005", "DTZ007", "BLE001", "S110", "S112",
# Examples are teaching material first. `open(filename)` and `os.path.join` are more
# widely understood than the pathlib equivalents; the library itself uses pathlib.
"PTH107", "PTH110", "PTH118", "PTH123",
# Scripts adjust sys.path before importing siblings, so imports cannot all be at top.
"E402",
# Raising ValueError for bad input is the established contract in these scripts;
# switching to TypeError would break callers that catch it.
"TRY004", "TRY301",
# Example scripts reach into client internals to demonstrate behaviour.
"SLF001",
"PTH105",
# Session log files are opened once and closed at the end of the run, so they cannot
# use a context manager; the handle is passed around deliberately.
"SIM115",
# Opening the user's PDF viewer on a file the script itself just downloaded. The
# argument is a local path, never user-supplied text, and no shell is involved.
"S603", "S606",
# Seed data is deliberately random-but-not-cryptographic; it is test content.
"S311",
# Module-level caches for short-lived API access tokens, guarded by expiry checks.
"PLW0602", "PLW0603",
# Rebinding the loop variable while normalising a value is intentional and local.
"PLW2901",
]
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]