dcicutils 7.6.0.2b10__py3-none-any.whl → 7.7.0.1b1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

@@ -0,0 +1,224 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from functools import lru_cache
5
+ from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, Union
6
+
7
+ import structlog
8
+
9
+ from . import ff_utils
10
+
11
+
12
+ logger = structlog.getLogger(__name__)
13
+
14
+ LinkTo = Union[str, Dict[str, Any]]
15
+
16
+
17
+ def get_link_to(
18
+ existing_item: PortalItem,
19
+ link_to: LinkTo,
20
+ item_to_create: PortalItem,
21
+ ) -> Union[str, PortalItem]:
22
+ """Create new item model from existing one for given linkTo.
23
+
24
+ LinkTos be identifiers (e.g. UUIDs) or (partially) embedded objects.
25
+
26
+ Follow rules of existing item model for fetching linkTo via
27
+ request. If not fetching via request, then make item model from
28
+ existing properties if possible.
29
+ """
30
+ fetch_links = existing_item.should_fetch_links()
31
+ identifier = get_item_identifier(link_to)
32
+ if fetch_links and identifier:
33
+ return item_to_create.from_identifier_and_existing_item(
34
+ identifier, existing_item
35
+ )
36
+ if isinstance(link_to, Mapping):
37
+ return item_to_create.from_properties_and_existing_item(link_to, existing_item)
38
+ return link_to
39
+
40
+
41
+ def get_item_identifier(item: LinkTo) -> str:
42
+ if isinstance(item, str):
43
+ return item
44
+ if isinstance(item, Mapping):
45
+ return item.get(PortalItem.UUID, "")
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class PortalItem:
50
+ ACCESSION = "accession"
51
+ AT_ID = "@id"
52
+ TYPE = "@type"
53
+ UUID = "uuid"
54
+
55
+ properties: Dict[str, Any]
56
+ auth: Optional[Dict[str, Any]] = field(default=None, hash=False)
57
+ fetch_links: Optional[bool] = field(default=False, hash=False)
58
+
59
+ def __repr__(self) -> str:
60
+ return f"{self.__class__.__name__}({self._uuid})"
61
+
62
+ @property
63
+ def _uuid(self) -> str:
64
+ return self.properties.get(self.UUID, "")
65
+
66
+ @property
67
+ def _at_id(self) -> str:
68
+ return self.properties.get(self.AT_ID, "")
69
+
70
+ @property
71
+ def _accession(self) -> str:
72
+ return self.properties.get(self.ACCESSION, "")
73
+
74
+ @property
75
+ def _types(self) -> List[str]:
76
+ return self.properties.get(self.TYPE, [])
77
+
78
+ def should_fetch_links(self) -> bool:
79
+ return self.fetch_links
80
+
81
+ def get_auth(self) -> Union[Dict[str, Any], None]:
82
+ return self.auth
83
+
84
+ def get_properties(self) -> Dict[str, Any]:
85
+ return self.properties
86
+
87
+ def get_accession(self) -> str:
88
+ return self._accession
89
+
90
+ def get_uuid(self) -> str:
91
+ return self._uuid
92
+
93
+ def get_at_id(self) -> str:
94
+ return self._at_id
95
+
96
+ def get_types(self) -> List[str]:
97
+ return self._types
98
+
99
+ def _get_link_tos(
100
+ self, link_tos: Iterable[LinkTo], item_to_create: PortalItem
101
+ ) -> List[Union[str, PortalItem]]:
102
+ return [self._get_link_to(link_to, item_to_create) for link_to in link_tos]
103
+
104
+ def _get_link_to(
105
+ self,
106
+ link_to: LinkTo,
107
+ item_to_create: PortalItem,
108
+ ) -> Union[str, PortalItem]:
109
+ return get_link_to(self, link_to, item_to_create)
110
+
111
+ @classmethod
112
+ def from_properties(
113
+ cls,
114
+ properties: Dict[str, Any],
115
+ fetch_links: bool = False,
116
+ auth: Dict[str, Any] = None,
117
+ **kwargs: Any,
118
+ ) -> PortalItem:
119
+ return cls(properties, fetch_links=fetch_links, auth=auth)
120
+
121
+ @classmethod
122
+ def from_identifier_and_auth(
123
+ cls, identifier: str, auth: Dict[str, Any], fetch_links=False, **kwargs: Any
124
+ ) -> PortalItem:
125
+ properties = cls._get_item_via_auth(identifier, auth)
126
+ return cls.from_properties(properties, auth=auth, fetch_links=fetch_links)
127
+
128
+ @classmethod
129
+ def _get_item_via_auth(
130
+ cls,
131
+ identifier: str,
132
+ auth: Dict[str, Any],
133
+ add_on: Optional[str] = "frame=object",
134
+ ) -> Dict[str, Any]:
135
+ hashable_auth = cls._make_hashable_auth(auth)
136
+ return cls._get_and_cache_item_via_auth(identifier, hashable_auth, add_on)
137
+
138
+ @classmethod
139
+ def _make_hashable_auth(cls, auth: Mapping[str, str]) -> Tuple[Tuple[str, str]]:
140
+ """Assuming nothing nested here."""
141
+ return tuple(auth.items())
142
+
143
+ @classmethod
144
+ def _undo_make_hashable_auth(
145
+ cls, hashable_auth: Tuple[Tuple[str, str]]
146
+ ) -> Dict[str, Any]:
147
+ return dict(hashable_auth)
148
+
149
+ @classmethod
150
+ @lru_cache(maxsize=256)
151
+ def _get_and_cache_item_via_auth(
152
+ cls,
153
+ identifier: str,
154
+ hashable_auth: Tuple[Tuple[str, Any]],
155
+ add_on: Optional[str] = None,
156
+ ) -> Dict[str, Any]:
157
+ """Save on requests by caching items."""
158
+ auth = cls._undo_make_hashable_auth(hashable_auth)
159
+ try:
160
+ result = ff_utils.get_metadata(identifier, key=auth, add_on=add_on)
161
+ except Exception as e:
162
+ result = {}
163
+ logger.error(f"Error getting metadata for {identifier}: {e}")
164
+ return result
165
+
166
+ @classmethod
167
+ def from_identifier_and_existing_item(
168
+ cls, identifier: str, existing_item: PortalItem, **kwargs: Any
169
+ ) -> PortalItem:
170
+ fetch_links = existing_item.should_fetch_links()
171
+ auth = existing_item.get_auth()
172
+ if auth:
173
+ return cls.from_identifier_and_auth(
174
+ identifier, auth, fetch_links=fetch_links
175
+ )
176
+ raise RuntimeError("Unable to fetch given identifier without auth key")
177
+
178
+ @classmethod
179
+ def from_properties_and_existing_item(
180
+ cls, properties: Dict[str, Any], existing_item: PortalItem, **kwargs: Any
181
+ ) -> PortalItem:
182
+ fetch_links = existing_item.should_fetch_links()
183
+ auth = existing_item.get_auth()
184
+ return cls.from_properties(properties, fetch_links=fetch_links, auth=auth)
185
+
186
+
187
+ @dataclass(frozen=True)
188
+ class NestedProperty:
189
+ properties: Dict[str, Any]
190
+ parent_item: Optional[PortalItem] = field(default=None, hash=False)
191
+
192
+ def __repr__(self) -> str:
193
+ return f"{self.__class__.__name__}(parent={self.parent_item.__repr__()})"
194
+
195
+ def get_properties(self) -> Dict[str, Any]:
196
+ return self.properties
197
+
198
+ def get_parent_item(self) -> Union[PortalItem, None]:
199
+ return self.parent_item
200
+
201
+ def _get_link_tos(
202
+ self, link_tos: LinkTo, item_to_create: PortalItem
203
+ ) -> List[Union[str, PortalItem]]:
204
+ return [self._get_link_to(link_to, item_to_create) for link_to in link_tos]
205
+
206
+ def _get_link_to(
207
+ self,
208
+ link_to: LinkTo,
209
+ item_to_create: PortalItem,
210
+ ) -> Union[str, PortalItem]:
211
+ if self.parent_item:
212
+ return get_link_to(self.parent_item, link_to, item_to_create)
213
+ if isinstance(link_to, Mapping):
214
+ return item_to_create.from_properties(link_to)
215
+ return link_to
216
+
217
+ @classmethod
218
+ def from_properties(
219
+ cls,
220
+ properties: Dict[str, Any],
221
+ parent_item: Optional[PortalItem] = None,
222
+ **kwargs: Any,
223
+ ) -> NestedProperty:
224
+ return cls(properties, parent_item=parent_item)
dcicutils/lang_utils.py CHANGED
@@ -198,13 +198,13 @@ class EnglishUtils:
198
198
  _PREFIX_PATTERN_FOR_A = re.compile("^(%s)" % "|".join({
199
199
  "[^aeioux]", # Consonants other than x need 'a' (bicycle, dog, etc.)
200
200
  "x[aeiouy]", # x followed by any vowel makes it pronounceable like a consonant (xylophone), so needs 'a'
201
- "uni([^aeiuym]|[aeiuy][^aeiy])", # things starting with "uni" are pronounced like "yuni", so need "a"
201
+ "uni([^aeiuym]|[aeiuy][^aeiy])", # things starting with with "uni" are pronounced like "yuni", so need "a"
202
202
  }), flags=re.IGNORECASE)
