Skip to content

Fix ImportError: use Django's cached_property instead of cryptography's - #46

Merged
alexlambson merged 1 commit into
mainfrom
fix/cryptography-cached-property-import
Aug 21, 2026
Merged

Fix ImportError: use Django's cached_property instead of cryptography's#46
alexlambson merged 1 commit into
mainfrom
fix/cryptography-cached-property-import

Conversation

@brichardson1991

@brichardson1991 brichardson1991 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

What broke

The production site (mapdb2.cncnet.org) returned HTTP 500 on every route:

File "/cncnet-map-api/kirovy/urls.py", line 27, in <module>
    from kirovy.views import (
File "/cncnet-map-api/kirovy/views/map_upload_views.py", line 4, in <module>
    from cryptography.utils import cached_property
ImportError: cannot import name 'cached_property' from 'cryptography.utils'

The failure happens while Django loads the root URLconf, so no URL resolves at all — this is not limited to the upload endpoints, despite the module name.

cryptography.utils.cached_property was a private, undocumented shim that has since been removed upstream. The server had resolved cryptography==50.0.0, where it no longer exists.

Critically: cryptography is not a declared dependency of this project. It is absent from requirements.txt and arrives transitively, unpinned, via pyjwt[crypto]. The code was reaching into a private API of a package it never asked for, so a routine image rebuild broke production with no code change on our side.

The fix

Two occurrences, import line only. Replace:

from cryptography.utils import cached_property

with:

from django.utils.functional import cached_property

in kirovy/services/legacy_upload/base.py and kirovy/views/map_upload_views.py.

Why this is safe

django.utils.functional.cached_property is a true drop-in here:

  • Every decorated attribute sits on a plain class with a normal __dict__.
  • __slots__ appears nowhere in the codebase, so the descriptor can write its cache.
  • Both are non-data descriptors caching on first access; semantics match for all five usages (user_log_attrs in map_upload_views.py; expected_files, map_sha1_from_filename, file_contents_merged, map_name in base.py).
  • Note expected_files is a @cached_property in the base class that raises NotImplementedError and is overridden in subclasses — this pattern works identically under Django's implementation.
  • After the change, no cryptography reference remains in any .py file, and both files pass python -m py_compile.

Pinning cryptography to an older version was rejected: it papers over the problem and leaves the project depending on a private API of an undeclared transitive dependency.

Optional follow-ups (not bundled here)

  • Consider whether requirements.txt should pin anything it imports directly.
  • The repo pulls cryptography only via pyjwt[crypto]; nothing else uses it.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alexlambson
alexlambson merged commit c454e5b into main Aug 21, 2026
1 check passed
@alexlambson
alexlambson deleted the fix/cryptography-cached-property-import branch August 21, 2026 22:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants