hh-applicant-tool 0.6.3__py3-none-any.whl → 0.6.12__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.
@@ -0,0 +1,67 @@
1
+ import logging
2
+
3
+ import requests
4
+
5
+ logger = logging.getLogger(__package__)
6
+
7
+
8
+ class OpenAIError(Exception):
9
+ pass
10
+
11
+
12
+ class OpenAIChat:
13
+ chat_endpoint: str = "https://api.openai.com/v1/chat/completions"
14
+
15
+ def __init__(
16
+ self,
17
+ token: str,
18
+ model: str,
19
+ system_prompt: str,
20
+ proxies: dict[str, str] = {}
21
+ ):
22
+ self.token = token
23
+ self.model = model
24
+ self.system_prompt = system_prompt
25
+ self.proxies = proxies
26
+
27
+ def default_headers(self) -> dict[str, str]:
28
+ return {
29
+ "Authorization": f"Bearer {self.token}",
30
+ "Content-Type": "application/json",
31
+ }
32
+
33
+ def send_message(self, message: str) -> str:
34
+
35
+ payload = {
36
+ "model": self.model,
37
+ "messages": [
38
+ {
39
+ "role": "system",
40
+ "content": self.system_prompt
41
+ },
42
+ {
43
+ "role": "user",
44
+ "content": message
45
+ }
46
+ ],
47
+ "temperature": 0.7,
48
+ "max_completion_tokens": 1000
49
+ }
50
+
51
+ try:
52
+ response = requests.post(
53
+ self.chat_endpoint,
54
+ json=payload,
55
+ headers=self.default_headers(),
56
+ proxies=self.proxies,
57
+ timeout=30
58
+ )
59
+ response.raise_for_status()
60
+
61
+ data = response.json()
62
+ assistant_message = data["choices"][0]["message"]["content"]
63
+
64
+ return assistant_message
65
+
66
+ except requests.exceptions.RequestException as ex:
67
+ raise OpenAIError(f"OpenAI API Error: {str(ex)}") from ex
@@ -4,11 +4,12 @@ import random
4
4
  import time
5
5
  from collections import defaultdict
6
6
  from datetime import datetime, timedelta, timezone
7
- from typing import TextIO
7
+ from typing import Any, TextIO
8
8
 
9
+ from ..ai.blackbox import BlackboxChat
10
+ from ..ai.openai import OpenAIChat
11
+ from ..api import ApiClient, ApiError
9
12
  from ..api.errors import LimitExceeded
10
- from ..ai.blackbox import BlackboxChat, BlackboxError
11
- from ..api import ApiError, ApiClient
12
13
  from ..main import BaseOperation
13
14
  from ..main import Namespace as BaseNamespace
14
15
  from ..mixins import GetResumeIdMixin
@@ -35,11 +36,47 @@ class Namespace(BaseNamespace):
35
36
  page_interval: tuple[float, float]
36
37
  order_by: str
37
38
  search: str
39
+ schedule: str
38
40
  dry_run: bool
41
+ # Пошли доп фильтры, которых не было
42
+ experience: str
43
+ employment: list[str] | None
44
+ area: list[str] | None
45
+ metro: list[str] | None
46
+ professional_role: list[str] | None
47
+ industry: list[str] | None
48
+ employer_id: list[str] | None
49
+ excluded_employer_id: list[str] | None
50
+ currency: str | None
51
+ salary: int | None
52
+ only_with_salary: bool
53
+ label: list[str] | None
54
+ period: int | None
55
+ date_from: str | None
56
+ date_to: str | None
57
+ top_lat: float | None
58
+ bottom_lat: float | None
59
+ left_lng: float | None
60
+ right_lng: float | None
61
+ sort_point_lat: float | None
62
+ sort_point_lng: float | None
63
+ no_magic: bool
64
+ premium: bool
65
+
66
+
67
+ def _bool(v: bool) -> str:
68
+ return str(v).lower()
69
+
70
+
71
+ def _join_list(items: list[Any] | None) -> str:
72
+ return ",".join(f"{v}" for v in items) if items else ""
39
73
 
40
74
 
