Skip to content

cli

Camply Command Line Interface

CamplyContext dataclass #

Context Object Passed Around Application

Source code in camply/cli.py
@dataclass
class CamplyContext:
    """
    Context Object Passed Around Application
    """

    debug: Optional[bool] = None
    provider: Optional[str] = None

campgrounds(context, debug, search=None, state=None, rec_area=None, campground=None, campsite=None, provider=DEFAULT_CAMPLY_PROVIDER) #

Search for Campgrounds (inside of Recreation Areas) and list them

Search for Campgrounds and their IDs. Campgrounds are facilities inside of Recreation Areas that contain campsites. Most 'campgrounds' are areas made up of multiple campsites, others are facilities like fire towers or cabins that might only contain a single 'campsite' to book.

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@search_argument
@state_argument
@rec_area_argument
@campground_argument
@campsite_id_argument
@provider_argument
@debug_option
@click.pass_obj
def campgrounds(
    context: CamplyContext,
    debug: bool,
    search: Optional[str] = None,
    state: Optional[str] = None,
    rec_area: Optional[int] = None,
    campground: Optional[int] = None,
    campsite: Optional[int] = None,
    provider: Optional[str] = DEFAULT_CAMPLY_PROVIDER,
) -> None:
    """
    Search for Campgrounds (inside of Recreation Areas) and list them

    Search for Campgrounds and their IDs. Campgrounds are facilities inside of
    Recreation Areas that contain campsites. Most 'campgrounds' are areas made up of
    multiple campsites, others are facilities like fire towers or cabins that might only
    contain a single 'campsite' to book.
    """
    provider = _preferred_provider(context, provider)
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    if all(
        [
            search is None,
            state is None,
            len(rec_area) == 0,
            len(campground) == 0,
            len(campsite) == 0,
            provider not in [Yellowstone.__name__, GoingToCamp.__name__],
        ]
    ):
        logger.error(
            "You must add a --search, --state, --campground, --campsite, "
            "or --rec-area parameter to search for Campgrounds."
        )
        sys.exit(1)
    search_provider_class = CAMPSITE_SEARCH_PROVIDER[provider]
    camp_finder = search_provider_class.provider_class()
    params = {}
    if state is not None:
        params.update({"state": state})
    camp_finder.find_campgrounds(
        search_string=search,
        rec_area_id=make_list(rec_area, coerce=int),
        campground_id=make_list(campground, coerce=int),
        campsite_id=make_list(campsite, coerce=int),
        **params,
    )

camply_command_line(ctx, debug, provider) #

Welcome to camply, the campsite finder.

Finding reservations at sold out campgrounds can be tough. That's where camply comes in. It searches the APIs of booking services like https://recreation.gov (which indexes thousands of campgrounds across the USA) to continuously check for cancellations and availabilities to pop up. Once a campsite becomes available, camply sends you a notification to book your spot!



visit the camply documentation at https://juftin.com/camply

Source code in camply/cli.py
@tui()
@click.group(cls=RichGroup)
@debug_option
@provider_argument
@click.version_option(version=__version__, prog_name=__application__)
@click.pass_context
def camply_command_line(
    ctx: click.core.Context, debug: bool, provider: Optional[str]
) -> None:
    """
    Welcome to camply, the campsite finder.

    Finding reservations at sold out campgrounds can be
    tough. That's where camply comes in. It searches the APIs of booking services like
    https://recreation.gov (which indexes thousands of campgrounds across the USA) to continuously
    check for cancellations and availabilities to pop up. Once a campsite becomes available,
    camply sends you a notification to book your spot!

    \b

    visit the camply documentation at https://juftin.com/camply
    """
    set_up_logging(log_level=None if debug is False else logging.INFO)
    logger.camply("camply, the campsite finder ⛺️")
    ctx.obj = CamplyContext(debug=debug, provider=provider)
    _set_up_debug(debug=debug)

campsites(context, debug, rec_area, campground, campsite, start_date, end_date, weekends, nights, provider, continuous, polling_interval, notifications, notify_first_try, search_forever, search_once, yaml_config, offline_search, offline_search_path, equipment, equipment_id, day) #

Find Available Campsites with Custom Search Criteria

