def _get_active_threads_names(): """May contain sensitive info (like user ids). Use with care.""" active_threads = threading.enumerate() return FormattedText().join([ FormattedText().newline().normal(" - {name}").start_format().bold( name=thread.name).end_format() for thread in active_threads ])
def work_error(self, error: BaseException, work: Work, worker: Worker): self.__error( FormattedText().bold(ExceptionFormatter.format(error)), FormattedText().normal("Work: {work}").start_format().bold( work=work.name).end_format(), FormattedText().normal("Worker: {worker}").start_format().bold( worker=worker.name).end_format())
def _formatted_size(size_in_bytes): if size_in_bytes is not None: size = SizeFormatter.format(size_in_bytes) return FormattedText().normal(" ({size})").start_format().bold( size=size).end_format() else: return FormattedText()
def __get_donation_addresses(donation_addresses: Sequence[Sequence[str]]): texts = [] for name, address in donation_addresses: texts.append(FormattedText().normal( " - {name}: {address}").start_format().normal(name=name).bold( address=address).end_format()) return FormattedText().newline().join(texts)
def __build_success_response_message(event, title, printable_messages): footer = FormattedText().normal("\n\nWrite ").bold( event.command + " help").normal(" to see more options.") if not isinstance(title, FormattedText): title = FormattedText().normal(title) return FormattedText().concat(title).newline().concat( printable_messages).concat(footer).build_message()
def __get_authors(authors: Sequence[Sequence[str]]): texts = [] for name, credit in authors: texts.append(FormattedText().normal( " - {name} ({credit})").start_format().normal( name=name, credit=credit).end_format()) return FormattedText().newline().join(texts)
def process(self, event): response = FormattedText().newline().join(ConfigStatus(self.config, self.state).get_config_status()) response.newline().newline()\ .italic("These are the current values read from storage.").newline()\ .italic("But please, note that most of them are being cached at startup and " "changing them will not modify bot behavior until it is restarted.") self.api.send_message(response.build_message().to_chat_replying(event.message))
def _get_bot_status(self): process_uptime_value = TimeFormatter.format( self.__get_process_uptime()) process_uptime = FormattedText()\ .normal("Uptime: {bot_uptime}").start_format().bold(bot_uptime=process_uptime_value).end_format() process_memory_usage_value, process_memory_usage_attribute_name = self.__get_process_memory_usage( ) process_memory_usage_formatted_value = SizeFormatter.format( process_memory_usage_value) process_memory_usage = FormattedText()\ .normal("Memory usage: {memory_usage} ({memory_usage_attribute_name})").start_format()\ .bold(memory_usage=process_memory_usage_formatted_value)\ .normal(memory_usage_attribute_name=process_memory_usage_attribute_name).end_format() thread_number = WorkersAction.get_active_threads_number() workers_value = self.scheduler.get_running_workers() workers_number = WorkersAction.get_running_workers_number( workers_value) worker_pools_value = self.scheduler.get_worker_pools() worker_pools_number = WorkersAction.get_worker_pools_number( worker_pools_value) return FormattedText().newline().join( (FormattedText().bold("Bot status"), process_uptime, process_memory_usage, thread_number, workers_number, worker_pools_number))
def _summarized(self, field="text", max_characters=15): text = FormattedText() content = getattr(self.last_message, field) if content: summarized_content = TextSummarizer.summarize( content, max_number_of_characters=max_characters) text.normal(" [ ").italic(summarized_content).normal(" ]") return text
def __init__(self, project_package_name: str, releases_url: str = None): super().__init__() version = self.get_version(project_package_name) self.text = FormattedText().normal("Version {version}") if releases_url: self.text.newline().newline().normal("Releases: {releases_url}") self.text.start_format().bold(version=version).normal( releases_url=releases_url).end_format()
def get_random_in_range(start, end): if start > end: return FormattedText().bold("Sorry").normal(", for this to work the first number must be ").bold("lower")\ .normal(" than the second number.").build_message() chosen = random.randint(start, end) return FormattedText().normal("Choosing a random number between ").bold(start).normal(" and ").bold(end).normal(" (both included).").newline().newline()\ .normal("Chosen number: ").bold(chosen)\ .build_message()
def __send_throttling_warning(self, event, throttling_state): remaining_seconds = throttling_state.remaining_seconds( event.message.date) self.__log_throttling(event, remaining_seconds) message = FormattedText().bold("Ignoring repeated command.").normal(" Try again in ")\ .code_inline(remaining_seconds).normal(" seconds.")\ .build_message() message.to_chat_replying(event.message) self.api. async .send_message(message)
def _item(label: str, value, additional_text: str = ""): text = FormattedText()\ .normal("{label}: {value}")\ .start_format()\ .normal(label=label)\ .bold(value=value)\ .end_format() if additional_text: text.normal(" ").normal(additional_text) return text
def get_response_mod(self, event, action_params, handler): alias = action_params[0] success = self.set_timezone_data(action_params, handler) if not success: return FormattedText().bold("ERROR while modifying timezone").normal(", check name and offset are valid.")\ .normal(" See help for more info")\ .build_message() return FormattedText().normal("Timezone ").bold(alias).normal(" updated!").newline().newline()\ .concat(self.get_timezone_info_text(handler.get_timezone_state(alias)))\ .build_message()
def process(self, event): api = self.api.no_async error = NotARealError("simulated error") response = FormattedText().bold("Simulating bot error...") args = event.command_args.split() if "fatal" in args: error = NotARealFatalError("simulated fatal error") response.newline().normal(" - ").bold("FATAL") if "async" in args: api = self.api. async response.newline().normal(" - ").bold("async")
def get_response_whereis(self, event, message_id): return FormattedText().bold("👆 Here is message ").code_inline(message_id).bold(".")\ .build_message().reply_to_message(message_id=message_id)\ .with_error_callback(lambda e: self.api.send_message( FormattedText().bold("❌ Sorry, message ").code_inline(message_id).bold(" cannot be located.") .newline().newline().normal("Possible causes:").newline() .normal("· The message may have been deleted.").newline() .normal("· The message ID you entered may not be valid. They should be positive numbers.").newline() .normal("· If you recently converted the group to a supergroup, messages sent before the conversion" " took place cannot be replied to.") .build_message().to_chat_replying(event.message)))
def __send_traceback(self): try: self.traceback_logger.log( TRACEBACK_TAG, FormattedText().code_block(traceback.format_exc())) except ApiException: # tracebacks can be very long and reach message length limit # retry with a shorter traceback self.traceback_logger.log( TRACEBACK_TAG, FormattedText().code_block(traceback.format_exc(limit=1)))
def do_enable(self, event): disable_command = UnderscoredCommandBuilder.build_command( event.command, "off") message = FormattedText().normal("Activating #silence mode. I won't send anything here until you ")\ .normal(disable_command).normal(" me.")\ .build_message() # sending reply before activating silence mode, so that it is actually sent message.to_chat_replying(event.message) self.api.send_message(message) event.state.silenced = "yes" # returning a message to avoid caller failing, but message should not be sent, as silence mode is now enabled return message
def __log_command_execution(event, elapsed_seconds: float): event.logger.log( COMMAND_LOG_TAG, FormattedText().normal("{command} {args}").start_format().bold( command=event.command, args=event.command_args).end_format(), FormattedText().normal("User: {user}").start_format().bold( user=UserFormatter( event.message.from_).full_data).end_format(), FormattedText().normal("Chat: {chat}").start_format().bold( chat=ChatFormatter(event.chat).full_data).end_format(), FormattedText().normal("Execution time: {time}").start_format(). bold(time=TimeFormatter.format(elapsed_seconds)).end_format())
def _full_content_header(self): text = FormattedText()\ .normal(self.bullet)\ .normal("Message ").bold(self.message_id)\ .normal(" sent on ").bold(self.full_date)\ .normal(" by ").bold(self.full_user)\ .normal(".").newline() self.__add_reply_info_if_needed(text) self.__add_forwarded_info_if_needed(text) self.__add_edit_info_if_needed(text) self.__add_incomplete_info_if_needed(text) return text.newline()
def __log_throttling(event, remaining_seconds): event.logger.log( LOG_TAG, FormattedText().normal("{command} {args}").start_format().bold( command=event.command, args=event.command_args).end_format(), FormattedText().normal("User: {user}").start_format().bold( user=UserFormatter( event.message.from_).full_data).end_format(), FormattedText().normal("Chat: {chat}").start_format().bold( chat=ChatFormatter(event.chat).full_data).end_format(), FormattedText().normal("Throttling for {seconds} seconds."). start_format().bold(seconds=remaining_seconds).end_format())
def poll_completed(self, message: MessageViewModel, poll_id: PollIdViewModel, full_poll: FullPollViewModel): text = FormattedText()\ .normal("Poll #{id}:\n\n{poll}")\ .start_format()\ .normal( id=poll_id.id ).concat( poll=self.poll_formatter.format_poll(full_poll) ).end_format() inline_keyboard = self.inline_keyboard_formatter.poll_creation_inline_keyboard(poll_id) api_message = text.build_message().with_reply_markup(inline_keyboard) self._send_message(api_message, message)
def _full_content(self, content_field="text", prepend_newlines_if_content=False): text = FormattedText() content = getattr(self.message, content_field) if content is not None: if prepend_newlines_if_content: text.newline().newline() text.normal(self.start_content).bold( content_field.capitalize()).bold(":").newline() text.normal(content) text.concat(self._full_edits_content(content_field)) return text
def _get_system_status(self): system_uptime_value = TimeFormatter.format( self.__get_elapsed_seconds_since(psutil.boot_time())) system_uptime = FormattedText()\ .normal("Uptime: {system_uptime}").start_format().bold(system_uptime=system_uptime_value).end_format() cpu_usage_value = str( psutil.cpu_percent(interval=self.cpu_usage_sample_seconds)) + " %" cpu_usage = FormattedText()\ .normal("CPU usage: {cpu_usage} ({sample_interval} sec. sample)").start_format()\ .bold(cpu_usage=cpu_usage_value).normal(sample_interval=self.cpu_usage_sample_seconds).end_format() return FormattedText().newline().join( (FormattedText().bold("System status"), system_uptime, cpu_usage))
def get_response_del(event, action_params, handler): alias = action_params[0] if alias not in handler.get_timezones(): return FormattedText().bold("ERROR").normal(", no ").bold(alias).normal(" timezone found.")\ .build_message() if alias == "main": return FormattedText().normal("Sorry, main timezone cannot be removed")\ .build_message() handler.del_timezone(alias) return FormattedText().normal("Timezone ").bold(alias).normal(" removed.").newline().newline()\ .normal("Ranking in that timezone is still accessible, but no new poles will be added.").newline()\ .normal("If you add a timezone with the same alias in the future," " new poles will be added to the ranking again.").newline()\ .normal("Contact the bot admin if you want the ranking to be wiped.")\ .build_message()
def set_new_value(self, settings, key, new_value): previous_value = self.__get_current_value(settings, key) try: settings.set(key, new_value) except Exception as e: return FormattedText().bold("Setting could not be updated").newline().newline()\ .normal("Please, input a valid value.").newline().newline()\ .normal("Error was: ").code_inline(e)\ .build_message() current_value = self.__get_current_value(settings, key) return FormattedText().bold("Setting updated!").newline().newline()\ .bold("Name").normal(":").newline().code_block(key).newline().newline()\ .bold("Previous value").normal(":").newline().concat(previous_value).newline().newline()\ .bold("Current value").normal(":").newline().concat(current_value)\ .build_message()
def get_response_list(event, action_params, handler): text = FormattedText().normal("List of pole timezones:").newline() for alias in handler.get_timezones(): state = handler.get_timezone_state(alias) name = state.get_value("timezone", DEFAULT_TIMEZONE) text.bold(alias).normal(" → ").bold(name) offset_seconds = state.offset_seconds if offset_seconds is not None: text.normal(" (with ").bold(offset_seconds).normal( " seconds offset)") text.newline() return text.build_message()
def __add_grouped_pole(self, text, grouped_pole): user_id, count = grouped_pole formatted_user = UserFormatter.retrieve_and_format( user_id, self.user_storage_handler) formatted_grouped_pole = FormattedText().normal(text).start_format()\ .bold(user=formatted_user).normal(pole_count=count).end_format() self.printable_poles.append(formatted_grouped_pole)
def get_response_add(self, event, action_params, handler): timezone_alias = action_params[0] if timezone_alias in handler.get_timezones(): return FormattedText().bold("ERROR").normal(", a timezone called ").bold(timezone_alias)\ .normal(" already exists. Modify it instead of trying to add it again.")\ .build_message() success = self.set_timezone_data(action_params, handler) if not success: return FormattedText().bold("ERROR while adding timezone").normal(", check name and offset are valid.")\ .normal(" See help for more info")\ .build_message() handler.add_timezone(timezone_alias) return FormattedText().bold("New timezone added!").newline().newline()\ .normal("Alias: ").bold(timezone_alias).newline()\ .concat(self.get_timezone_info_text(handler.get_timezone_state(timezone_alias)))\ .build_message()
def get_random_choice(choices): number_of_elements = len(choices) chosen = random.choice(choices) return FormattedText().normal("Choosing a random element from the ones you provided.").newline().newline()\ .normal("Number of elements: ").normal(number_of_elements).newline().newline()\ .normal("Chosen option: ").bold(chosen)\ .build_message()