41
75
  class Operation(BaseOperation, GetResumeIdMixin):
42
- """Откликнуться на все подходящие вакансии."""
76
+ """Откликнуться на все подходящие вакансии.
77
+
78
+ Описание фильтров для поиска вакансий: <https://api.hh.ru/openapi/redoc#tag/Poisk-vakansij-dlya-soiskatelya/operation/get-vacancies-similar-to-resume>
79
+ """
43
80
 
44
81
  def setup_parser(self, parser: argparse.ArgumentParser) -> None:
45
82
  parser.add_argument("--resume-id", help="Идентефикатор резюме")
@@ -100,12 +137,80 @@ class Operation(BaseOperation, GetResumeIdMixin):
100
137
  type=str,
101
138
  default=None,
102
139
  )
140
+
141
+ parser.add_argument(
142
+ "--schedule",
143
+ help="Тип графика. Возможные значения: fullDay, shift, flexible, remote, flyInFlyOut для полного дня, сменного графика, гибкого графика, удаленной работы и вахтового метода",
144
+ type=str,
145
+ default=None,
146
+ )
103
147
  parser.add_argument(
104
148
  "--dry-run",
105
149
  help="Не отправлять отклики, а только выводить параметры запроса",
106
150
  default=False,
107
151
  action=argparse.BooleanOptionalAction,
108
152
  )
153
+ parser.add_argument(
154
+ "--experience",
155
+ help="Уровень опыта работы в вакансии. Возможные значения: noExperience, between1And3, between3And6, moreThan6",
156
+ type=str,
157
+ default=None,
158
+ )
159
+ parser.add_argument(
160
+ "--employment", nargs="+", help="Тип занятости (employment)"
161
+ )
162
+ parser.add_argument("--area", nargs="+", help="Регион (area id)")
163
+ parser.add_argument("--metro", nargs="+", help="Станции метро (metro id)")
164
+ parser.add_argument("--professional-role", nargs="+", help="Проф. роль (id)")
165
+ parser.add_argument("--industry", nargs="+", help="Индустрия (industry id)")
166
+ parser.add_argument("--employer-id", nargs="+", help="ID работодателей")
167
+ parser.add_argument(
168
+ "--excluded-employer-id", nargs="+", help="Исключить работодателей"
169
+ )
170
+ parser.add_argument("--currency", help="Код валюты (RUR, USD, EUR)")
171
+ parser.add_argument("--salary", type=int, help="Минимальная зарплата")
172
+ parser.add_argument(
173
+ "--only-with-salary", default=False, action=argparse.BooleanOptionalAction
174
+ )
175
+ parser.add_argument("--label", nargs="+", help="Метки вакансий (label)")
176
+ parser.add_argument("--period", type=int, help="Искать вакансии за N дней")
177
+ parser.add_argument("--date-from", help="Дата публикации с (YYYY-MM-DD)")
178
+ parser.add_argument("--date-to", help="Дата публикации по (YYYY-MM-DD)")
179
+ parser.add_argument("--top-lat", type=float, help="Гео: верхняя широта")
180
+ parser.add_argument("--bottom-lat", type=float, help="Гео: нижняя широта")
181
+ parser.add_argument("--left-lng", type=float, help="Гео: левая долгота")
182
+ parser.add_argument("--right-lng", type=float, help="Гео: правая долгота")
183
+ parser.add_argument(
184
+ "--sort-point-lat",
185
+ type=float,
186
+ help="Координата lat для сортировки по расстоянию",
187
+ )
188
+ parser.add_argument(
189
+ "--sort-point-lng",
190
+ type=float,
191
+ help="Координата lng для сортировки по расстоянию",
192
+ )
193
+ parser.add_argument(
194
+ "--no-magic",
195
+ default=False,
196
+ action=argparse.BooleanOptionalAction,
197
+ help="Отключить авторазбор текста запроса",
198
+ )
199
+ parser.add_argument(
200
+ "--premium",
201
+ default=False,
202
+ action=argparse.BooleanOptionalAction,
203
+ help="Только премиум вакансии",
204
+ )
205
+ parser.add_argument(
206
+ "--search-field", nargs="+", help="Поля поиска (name, company_name и т.п.)"
207
+ )
208
+ parser.add_argument(
209
+ "--clusters",
210
+ action=argparse.BooleanOptionalAction,
211
+ help="Включить кластеры (по умолчанию None)",
212
+ )
213
+ # parser.add_argument("--describe-arguments", action=argparse.BooleanOptionalAction, help="Вернуть описание параметров запроса")
109
214
 