203
203
 
204
204
  @classmethod
205
205
  def select_a_or_an(cls, word):
206
206
  """
207
- Uses a heuristic to try to select the appropriate article ("a" or "an") for a given English noun.
207
+ Uses a heuristic to try to select the appropriate article ('a' or 'an') for a given English noun.
208
208
  select_a_or_an("gene") => 'a'
209
209
  select_a_or_an("accession") => 'an'
210
210
  """
@@ -278,7 +278,7 @@ class EnglishUtils:
278
278
  "Possible options are foo, bar and baz."
279
279
 
280
280
  :param items: the items to enumerate
281
- :param possible: whether to use the word 'possible' before the given kind (default True), or a string to use
281
+ :param possible: whether to use the word 'possible' before the given kind (default True), or an string to use
282
282
  :param kind: the kind of items being enumerated (default "option")
283
283
  :param quote: whether to put quotes around each option
284
284
  :param capitalize: whether to capitalize the first letter of the sentence (default True)
@@ -351,7 +351,7 @@ class EnglishUtils:
351
351
  @classmethod
352
352
  def there_are(cls, items, *, kind: str = "thing", count: Optional[int] = None, there: str = "there",
353
353
  capitalize=True, joiner=None, zero: object = "no", punctuate=None, punctuate_none=None,
354
- use_article=False, show=True, context=None, tense='present', punctuation_mark: str = ".",
354
+ use_article=False, show=True, context=None, tense='present',
355
355
  **joiner_options) -> str:
356
356
  """
357
357
  Constructs a sentence that enumerates a set of things.
@@ -366,7 +366,6 @@ class EnglishUtils:
366
366
  :param punctuate: in the case of one or more values (not zero), whether to end with a period (default False)
367
367
  :param punctuate_none: in the case of no values or not showing values, whether to end with a period
368
368
  (default True if show is True, and otherwise is the same as the value of punctuate)
369
- :param punctuation_mark: if specified, something to use at the end if punctuating
370
369
  :param use_article: whether to put 'a' or 'an' in front of each option (default False)
371
370
  :param joiner_options: additional (keyword) options to be used with a joiner function if one is supplied
372
371
  :param show: whether to show the items if there are any (default True)
@@ -407,7 +406,7 @@ class EnglishUtils:
407
406
  if context:
408
407
  part1 += f" {context}"
409
408
  if n == 0 or not show:
410
- punctuation = punctuation_mark if punctuate_none else ""
409
+ punctuation = "." if punctuate_none else ""
411
410
  return part1 + punctuation
412
411
  else:
413
412
  if use_article:
@@ -418,7 +417,7 @@ class EnglishUtils:
418
417
  joined = ", ".join(items)
419
418
  else:
420
419
  joined = joiner(items, **joiner_options)
421
- punctuation = punctuation_mark if punctuate else ""
420
+ punctuation = "." if punctuate else ""
422
421
  return f"{part1}: {joined}{punctuation}"
423
422
 
424
423
  @classmethod
@@ -473,7 +472,7 @@ class EnglishUtils:
473
472
  f" of the form '<n1> <unit1> <n2> <unit2>...': {s!r}")
474
473
  kwargs = {}
475
474
  for i in range(len(parts) // 2):
476
- # Canonicalize "1 week" or "1 weeks" to "weeks": 1.0 for inclusion as kwarg to timedelta
475
+ # Canonicalize "1 week" or "1 weeks" to "weeks": 1.0 for inclusion as kwarg to to timedelta
477
476
  # Uses specialized knowledge that all time units don't end in "s" but pluralize with "+s"
478
477
  value = float(parts[2 * i])
479
478
  units = parts[2 * i + 1].rstrip(',s') + "s"
dcicutils/qa_checkers.py CHANGED
@@ -8,7 +8,6 @@ import warnings
8
8
  from collections import defaultdict
9
9
  from typing import Optional, List, Dict, Type
10
10
  from typing_extensions import Literal
11
- from .contribution_utils import Contributions
12
11
  from .lang_utils import conjoined_list, n_of, there_are
13
12
  from .misc_utils import PRINT, remove_prefix, remove_suffix, getattr_customized, CustomizableProperty
14
13
 
@@ -437,11 +436,3 @@ def confirm_no_uses(*, where: str, patterns: Dict[str, str],
437
436
  detail += f"\n In {file}, {summarize(matches)}."
438
437
  message = f"{n_of(n, 'problem')} detected:" + detail
439
438
  raise AssertionError(message)
440
-
441
-
442
- class ContributionsChecker:
443
-
444
- @classmethod
445
- def validate(cls):
446
- contributions = Contributions() # no repo specified, so use current directory
447
- contributions.show_repo_contributors(error_class=AssertionError)
@@ -0,0 +1,37 @@
1
+ from contextlib import contextmanager
2
+ from types import ModuleType
3
+ from typing import Any, Iterator, Optional
4
+ from unittest import mock
5
+
6
+
7
+ AN_UNLIKELY_RETURN_VALUE = "unlikely return value"
8
+
9
+
10
+ @contextmanager
11
+ def patch_context(
12
+ to_patch: object,
13
+ return_value: Any = AN_UNLIKELY_RETURN_VALUE,
14
+ module: Optional[ModuleType] = None,
15
+ **kwargs,
16
+ ) -> Iterator[mock.MagicMock]:
17
+ """Mock out the given object.
18
+
19
+ Essentially mock.patch_object with some hacks to enable linting
20
+ on the object to patch instead of providing as a string.
21
+
22
+ Depending on import structure, adding the module to patch may be
23
+ required.
24
+ """
25
+ if isinstance(to_patch, property):
26
+ to_patch = to_patch.fget
27
+ new_callable = mock.PropertyMock
28
+ else:
29
+ new_callable = mock.MagicMock
30
+ if module is None:
31
+ target = f"{to_patch.__module__}.{to_patch.__qualname__}"
32
+ else:
33
+ target = f"{module.__name__}.{to_patch.__qualname__}"
34
+ with mock.patch(target, new_callable=new_callable, **kwargs) as mocked_item:
35
+ if return_value != AN_UNLIKELY_RETURN_VALUE:
36
+ mocked_item.return_value = return_value
37
+ yield mocked_item
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright 2017-2023 President and Fellows of Harvard College
3
+ Copyright 2017 President and Fellows of Harvard College.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 7.6.0.2b10
3
+ Version: 7.7.0.1b1
4
4
  Summary: Utility package for interacting with the 4DN Data Portal and other 4DN resources
5
5
  Home-page: https://github.com/4dn-dcic/utils
6
6
  License: MIT
@@ -5,8 +5,6 @@ dcicutils/cloudformation_utils.py,sha256=MtWJrSTXyiImgbPHgRvfH9bWso20ZPLTFJAfhDQ
5
5
  dcicutils/codebuild_utils.py,sha256=CKpmhJ-Z8gYbkt1I2zyMlKtFdsg7T8lqrx3V5ieta-U,1155
6
6
  dcicutils/command_utils.py,sha256=JExll5TMqIcmuiGvuS8q4XDUvoEfi2oSH0E2FVF6suU,15285
7
7
  dcicutils/common.py,sha256=WDZ8PaMeMuISbfeR3os0C0lgLv9cwo6Fa4o8oJbcETY,3763
8
- dcicutils/contribution_scripts.py,sha256=0k5Gw1TumcD5SAcXVkDd6-yvuMEw-jUp5Kfb7FJH6XQ,2015
9
- dcicutils/contribution_utils.py,sha256=vYLS1JUB3sKd24BUxZ29qUBqYeQBLK9cwo8x3k64uPg,25653
10
8
  dcicutils/creds_utils.py,sha256=xrLekD49Ex0GOpL9n7LlJA4gvNcY7txTVFOSYD7LvEU,11113
11
9
  dcicutils/data_utils.py,sha256=k2OxOlsx7AJ6jF-YNlMyGus_JqSUBe4_n1s65Mv1gQQ,3098
12
10
  dcicutils/deployment_utils.py,sha256=rgdJGDOuivmSMqrOGyMtw978hDGiI657hEejmfRqJ7U,68885
@@ -26,17 +24,17 @@ dcicutils/ff_mocks.py,sha256=6RKS4eUiu_Wl8yP_8V0CaV75w4ZdWxdCuL1CVlnMrek,36918
26
24
  dcicutils/ff_utils.py,sha256=3B8jdsX6N5B6jX31rSk_t7eRgg3kPROQAQfdUCwr6OE,66453
27
25
  dcicutils/function_cache_decorator.py,sha256=XMyiEGODVr2WoAQ68vcoX_9_Xb9p8pZXdXl7keU8i2g,10026
28
26
  dcicutils/glacier_utils.py,sha256=x4zRGeSBS9c3LeurjR2gvEr_ipDTVpULvRFsIMfOVrs,33704
27
+ dcicutils/item_model_utils.py,sha256=43wzfIld7PSAeLxrC3h6UOlxpn2U7Edvq6HJpbt1slA,6881
29
28
  dcicutils/jh_utils.py,sha256=Gpsxb9XEzggF_-Eq3ukjKvTnuyb9V1SCSUXkXsES4Kg,11502
30
29
  dcicutils/kibana/dashboards.json,sha256=wHMB_mpJ8OaYhRRgvpZuihaB2lmSF64ADt_8hkBWgQg,16225
31
30
  dcicutils/kibana/readme.md,sha256=3KmHF9FH6A6xwYsNxRFLw27q0XzHYnjZOlYUnn3VkQQ,2164
32
- dcicutils/lang_utils.py,sha256=cVLRUGyYeSPJAq3z_RJjA6miajHrXoi6baxF8HzHmLc,27797
33
- dcicutils/license_utils.py,sha256=rOOjX0qKEobeeW3lhOqtAKiQ5z6EM5E1w2415X2_umk,38936
31
+ dcicutils/lang_utils.py,sha256=D7HrJrESvWZPF64hTXFyy6eS-j8TB2RBFjPJfBTbK_8,27661
34
32
  dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
35
33
  dcicutils/misc_utils.py,sha256=s_6_6X1It5dklv6UOd4XfZdtbw8xWwpOysWbclUdYNA,90749
36
34
  dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmjw,5963
37
35
  dcicutils/opensearch_utils.py,sha256=V2exmFYW8Xl2_pGFixF4I2Cc549Opwe4PhFi5twC0M8,1017
38
36
  dcicutils/project_utils.py,sha256=K-KPGjtgVFDEirHhgsBIyH2YJUAM_Au_u00tIv4fTto,30631
39
- dcicutils/qa_checkers.py,sha256=uQ2rNNFMLTCrcTloKr_7Hkkc80gMp8SFijvwJLI-n6g,20511
37
+ dcicutils/qa_checkers.py,sha256=Pd40yGTxMsae1IZP86qWExBQ9kFiEMQIrsi5sWA55WE,20234
40
38
  dcicutils/qa_utils.py,sha256=aEyS6inFDCzMU7PR1al-k3bjr53vuFlzUpaBtKj0YEU,156269
41
39
  dcicutils/redis_tools.py,sha256=rqGtnVUjNjTlCdL1EMKuEhEMAgRJMiXZJkrKuX255QA,6509
42
40
  dcicutils/redis_utils.py,sha256=VJ-7g8pOZqR1ZCtdcjKz3-6as2DMUcs1b1zG6wSprH4,6462
@@ -46,9 +44,10 @@ dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19
46
44
  dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
47
45
  dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
48
46
  dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
47
+ dcicutils/testing_utils.py,sha256=yzYXtHBajpRX4A6I-T0XhHIxg39qYhvZsP4eX0Exz00,1174
49
48
  dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
50
- dcicutils-7.6.0.2b10.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
51
- dcicutils-7.6.0.2b10.dist-info/METADATA,sha256=GTUj2qMJbAps_pttsWT1OVAjx0fBjKR_ic_yUvwDO4c,3003
52
- dcicutils-7.6.0.2b10.dist-info/entry_points.txt,sha256=Z3vezbXsTpTIY4N2F33c5e-WDVQxgz_Vsk1oV_JBN7A,146
53
- dcicutils-7.6.0.2b10.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
54
- dcicutils-7.6.0.2b10.dist-info/RECORD,,
49
+ dcicutils-7.7.0.1b1.dist-info/entry_points.txt,sha256=xUFTG_l0IJJFMY-WLeijpjCzTv3_3cdmXVqClOeuIGs,74
50
+ dcicutils-7.7.0.1b1.dist-info/METADATA,sha256=4YxtAf92lNlGBb4dTVLVxTB0K7Ad-vImUyd0Fk3NelQ,3002
51
+ dcicutils-7.7.0.1b1.dist-info/LICENSE.txt,sha256=_lknlhA5bbBFtUCrhmOtUogQuvKDYd_AkLCRcjPoMBc,1098
52
+ dcicutils-7.7.0.1b1.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
53
+ dcicutils-7.7.0.1b1.dist-info/RECORD,,
@@ -1,4 +1,3 @@
1
1
  [console_scripts]
2
2
  publish-to-pypi=dcicutils.scripts.publish_to_pypi:main
3
- show-contributors=dcicutils.contribution_scripts:show_contributors_main
4
3
 
@@ -1,39 +0,0 @@
1
- import argparse
2
-
3
- from dcicutils.command_utils import script_catch_errors, ScriptFailure
4
- from .contribution_utils import Contributions, PROJECT_HOME
5
-
6
-
7
- EPILOG = __doc__
8
-
9
-
10
- def show_contributors(repo, exclude_fork=None, verbose=False, save_contributors=False, test=False):
11
- contributions = Contributions(repo=repo, exclude_fork=exclude_fork, verbose=verbose)
12
- if save_contributors:
13
- contributions.save_contributor_data()
14
- contributions.show_repo_contributors(error_class=ScriptFailure if test else None)
15
-
16
-
17
- def show_contributors_main(*, simulated_args=None):
18
- parser = argparse.ArgumentParser( # noqa - PyCharm wrongly thinks the formatter_class is specified wrong here.
19
- description=(f"Show authors of a specified repository, which will be presumed"
20
- f" to have been cloned as a subdirectory of $PROJECT_HOME ({PROJECT_HOME})"),
21
- epilog=EPILOG,
22
- formatter_class=argparse.RawDescriptionHelpFormatter,
23
- )
24
- parser.add_argument('repo', default=None,
25
- help="name of repository to show contributors for")
26
- parser.add_argument('--exclude', '-x', default=None,
27
- help="name of repository that repo was forked from, whose contributors to exclude")
28
- parser.add_argument('--save-contributors', '-s', action="store_true", default=False,
29
- help="whether to store contributor data to CONTRIBUTORS.json")
30
- parser.add_argument('--test', '-t', action="store_true", default=False,
31
- help="whether to treat this as a test, erring if a cache update is needed")
32
- parser.add_argument('--verbose', '-v', action="store_true", default=False,
33
- help="whether to do verbose output while working")
34
- args = parser.parse_args(args=simulated_args)
35
-
36
- with script_catch_errors():
37
-
38
- show_contributors(repo=args.repo, exclude_fork=args.exclude, verbose=args.verbose,
39
- save_contributors=args.save_contributors, test=args.test)