hh-applicant-tool 0.6.7__py3-none-any.whl → 0.6.9__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 hh-applicant-tool might be problematic. Click here for more details.
- hh_applicant_tool/operations/apply_similar.py +153 -13
- hh_applicant_tool/operations/reply_employers.py +1 -1
- {hh_applicant_tool-0.6.7.dist-info → hh_applicant_tool-0.6.9.dist-info}/METADATA +1 -1
- {hh_applicant_tool-0.6.7.dist-info → hh_applicant_tool-0.6.9.dist-info}/RECORD +6 -6
- {hh_applicant_tool-0.6.7.dist-info → hh_applicant_tool-0.6.9.dist-info}/WHEEL +0 -0
- {hh_applicant_tool-0.6.7.dist-info → hh_applicant_tool-0.6.9.dist-info}/entry_points.txt +0 -0
|
@@ -37,11 +37,43 @@ class Namespace(BaseNamespace):
|
|
|
37
37
|
search: str
|
|
38
38
|
schedule: str
|
|
39
39
|
dry_run: bool
|
|
40
|
+
# Пошли доп фильтры, которых не было
|
|
40
41
|
experience: str
|
|
41
|
-
|
|
42
|
+
employment: list[str] | None
|
|
43
|
+
area: list[str] | None
|
|
44
|
+
metro: list[str] | None
|
|
45
|
+
professional_role: list[str] | None
|
|
46
|
+
industry: list[str] | None
|
|
47
|
+
employer_id: list[str] | None
|
|
48
|
+
excluded_employer_id: list[str] | None
|
|
49
|
+
currency: str | None
|
|
50
|
+
salary: int | None
|
|
51
|
+
only_with_salary: bool
|
|
52
|
+
label: list[str] | None
|
|
53
|
+
period: int | None
|
|
54
|
+
date_from: str | None
|
|
55
|
+
date_to: str | None
|
|
56
|
+
top_lat: float | None
|
|
57
|
+
bottom_lat: float | None
|
|
58
|
+
left_lng: float | None
|
|
59
|
+
right_lng: float | None
|
|
60
|
+
sort_point_lat: float | None
|
|
61
|
+
sort_point_lng: float | None
|
|
62
|
+
no_magic: bool
|
|
63
|
+
premium: bool
|
|
64
|
+
responses_count_enabled: bool
|
|
65
|
+
|
|
66
|
+
def _bool(v: bool) -> str:
|
|
67
|
+
return str(v).lower()
|
|
68
|
+
|
|
69
|
+
def _join_list(items: list[Any] | None) -> str:
|
|
70
|
+
return ",".join(f"{v}" for v in items) if items else ""
|
|
42
71
|
|
|
43
72
|
class Operation(BaseOperation, GetResumeIdMixin):
|
|
44
|
-
"""Откликнуться на все подходящие вакансии.
|
|
73
|
+
"""Откликнуться на все подходящие вакансии.
|
|
74
|
+
|
|
75
|
+
Описание фильтров для поиска вакансий: <https://api.hh.ru/openapi/redoc#tag/Poisk-vakansij-dlya-soiskatelya/operation/get-vacancies-similar-to-resume>
|
|
76
|
+
"""
|
|
45
77
|
|
|
46
78
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
47
79
|
parser.add_argument("--resume-id", help="Идентефикатор резюме")
|
|
@@ -121,6 +153,32 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
121
153
|
type=str,
|
|
122
154
|
default=None,
|
|
123
155
|
)
|
|
156
|
+
parser.add_argument("--employment", nargs="+", help="Тип занятости (employment)")
|
|
157
|
+
parser.add_argument("--area", nargs="+", help="Регион (area id)")
|
|
158
|
+
parser.add_argument("--metro", nargs="+", help="Станции метро (metro id)")
|
|
159
|
+
parser.add_argument("--professional-role", nargs="+", help="Проф. роль (id)")
|
|
160
|
+
parser.add_argument("--industry", nargs="+", help="Индустрия (industry id)")
|
|
161
|
+
parser.add_argument("--employer-id", nargs="+", help="ID работодателей")
|
|
162
|
+
parser.add_argument("--excluded-employer-id", nargs="+", help="Исключить работодателей")
|
|
163
|
+
parser.add_argument("--currency", help="Код валюты (RUR, USD, EUR)")
|
|
164
|
+
parser.add_argument("--salary", type=int, help="Минимальная зарплата")
|
|
165
|
+
parser.add_argument("--only-with-salary", default=False, action=argparse.BooleanOptionalAction)
|
|
166
|
+
parser.add_argument("--label", nargs="+", help="Метки вакансий (label)")
|
|
167
|
+
parser.add_argument("--period", type=int, help="Искать вакансии за N дней")
|
|
168
|
+
parser.add_argument("--date-from", help="Дата публикации с (YYYY-MM-DD)")
|
|
169
|
+
parser.add_argument("--date-to", help="Дата публикации по (YYYY-MM-DD)")
|
|
170
|
+
parser.add_argument("--top-lat", type=float, help="Гео: верхняя широта")
|
|
171
|
+
parser.add_argument("--bottom-lat", type=float, help="Гео: нижняя широта")
|
|
172
|
+
parser.add_argument("--left-lng", type=float, help="Гео: левая долгота")
|
|
173
|
+
parser.add_argument("--right-lng", type=float, help="Гео: правая долгота")
|
|
174
|
+
parser.add_argument("--sort-point-lat", type=float, help="Координата lat для сортировки по расстоянию")
|
|
175
|
+
parser.add_argument("--sort-point-lng", type=float, help="Координата lng для сортировки по расстоянию")
|
|
176
|
+
parser.add_argument("--no-magic", default=False, action=argparse.BooleanOptionalAction, help="Отключить авторазбор текста запроса")
|
|
177
|
+
parser.add_argument("--premium", default=False, action=argparse.BooleanOptionalAction, help="Только премиум вакансии")
|
|
178
|
+
parser.add_argument("--responses-count-enabled", default=False, action=argparse.BooleanOptionalAction, help="Включить счётчик откликов")
|
|
179
|
+
parser.add_argument("--search-field", nargs="+", help="Поля поиска (name, company_name и т.п.)")
|
|
180
|
+
parser.add_argument("--clusters", action=argparse.BooleanOptionalAction, help="Включить кластеры (по умолчанию None)")
|
|
181
|
+
#parser.add_argument("--describe-arguments", action=argparse.BooleanOptionalAction, help="Вернуть описание параметров запроса")
|
|
124
182
|
|
|
125
183
|
def run(
|
|
126
184
|
self, args: Namespace, api_client: ApiClient, telemetry_client: TelemetryClient
|
|
@@ -165,6 +223,31 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
165
223
|
self.schedule = args.schedule
|
|
166
224
|
self.dry_run = args.dry_run
|
|
167
225
|
self.experience = args.experience
|
|
226
|
+
self.search_field = args.search_field
|
|
227
|
+
self.employment = args.employment
|
|
228
|
+
self.area = args.area
|
|
229
|
+
self.metro = args.metro
|
|
230
|
+
self.professional_role = args.professional_role
|
|
231
|
+
self.industry = args.industry
|
|
232
|
+
self.employer_id = args.employer_id
|
|
233
|
+
self.excluded_employer_id = args.excluded_employer_id
|
|
234
|
+
self.currency = args.currency
|
|
235
|
+
self.salary = args.salary
|
|
236
|
+
self.only_with_salary = args.only_with_salary
|
|
237
|
+
self.label = args.label
|
|
238
|
+
self.period = args.period
|
|
239
|
+
self.date_from = args.date_from
|
|
240
|
+
self.date_to = args.date_to
|
|
241
|
+
self.top_lat = args.top_lat
|
|
242
|
+
self.bottom_lat = args.bottom_lat
|
|
243
|
+
self.left_lng = args.left_lng
|
|
244
|
+
self.right_lng = args.right_lng
|
|
245
|
+
self.sort_point_lat = args.sort_point_lat
|
|
246
|
+
self.sort_point_lng = args.sort_point_lng
|
|
247
|
+
self.clusters = args.clusters
|
|
248
|
+
#self.describe_arguments = args.describe_arguments
|
|
249
|
+
self.no_magic = args.no_magic
|
|
250
|
+
self.premium = args.premium
|
|
168
251
|
self._apply_similar()
|
|
169
252
|
|
|
170
253
|
def _get_application_messages(self, message_list: TextIO | None) -> list[str]:
|
|
@@ -366,20 +449,77 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
366
449
|
except TelemetryError as ex:
|
|
367
450
|
logger.error(ex)
|
|
368
451
|
|
|
452
|
+
def _get_search_params(self, page: int, per_page: int) -> dict:
|
|
453
|
+
params = {
|
|
454
|
+
"page": page,
|
|
455
|
+
"per_page": per_page,
|
|
456
|
+
"order_by": self.order_by,
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if self.search:
|
|
460
|
+
params["text"] = self.search
|
|
461
|
+
if self.schedule:
|
|
462
|
+
params['schedule'] = self.schedule
|
|
463
|
+
if self.experience:
|
|
464
|
+
params['experience'] = self.experience
|
|
465
|
+
if self.currency:
|
|
466
|
+
params["currency"] = self.currency
|
|
467
|
+
if self.salary:
|
|
468
|
+
params["salary"] = self.salary
|
|
469
|
+
if self.period:
|
|
470
|
+
params["period"] = self.period
|
|
471
|
+
if self.date_from:
|
|
472
|
+
params["date_from"] = self.date_from
|
|
473
|
+
if self.date_to:
|
|
474
|
+
params["date_to"] = self.date_to
|
|
475
|
+
if self.top_lat:
|
|
476
|
+
params["top_lat"] = self.top_lat
|
|
477
|
+
if self.bottom_lat:
|
|
478
|
+
params["bottom_lat"] = self.bottom_lat
|
|
479
|
+
if self.left_lng:
|
|
480
|
+
params["left_lng"] = self.left_lng
|
|
481
|
+
if self.right_lng:
|
|
482
|
+
params["right_lng"] = self.right_lng
|
|
483
|
+
if self.sort_point_lat:
|
|
484
|
+
params["sort_point_lat"] = self.sort_point_lat
|
|
485
|
+
if self.sort_point_lng:
|
|
486
|
+
params["sort_point_lng"] = self.sort_point_lng
|
|
487
|
+
if self.search_field:
|
|
488
|
+
params["search_field"] = _join_list(self.search_field)
|
|
489
|
+
if self.employment:
|
|
490
|
+
params["employment"] = _join_list(self.employment)
|
|
491
|
+
if self.area:
|
|
492
|
+
params["area"] = _join_list(self.area)
|
|
493
|
+
if self.metro:
|
|
494
|
+
params["metro"] = _join_list(self.metro)
|
|
495
|
+
if self.professional_role:
|
|
496
|
+
params["professional_role"] = _join_list(self.professional_role)
|
|
497
|
+
if self.industry:
|
|
498
|
+
params["industry"] = _join_list(self.industry)
|
|
499
|
+
if self.employer_id:
|
|
500
|
+
params["employer_id"] = _join_list(self.employer_id)
|
|
501
|
+
if self.excluded_employer_id:
|
|
502
|
+
params["excluded_employer_id"] = _join_list(self.excluded_employer_id)
|
|
503
|
+
if self.label:
|
|
504
|
+
params["label"] = _join_list(self.label)
|
|
505
|
+
if self.only_with_salary is not None:
|
|
506
|
+
params["only_with_salary"] = _bool(self.only_with_salary)
|
|
507
|
+
if self.clusters is not None:
|
|
508
|
+
params["clusters"] = _bool(self.clusters)
|
|
509
|
+
if self.no_magic is not None:
|
|
510
|
+
params["no_magic"] = _bool(self.no_magic)
|
|
511
|
+
if self.premium is not None:
|
|
512
|
+
params["premium"] = _bool(self.premium)
|
|
513
|
+
if self.responses_count_enabled is not None:
|
|
514
|
+
params["responses_count_enabled"] = _bool(self.responses_count_enabled)
|
|
515
|
+
|
|
516
|
+
return params
|
|
517
|
+
|
|
369
518
|
def _get_vacancies(self, per_page: int = 100) -> list[VacancyItem]:
|
|
370
519
|
rv = []
|
|
520
|
+
# API отдает только 2000 результатов
|
|
371
521
|
for page in range(20):
|
|
372
|
-
params =
|
|
373
|
-
"page": page,
|
|
374
|
-
"per_page": per_page,
|
|
375
|
-
"order_by": self.order_by,
|
|
376
|
-
}
|
|
377
|
-
if self.search:
|
|
378
|
-
params["text"] = self.search
|
|
379
|
-
if self.schedule:
|
|
380
|
-
params['schedule'] = self.schedule
|
|
381
|
-
if self.experience:
|
|
382
|
-
params['experience'] = self.experience
|
|
522
|
+
params = self._get_search_params(page, per_page)
|
|
383
523
|
res: ApiListResponse = self.api_client.get(
|
|
384
524
|
f"/resumes/{self.resume_id}/similar_vacancies", params
|
|
385
525
|
)
|
|
@@ -61,7 +61,7 @@ class Operation(BaseOperation, GetResumeIdMixin):
|
|
|
61
61
|
"-m",
|
|
62
62
|
"--reply-message",
|
|
63
63
|
"--reply",
|
|
64
|
-
help="Отправить сообщение во все чаты, где ожидают ответа либо не прочитали ответ.
|
|
64
|
+
help="Отправить сообщение во все чаты, где ожидают ответа либо не прочитали ответ. Если не передать сообщение, то нужно будет вводить его в интерактивном режиме.",
|
|
65
65
|
)
|
|
66
66
|
parser.add_argument(
|
|
67
67
|
"-p",
|
|
@@ -11,7 +11,7 @@ hh_applicant_tool/jsonc.py,sha256=QNS4gRHfi7SAeOFnffAIuhH7auC4Y4HAkmH12eX5PkI,40
|
|
|
11
11
|
hh_applicant_tool/main.py,sha256=A4YPkNXAdZY0GoGm0iigiQtzXTrpR3SaIGo54q9-Dd0,5652
|
|
12
12
|
hh_applicant_tool/mixins.py,sha256=8VoyrNgdlljy6pLTSFGJOYd9kagWT3yFOZYIGR6MEbI,425
|
|
13
13
|
hh_applicant_tool/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
hh_applicant_tool/operations/apply_similar.py,sha256=
|
|
14
|
+
hh_applicant_tool/operations/apply_similar.py,sha256=LqZl2j8a5RUzI9VQmBIOkSQmPZZl62hWEB05mcA5MYQ,23975
|
|
15
15
|
hh_applicant_tool/operations/authorize.py,sha256=NYrxe6oemUBcDHioT1t1lJmi9l45V4ZXzQPD_-nf6hk,3328
|
|
16
16
|
hh_applicant_tool/operations/call_api.py,sha256=o3GZgtqk6w4zpCm-JTHVjFrKVOwW-vsu1HdRi-hqAjo,1423
|
|
17
17
|
hh_applicant_tool/operations/clear_negotiations.py,sha256=FG_43P5GWmfKUggkKZqDznQ2_iBJ3zrZtv8yEI2XOXQ,4527
|
|
@@ -20,13 +20,13 @@ hh_applicant_tool/operations/delete_telemetry.py,sha256=JHdh_l7IJL_qy5AIIy8FQpUu
|
|
|
20
20
|
hh_applicant_tool/operations/get_employer_contacts.py,sha256=Sd-x3O08bmKm1OGVLtJ6rcPZ_j1jwjlqKV4z1n_G-38,9918
|
|
21
21
|
hh_applicant_tool/operations/list_resumes.py,sha256=dILHyBCSEVqdNAvD8SML5f2Lau1R2AzTaKE9B4FG8Wg,1109
|
|
22
22
|
hh_applicant_tool/operations/refresh_token.py,sha256=v_Fcw9mCfOdE6MLTCQjZQudhJPX0fup3k0BaIM394Qw,834
|
|
23
|
-
hh_applicant_tool/operations/reply_employers.py,sha256=
|
|
23
|
+
hh_applicant_tool/operations/reply_employers.py,sha256=40rsTgpoEUaRQUq5ZQYgojKb42smYRkbDDD2S_7Vwtg,13512
|
|
24
24
|
hh_applicant_tool/operations/update_resumes.py,sha256=_r7HA_vpYMs5DFY-mVP1ZRG9bggsv7ebKYrwteBmJ30,1053
|
|
25
25
|
hh_applicant_tool/operations/whoami.py,sha256=pNWJMmEQLBk3U6eiGz4CHcX7eXzDXcfezFjX7zLjqyA,711
|
|
26
26
|
hh_applicant_tool/telemetry_client.py,sha256=1EKZWc5kMx2yERW9SrR9vaf-OB6M_KKcMXeicH5YyY0,3834
|
|
27
27
|
hh_applicant_tool/types.py,sha256=sQbt_vGXtWPRJ3UzcUkE87BTHOaGTsFxqdZa_qFghZE,864
|
|
28
28
|
hh_applicant_tool/utils.py,sha256=3T4A2AykGqTwtGAttmYplIjHwFl3pNAcbWIVuA-OheQ,3080
|
|
29
|
-
hh_applicant_tool-0.6.
|
|
30
|
-
hh_applicant_tool-0.6.
|
|
31
|
-
hh_applicant_tool-0.6.
|
|
32
|
-
hh_applicant_tool-0.6.
|
|
29
|
+
hh_applicant_tool-0.6.9.dist-info/METADATA,sha256=vJhPJE35bjzd49jfJ2lpTzD8tDCSjMrL6gy5X-QObIY,21401
|
|
30
|
+
hh_applicant_tool-0.6.9.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
31
|
+
hh_applicant_tool-0.6.9.dist-info/entry_points.txt,sha256=Vb7M2YaYLMtKYJZh8chIrXZApMzSRFT1-rQw-U9r10g,65
|
|
32
|
+
hh_applicant_tool-0.6.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|