110
215
  def run(
111
216
  self, args: Namespace, api_client: ApiClient, telemetry_client: TelemetryClient
@@ -138,6 +243,19 @@ class Operation(BaseOperation, GetResumeIdMixin):
138
243
  chat_payload=config["chat_payload"],
139
244
  proxies=self.api_client.proxies or {},
140
245
  )
246
+ elif config := args.config.get("openai"):
247
+ model = "gpt-5.1"
248
+ system_prompt = "Напиши сопроводительное письмо для отклика на эту вакансию. Не используй placeholder'ы, твой ответ будет отправлен без обработки."
249
+ if "model" in config.keys():
250
+ model = config["model"]
251
+ if "system_prompt" in config.keys():
252
+ system_prompt = config["system_prompt"]
253
+ self.chat = OpenAIChat(
254
+ token=config["token"],
255
+ model=model,
256
+ system_prompt=system_prompt,
257
+ proxies=self.api_client.proxies or {},
258
+ )
141
259
 
142
260
  self.pre_prompt = args.pre_prompt
143
261
 
@@ -147,7 +265,34 @@ class Operation(BaseOperation, GetResumeIdMixin):
147
265
  self.force_message = args.force_message
148
266
  self.order_by = args.order_by
149
267
  self.search = args.search
268
+ self.schedule = args.schedule
150
269
  self.dry_run = args.dry_run
270
+ self.experience = args.experience
271
+ self.search_field = args.search_field
272
+ self.employment = args.employment
273
+ self.area = args.area
274
+ self.metro = args.metro
275
+ self.professional_role = args.professional_role
276
+ self.industry = args.industry
277
+ self.employer_id = args.employer_id
278
+ self.excluded_employer_id = args.excluded_employer_id
279
+ self.currency = args.currency
280
+ self.salary = args.salary
281
+ self.only_with_salary = args.only_with_salary
282
+ self.label = args.label
283
+ self.period = args.period
284
+ self.date_from = args.date_from
285
+ self.date_to = args.date_to
286
+ self.top_lat = args.top_lat
287
+ self.bottom_lat = args.bottom_lat
288
+ self.left_lng = args.left_lng
289
+ self.right_lng = args.right_lng
290
+ self.sort_point_lat = args.sort_point_lat
291
+ self.sort_point_lng = args.sort_point_lng
292
+ self.clusters = args.clusters
293
+ # self.describe_arguments = args.describe_arguments
294
+ self.no_magic = args.no_magic
295
+ self.premium = args.premium
151
296
  self._apply_similar()
152
297
 
153
298
  def _get_application_messages(self, message_list: TextIO | None) -> list[str]:
@@ -267,10 +412,9 @@ class Operation(BaseOperation, GetResumeIdMixin):
267
412
 
268
413
  if not do_apply:
269
414
  logger.debug(
270
- "Пропускаем вакансию так как достигла лимита заявок: %s",
271
- vacancy["alternate_url"],
415
+ "Останавливаем рассылку откликов, так как достигли лимита, попробуйте через сутки."
272
416
  )
273
- continue
417
+ break
274
418
 
275
419
  if relations:
