Module: init¶
There is a really primitive program that will interactively ask you some questions
- Path to credentials file
- Hashtag to track
- Mastodon server URL
- Bot's username
- Timezone [UTC]
- Number of top posts to show
- Days to look back for posts
- Tag users in posts?
- Maximum toots to fetch
- Dry run mode?
- Hours margin for analysis
It will spit out a basic ini file that you can then modify.
Code Reference¶
Interactive initialization for mastoscore configuration using prompt_toolkit
confirm_abandon()
¶
Confirm if the user wants to abandon changes
Source code in mastoscore/init.py
def confirm_abandon() -> bool:
"""Confirm if the user wants to abandon changes"""
try:
response = get_input(PromptSession(), "Are you sure you want to abandon? (yes/no)", "no")
return response.lower() in ['y', 'yes']
except (KeyboardInterrupt, EOFError):
return False
display_config(config)
¶
Display the current configuration in a scrollable window
Source code in mastoscore/init.py
def display_config(config: ConfigParser) -> None:
"""Display the current configuration in a scrollable window"""
from io import StringIO
# Convert config to string
output = StringIO()
config.write(output)
content = output.getvalue()
# Create text area with content
text_area = TextArea(
text=content,
read_only=True,
scrollbar=True,
wrap_lines=True,
focusable=True
)
# Create key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
event.app.exit()
# Create window with content
window = HSplit([
text_area,
Window(height=1, content=FormattedTextControl(
'Use up/down/pageup/pagedown to scroll, q to continue'))
])
# Create and run application
app = Application(
layout=Layout(window),
key_bindings=kb,
full_screen=True,
mouse_support=True
)
app.run()
display_section_values(title, values)
¶
Display the current section's values in yellow
Source code in mastoscore/init.py
def display_section_values(title, values):
"""Display the current section's values in yellow"""
print(f"\n=== {title} ===")
for key, value in values.items():
if not key.startswith(('event_', 'episode_')):
print(f" {key}: \033[33m{value}\033[0m")
edit_section(config, section, session)
¶
Re-prompt for all values in a section
Source code in mastoscore/init.py
def edit_section(config: ConfigParser, section: str, session: PromptSession) -> bool:
"""Re-prompt for all values in a section"""
if section not in config:
print(f"\nError: Section {section} not found")
return False
print(f"\n=== Editing {section} section ===")
try:
if section == 'mastoscore':
config[section]['cred_file'] = get_input(session, "Path to credentials file (e.g., .env/mybot.env)",
config[section].get('cred_file'))
config[section]['hashtag'] = get_input(session, "Hashtag to track (without the # symbol)",
config[section].get('hashtag'))
config[section]['api_base_url'] = get_input(session, "Mastodon server URL",
config[section].get('api_base_url'))
config[section]['botusername'] = get_input(session, "Bot's username (without @)",
config[section].get('botusername'))
config[section]['timezone'] = get_input(session, "Timezone",
config[section].get('timezone', "UTC"))
config[section]['top_n'] = get_input(session, "Number of top posts to show",
config[section].get('top_n', "3"))
config[section]['lookback'] = get_input(session, "Days to look back for posts",
config[section].get('lookback', "2"))
config[section]['tag_users'] = get_input(session, "Tag users in posts? (true/false)",
config[section].get('tag_users', "false"))
elif section == 'fetch':
config[section]['max'] = get_input(session, "Maximum toots to fetch",
config[section].get('max', "3000"))
config[section]['dry_run'] = get_input(session, "Enable dry run mode for fetching? (true/false)",
config[section].get('dry_run', "false"))
elif section == 'analyse':
config[section]['hours_margin'] = get_input(session, "Hours margin for analysis",
config[section].get('hours_margin', "1"))
display_section_values(f"{section} Section Updated", config[section])
return True
except (KeyboardInterrupt, EOFError):
print(f"\nSection {section} edit cancelled.")
return False
get_input(session, prompt, default=None, required=True)
¶
Get input with light blue prompt and yellow response
Source code in mastoscore/init.py
def get_input(session, prompt, default=None, required=True) -> str:
"""Get input with light blue prompt and yellow response"""
while True:
try:
if default:
result = session.prompt(
HTML(f'<ansicyan>{prompt}</ansicyan> [<ansiyellow>{default}</ansiyellow>]: ')
)
if not result and default:
return str(default)
else:
result = session.prompt(HTML(f'<ansicyan>{prompt}</ansicyan>: '))
if result or not required:
return str(result) if result else ""
print("This field is required. Please provide a value.")
except (KeyboardInterrupt, EOFError):
print("\nInput cancelled.")
raise
init()
¶
Interactive configuration setup for mastoscore using prompt_toolkit
Source code in mastoscore/init.py
def init():
"""
Interactive configuration setup for mastoscore using prompt_toolkit
"""
# Set up signal handlers
def signal_handler(signum, frame):
print("\nReceived interrupt signal Exiting...")
exit(1)
signal(SIGINT, signal_handler)
signal(SIGQUIT, signal_handler)
logger = getLogger(__name__)
basicConfig(format='%(levelname)s\t%(message)s')
logger.setLevel(INFO)
# Define prompt style
style = Style.from_dict({
'ansicyan': '#00B7EB bold', # Light blue
'ansiyellow': '#FFFF00', # Yellow
})
# Create prompt session
session = PromptSession(style=style)
print("\nWelcome to Mastoscore Configuration\n")
print("This wizard will help you create a configuration file for your event.\n")
config = ConfigParser(interpolation=ExtendedInterpolation())
# [mastoscore] section
config['mastoscore'] = {}
ms = config['mastoscore']
print("\n=== Basic Configuration (mastoscore section) ===")
try:
# Core values
ms['cred_file'] = get_input(session, "Path to credentials file (e.g., .env/mybot.env)")
ms['hashtag'] = get_input(session, "Hashtag to track (without the # symbol)")
ms['api_base_url'] = get_input(session, "Mastodon server URL")
ms['botusername'] = get_input(session, "Bot's username (without @)")
ms['timezone'] = get_input(session, "Timezone", "UTC")
ms['top_n'] = get_input(session, "Number of top posts to show", "3")
ms['lookback'] = get_input(session, "Days to look back for posts", "2")
ms['tag_users'] = get_input(session, "Tag users in posts? (true/false)", "false")
# Standard paths
ms['journaldir'] = 'data'
ms['journalfile'] = '${mastoscore:hashtag}'
# [fetch] section
print("\n=== Fetch Configuration ===")
config['fetch'] = {}
fetch = config['fetch']
fetch['max'] = get_input(session, "Maximum toots to fetch", "3000")
fetch['dry_run'] = get_input(session, "Enable dry run mode for fetching? (true/false)", "false")
# [analyse] section
print("\n=== Analysis Configuration ===")
config['analyse'] = {}
analyse = config['analyse']
analyse['hours_margin'] = get_input(session, "Hours margin for analysis", "1")
# Add debug level to sections
config['fetch']['debug'] = '20'
config['analyse']['debug'] = '20'
analyse['hours_margin'] = get_input(session, "Hours margin for analysis", "1")
except (KeyboardInterrupt, EOFError):
print("\nConfiguration cancelled.")
return False
except Exception as e:
logger.error(f"Error during configuration: {e}")
return False
# Clear screen and show final configuration
clear()
print("\nConfiguration Summary:\n")
display_config(config)
# Ask user what to do
while True:
action = get_input(session, "Choose action (save/change/abandon)", "save")
if action.lower() == 'save':
filename = f"ini/{ms['hashtag']}.ini"
if save_config(config, filename):
print(f"\nConfiguration saved to {filename}")
exit(0)
else:
print("\nFailed to save configuration. Please try save again or abandon to exit.")
continue
elif action.lower() == 'change':
section = select_section()
if section:
if edit_section(config, section, session):
# Show updated configuration
clear()
print("\nConfiguration Summary:\n")
display_config(config)
continue
elif action.lower() == 'abandon':
if confirm_abandon():
print("\nConfiguration abandoned.")
exit(1)
else:
print("\nInvalid choice. Please choose 'save', 'change', or 'abandon'")
save_config(config, filename)
¶
Save configuration to file with error handling
Source code in mastoscore/init.py
def save_config(config: ConfigParser, filename: str) -> bool:
"""Save configuration to file with error handling"""
import os
try:
# Create directory if it doesn't exist
os.makedirs(os.path.dirname(filename), exist_ok=True)
# Write configuration file
with open(filename, 'w') as f:
config.write(f)
return True
except PermissionError:
print(f"\nError: Permission denied writing to {filename}")
return False
except FileNotFoundError:
print(f"\nError: Directory path not found for {filename}")
return False
except Exception as e:
print(f"\nError writing configuration file: {e}")
return False
select_section()
¶
Display a menu to select a section to edit
Source code in mastoscore/init.py
def select_section() -> str:
"""Display a menu to select a section to edit"""
sections = [
("mastoscore", "1. mastoscore - Basic Configuration"),
("fetch", "2. fetch - Fetch Configuration"),
("analyse", "3. analyse - Analysis Configuration")
]
radio_list = RadioList(sections)
# Create application
app = Application(
layout=Layout(HSplit([
Window(content=FormattedTextControl(
"Select a section to edit (use arrow keys or number keys):")),
radio_list,
])),
full_screen=True,
)
result = app.run()
return result if result else ""