Skip to content

Commit ec87c85

Browse files
authored
Merge pull request #69 from unicef/feature/dev_env
CI updates
2 parents 6d63899 + 7357438 commit ec87c85

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+353
-244
lines changed

.github/CODEOWNERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*
2+
docker/*.* @unicef/hope-arch
3+
4+
src/country_workspace/migrations/*.py @saxix @unicef/hope-arch
5+
pyproject.toml @saxix @unicef/hope-arch
6+
uv.lock @saxix @unicef/hope-arch

.github/file-filters.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ docker: &docker
33
- added|modified: './docker/**/*'
44
- added|modified: './docker/*'
55

6+
code_conventions: &dependencies
7+
- '.mypy.ini'
8+
- '.pre-commit-config.yaml'
9+
- 'pytest.ini'
10+
- 'ruff.toml'
11+
- 'tox.ini'
12+
- 'pyproject.toml'
13+
614
dependencies: &dependencies
715
- 'uv.lock'
816
- 'pyproject.toml'

.github/workflows/close_stale.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: 'Close stale issues and PRs'
2+
on:
3+
schedule:
4+
- cron: '30 1 * * *'
5+
6+
jobs:
7+
stale:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/stale@v9
11+
with:
12+
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
13+
days-before-stale: 30
14+
days-before-close: 5
15+
16+
stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.'
17+
exempt-all-pr-assignees: true
18+
days-before-pr-stale: 30
19+
days-before-pr-close: 5

.github/workflows/label-pullrequest.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ jobs:
1414
name: labels pull requests
1515
runs-on: ubuntu-latest
1616
steps:
17-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
17+
- uses: actions/checkout@v4
1818
with:
1919
persist-credentials: false
2020

2121
- name: Check for file changes
22-
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
22+
uses: dorny/paths-filter@v3
2323
id: changes
2424
with:
2525
token: ${{ github.token }}
@@ -36,3 +36,9 @@ jobs:
3636
if: steps.changes.outputs.dependencies == 'true'
3737
with:
3838
labels: 'Add/Change dependencies'
39+
40+
- name: Add Dependencies label
41+
uses: actions-ecosystem/action-add-labels@v1
42+
if: steps.changes.outputs.code_conventions == 'true'
43+
with:
44+
labels: 'Change Code Style/Conventions'

