PatcherClient¶
- class PatcherClient(client_id: str | None = None, client_secret: str | None = None, server: str | None = None, *, config: ConfigManager | None = None, concurrency: int = 5, disable_cache: bool = False, debug: bool = False, enable_installomator: bool = True, enable_homebrew: bool = False, ui_config: dict | None = None)[source]¶
Construct a
PatcherClientwith all collaborators wired up.Library callers pass credentials directly:
from patcher import PatcherClient async with PatcherClient( client_id="...", client_secret="...", server="https://myorg.jamfcloud.com", ) as patcher: summaries = await patcher.jamf.get_summaries( await patcher.jamf.get_policies() ) # connection pool released here
An in-memory
ConfigManageris built internally. No keyring backend required, no plist mutation, no disk I/O on construction.PatcherClientis usable as an async context manager (preferred for clean shutdown) or as a regular object (callaclose()manually when done).Exactly one of
(client_id + client_secret + server)orconfigmust be provided.Note
The
config=parameter exists for internal CLI use, where theSetupflow has already populated keyring with credentials. Library callers should use the credentials path above.- Parameters:
client_id (str | None) – Jamf Pro API client ID.
client_secret (str | None) – Jamf Pro API client secret.
server (str | None) – Jamf Pro instance URL (e.g.
https://myorg.jamfcloud.com).config (
ConfigManager| None) – ExistingConfigManagerinstance, mutually exclusive with the credentials arguments.concurrency (int) – Maximum concurrent API requests. Defaults to 5, the recommended ceiling per the Jamf Developer Guide.
disable_cache (bool) – If True,
DataManagerskips on-disk patch-data caching.debug (bool) – Enables debug-mode handling in collaborators (notably disables the spinner animation when set in the CLI path).
enable_installomator (bool) – If False,
apiisNoneand Installomator-label matching (now sourced from the Patcher API catalog) is skipped. Kept under the legacy name for backward compatibility with existing CLI flags.enable_homebrew (bool) – Default for whether
fetch_patches()also matches titles against the Homebrew Cask source (a second matching dimension), populatinghomebrew_cask. Has no effect whenapiisNone(i.e.enable_installomator=False), since matching rides on the same catalog client. Defaults to False.ui_config (dict | None) – Optional dict of UI settings (header text, footer, font paths, header color, etc.) for PDF/HTML report styling. Defaults to
UIDefaultsvalues.
- Raises:
PatcherError – If neither credentials nor
configare provided.
- classmethod from_state(**overrides: Any) PatcherClient[source]¶
Construct a
PatcherClientusing state already persisted on this Mac.Reads Jamf credentials from the macOS keychain, UI customization from the property list, and the
enable_installomator/enable_homebrewtoggles. Equivalent to what thepatcherctlCLI does on startup; useful for library callers running on a workstation that has already been through the setup wizard.Any keyword argument accepted by
__init__can be passed as an override (commonlyconcurrencyordebug).- Parameters:
overrides (Any) – Optional
PatcherClientconstructor kwargs that take precedence over what’s read from on-disk state.- Returns:
A configured
PatcherClientready to call.- Return type:
- Raises:
PatcherError – If keychain credentials are missing (i.e.
patcherctlsetup hasn’t completed on this machine).
- async fetch_patches(*, match_installomator: bool = True, match_homebrew: bool | None = None, include_ios: bool = False, sort_by: str | None = None, omit_recent_hours: int | None = None) list[PatchTitle][source]¶
Fetch patch summaries in one call. The library equivalent of what the CLI’s
exportflow gathers before writing a report.Composes the granular pipeline: policies → summaries → (optional Installomator match) → (optional iOS append) → (optional sort/filter). Equivalent to manually chaining
self.jamf.get_policies,self.jamf.get_summaries,match_titles(),append_ios_status(),omit_recent(), andsort_titles().- Parameters:
match_installomator (bool) – If True (default), match each title to its Installomator label via the Patcher API catalog (
match_titles()). No-op whenenable_installomator=Falsewas passed at construction time.match_homebrew (bool | None) – Whether to also match titles against the Homebrew Cask source, populating
homebrew_cask.None(default) falls back to theenable_homebrewvalue set at construction time. Rides on the same match pass as Installomator, so it is a no-op whenmatch_installomatoris False orapiisNone.include_ios (bool) – If True, append per-iOS-version summaries to the returned list. Costs additional Jamf API calls.
sort_by (str | None) – Optional attribute name to sort titles by (e.g.
"released","completion_percent"). Normalized to lowercase + underscores.omit_recent_hours (int | None) – If provided, drop titles released within the past
Nhours. Mirrors the CLI’s--omitflag.
- Returns:
List of
PatchTitleobjects, optionally enriched and filtered.- Return type:
list[
PatchTitle]- Raises:
PatcherError – If the Jamf API calls fail or sort_by names an attribute that doesn’t exist on
PatchTitle.
- async analyze(titles: list[PatchTitle], criteria: str, *, threshold: float | None = 70.0, top_n: int | None = None) list[PatchTitle][source]¶
Filter and sort patch titles by a named criterion. The library equivalent of the CLI’s
analyzesubcommand.Accepts a CLI-style criterion string (e.g.
"most-installed","below-threshold"). Library callers who want type-checked, autocomplete-friendly access should constructTitleFilterdirectly and invoke the matching method.Changed in version 3.0: The
criteriaparameter no longer acceptsFilterCriteriaenum values; the enum was removed in favor ofTitleFiltermethods. Pass the kebab-case string form, or useTitleFilterdirectly.- Parameters:
titles (list[
PatchTitle]) – Patch titles to analyze. Typically the output offetch_patches().criteria (str) – CLI-style criterion (e.g.
"most-installed"). SeeTitleFilterfor the full list.threshold (float | None) – Completion-percent threshold for
below-thresholdcriterion. Ignored by other criteria. Defaults to 70.0.top_n (int | None) – If provided, return at most
top_nresults. Thebelow-thresholdandzero-completioncriteria ignore this (they return all matching titles).
- Returns:
Filtered + sorted list of
PatchTitleobjects.- Return type:
list[
PatchTitle]- Raises:
PatcherError – If
criteriais not a recognized value.
- async analyze_excel(excel_path: str | Path, criteria: str, *, threshold: float | None = 70.0, top_n: int | None = None) list[PatchTitle][source]¶
Filter and sort patch titles loaded from a saved Excel report.
Library equivalent of
patcherctl analyze --excel-file.Note
Excel-to-
PatchTitlehydration is parked for v3.0.1. Today this method filters the currently cacheddata.titlesand ignoresexcel_path. Behavior is unchanged from v2 to preserve existing callers; the parking is purely about closing the no-op gap.- Parameters:
excel_path (str |
pathlib.Path) – Path to a previously-exported Patcher Excel report. Currently accepted but not read (see note).criteria (str) – CLI-style filter criterion.
threshold (float | None) – Completion-percent cutoff for
below-threshold.top_n (int | None) – Optional result cap. Ignored by
below-thresholdandzero-completion.
- Returns:
Filtered + sorted titles.
- Return type:
list[
PatchTitle]
- async analyze_trend(criteria: str, *, save_to: str | Path | None = None)[source]¶
Compute trend analysis across every cached patch dataset.
Library equivalent of
patcherctl analyze --all-time --criteria. Reads every cached snapshot in the data cache and builds a trend DataFrame keyed on the requested criterion.Changed in version 3.0: The
criteriaparameter no longer acceptsTrendCriteriaenum values; the enum was removed in favor ofTrendAnalysismethods. Pass the kebab-case string form, or useTrendAnalysisdirectly.- Parameters:
- Returns:
Trend results as a ~pandas.DataFrame.
- Return type:
- Raises:
PatcherError – If fewer than two cached snapshots exist or
criteriais unrecognized.
- async diff(*, since: timedelta | None = None, all_time: bool = False, between: tuple[date, date] | None = None, no_fetch: bool = False) DiffResult[source]¶
Pairwise comparison between two patch-state snapshots.
Default (no flags): live fetch via
fetch_patches()compared against the most-recent cached snapshot. Override behavior with one of the keyword arguments below.Added in version 3.1.
- Parameters:
since (timedelta | None) – When set, compare against the earliest cached snapshot in the trailing window (e.g.
timedelta(days=30)for “what changed in the last 30 days”).all_time (bool) – When True, compare against the earliest cached snapshot ever recorded. Mutually exclusive with
since.between (tuple[date, date] | None) – Two-date pair selecting cached snapshots closest to each date. Implies cache-only (no live fetch). Cannot be combined with
sinceorall_time.no_fetch (bool) – When True, skip the live fetch and compare two cached snapshots only. Defaults to the second-most-recent and most-recent unless
sinceorall_timeis also passed.
- Returns:
Structured delta covering added, removed, and changed titles.
- Return type:
- Raises:
PatcherError – On invalid flag combinations, or when no cached snapshots are available for the requested mode.
- async detect_drift(*, slug: str | None = None, vendor: str | None = None, source: str | None = None, limit: int = 100, offset: int = 0) DriftResponse | DriftEntry | None[source]¶
Cross-source version drift detection via the Patcher catalog API.
Without
slug: returns aDriftResponselisting apps whose upstream sources disagree on the current version. Withslug: returns aDriftEntryfor that single app, orNoneif the app doesn’t exist or has no drift.Works without
enable_installomator; the catalog API is constructed on demand when needed.Added in version 3.1.
- Parameters:
slug (str | None) – When set, narrow to a single app. Filters below are ignored.
Nonereturns the paginated list.vendor (str | None) – Case-insensitive exact vendor match for list mode.
source (str | None) – Drop list entries where this source did not participate in the disagreement.
limit (int) – Max entries per list page.
offset (int) – Entries to skip before the list page.
- Returns:
Drift result. Shape depends on whether
slugwas set.- Return type:
DriftResponse|DriftEntry| None- Raises:
PatcherError – If list-mode filters are passed with a slug.
- async export(titles: list[PatchTitle], *, output_dir: str | Path, formats: set[str] | None = None, report_title: str | None = None, date_format: str = '%B %d %Y', header_color: str | None = None, analysis: bool = False, device_reports: dict[str, list] | None = None) dict[str, str][source]¶
Export patch titles to one or more report formats. Convenience wrapper around
self.data.export.- Parameters:
titles (list[
PatchTitle]) – Patch titles to include in the report.output_dir (str | Path) – Directory to write report file(s) into.
formats (set[str] | None) – Set of format strings to emit. Defaults to all four:
{"excel", "html", "pdf", "json"}.report_title (str | None) – Title used in PDF/HTML headers. Defaults to the
header_textvalue from this client’sui_config.date_format (str) – Date format for PDF/HTML headers (strftime). Defaults to
"%B %d %Y".header_color (str | None) – Hex color for the HTML report header background. Falls back to
header_colorwhenNone.analysis (bool) – If True, treats this as an analysis report (affects HTML output path naming).
device_reports (dict[str, list] | None) – Optional per-title device detail data for Excel’s per-title sheets.
- Returns:
Mapping of format → output path for every report written.
- Return type:
- async reset(kind: Literal['full', 'UI', 'creds', 'cache'], *, credential: Literal['url', 'client_id', 'client_secret'] | None = None) None[source]¶
Reset persisted state on this Mac. Library equivalent of
patcherctl reset <kind>.Unlike the CLI,
reset()does not re-launch the setup wizard after a full reset — library callers can re-construct aPatcherClientthemselves once they’ve supplied new credentials.Kinds:
"cache"— empty the on-disk patch-data cache. Works in any mode."creds"— delete Jamf credentials from the keychain. Passcredential=to scope to a single key. Requires keychain-backed mode (raises in in-memory mode)."UI"— clear UI customization from the property list. Requires keychain-backed mode."full"— every reset above, plus clears thesetup_completedflag so the nextpatcherctlinvocation re-runs the wizard.
- Parameters:
- Raises:
PatcherError – If
kindis not"cache"and this client was constructed with in-memory credentials (nothing on disk to reset).- Return type:
None