276
420
  logger.debug(
@@ -292,7 +436,7 @@ class Operation(BaseOperation, GetResumeIdMixin):
292
436
  msg += message_placeholders["vacancy_name"]
293
437
  logger.debug(msg)
294
438
  msg = self.chat.send_message(msg)
295
- except BlackboxError as ex:
439
+ except Exception as ex:
296
440
  logger.error(ex)
297
441
  continue
298
442
  else:
@@ -352,16 +496,77 @@ class Operation(BaseOperation, GetResumeIdMixin):
352
496
  except TelemetryError as ex:
353
497
  logger.error(ex)
354
498
 
499
+ def _get_search_params(self, page: int, per_page: int) -> dict:
500
+ params = {
501
+ "page": page,
502
+ "per_page": per_page,
503
+ "order_by": self.order_by,
504
+ }
505
+
506
+ if self.search:
507
+ params["text"] = self.search
508
+ if self.schedule:
509
+ params["schedule"] = self.schedule
510
+ if self.experience:
511
+ params["experience"] = self.experience
512
+ if self.currency:
513
+ params["currency"] = self.currency
514
+ if self.salary:
515
+ params["salary"] = self.salary
516
+ if self.period:
517
+ params["period"] = self.period
518
+ if self.date_from:
519
+ params["date_from"] = self.date_from
520
+ if self.date_to:
521
+ params["date_to"] = self.date_to
522
+ if self.top_lat:
523
+ params["top_lat"] = self.top_lat
524
+ if self.bottom_lat:
525
+ params["bottom_lat"] = self.bottom_lat
526
+ if self.left_lng:
527
+ params["left_lng"] = self.left_lng
528
+ if self.right_lng:
529
+ params["right_lng"] = self.right_lng
530
+ if self.sort_point_lat:
531
+ params["sort_point_lat"] = self.sort_point_lat
532
+ if self.sort_point_lng:
533
+ params["sort_point_lng"] = self.sort_point_lng
534
+ if self.search_field:
535
+ params["search_field"] = _join_list(self.search_field)
536
+ if self.employment:
537
+ params["employment"] = _join_list(self.employment)
538
+ if self.area:
539
+ params["area"] = _join_list(self.area)
540
+ if self.metro:
541
+ params["metro"] = _join_list(self.metro)
542
+ if self.professional_role:
543
+ params["professional_role"] = _join_list(self.professional_role)
544
+ if self.industry:
545
+ params["industry"] = _join_list(self.industry)
546
+ if self.employer_id:
547
+ params["employer_id"] = _join_list(self.employer_id)
548
+ if self.excluded_employer_id:
549
+ params["excluded_employer_id"] = _join_list(self.excluded_employer_id)
550
+ if self.label:
551
+ params["label"] = _join_list(self.label)
552
+ if self.only_with_salary is not None:
553
+ params["only_with_salary"] = _bool(self.only_with_salary)
554
+ if self.clusters is not None:
555
+ params["clusters"] = _bool(self.clusters)
556
+ if self.no_magic is not None:
557
+ params["no_magic"] = _bool(self.no_magic)
558
+ if self.premium is not None:
559
+ params["premium"] = _bool(self.premium)
560
+ # if self.responses_count_enabled is not None:
561
+ # params["responses_count_enabled"] = _bool(self.responses_count_enabled)
562
+
563
+ return params
564
+
355
565
  def _get_vacancies(self, per_page: int = 100) -> list[VacancyItem]:
356
566
  rv = []
567
+ # API отдает только 2000 результатов
357
568
  for page in range(20):
358
- params = {
359
- "page": page,
360
- "per_page": per_page,
361
- "order_by": self.order_by,
362
- }
363
- if self.search:
364
- params["text"] = self.search
569
+ params = self._get_search_params(page, per_page)
365
570
  res: ApiListResponse = self.api_client.get(
366
571
  f"/resumes/{self.resume_id}/similar_vacancies", params
367
572
  )
@@ -377,3 +582,4 @@ class Operation(BaseOperation, GetResumeIdMixin):
377
582
  time.sleep(interval)
378
583
 
379
584
  return rv
585
+
@@ -16,6 +16,7 @@ logger = logging.getLogger(__package__)
16
16
  class Namespace(BaseNamespace):
17
17
  older_than: int
18
18
  blacklist_discard: bool
19
+ all: bool
19
20
 
20
21
 
21
22
  class Operation(BaseOperation):
@@ -93,7 +94,10 @@ class Operation(BaseOperation):
93
94
  ")",
94
95
  )
95
96
  if is_discard and args.blacklist_discard:
