Skip to content

Commit

Permalink
chore(docs): improve docstrings and comments (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
sergerdn authored Oct 10, 2023
1 parent a5de23d commit 16ad537
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 100 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ lint_fix:
#poetry run autopep8 --in-place --aggressive --aggressive pybas_automation/utils/utils.py

lint:
mkdir ./dist || echo ""
touch ./dist/README.md
poetry check
poetry run mypy cmd_initial.py cmd_worker.py pybas_automation/ tests/ || echo ""
poetry run flake8 cmd_initial.py cmd_worker.py pybas_automation/ tests/ || echo ""
Expand Down
185 changes: 146 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,77 +155,184 @@ Please note that this is not currently recommended as the latest release may hav

## Advanced Usage

Here's a basic example of using `py-bas-automation`:
This guide introduces a Python script that integrates the `Browser Automation Studio` (BAS) with `py-bas-automation`.
The
purpose is to handle the creation of browser profiles through FingerprintSwitcher and manage tasks related to these
profiles.

- [Initial script](./cmd_initial.py) to create tasks:
### [Initial script: cmd_initial.py](./cmd_initial.py)

### Description:

This script facilitates the integration between `BAS (Browser Automation Studio)` and `py-bas-automation`. It manages
the creation of browser profiles using `FingerprintSwitcher` and generates tasks associated with these profiles.

### Overview:

- **Initialization**: Import essential modules and configure logging.
- **Browser Profiles**: Use FingerprintSwitcher's fingerprint key to generate or manage browser profiles.
- **Tasks Generation**: For each browser profile, create an associated task and store it.

```python
"""
This script facilitates the integration between BAS (Browser Automation Studio) and `py-bas-automation`.
It handles the creation of browser profiles using FingerprintSwitcher and manages tasks associated with these profiles.
"""

import json
from pybas_automation.task import BasTask, TaskStorage, TaskStorageModeEnum
import logging
import os

import click
from pydantic import FilePath

from pybas_automation.browser_profile import BrowserProfileStorage
from pybas_automation.task import BasTask, TaskStorage, TaskStorageModeEnum

logger = logging.getLogger("[cmd_worker]")


def run(fingerprint_key: str, count_profiles: int) -> FilePath:
"""
Initialize and run the script.
:param fingerprint_key: Personal fingerprint key from FingerprintSwitcher.
:param count_profiles: Number of profiles to be created.
:return: Path to the generated tasks file.
"""

# Initialize task storage with read-write access and clear it.
# The default storage location is C:\Users\{username}\AppData\Local\PyBASTasks
task_storage = TaskStorage(mode=TaskStorageModeEnum.READ_WRITE)
task_storage.clear()

# Initialize browser profiles using the given fingerprint key.
# The default profile storage location is C:\Users\{username}\AppData\Local\PyBASProfiles
browser_profile_storage = BrowserProfileStorage(fingerprint_key=fingerprint_key)

needs = count_profiles - browser_profile_storage.count()

fingerprint_key = "your_fingerprint_key"
# Create any additional profiles if necessary
if needs > 0:
for _ in range(needs):
browser_profile = browser_profile_storage.new()
logger.debug("Created new profile: %s", browser_profile.profile_dir)

# Create a new task
task = BasTask()
# Generate tasks corresponding to each profile
for browser_profile in browser_profile_storage.load_all()[:count_profiles]:
task = BasTask()
task.browser_settings.profile.profile_folder_path = browser_profile.profile_dir
task_storage.save(task=task)

# Save the task to storage, default location is
# C:\Users\{username}\AppData\Local\PyBASTasks
task_storage = TaskStorage(mode=TaskStorageModeEnum.READ_WRITE)
task_storage.save(task)
logger.info("Total tasks generated: %d", task_storage.count())
task_storage.save_all()

# Initialize a browser profile storage, default location is
# C:\Users\{username}\AppData\Local\PyBASProfiles
browser_profile_storage = BrowserProfileStorage(fingerprint_key=fingerprint_key)
return task_storage.task_file_path

# Create 20 fresh profiles on disk
for _ in range(0, 20):
browser_profile = browser_profile_storage.new()

# Add created browser profiles to tasks
for browser_profile in browser_profile_storage.load_all():
task = BasTask()
task.browser_settings.profile.profile_folder_path = browser_profile.profile_dir
task_storage.save(task=task)
@click.command()
@click.option(
"--bas_fingerprint_key",
help="Your personal fingerprint key of FingerprintSwitcher.",
required=True,
)
@click.option(
"--count_profiles",
help="Number of profiles.",
default=10,
)
def main(bas_fingerprint_key: str, count_profiles: int) -> None:
"""
Entry point of the script. Sets up logging, validates the fingerprint key,
triggers the primary function, and prints the path to the tasks file.
task_file_path = task_storage.task_file_path
:param bas_fingerprint_key: Personal fingerprint key from FingerprintSwitcher.
:param count_profiles: Number of profiles to be created.
# print path to tasks file for use it in BAS
print(json.dumps({"tasks_file": str(task_file_path)}, indent=4))
:return: None.
"""

import multiprocessing

process = multiprocessing.current_process()

# Configure logging settings
logging.basicConfig(
level=logging.DEBUG,
format=f"%(asctime)s {process.pid} %(levelname)s %(name)s %(message)s",
filename=os.path.join(os.path.dirname(__file__), "logs", "cmd_initial.log"),
)
logger.info("Script cmd_initial has started.")

# Ensure the fingerprint key is present
bas_fingerprint_key = bas_fingerprint_key.strip()
if not bas_fingerprint_key:
raise ValueError("bas_fingerprint_key is not provided")

# Invoke the main function to get the path to the tasks file
task_file_path = run(fingerprint_key=bas_fingerprint_key, count_profiles=count_profiles)

# Print the path for potential use in BAS
print(json.dumps({"tasks_file": str(task_file_path)}, indent=4))

logger.info("cmd_initial script execution completed.")


if __name__ == "__main__":
main()
```

- [Worker script](./cmd_worker.py) to retrieve the ws_endpoint from bas and handle the complex tasks:
### [Worker script: cmd_worker.py](./cmd_worker.py)

### Description:

This script demonstrates how to execute tasks using the `Playwright` Python library in conjunction with the
`pybas_automation` package. The primary goal is to fetch task data, connect to an existing browser instance using
`Playwright`, and perform actions on a webpage.

### Overview:

- **Initialization**: Import necessary libraries and set up our task id and debugging port.
- **Task Storage**: Fetch a specific task from our task storage.
- **Remote Browser Connection**: Use the remote debugging port to get a WebSocket endpoint, which allows us to connect
to an existing browser instance.
- **Playwright Actions**: Utilize Playwright to interact with a web page.

```python
from uuid import UUID
from playwright.sync_api import sync_playwright
from pybas_automation.task import BasTask, TaskStorage, TaskStorageModeEnum
from pybas_automation.browser_remote import BrowserRemote

# skip code to getting ws_endpoint from cmd line ...
# 1. Initialization
# For demonstration purposes, we're using hardcoded values. In a real scenario, these will be fetched dynamically.
task_id = UUID("some_task_id_that_we_getting_from_cmd_line_from_BAS")
remote_debugging_port = 9222

# Create a new task storage
# 2. Task Storage
# Create a new task storage instance in READ mode to fetch tasks.
task_storage = TaskStorage(mode=TaskStorageModeEnum.READ)
found_task = task_storage.get(task_id=task_id)
# Do something with task if needed...
# Save the task to storage, default location is

# Skip code to getting remote_debugging_port from cmd line ...
remote_debugging_port = 9222
# Note: You can manipulate or inspect the `found_task` as needed.

# 3. Remote Browser Connection
# Create an instance of BrowserRemote with the specified debugging port.
remote_browser = BrowserRemote(remote_debugging_port=remote_debugging_port)

# Get ws_endpoint from remote_debugging_port
remote_browser.find_ws()
# Fetch the WebSocket (ws) endpoint using the debugging port.
if not remote_browser.find_ws():
raise ValueError("Failed to find ws endpoint")

ws_endpoint = remote_browser.ws_endpoint

# 4. Playwright Actions
with sync_playwright() as pw:
# Connect to an existing browser instance
# Connect to an existing browser instance using the fetched WebSocket endpoint.
browser = pw.chromium.connect_over_cdp(ws_endpoint)
# Get the existing pages in the connected browser instance
# Access the main page of the connected browser instance.
page = browser.contexts[0].pages[0]
# Doing some work with page
# Perform actions using Playwright, like navigating to a webpage.
page.goto("https://playwright.dev/python/")
```

Expand All @@ -239,8 +346,8 @@ with sync_playwright() as pw:
## Contributing

Your ideas and contributions are highly valued. Please do not hesitate to open
an [issue](https://github.com/sergerdn/py-bas-automation/issues/new) if you have suggestions, questions, or if you
would like to contribute to its enhancement.
an [issue](https://github.com/sergerdn/py-bas-automation/issues/new) if you have suggestions, questions, or if you would
like to contribute to its enhancement.

## License

Expand Down
42 changes: 27 additions & 15 deletions cmd_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""
Initial script to create tasks and profiles if needed.
This script facilitates the integration between BAS (Browser Automation Studio) and `py-bas-automation`.
It handles the creation of browser profiles using FingerprintSwitcher and manages tasks associated with these profiles.
"""

import json
Expand All @@ -17,31 +18,38 @@

def run(fingerprint_key: str, count_profiles: int) -> FilePath:
"""
Run initial script.
Initialize and run the script.
:param fingerprint_key: Your personal fingerprint key of FingerprintSwitcher.
:param count_profiles: Count profiles to be created.
:param fingerprint_key: Personal fingerprint key from FingerprintSwitcher.
:param count_profiles: Number of profiles to be created.
:return: Path to the tasks file.
:return: Path to the generated tasks file.
"""

# Initialize task storage with read-write access and clear it.
# The default storage location is C:\Users\{username}\AppData\Local\PyBASTasks
task_storage = TaskStorage(mode=TaskStorageModeEnum.READ_WRITE)
task_storage.clear()

# Initialize browser profiles using the given fingerprint key.
# The default profile storage location is C:\Users\{username}\AppData\Local\PyBASProfiles
browser_profile_storage = BrowserProfileStorage(fingerprint_key=fingerprint_key)

needs = count_profiles - browser_profile_storage.count()

# Create any additional profiles if necessary
if needs > 0:
for _ in range(0, needs):
for _ in range(needs):
browser_profile = browser_profile_storage.new()
logger.debug("Created new profile: %s", browser_profile.profile_dir)

# Generate tasks corresponding to each profile
for browser_profile in browser_profile_storage.load_all()[:count_profiles]:
task = BasTask()
task.browser_settings.profile.profile_folder_path = browser_profile.profile_dir
task_storage.save(task=task)

logger.info("Count tasks: %d", task_storage.count())
logger.info("Total tasks generated: %d", task_storage.count())
task_storage.save_all()

return task_storage.task_file_path
Expand All @@ -55,15 +63,16 @@ def run(fingerprint_key: str, count_profiles: int) -> FilePath:
)
@click.option(
"--count_profiles",
help="Count profiles.",
help="Number of profiles.",
default=10,
)
def main(bas_fingerprint_key: str, count_profiles: int) -> None:
"""
Main function.
Entry point of the script. Sets up logging, validates the fingerprint key,
triggers the primary function, and prints the path to the tasks file.
:param bas_fingerprint_key: Your personal fingerprint key of FingerprintSwitcher.
:param count_profiles: Count profiles to be created.
:param bas_fingerprint_key: Personal fingerprint key from FingerprintSwitcher.
:param count_profiles: Number of profiles to be created.
:return: None.
"""
Expand All @@ -72,23 +81,26 @@ def main(bas_fingerprint_key: str, count_profiles: int) -> None:

process = multiprocessing.current_process()

# Configure logging settings
logging.basicConfig(
level=logging.DEBUG,
format=f"%(asctime)s {process.pid} %(levelname)s %(name)s %(message)s",
filename=os.path.join(os.path.dirname(__file__), "logs", "cmd_initial.log"),
)
logger.info("Started cmd_initial.")
logger.info("Script cmd_initial has started.")

# Ensure the fingerprint key is present
bas_fingerprint_key = bas_fingerprint_key.strip()

if not bas_fingerprint_key:
raise ValueError("bas_fingerprint_key is not set")
raise ValueError("bas_fingerprint_key is not provided")

# Invoke the main function to get the path to the tasks file
task_file_path = run(fingerprint_key=bas_fingerprint_key, count_profiles=count_profiles)

# Print the path for potential use in BAS
print(json.dumps({"tasks_file": str(task_file_path)}, indent=4))

logger.info("Finished cmd_initial.")
logger.info("cmd_initial script execution completed.")


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit 16ad537

Please sign in to comment.