.github/workflows/lint.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ jobs:
5454
- uses: actions/setup-python@v5
5555
with:
5656
python-version: '3.12'
57+
5758
- name: Install requirements
5859
run: pip install ruff==0.9.3
60+
5961
- name: Check syntax
6062
# Stop the build if there are Python syntax errors or undefined names
6163
run: ruff check --output-format concise src/

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ dependencies = [
3030
"django-jsoneditor>=0.2.4",
3131
"django-mptt>=0.16.0",
3232
"django-regex>=0.5.0",
33-
"django-reversion>=5.1.0",
3433
"django-select2",
3534
"django-smart-admin>=2.6.0",
3635
"django-smart-env>=0.1.0",

ruff.toml

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,84 @@ line-length = 120
33

44
[lint]
55
select = [
6-
"A", # prevent using keywords that clobber python builtins
7-
"ANN", # flake8 annotations
8-
"B", # bugbear: security warnings
9-
"BLE", # blind exceptions
10-
"C4", # flake8-comprehensions
11-
"C90", # McCabe complexity
12-
"COM", # flake8-commas
13-
"D", # pydocstyle
14-
"DJ", # flake8-django
15-
"E", # pycodestylex
16-
"E4", "E7", "E9",
17-
"ERA", # eradicate
18-
"F", # pyflakes
19-
"FLY", # flynt
20-
"FURB", # refurb
21-
"I", # isort
22-
"ICN", # flake8-import-conventions
23-
"ISC", # implicit string concatenation
24-
"N", # Pep* naming
25-
"PERF", # perflint
26-
"PIE", # flake8-pie
27-
"PL", # PyLint
28-
"PT", # flake8-pytest-style
29-
"Q", # flake8-quotes
30-
"R", # PyLint Refactor
31-
"RET", # flake8-return
32-
"S", # bandit,
33-
"SIM", # flake8-simplify
34-
"T10", # flake8-debugger
35-
"T20", # flake8-print
36-
"TC", # flake8-type-checking
37-
"UP", # pyupgrade
38-
"W", # pycodestyle warnings
39-
"YTT", # flake8 2020
6+
"ALL",
7+
# "A", # prevent using keywords that clobber python builtins
8+
# "ANN", # flake8 annotations
9+
# "B", # bugbear: security warnings
10+
# "BLE", # blind exceptions
11+
# "C4", # flake8-comprehensions
12+
# "C90", # McCabe complexity
13+
# "COM", # flake8-commas
14+
# "D", # pydocstyle
15+
# "DJ", # flake8-django
16+
# "E", # pycodestylex
17+
# "E4", "E7", "E9",
18+
# "ERA", # eradicate
19+
# "F", # pyflakes
20+
# "FLY", # flynt
21+
# "FURB", # refurb
22+
# "I", # isort
23+
# "ICN", # flake8-import-conventions
24+
# "ISC", # implicit string concatenation
25+
# "N", # Pep* naming
26+
# "PERF", # perflint
27+
# "PIE", # flake8-pie
28+
# "PL", # PyLint
29+
# "PT", # flake8-pytest-style
30+
# "Q", # flake8-quotes
31+
# "R", # PyLint Refactor
32+
# "RET", # flake8-return
33+
# "S", # bandit,
34+
# "SIM", # flake8-simplify
35+
# "T10", # flake8-debugger
36+
# "T20", # flake8-print
37+
# "TC", # flake8-type-checking
38+
# "UP", # pyupgrade
39+
# "W", # pycodestyle warnings
40+
# "YTT", # flake8 2020
4041
]
4142
extend-select = ["UP", ]
4243
ignore = [
43-
"A005", # Module `???` shadows a Python standard-library module
44-
"ANN401",
45-
"B904", # raise-without-from-inside-except: syntax not compatible with py2
46-
"COM812",
47-
"D100", # Missing docstring in public module
48-
"D101", # Missing docstring in public class
49-
"D102", # Missing docstring in public method
50-
"D103", # Missing docstring in public function
51-
"D104", # Missing docstring in public package
52-
"D105", # Missing docstring in magic method
53-
"D106", # Missing docstring in public nested class
54-
"D107", # Missing docstring in `__init__`
55-
"D203", # one-blank-line-before-class
56-
"D212", # multi-line-summary-first-line
57-
"D213", # multi-line-summary-second-line
58-
"E731", # lambda-assignment: lambdas are substential in maintenance of py2/3 codebase
59-
"ISC001", # conflicts with ruff format command
60-
"RUF005", # collection-literal-concatenation: syntax not compatible with py2
61-
"RUF012", # mutable-class-default: typing is not available for py2
62-
"I001", # unsorted imports https://docs.astral.sh/ruff/rules/unsorted-imports/#unsorted-imports-i001
63-
"UP037", # [*] Remove quotes from type annotation
64-
"UP035", # Import from `collections.abc` instead: `Sequence`
65-
"UP031", # Use format specifiers instead of percent format
66-
"SIM108", # Use ternary operator instead of...
67-
"PLR2004", # Magic value used in comparison
68-
"DJ001", # Avoid using `null=True` on string-based fields such as `CharField`
44+
"A005", # Module `???` shadows a Python standard-library module
45+
"ARG001", # Unused function argument
46+
"ARG002", # Unused method argument
47+
"ARG005", # Unused lambda argument:
48+
"ANN401",
49+
"B904", # raise-without-from-inside-except: syntax not compatible with py2
50+
"COM812",
51+
"D100", # Missing docstring in public module
52+
"D101", # Missing docstring in public class
53+
"D102", # Missing docstring in public method
54+
"D103", # Missing docstring in public function
55+
"D104", # Missing docstring in public package
56+
"D105", # Missing docstring in magic method
57+
"D106", # Missing docstring in public nested class
58+
"D107", # Missing docstring in `__init__`
59+
"D203", # one-blank-line-before-class
60+
"D212", # multi-line-summary-first-line
61+
"D213", # multi-line-summary-second-line
62+
"DJ001", # Avoid using `null=True` on string-based fields such as `CharField`
63+
"E731", # lambda-assignment: lambdas are substential in maintenance of py2/3 codebase
64+
"EM101", # Exception must not use a string literal, assign to variable first
65+
"EM102", # Exception must not use an f-string literal, assign to variable first
66+
"FBT001", # Boolean-typed positional argument in function definition
67+
"FBT002", # Boolean default positional argument in function definition
68+
"FBT003", # Boolean positional value in function call
69+
"FIX002", # Line contains TODO, consider resolving the issue
70+
"I001", # unsorted imports https://docs.astral.sh/ruff/rules/unsorted-imports/#unsorted-imports-i001
71+
"ISC001", # conflicts with ruff format command
72+
"PLR2004", # Magic value used in comparison
73+
"RUF005", # collection-literal-concatenation: syntax not compatible with py2
74+
"RUF012", # mutable-class-default: typing is not available for py2
75+
"SIM108", # Use ternary operator instead of...
76+
"SLF001", # Private member accessed:
77+
"TD003", # Missing issue link for this TODO
78+
"TID252", # Prefer absolute imports over relative imports from parent modules
79+
"TRY401", # Redundant exception object included in `logging.exception` call
80+
"TRY003", # Avoid specifying long messages outside the exception class
81+
"UP031", # Use format specifiers instead of percent format
82+
"UP035", # Import from `collections.abc` instead: `Sequence`
83+
"UP037", # [*] Remove quotes from type annotation
6984
]
7085

7186
[format]
@@ -84,10 +99,10 @@ known-first-party = ['country_workspace']
8499
no-sections = false
85100
lines-after-imports = 1
86101
relative-imports-order = "furthest-to-closest"
87-
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder",]
102+
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder", ]
88103

89104

90105
[lint.per-file-ignores]
91-
"tests/**.py" = ["S101", "PLR2004", "S", "SIM117", "D", "UP", "PLR0913", "ANN", "N999"]
106+
"tests/**.py" = ["S101", "PGH004", "TRY002", "TRY", "PYI024", "PD901", "INP001", "PLR2004", "S", "SIM117", "D", "UP", "PLR0913", "ANN", "N999"]
92107
"src/**/versioning/**.py" = ["N999", ]
93108
"src/**/migrations/**.py" = ["E501", ]

src/country_workspace/admin/__init__.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,42 @@
55
from smart_admin.smart_auth.admin import ContentTypeAdmin, PermissionAdmin
66

77
from ..cache.smart_panel import panel_cache
8-
from .batch import BatchAdmin # noqa
9-
from .beneficiary_group import BeneficiaryGroupAdmin # noqa
10-
from .constance import ConstanceAdmin # noqa
11-
from .household import HouseholdAdmin # noqa
12-
from .individual import IndividualAdmin # noqa
13-
from .job import AsyncJobAdmin # noqa
14-
from .locations import AreaAdmin, AreaTypeAdmin, CountryAdmin # noqa
15-
from .office import OfficeAdmin # noqa
16-
from .program import ProgramAdmin # noqa
17-
from .role import UserRoleAdmin # noqa
18-
from .sync import SyncLog # noqa
19-
from .user import UserAdmin # noqa
8+
from .batch import BatchAdmin
9+
from .beneficiary_group import BeneficiaryGroupAdmin
10+
from .constance import ConstanceAdmin
11+
from .household import HouseholdAdmin
12+
from .individual import IndividualAdmin
13+
from .job import AsyncJobAdmin
14+
from .locations import AreaAdmin, AreaTypeAdmin, CountryAdmin
15+
from .office import OfficeAdmin
16+
from .program import ProgramAdmin
17+
from .role import UserRoleAdmin
18+
from .sync import SyncLog
19+
from .user import UserAdmin
2020

2121
site.register(ContentType, admin_class=ContentTypeAdmin)
2222
site.register(Permission, admin_class=PermissionAdmin)
2323

24-
2524
site.register_panel(panel_sentry)
2625
site.register_panel(panel_cache)
2726
site.register_panel(panel_sysinfo)
2827
site.register_panel(panel_migrations)
2928
site.register_panel(panel_redis)
29+
30+
__all__ = [
31+
"AreaAdmin",
32+
"AreaTypeAdmin",
33+
"AsyncJobAdmin",
34+
"BatchAdmin",
35+
"BeneficiaryGroupAdmin",
36+
"ConstanceAdmin",
37+
"CountryAdmin",
38+
"HouseholdAdmin",
39+
"IndividualAdmin",
40+
"OfficeAdmin",
41+
"ProgramAdmin",
42+
"SyncLog",
43+
"SyncLog",
44+
"UserAdmin",
45+
"UserRoleAdmin",
46+
]

src/country_workspace/apps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def ready(self) -> None:
1616

1717
import country_workspace.compat.admin_extra_buttons as c
1818

19-
from .utils import flags # noqa
19+
from .utils import flags # noqa: F401
2020

2121
admin_extra_buttons.api.confirm_action = c.confirm_action
2222
django_celery_boost.admin.confirm_action = c.confirm_action

src/country_workspace/cache/manager.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def cache(self) -> RedisCache:
3535
return caches["default"]
3636

3737
def init(self) -> None:
38-
from . import handlers # noqa
38+
from . import handlers # noqa: F401
3939

4040
try:
4141
self.cache_timeout = config.CACHE_TIMEOUT
@@ -75,7 +75,7 @@ def reset_cache_version(self, *, office: "Office | None" = None, program: "Progr
7575
key = self._get_version_key(office, program)
7676
self.cache.delete(key)
7777

78-
def get_cache_version(self, *, office: "Office | None" = None, program: "Program | None" = None) -> None:
78+
def get_cache_version(self, *, office: "Office | None" = None, program: "Program | None" = None) -> int:
7979
key = self._get_version_key(office, program)
8080
version = self.cache.get(key)
8181
if not version:
@@ -119,15 +119,13 @@ def build_key(self, prefix: str, *parts: list[str]) -> str:
119119
tenant = state.tenant.slug
120120
version = str(self.get_cache_version(office=state.tenant))
121121

122-
parts = [self.prefix, "entry", prefix, self.cw_version, ts, version, tenant, program, *parts]
123-
return ":".join(parts)
122+
final_parts = [self.prefix, "entry", prefix, self.cw_version, ts, version, tenant, program, *parts]
123+
return ":".join(map(str, final_parts))
124124

125125
def build_key_from_request(self, request: HttpRequest, prefix: str = "view", *args: list[str]) -> str:
126126
return self.build_key(
127127
prefix,
128-
slugify(request.path),
129-
slugify(str(sorted(request.GET.items()))),
130-
*[str(e) for e in args],
128+
*[slugify(request.path), slugify(str(sorted(request.GET.items()))), *[str(e) for e in args]],
131129
)
132130

133131

0 commit comments

Comments
 (0)