96
- employer = vacancy["employer"]
97
+ employer = vacancy.get("employer", {})
98
+ if not employer or 'id' not in employer:
99
+ # Работодатель удален или скрыт
100
+ continue
97
101
  try:
98
102
  r = api_client.put(f"/employers/blacklisted/{employer['id']}")
99
103
  assert not r
@@ -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",
@@ -104,10 +104,11 @@ class Operation(BaseOperation, GetResumeIdMixin):
104
104
 
105
105
  def _get_blacklisted(self) -> list[str]:
106
106
  rv = []
107
+ # В этом методе API страницы с 0 начинаются
107
108
  for page in count(0):
108
109
  r = self.api_client.get("/employers/blacklisted", page=page)
109
110
  rv += [item["id"] for item in r["items"]]
110
- if page >= r["pages"]:
111
+ if page + 1 >= r["pages"]:
111
112
  break
112
113
  return rv
113
114
 
@@ -42,3 +42,4 @@ class VacancyItem(TypedDict):
42
42
  sort_point_distance: float
43
43
  type: dict
44
44
  url: str
45
+ experience: dict
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: hh-applicant-tool
3
- Version: 0.6.3
3
+ Version: 0.6.12
4
4
  Summary:
5
5
  Author: Senior YAML Developer
6
6
  Author-email: yamldeveloper@proton.me
@@ -10,6 +10,7 @@ Classifier: Programming Language :: Python :: 3.10
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
13
14
  Provides-Extra: qt
14
15
  Requires-Dist: prettytable (>=3.6.0,<4.0.0)
15
16
  Requires-Dist: pyqt6 (==6.7.0) ; extra == "qt"
@@ -34,7 +35,7 @@ Description-Content-Type: text/markdown
34
35
 
35
36
  > Утилита для генерации сопроводительного письма может использовать AI
36
37
 
