clinicedc 2.0.16__py3-none-any.whl → 2.0.17__py3-none-any.whl

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 clinicedc might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clinicedc
3
- Version: 2.0.16
3
+ Version: 2.0.17
4
4
  Summary: A clinical trials data management framework built on Django
5
5
  Keywords: django,clinicedc,edc,clinical trials,research,data management,esource
6
6
  Author: Erik van Widenfelt, Jonathan Willitts
@@ -1966,8 +1966,8 @@ edc_model_form/utils.py,sha256=gGe3etrp5YF4AKMGFIR3I9V1CfX4c5Wm6fK-8JkUeT4,538
1966
1966
  edc_model_to_dataframe/__init__.py,sha256=iDR_F5oKkKDL9FfBXl0WKpwc2iOWbOlY-8wpCipBNnQ,115
1967
1967
  edc_model_to_dataframe/apps.py,sha256=US1ehhJPgkvmIDZXiUPMoSjHTWIztUbYGtx_azTXPIQ,290
1968
1968
  edc_model_to_dataframe/constants.py,sha256=xgCr2ZXUsjZqf4wfpY0JBhQoARzQEVS8tnkfBWwOMVQ,702
1969
- edc_model_to_dataframe/model_to_dataframe.py,sha256=DDuDIEpgEHjTTrqcjdYMLERvFl9h-HHhxYaapFepO9U,18829
1970
- edc_model_to_dataframe/read_frame_edc.py,sha256=D3Bai4ce4u6942OU8sad1OEAeDRIT1DQxYOQib5AMDE,791
1969
+ edc_model_to_dataframe/model_to_dataframe.py,sha256=Ut-Ixi7eoppBlnlgq4gBnhBh3ts13n1UjLMGQcKY7Bs,18684
1970
+ edc_model_to_dataframe/read_frame_edc.py,sha256=aOj3FUUvTCr-V-RmkBQtSGpg46zpWfX40HfOT3eRS4U,800
1971
1971
  edc_model_to_dataframe/urls.py,sha256=KChLHeE6yfONC6IdMm3Q4U3u7tmy_Mb1w2lrbpFz96g,148
1972
1972
  edc_navbar/__init__.py,sha256=Y95juevvOawGZmOV3Ofef7oGwYSWWttAYT0v0mehkJc,195
1973
1973
  edc_navbar/apps.py,sha256=fiWHsCYaDnHXNfYUu6DuvlAcO2k45-zkdbuXwXI3ksc,367
@@ -3406,7 +3406,7 @@ edc_vitals/models/fields/waist_circumference.py,sha256=fZcHFDdEwWLjIVLktKrFCD9UU
3406
3406
  edc_vitals/models/fields/weight.py,sha256=zo9_9e3Cpu0UqoRbWS-iDkcDo6fK80b1dDQy4x4MyxE,921
3407
3407
  edc_vitals/utils.py,sha256=vXid44KUXxeaSyund_y5MNXc5DFJs052_PwUAjszE2k,1384
3408
3408
  edc_vitals/validators.py,sha256=vNiElWMs0rRnHRNuVoPLRf0rW_C_0xcfUyep1Y_Si5s,156
3409
- clinicedc-2.0.16.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
3410
- clinicedc-2.0.16.dist-info/WHEEL,sha256=-neZj6nU9KAMg2CnCY6T3w8J53nx1kFGw_9HfoSzM60,79
3411
- clinicedc-2.0.16.dist-info/METADATA,sha256=yACQMEfCdkmBMoz9yz7R4jaTs-ToDfcahB4QqGBUqII,15899
3412
- clinicedc-2.0.16.dist-info/RECORD,,
3409
+ clinicedc-2.0.17.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
3410
+ clinicedc-2.0.17.dist-info/WHEEL,sha256=-neZj6nU9KAMg2CnCY6T3w8J53nx1kFGw_9HfoSzM60,79
3411
+ clinicedc-2.0.17.dist-info/METADATA,sha256=Vh9mgF060UWvEzXQ9O7I8XTXxKqDH9REwVJLEdtoDrs,15899
3412
+ clinicedc-2.0.17.dist-info/RECORD,,
@@ -1,27 +1,30 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
3
4
  from copy import copy
4
- from typing import TYPE_CHECKING
5
5
 
6
6
  import numpy as np
7
7
  import pandas as pd
8
8
  from django.apps import apps as django_apps
9
+ from django.contrib.sites.models import Site
9
10
  from django.core.exceptions import FieldError
10
11
  from django.db import OperationalError
12
+ from django.db.models import QuerySet
11
13
  from django_crypto_fields.utils import get_encrypted_fields, has_encrypted_fields
12
14
  from django_pandas.io import read_frame
15
+ from pandas import Series
13
16
 
14
- from .constants import ACTION_ITEM_COLUMNS, SYSTEM_COLUMNS
17
+ from edc_lab.models import Panel
18
+ from edc_list_data.model_mixins import ListModelMixin, ListUuidModelMixin
19
+ from edc_model.models import BaseUuidModel
20
+ from edc_sites.model_mixins import SiteModelMixin
15
21
 
