|
8 | 8 | from pathlib import Path |
9 | 9 | from typing import Callable, Iterable, Mapping, Optional, Protocol, Union |
10 | 10 |
|
| 11 | +import requests |
11 | 12 | from numpy import dtype |
12 | 13 | from pandas import DataFrame, Series |
13 | 14 | from pandas._typing import Axes # pyright: ignore[reportPrivateImportUsage] |
@@ -312,6 +313,240 @@ def from_dataset( |
312 | 313 | "The dataset must be a directory containing a device.yml file." |
313 | 314 | ) |
314 | 315 |
|
| 316 | + @classmethod |
| 317 | + def from_file( |
| 318 | + cls, |
| 319 | + filepath: PathLike, |
| 320 | + base_path: Optional[PathLike] = None, |
| 321 | + include_common_registers: bool = True, |
| 322 | + epoch: Optional[datetime] = None, |
| 323 | + keep_type: bool = False, |
| 324 | + ) -> "DeviceReader": |
| 325 | + """Creates a device reader object from the specified schema yml file. |
| 326 | +
|
| 327 | + Parameters |
| 328 | + ---------- |
| 329 | + filepath |
| 330 | + A path to the device yml schema describing the device. |
| 331 | + base_path |
| 332 | + The path to attempt to resolve the location of data files. |
| 333 | + include_common_registers |
| 334 | + Specifies whether to include the set of Harp common registers in the |
| 335 | + parsed device schema object. If a parsed device schema object is provided, |
| 336 | + this parameter is ignored. |
| 337 | + epoch |
| 338 | + The default reference datetime at which time zero begins. If specified, |
| 339 | + the data frames returned by each register reader will have a datetime index. |
| 340 | + keep_type |
| 341 | + Specifies whether to include a column with the message type by default. |
| 342 | +
|
| 343 | + Returns |
| 344 | + ------- |
| 345 | + A device reader object which can be used to read binary data for each |
| 346 | + register or to access metadata about each register. Individual registers |
| 347 | + can be accessed using dot notation using the name of the register as the |
| 348 | + key. |
| 349 | + """ |
| 350 | + |
| 351 | + device = read_schema(filepath, include_common_registers) |
| 352 | + if base_path is None: |
| 353 | + path = Path(filepath).absolute().resolve() |
| 354 | + base_path = path.parent / device.device |
| 355 | + else: |
| 356 | + base_path = Path(base_path).absolute().resolve() / device.device |
| 357 | + |
| 358 | + reg_readers = { |
| 359 | + name: _create_register_handler(device, name, _ReaderParams(base_path, epoch, keep_type)) |
| 360 | + for name in device.registers.keys() |
| 361 | + } |
| 362 | + return cls(device, reg_readers) |
| 363 | + |
| 364 | + @classmethod |
| 365 | + def from_url( |
| 366 | + cls, |
| 367 | + url: str, |
| 368 | + base_path: Optional[PathLike] = None, |
| 369 | + include_common_registers: bool = True, |
| 370 | + epoch: Optional[datetime] = None, |
| 371 | + keep_type: bool = False, |
| 372 | + timeout: int = 5, |
| 373 | + ) -> "DeviceReader": |
| 374 | + """Creates a device reader object from a url pointing to a device.yml file. |
| 375 | +
|
| 376 | + Parameters |
| 377 | + ---------- |
| 378 | + url |
| 379 | + The url pointing to the device.yml schema describing the device. |
| 380 | + base_path |
| 381 | + The path to attempt to resolve the location of data files. |
| 382 | + include_common_registers |
| 383 | + Specifies whether to include the set of Harp common registers in the |
| 384 | + parsed device schema object. If a parsed device schema object is provided, |
| 385 | + this parameter is ignored. |
| 386 | + epoch |
| 387 | + The default reference datetime at which time zero begins. If specified, |
| 388 | + the data frames returned by each register reader will have a datetime index. |
| 389 | + keep_type |
| 390 | + Specifies whether to include a column with the message type by default. |
| 391 | + timeout |
| 392 | + The number of seconds to wait for the server to send data before giving up. |
| 393 | + Returns |
| 394 | + ------- |
| 395 | + A device reader object which can be used to read binary data for each |
| 396 | + register or to access metadata about each register. Individual registers |
| 397 | + can be accessed using dot notation using the name of the register as the |
| 398 | + key. |
| 399 | + """ |
| 400 | + |
| 401 | + response = requests.get(url, timeout=timeout) |
| 402 | + text = response.text |
| 403 | + |
| 404 | + device = read_schema(text, include_common_registers) |
| 405 | + if base_path is None: |
| 406 | + base_path = Path(device.device).absolute().resolve() |
| 407 | + else: |
| 408 | + base_path = Path(base_path).absolute().resolve() |
| 409 | + |
| 410 | + reg_readers = { |
| 411 | + name: _create_register_handler(device, name, _ReaderParams(base_path, epoch, keep_type)) |
| 412 | + for name in device.registers.keys() |
| 413 | + } |
| 414 | + return cls(device, reg_readers) |
| 415 | + |
| 416 | + @classmethod |
| 417 | + def from_str( |
| 418 | + cls, |
| 419 | + schema: str, |
| 420 | + base_path: Optional[PathLike] = None, |
| 421 | + include_common_registers: bool = True, |
| 422 | + epoch: Optional[datetime] = None, |
| 423 | + keep_type: bool = False, |
| 424 | + ) -> "DeviceReader": |
| 425 | + """Creates a device reader object from a string containing a device.yml schema. |
| 426 | +
|
| 427 | + Parameters |
| 428 | + ---------- |
| 429 | + schema |
| 430 | + The string containing the device.yml schema describing the device. |
| 431 | + base_path |
| 432 | + The path to attempt to resolve the location of data files. |
| 433 | + include_common_registers |
| 434 | + Specifies whether to include the set of Harp common registers in the |
| 435 | + parsed device schema object. If a parsed device schema object is provided, |
| 436 | + this parameter is ignored. |
| 437 | + epoch |
| 438 | + The default reference datetime at which time zero begins. If specified, |
| 439 | + the data frames returned by each register reader will have a datetime index. |
| 440 | + keep_type |
| 441 | + Specifies whether to include a column with the message type by default. |
| 442 | +
|
| 443 | + Returns |
| 444 | + ------- |
| 445 | + A device reader object which can be used to read binary data for each |
| 446 | + register or to access metadata about each register. Individual registers |
| 447 | + can be accessed using dot notation using the name of the register as the |
| 448 | + key. |
| 449 | + """ |
| 450 | + |
| 451 | + device = read_schema(schema, include_common_registers) |
| 452 | + if base_path is None: |
| 453 | + base_path = Path(device.device).absolute().resolve() |
| 454 | + else: |
| 455 | + base_path = Path(base_path).absolute().resolve() |
| 456 | + |
| 457 | + reg_readers = { |
| 458 | + name: _create_register_handler(device, name, _ReaderParams(base_path, epoch, keep_type)) |
| 459 | + for name in device.registers.keys() |
| 460 | + } |
| 461 | + return cls(device, reg_readers) |
| 462 | + |
| 463 | + @classmethod |
| 464 | + def from_model( |
| 465 | + cls, |
| 466 | + model: Model, |
| 467 | + base_path: Optional[PathLike] = None, |
| 468 | + epoch: Optional[datetime] = None, |
| 469 | + keep_type: bool = False, |
| 470 | + ) -> "DeviceReader": |
| 471 | + """Creates a device reader object from a parsed device schema object. |
| 472 | +
|
| 473 | + Parameters |
| 474 | + ---------- |
| 475 | + model |
| 476 | + The parsed device schema object describing the device. |
| 477 | + base_path |
| 478 | + The path to attempt to resolve the location of data files. |
| 479 | + epoch |
| 480 | + The default reference datetime at which time zero begins. If specified, |
| 481 | + the data frames returned by each register reader will have a datetime index. |
| 482 | + keep_type |
| 483 | + Specifies whether to include a column with the message type by default. |
| 484 | +
|
| 485 | + Returns |
| 486 | + ------- |
| 487 | + A device reader object which can be used to read binary data for each |
| 488 | + register or to access metadata about each register. Individual registers |
| 489 | + can be accessed using dot notation using the name of the register as the |
| 490 | + key. |
| 491 | + """ |
| 492 | + |
| 493 | + if base_path is None: |
| 494 | + base_path = Path(model.device).absolute().resolve() |
| 495 | + else: |
| 496 | + base_path = Path(base_path).absolute().resolve() |
| 497 | + |
| 498 | + reg_readers = { |
| 499 | + name: _create_register_handler(model, name, _ReaderParams(base_path, epoch, keep_type)) |
| 500 | + for name in model.registers.keys() |
| 501 | + } |
| 502 | + return cls(model, reg_readers) |
| 503 | + |
| 504 | + @classmethod |
| 505 | + def from_dataset( |
| 506 | + cls, |
| 507 | + dataset: PathLike, |
| 508 | + include_common_registers: bool = True, |
| 509 | + epoch: Optional[datetime] = None, |
| 510 | + keep_type: bool = False, |
| 511 | + ) -> "DeviceReader": |
| 512 | + """Creates a device reader object from the specified dataset folder. |
| 513 | +
|
| 514 | + Parameters |
| 515 | + ---------- |
| 516 | + dataset |
| 517 | + A path to the dataset folder containing a device.yml schema describing the device. |
| 518 | + include_common_registers |
| 519 | + Specifies whether to include the set of Harp common registers in the |
| 520 | + parsed device schema object. If a parsed device schema object is provided, |
| 521 | + this parameter is ignored. |
| 522 | + epoch |
| 523 | + The default reference datetime at which time zero begins. If specified, |
| 524 | + the data frames returned by each register reader will have a datetime index. |
| 525 | + keep_type |
| 526 | + Specifies whether to include a column with the message type by default. |
| 527 | +
|
| 528 | + Returns |
| 529 | + ------- |
| 530 | + A device reader object which can be used to read binary data for each |
| 531 | + register or to access metadata about each register. Individual registers |
| 532 | + can be accessed using dot notation using the name of the register as the |
| 533 | + key. |
| 534 | + """ |
| 535 | + |
| 536 | + path = Path(dataset).absolute().resolve() |
| 537 | + is_dir = os.path.isdir(path) |
| 538 | + if is_dir: |
| 539 | + filepath = path / "device.yml" |
| 540 | + return cls.from_file( |
| 541 | + filepath=filepath, |
| 542 | + base_path=path, |
| 543 | + include_common_registers=include_common_registers, |
| 544 | + epoch=epoch, |
| 545 | + keep_type=keep_type, |
| 546 | + ) |
| 547 | + else: |
| 548 | + raise ValueError("The dataset must be a directory containing a device.yml file.") |
| 549 | + |
315 | 550 |
|
316 | 551 | def _compose_parser( |
317 | 552 | f: Callable[[DataFrame], DataFrame], |
|
0 commit comments