37
- Утилита для успешных волчат и старых волков с опытом, служащая для автоматизации действий на HH.RU таких как рассылка откликов на подходящие вакансии и обновление всех резюме (бесплатный аналог услуги на HH). Утилита сохраняет контактные данные, всех кто вам писал, и позволяет вам по ним проводить поиск (название компании, сайт и тп). Это удобно, так как контакт сохранится даже, если вышлют отказ в дальнейшем. У утилиты есть группа: [HH Resume Automate](https://t.me/hh_resume_automate).
38
+ Утилита для успешных волчат и старых волков с опытом, служащая для автоматизации действий на HH.RU таких как рассылка откликов на подходящие вакансии и обновление всех резюме (бесплатный аналог услуги на HH). Утилита сохраняет контактные данные, всех кто вам писал, и позволяет вам по ним проводить поиск (название компании, сайт и тп). Это удобно, так как контакт сохранится даже, если вышлют отказ в дальнейшем. У утилиты есть канал в пашкограме: [HH Applicant Tool](https://t.me/hh_applicant_tool). Старый <s>[HH Resume Automate](https://t.me/hh_resume_automate)</s> был выпилен какими-то долбоебами, углядевшими во флаге Японии с двумя буквами h нарушение авторских прав...
38
39
 
39
40
  Работает с Python >= 3.10. Нужную версию Python можно поставить через
40
41
  asdf/pyenv/conda и что-то еще. В школотронской Manjaro и даже в последних Ubuntu
@@ -64,6 +65,8 @@ $$('[data-qa="vacancy-serp__vacancy_response"]').forEach((el) => el.click());
64
65
 
65
66
  ### Установка
66
67
 
68
+ Универсальный с использованием pipx (требует пакета `python-pipx` в Arch):
69
+
67
70
  ```bash
68
71
  # Версия с поддержкой авторизации через запуск окна с браузером (эта версия очень много весит)
69
72
  # Можно использовать обычный pip
@@ -76,6 +79,18 @@ $ pipx install git+https://github.com/s3rgeym/hh-applicant-tool
76
79
  $ pipx upgrade hh-applicant-tool
77
80
  ```
78
81
 
82
+ pipx добавляет исполняемый файл `hh-appplicant-tool` в `~/.local/bin`, делая эту команду доступной. Путь до `~/.local/bin` должен быть в `$PATH` (в большинстве дистрибутивов он добавлен).
83
+
84
+ Традиционный способ для Linux/Mac:
85
+
86
+ ```sh
87
+ mkdir -p ~/.venvs
88
+ python -m venv ~/.venvs/hh-applicant-tool
89
+ # Это придется делать постоянно, чтобы команда hh-applicant-tool стала доступна
90
+ . ~/.venvs/hh-applicant-tool/bin/activate
91
+ pip install 'hh-applicant-tool[qt]'
92
+ ```
93
+
79
94
  Отдельно я распишу процесс установки в **Windows** в подробностях:
80
95
 
81
96
  * Для начала поставьте последнюю версию **Python 3** любым удобным способом.
@@ -88,7 +103,8 @@ $ pipx upgrade hh-applicant-tool
88
103
  ```ps
89
104
  PS> python -m venv hh-applicant-venv
90
105
  PS> .\hh-applicant-venv\Scripts\activate
91
- ```
106
+ ```
107
+
92
108
  * Поставьте все пакеты в виртуальное окружение `hh-applicant-venv`:
93
109
  ```ps
94
110
  (hh-applicant-venv) PS> pip install hh-applicant-tool[qt]
@@ -261,7 +277,7 @@ https://hh.ru/employer/1918903
261
277
  | **refresh-token** | Обновляет access_token. |
262
278
  | **config** | Редактировать конфигурационный файл. |
263
279
  | **get-employer-contacts** | Получить список полученных вами контактов работодателей. Поддерживается так же экспорт в html/jsonl. Если хотите собирать контакты с нескольких акков, то укажите им одинаковый `client_telemetry_id` в конфигах. |
264
- | **delete-telemetry** | Удадяет телеметрию, если та была включена. |
280
+ | **delete-telemetry** | Удадяет телеметрию (контакты работодателей, которые вас пригласили), если та была включена. |
265
281
 
266
282
  ### Формат текста сообщений
267
283
 
@@ -2,6 +2,7 @@ hh_applicant_tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
2
2
  hh_applicant_tool/__main__.py,sha256=cwKJAAML0RRKT9Qbzcwf07HHcuSd8oh7kx4P1apndWQ,84
3
3
  hh_applicant_tool/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  hh_applicant_tool/ai/blackbox.py,sha256=vqkEpsX7q7bgX49dmmifYJmrbuz_WBg5u9M9J9XdQlI,1670
5
+ hh_applicant_tool/ai/openai.py,sha256=jEh8y4Y51rcuvZ41tkcq65EHKt8bdT6NahzbHJN5KhI,1682
5
6
  hh_applicant_tool/api/__init__.py,sha256=kgFSHibRaAugN2BA3U1djEa20qgKJUUVouwJzjEB0DU,84
6
7
  hh_applicant_tool/api/client.py,sha256=-nQMX_KY2zcV98CtBqq7BHyseDs5LglhHoMF1C7Oi4M,9895
7
8
  hh_applicant_tool/api/errors.py,sha256=Rd1XE2OTtZDa3GDqght2LtOnTHWtOx7Zsow87nn4x4A,1807
@@ -11,22 +12,22 @@ hh_applicant_tool/jsonc.py,sha256=QNS4gRHfi7SAeOFnffAIuhH7auC4Y4HAkmH12eX5PkI,40
11
12
  hh_applicant_tool/main.py,sha256=A4YPkNXAdZY0GoGm0iigiQtzXTrpR3SaIGo54q9-Dd0,5652
12
13
  hh_applicant_tool/mixins.py,sha256=8VoyrNgdlljy6pLTSFGJOYd9kagWT3yFOZYIGR6MEbI,425
13
14
  hh_applicant_tool/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- hh_applicant_tool/operations/apply_similar.py,sha256=EXY7LXuUGx5CjbHG22bR2-22gG3c--IniQjreHTG1pY,15568
15
+ hh_applicant_tool/operations/apply_similar.py,sha256=dS775_LJKpb7sHGLTno60KLJcIj4DnzY3Bu7yfzGadw,24916
15
16
  hh_applicant_tool/operations/authorize.py,sha256=NYrxe6oemUBcDHioT1t1lJmi9l45V4ZXzQPD_-nf6hk,3328
16
17
  hh_applicant_tool/operations/call_api.py,sha256=o3GZgtqk6w4zpCm-JTHVjFrKVOwW-vsu1HdRi-hqAjo,1423
17
- hh_applicant_tool/operations/clear_negotiations.py,sha256=mu9nBdP7b_dlEMQk88w0IWX1lNTTFqnWbS1tCO1Mlws,4329
18
+ hh_applicant_tool/operations/clear_negotiations.py,sha256=FG_43P5GWmfKUggkKZqDznQ2_iBJ3zrZtv8yEI2XOXQ,4527
18
19
  hh_applicant_tool/operations/config.py,sha256=BzGWbHwNlXIpYHxnZUidDZTk1-7GZb8UL-asy8w4uN4,1390
19
20
  hh_applicant_tool/operations/delete_telemetry.py,sha256=JHdh_l7IJL_qy5AIIy8FQpUupmH60D3a6zjfEVKkT2U,986
20
21
  hh_applicant_tool/operations/get_employer_contacts.py,sha256=Sd-x3O08bmKm1OGVLtJ6rcPZ_j1jwjlqKV4z1n_G-38,9918
21
22
  hh_applicant_tool/operations/list_resumes.py,sha256=dILHyBCSEVqdNAvD8SML5f2Lau1R2AzTaKE9B4FG8Wg,1109
22
23
  hh_applicant_tool/operations/refresh_token.py,sha256=v_Fcw9mCfOdE6MLTCQjZQudhJPX0fup3k0BaIM394Qw,834
23
- hh_applicant_tool/operations/reply_employers.py,sha256=eJlVuliQO_fy7_sBj-1RqgjphqbqP_yejbNFVxiUhNM,13426
24
+ hh_applicant_tool/operations/reply_employers.py,sha256=40rsTgpoEUaRQUq5ZQYgojKb42smYRkbDDD2S_7Vwtg,13512
24
25
  hh_applicant_tool/operations/update_resumes.py,sha256=_r7HA_vpYMs5DFY-mVP1ZRG9bggsv7ebKYrwteBmJ30,1053
25
26
  hh_applicant_tool/operations/whoami.py,sha256=pNWJMmEQLBk3U6eiGz4CHcX7eXzDXcfezFjX7zLjqyA,711
26
27
  hh_applicant_tool/telemetry_client.py,sha256=1EKZWc5kMx2yERW9SrR9vaf-OB6M_KKcMXeicH5YyY0,3834
27
- hh_applicant_tool/types.py,sha256=q3yaIcq-UOkPzjxws0OFa4w9fTty-yx79_dic70_dUM,843
28
+ hh_applicant_tool/types.py,sha256=sQbt_vGXtWPRJ3UzcUkE87BTHOaGTsFxqdZa_qFghZE,864
28
29
  hh_applicant_tool/utils.py,sha256=3T4A2AykGqTwtGAttmYplIjHwFl3pNAcbWIVuA-OheQ,3080
29
- hh_applicant_tool-0.6.3.dist-info/METADATA,sha256=kBijByhrEeWXEBq6dNd6Y4x_LScU9kC1dW-_yPWhSFo,20600
30
- hh_applicant_tool-0.6.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
31
- hh_applicant_tool-0.6.3.dist-info/entry_points.txt,sha256=Vb7M2YaYLMtKYJZh8chIrXZApMzSRFT1-rQw-U9r10g,65
32
- hh_applicant_tool-0.6.3.dist-info/RECORD,,
30
+ hh_applicant_tool-0.6.12.dist-info/METADATA,sha256=Bm4jg3-5ajaUefjiFHB9mIkQzw4MKMhy6fPv4TWZY84,21781
31
+ hh_applicant_tool-0.6.12.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
32
+ hh_applicant_tool-0.6.12.dist-info/entry_points.txt,sha256=Vb7M2YaYLMtKYJZh8chIrXZApMzSRFT1-rQw-U9r10g,65
33
+ hh_applicant_tool-0.6.12.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any