Search for a campsite within camply. Campsites are returned based on the search criteria provided. Campsites contain properties like booking date, site type (tent, RV, cabin, etc), capacity, price, and a link to make the booking. Required parameters include --start-date, --end-date, --rec-area / --campground. Constant searching functionality can be enabled with --continuous and notifications can be enabled using --notifications.

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@rec_area_argument
@campground_argument
@campsite_id_argument
@start_date_argument
@end_date_argument
@nights_argument
@weekends_argument
@day_of_the_week_argument
@notifications_argument
@continuous_argument
@search_forever_argument
@yaml_config_argument
@offline_search_argument
@offline_search_path_argument
@search_once_argument
@polling_interval_argument
@notify_first_try_argument
@equipment_argument
@equipment_id_argument
@provider_argument
@debug_option
@click.pass_obj
def campsites(
    context: CamplyContext,
    debug: bool,
    rec_area: Tuple[Union[str, int]],
    campground: Tuple[Union[str, int]],
    campsite: Tuple[Union[str, int]],
    start_date: str,
    end_date: str,
    weekends: bool,
    nights: int,
    provider: Optional[str],
    continuous: bool,
    polling_interval: Optional[str],
    notifications: Tuple[str],
    notify_first_try: Optional[str],
    search_forever: Optional[str],
    search_once: bool,
    yaml_config: Optional[str],
    offline_search: bool,
    offline_search_path: Optional[str],
    equipment: Tuple[Union[str, int]],
    equipment_id: Tuple[Union[str, int]],
    day: Optional[Tuple[str]],
) -> None:
    """
    Find Available Campsites with Custom Search Criteria

    Search for a campsite within camply. Campsites are returned based on the search criteria
    provided. Campsites contain properties like booking date, site type (tent, RV, cabin, etc),
    capacity, price, and a link to make the booking. Required parameters include
    `--start-date`, `--end-date`, `--rec-area` / `--campground`. Constant searching
    functionality can be enabled with  `--continuous` and notifications can be enabled using
    `--notifications`.
    """
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    if yaml_config is not None:
        provider, provider_kwargs, search_kwargs = yaml_utils.yaml_file_to_arguments(
            file_path=yaml_config
        )
        provider = _preferred_provider(context, provider)
    else:
        provider = _preferred_provider(context, provider)
        provider_kwargs, search_kwargs = _get_provider_kwargs_from_cli(
            rec_area=rec_area,
            campground=campground,
            campsite=campsite,
            start_date=start_date,
            end_date=end_date,
            weekends=weekends,
            nights=nights,
            provider=provider,
            continuous=continuous,
            polling_interval=polling_interval,
            notifications=notifications,
            notify_first_try=notify_first_try,
            search_forever=search_forever,
            search_once=search_once,
            offline_search=offline_search,
            offline_search_path=offline_search_path,
            equipment=equipment,
            equipment_id=equipment_id,
            day=day,
            yaml_config=yaml_config,
        )
    provider_class: Type[BaseCampingSearch] = CAMPSITE_SEARCH_PROVIDER[provider]
    camping_finder: BaseCampingSearch = provider_class(**provider_kwargs)
    camping_finder.get_matching_campsites(**search_kwargs)

cli() #

Camply Command Line Utility Wrapper

Source code in camply/cli.py
def cli():
    """
    Camply Command Line Utility Wrapper
    """
    try:
        camply_command_line()
    except KeyboardInterrupt:
        logger.debug("Handling Exit Request")
    finally:
        logger.camply("Exiting camply 👋")

configure(context, debug) #

Set up camply configuration file with an interactive console