16
- if TYPE_CHECKING:
17
- from django.db.models import QuerySet
22
+ from .constants import ACTION_ITEM_COLUMNS, SYSTEM_COLUMNS
18
23
 
19
- from edc_model.models import BaseUuidModel
20
- from edc_sites.model_mixins import SiteModelMixin
21
24
 
22
- class MyModel(SiteModelMixin, BaseUuidModel):
23
- class Meta(BaseUuidModel.Meta):
24
- pass
25
+ class MyModel(SiteModelMixin, BaseUuidModel):
26
+ class Meta(BaseUuidModel.Meta):
27
+ pass
25
28
 
26
29
 
27
30
  __all__ = ["ModelToDataframe", "ModelToDataframeError"]
@@ -52,16 +55,16 @@ class ModelToDataframe:
52
55
  See also: get_crf()
53
56
  """
54
57
 
55
- sys_field_names: list[str] = [
58
+ sys_field_names: tuple[str, ...] = (
56
59
  "_state",
57
60
  "_user_container_instance",
58
61
  "_domain_cache",
59
62
  "using",
60
63
  "slug",
61
- ]
62
- edc_sys_columns: list[str] = SYSTEM_COLUMNS
63
- action_item_columns: list[str] = ACTION_ITEM_COLUMNS
64
- illegal_chars: dict[str] = {
64
+ )
65
+ edc_sys_columns: tuple[str, ...] = SYSTEM_COLUMNS
66
+ action_item_columns: tuple[str, ...] = ACTION_ITEM_COLUMNS
67
+ illegal_chars: dict[str, str] = { # noqa: RUF012
65
68
  "\u2019": "'",
66
69
  "\u2018": "'",
67
70
  "\u201d": '"',
@@ -72,7 +75,7 @@ class ModelToDataframe:
72
75
  def __init__(
73
76
  self,
74
77
  model: str | None = None,
75
- queryset: QuerySet | None = None,
78
+ queryset: [QuerySet] | None = None,
76
79
  query_filter: dict | None = None,
77
80
  decrypt: bool | None = None,
78
81
  drop_sys_columns: bool | None = None,
@@ -104,7 +107,7 @@ class ModelToDataframe:
104
107
  try:
105
108
  self.model_cls = django_apps.get_model(self.model)
106
109
  except LookupError as e:
107
- raise LookupError(f"Model is {self.model}. Got `{e}`")
110
+ raise LookupError(f"Model is {self.model}. Got `{e}`") from e
108
111
  if self.sites:
109
112
  try:
110
113
  if queryset:
@@ -151,7 +154,7 @@ class ModelToDataframe:
151
154
 
152
155
  dataframe = self.merge_m2ms(dataframe)
153
156
 
154
- dataframe.rename(columns=self.columns, inplace=True)
157
+ dataframe = dataframe.rename(columns=self.columns)
155
158
 
156
159
  # remove timezone if asked
157
160
  if self.remove_timezone:
@@ -174,12 +177,12 @@ class ModelToDataframe:
174
177
  dataframe[column] = dataframe[column].dt.total_seconds()
175
178
 
176
179
  # fillna
177
- dataframe.fillna(value=np.nan, axis=0, inplace=True)
180
+ dataframe = dataframe.fillna(value=np.nan, axis=0)
178
181
 
179
182
  # remove illegal chars
180
183
  for column in list(dataframe.select_dtypes(include=["object"]).columns):
181
184
  dataframe[column] = dataframe.apply(
182
- lambda x: self._clean_chars(x[column]), axis=1
185
+ lambda x, col=column: self._clean_chars(x[col]), axis=1
183
186
  )
184
187
  self._dataframe = dataframe
185
188
  return self._dataframe
@@ -188,7 +191,7 @@ class ModelToDataframe:
188
191
  queryset = self.queryset.values_list(*self.columns).filter(**self.query_filter)
189
192
  return pd.DataFrame(list(queryset), columns=[v for v in self.columns])
190
193
 
191
- def get_dataframe_with_encrypted_fields(self, row_count: int) -> pd.DataFrame:
194
+ def get_dataframe_with_encrypted_fields(self, row_count: int) -> pd.DataFrame: # noqa: ARG002
192
195
  df = read_frame(
193
196
  self.queryset.filter(**self.query_filter), verbose=self.read_frame_verbose
194
197
  )
@@ -233,28 +236,27 @@ class ModelToDataframe:
233
236
  dataframe = dataframe.merge(df_m2m, on="id", how="left")
234
237
  return dataframe
235
238
 
236
- def _clean_chars(self, s):
237
- try:
238
- s = s if s else s
239
- except ValueError:
240
- pass
241
- else:
242
- if s:
243
- for k, v in self.illegal_chars.items():
244
- try:
245
- s = s.replace(k, v)
246
- except (AttributeError, TypeError):
247
- break
248
- return s
239
+ def _clean_chars(self, s: Series) -> Series:
240
+ if not s.empty:
241
+ for k, v in self.illegal_chars.items():
242
+ try:
243
+ s = s.replace(k, v)
244
+ except (AttributeError, TypeError):
245
+ break
246
+ return s
247
+ return np.nan
249
248
 
250
249
  def move_sys_columns_to_end(self, columns: dict[str, str]) -> dict[str, str]:
251
250
  system_columns = [
252
251
  f.name for f in self.model_cls._meta.get_fields() if f.name in SYSTEM_COLUMNS
253
252
  ]
254
253
  new_columns = {k: v for k, v in columns.items() if k not in system_columns}
255
- if system_columns:
256
- if len(new_columns.keys()) != len(columns.keys()) and not self.drop_sys_columns:
257
- new_columns.update({k: k for k in system_columns})
254
+ if (
255
+ system_columns
256
+ and len(new_columns.keys()) != len(columns.keys())
257
+ and not self.drop_sys_columns
258
+ ):
259
+ new_columns.update({k: k for k in system_columns})
258
260
  return new_columns
259
261
 
260
262
  def move_action_item_columns(self, columns: dict[str, str]) -> dict[str, str]:
@@ -262,12 +264,11 @@ class ModelToDataframe:
262
264
  f.name for f in self.model_cls._meta.get_fields() if f.name in ACTION_ITEM_COLUMNS
263
265
  ]
264
266
  new_columns = {k: v for k, v in columns.items() if k not in ACTION_ITEM_COLUMNS}
265
- if action_item_columns:
266
- if (
267
- len(new_columns.keys()) != len(columns.keys())
268
- and not self.drop_action_item_columns
269
- ):
270
- new_columns.update({k: k for k in ACTION_ITEM_COLUMNS})
267
+ if action_item_columns and (
268
+ len(new_columns.keys()) != len(columns.keys())
269
+ and not self.drop_action_item_columns
270
+ ):
271
+ new_columns.update({k: k for k in ACTION_ITEM_COLUMNS})
271
272
  return new_columns
272
273
 
273
274
  @property
@@ -285,12 +286,10 @@ class ModelToDataframe:
285
286
  columns = {col: col for col in columns_list}
286
287
  for column_name in columns_list:
287
288
  if column_name.endswith("_visit_id"):
288
- try:
289
+ with contextlib.suppress(FieldError):
289
290
  columns = self.add_columns_for_subject_visit(
290
291
  column_name=column_name, columns=columns
291
292
  )
292
- except FieldError:
293
- pass
294
293
  if column_name.endswith("_requisition") or column_name.endswith(
295
294
  "requisition_id"
296
295
  ):
@@ -316,10 +315,8 @@ class ModelToDataframe:
316
315
  else:
317
316
  raise
318
317
  for name in self.sys_field_names:
319
- try:
318
+ with contextlib.suppress(ValueError):
320
319
  columns_list.remove(name)
321
- except ValueError:
322
- pass
323
320
  if not self.decrypt:
324
321
  columns_list = [col for col in columns_list if col not in self.encrypted_columns]
325
322
  return columns_list
@@ -338,7 +335,6 @@ class ModelToDataframe:
338
335
  @property
339
336
  def list_columns(self) -> list[str]:
340
337
  """Return a list of column names with fk to a list model."""
341
- from edc_list_data.model_mixins import ListModelMixin, ListUuidModelMixin
342
338
 
343
339
  if not self._list_columns:
344
340
  list_columns = []
@@ -348,14 +344,13 @@ class ModelToDataframe:
348
344
  and fld_cls.related_model
349
345
  and issubclass(fld_cls.related_model, (ListModelMixin, ListUuidModelMixin))
350
346
  ):
351
- list_columns.append(fld_cls.attname)
347
+ list_columns.append(fld_cls.attname) # noqa: PERF401
352
348
  self._list_columns = list(set(list_columns))
353
349
  return self._list_columns
354
350
 
355
351
  @property
356
352
  def site_columns(self) -> list[str]:
357
353
  """Return a list of column names with fk to a site model."""
358
- from django.contrib.sites.models import Site
359
354
 
360
355
  if not self._site_columns:
361
356
  site_columns = []
@@ -372,10 +367,6 @@ class ModelToDataframe:
372
367
  @property
373
368
  def other_columns(self) -> list[str]:
374
369
  """Return other column names with fk to a common models."""
375
- from django.contrib.sites.models import Site
376
-
377
- from edc_lab.models import Panel
378
-
379
370
  related_model = [Site, Panel]
380
371
  if not self._list_columns:
381
372
  list_columns = []
@@ -7,7 +7,7 @@ __all__ = ["read_frame_edc"]
7
7
 
8
8
 
9
9
  def read_frame_edc(
10
- queryset: QuerySet | str = None,
10
+ queryset: [QuerySet] | str | None = None,
11
11
  drop_sys_columns: bool | None = None,
12
12
  drop_action_item_columns: bool | None = None,
13
13
  read_frame_verbose: bool | None = None,