In order to send notifications through camply you must set up some authorization values. Whether you need to set up pushover notifications (push notifications on your phone, your pushover account can be set up at https://pushover.net) or Email messages, everything can be done through the configure command. The end result is a file called .camply in your home folder.

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@debug_option
@click.pass_obj
def configure(context: CamplyContext, debug: bool) -> None:
    """
    Set up camply configuration file with an interactive console

    In order to send notifications through camply you must set up some authorization values.
    Whether you need to set up pushover notifications (push notifications on your phone,
    your pushover account can be set up at https://pushover.net) or Email messages, everything
    can be done through the configure command. The end result is a file called .camply in your
    home folder.
    """
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    configure_camply.generate_dot_camply_file()

equipment_types(context, rec_area=None, provider=DEFAULT_CAMPLY_PROVIDER) #

Get a list of supported equipment

This command returns supported equipment for the current provider/recreation area. Equipment are camping equipment that can be used at a campsite. Different providers and recreation areas have different types of equipment for which reservations can be made.

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@rec_area_argument
@provider_argument
@click.pass_obj
def equipment_types(
    context: CamplyContext,
    rec_area: Optional[int] = None,
    provider: str = DEFAULT_CAMPLY_PROVIDER,
) -> None:
    """
    Get a list of supported equipment

    This command returns supported equipment for the current provider/recreation area.
    Equipment are camping equipment that can be used at a campsite. Different providers
    and recreation areas have different types of equipment for which reservations can be made.
    """
    provider = _preferred_provider(context, provider)
    if not rec_area and provider == GoingToCamp.__name__:
        logger.error(
            "This provider requires --rec-area to be specified when listing equipment types"
        )
        sys.exit(1)

    if provider == GoingToCamp.__name__:
        GoingToCamp().list_equipment_types(rec_area[0])
    elif provider.startswith(RecreationDotGov.__name__):
        log_sorted_response(response_array=EquipmentOptions.__all_accepted_equipment__)
    else:
        logger.warning(
            "That Provider doesn't support equipment based searching, yet 🙂"
        )
    sys.exit(0)

list_campsites(context, debug, campground, rec_area, provider) #

List campsite IDs for a given campground or recreation area

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@rec_area_argument
@campground_argument
@provider_argument
@debug_option
@click.pass_obj
def list_campsites(
    context: CamplyContext,
    debug: bool,
    campground: Sequence[int],
    rec_area: Sequence[int],
    provider: str,
) -> None:
    """
    List campsite IDs for a given campground or recreation area
    """
    provider = _preferred_provider(context, provider)
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    if all(
        [
            len(rec_area) == 0,
            len(campground) == 0,
        ]
    ):
        logger.error(
            "You must provide a `--campground` or `--rec-area` to list campsites"
        )
        sys.exit(1)
    search_provider_class = CAMPSITE_SEARCH_PROVIDER[provider]
    if search_provider_class.list_campsites_supported is False:
        logger.error("That provider does not support listing campsites")
        sys.exit(1)
    camp_search = search_provider_class(
        search_window=SearchWindow(
            start_date=date.today() + timedelta(days=1),
            end_date=date.today() + timedelta(days=2),
        ),
        recreation_area=rec_area,
        campgrounds=campground,
        verbose=False,
    )
    logger.info("Searching for campsites to list")
    camp_search.list_campsite_units()

providers(context, debug) #

List the different camply providers

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@debug_option
@click.pass_obj
def providers(
    context: CamplyContext,
    debug: bool,
) -> None:
    """
    List the different camply providers
    """
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    logger.info(
        "camply currently supports %s providers:", len(CAMPSITE_SEARCH_PROVIDER.keys())
    )
    for provider_name, search_class in CAMPSITE_SEARCH_PROVIDER.items():
        logger.info(
            '    "%s":    %s',
            provider_name,
            search_class.__doc__.strip().splitlines()[0],
        )

recreation_areas(context, search, state, debug, provider=DEFAULT_CAMPLY_PROVIDER) #

Search for Recreation Areas and list them

Search for Recreation Areas and their IDs. Recreation Areas are places like National Parks and National Forests that can contain one or many campgrounds.

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@search_argument
@state_argument
@debug_option
@provider_argument
@click.pass_obj
def recreation_areas(
    context: CamplyContext,
    search: Optional[str],
    state: Optional[str],
    debug: bool,
    provider: str = DEFAULT_CAMPLY_PROVIDER,
) -> None:
    """
    Search for Recreation Areas and list them

    Search for Recreation Areas and their IDs. Recreation Areas are places like
    National Parks and National Forests that can contain one or many campgrounds.
    """
    provider = _preferred_provider(context, provider)
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    if all(
        [
            search is None,
            state is not None,
            provider in [Yellowstone.__name__, GoingToCamp.__name__],
        ]
    ):
        # State Filtering Not Supported
        logger.error(
            f"{provider} does not support filtering recreation areas by state. Leave --state blank."
        )
        sys.exit(1)
    if provider == GoingToCamp.__name__:
        rec_area_finder = GoingToCamp()
    elif provider.startswith(RecreationDotGov.__name__):
        rec_area_finder = RecreationDotGov()
    else:
        rec_area_finder = CAMPSITE_SEARCH_PROVIDER[provider]
    params = {}
    if state is not None:
        params.update({"state": state})
    rec_area_finder.find_recreation_areas(search_string=search, **params)

test_notifications(context, debug, notifications) #

Test your notification provider setup

Source code in camply/cli.py
@camply_command_line.command(cls=RichCommand)
@click.option("--notifications", **test_notifications_kwargs)
@debug_option
@click.pass_obj
def test_notifications(
    context: CamplyContext, debug: bool, notifications: Container[str]
) -> None:
    """
    Test your notification provider setup
    """
    if context.debug is None:
        context.debug = debug
        _set_up_debug(debug=context.debug)
    notification_providers = make_list(notifications)
    provider = MultiNotifierProvider(provider=notification_providers)
    logger.info("Testing your notification providers:")
    for sub_provider in provider.providers:
        logger.info('\t"%s"', sub_provider)
    provider.send_campsites(campsites=[example_campsite])

tui(*args, **kwargs) #

TUI Placeholder - trogon not installed

Source code in camply/cli.py
def tui(*args, **kwargs):
    """
    TUI Placeholder - trogon not installed
    """

    def placeholder(app: click.Group):
        """
        Return the group in place
        """
        return app

    return placeholder