Skip to content

Commit 5c2ec69

Browse files
authored
3.0: Merging functions and reorganized structure (#87)
1 parent 362b232 commit 5c2ec69

21 files changed

+1330
-900
lines changed

README.md

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,49 @@
11
# TFS-Pandas
2+
23
[![Cron Testing](https://github.com/pylhc/tfs/workflows/Cron%20Testing/badge.svg)](https://github.com/pylhc/tfs/actions?query=workflow%3A%22Cron+Testing%22)
34
[![Code Climate coverage](https://img.shields.io/codeclimate/coverage/pylhc/tfs.svg?style=popout)](https://codeclimate.com/github/pylhc/tfs)
45
[![Code Climate maintainability (percentage)](https://img.shields.io/codeclimate/maintainability-percentage/pylhc/tfs.svg?style=popout)](https://codeclimate.com/github/pylhc/tfs)
56
[![GitHub last commit](https://img.shields.io/github/last-commit/pylhc/tfs.svg?style=popout)](https://github.com/pylhc/tfs/)
67
[![GitHub release](https://img.shields.io/github/release/pylhc/tfs.svg?style=popout)](https://github.com/pylhc/tfs/)
78
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5070986.svg)](https://doi.org/10.5281/zenodo.5070986)
89

9-
This package provides reading and writing functionality for **table format system (tfs)** files.
10-
11-
## Getting Started
12-
13-
### Prerequisites
10+
This package provides reading and writing functionality for [**table format system (tfs)** files](http://mad.web.cern.ch/mad/madx.old/Introduction/tfs.html).
11+
Files are read into a `TfsDataFrame`, a class built on top of the famous `pandas.DataFrame`, which in addition to the normal behaviour attaches an `OrderedDict` of headers to the `DataFrame`.
1412

15-
The package depends heavily on `pandas` and also on `numpy`, so these packages need
16-
to be installed in your python environment.
13+
## Installing
1714

18-
### Installing
19-
20-
Installation is easily done via `pip`. The package is then used as `tfs`.
15+
Installation is easily done via `pip`:
2116

2217
```
2318
pip install tfs-pandas
2419
```
2520

26-
Example:
21+
## Example Usage
2722

23+
The package is imported as `tfs`, and exports top-level functions for reading and writing:
2824
```python
2925
import tfs
3026

31-
data_frame = tfs.read('path_to_input.tfs', index="index_column")
32-
tfs.write('path_to_output.tfs', data_frame, save_index="index_column")
33-
```
34-
## Description
27+
# Loading a TFS file is simple
28+
data_frame = tfs.read("path_to_input.tfs", index="index_column")
3529

36-
Reading and writing capabilities for [tfs-files](http://mad.web.cern.ch/mad/madx.old/Introduction/tfs.html)
37-
are provided by this package. The files are read into special `pandas` `Dataframes`, called `TfsDataFrames`,
38-
which in addition to the normal behaviour attach an `OrderedDict` of headers to the `DataFrame`.
30+
# You can access and modify the headers with the .headers attribute
31+
useful_variable = data_frame.headers["SOME_KEY"]
32+
data_frame.headers["NEW_KEY"] = some_variable
3933

40-
### Changelog
34+
# Manipulate data as you do with pandas DataFrames
35+
data_frame["NEWCOL"] = data_frame.COL_A * data_frame.COL_B
4136

42-
See the [CHANGELOG](CHANGELOG.md) file.
37+
# You can check the validity of a TfsDataFrame, and choose the behavior in case of errors
38+
tfs.frame.validate(data_frame, non_unique_behavior="raise") # or choose "warn"
4339

44-
## Known Issues
45-
46-
- Creating a new `DataFrame` by combining multiple `TfsDataFrame`,
47-
for example via `pandas.DataFrame.append()` or `pandas.concat()`,
48-
will convert the `TfsDataFrame` back to a `DataFrame` and lose therefore the headers.
49-
50-
## Authors
51-
52-
* **Jaime** - [jaimecp89](https://github.com/jaimecp89)
53-
* **Lukáš** - [lmalina](https://github.com/lmalina)
54-
* **Josch** - [JoschD](https://github.com/JoschD)
55-
* **Felix** - [fsoubelet](https://github.com/fsoubelet)
56-
* **pyLHC/OMC-Team** - *Working Group* - [pyLHC](https://github.com/orgs/pylhc/teams/omc-team)
40+
# Writing out to disk is simple too
41+
tfs.write("path_to_output.tfs", data_frame, save_index="index_column")
42+
```
5743

44+
It also provides some tools to validate and manipulate `TfsDataFrames` and their headers; or lazily manage a collection of TFS files.
45+
See the [API documentation](https://pylhc.github.io/tfs/) for details.
5846

5947
## License
6048

61-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
49+
This project is licensed under the `MIT License` - see the [LICENSE](LICENSE) file for details.

doc/conf.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,14 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
7979

8080
# General information about the project.
8181
project = ABOUT_TFS["__title__"]
82-
copyright_ = "2018-2020, pyLHC/OMC-TEAM"
82+
copyright_ = "2018-2021, pyLHC/OMC-TEAM"
8383
author = ABOUT_TFS["__author__"]
8484

85+
# Override link in 'Edit on Github'
86+
rst_prolog = f"""
87+
:github_url: {ABOUT_TFS['__url__']}
88+
"""
89+
8590
# The version info for the project you're documenting, acts as replacement for
8691
# |version| and |release|, also used in various other places throughout the
8792
# built documents.
@@ -117,15 +122,22 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
117122
html_theme = "sphinx_rtd_theme"
118123

119124
html_theme_options = {
120-
'collapse_navigation': False,
121-
'display_version': True,
122-
'logo_only': True,
123-
'navigation_depth': 2,
125+
"collapse_navigation": False,
126+
"display_version": True,
127+
"logo_only": True,
128+
"navigation_depth": 2,
124129
}
125130

126-
html_logo = '_static/img/omc_logo.svg'
127-
html_static_path = ['_static']
128-
html_context = {'css_files': ['_static/css/custom.css']}
131+
html_logo = "_static/img/omc_logo.svg"
132+
html_static_path = ["_static"]
133+
html_context = {
134+
"css_files": ["_static/css/custom.css"],
135+
"display_github": True,
136+
# the following are only needed if :github_url: is not set
137+
"github_user": author,
138+
"github_repo": project,
139+
"github_version": "master/doc/",
140+
}
129141

130142
smartquotes_action = "qe" # renders only quotes and ellipses (...) but not dashes (option: D)
131143

doc/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ Welcome to tfs-pandas' documentation!
33

44
``tfs-pandas`` is a library for reading and writing capabilities for `TFS files <http://mad.web.cern.ch/mad/madx.old/Introduction/tfs.html>`_ used at `CERN <https://home.cern/>`_.
55

6-
It provides an extension of the popular ``pandas`` `Dataframes`, called `TfsDataFrames` to do so, which in addition to the normal behaviour attach an `OrderedDict` of headers to the `DataFrame`.
7-
6+
It provides functionality through a ``TfsDataFrame`` object, an extension of the popular **pandas** ``DataFrame``, which in addition to the normal behaviour attaches a dictionary of headers to the ``DataFrame``.
7+
Functions are also exported that handle reading and writing of **TFS** files to and from ``TfsDataFrames`` as well as merging and validating for ``TfsDataFrames``.
88

99
Package Reference
1010
=================

doc/modules/index.rst

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,26 @@ TFS-Pandas Modules
55
:members:
66

77

8-
.. automodule:: tfs.handler
8+
.. automodule:: tfs.constants
9+
:members:
10+
11+
12+
.. automodule:: tfs.errors
13+
:members:
14+
15+
16+
.. automodule:: tfs.frame
17+
:members:
18+
19+
20+
.. automodule:: tfs.reader
921
:members:
1022

1123

1224
.. automodule:: tfs.tools
1325
:members:
1426

27+
28+
.. automodule:: tfs.writer
29+
:members:
30+

setup.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
2727
with README.open("r") as docs:
2828
long_description = docs.read()
2929

30-
3130
# Dependencies for the package itself
3231
DEPENDENCIES = [
3332
"numpy>=1.19.0",
@@ -36,12 +35,10 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
3635

3736
# Extra dependencies
3837
EXTRA_DEPENDENCIES = {
39-
"test": ["pytest>=5.2", "pytest-cov>=2.9"],
38+
"test": ["pytest>=5.2", "pytest-cov>=2.9", "cpymad>=1.8.1"],
4039
"doc": ["sphinx", "sphinx_rtd_theme"],
4140
}
42-
EXTRA_DEPENDENCIES.update(
43-
{"all": [elem for list_ in EXTRA_DEPENDENCIES.values() for elem in list_]}
44-
)
41+
EXTRA_DEPENDENCIES.update({"all": [elem for list_ in EXTRA_DEPENDENCIES.values() for elem in list_]})
4542

4643
setuptools.setup(
4744
name=ABOUT_TFS["__title__"],

tests/inputs/file_x.tfs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
@ TITLE %s "Title of tfs file"
2-
@ DPP %le 0.0
1+
@ TITLE %s "Title of your tfs file"
2+
@ DPP %le 1.0
33
@ Q1 %le 0.269974877952
44
@ Q1RMS %le 1.75642567736e-07
55
@ NATQ1 %le 0.280041400187

tests/inputs/file_y.tfs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
@ TITLE %s "Title of tfs file"
1+
@ TITLE %s "Title of this tfs file"
22
@ DPP %le 0.0
33
@ Q1 %le 0.289974877952
44
@ Q1RMS %le 1.35642567736e-07
55
@ NATQ1 %le 0.680041400187
6-
@ NATQ1RMS %le 0.00102479265802
7-
@ BPMCOUNT %d 9
6+
@ NATQ1RMS %le 0.00107479265802
7+
@ BPMCOUNT %d 12
88
# another comment line here
99
* NAME S NUMBER CO CORMS BPM_RES
1010
$ %s %le %d %le %le %le

tests/test_collection.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import os
22
import pathlib
3-
import tempfile
43

54
import pytest
65
from pandas.testing import assert_frame_equal
76

87
from tfs import read_tfs
98
from tfs.collection import Tfs, TfsCollection
10-
from tfs.handler import TfsDataFrame
9+
from tfs.frame import TfsDataFrame
1110

1211
CURRENT_DIR = pathlib.Path(__file__).parent
1312

@@ -27,9 +26,7 @@ def get_filename(self, template, plane=""):
2726
return template.format(plane)
2827

2928

30-
def test_read_pathlib_input(
31-
_input_dir_pathlib: pathlib.Path, _tfs_x: TfsDataFrame, _tfs_y: TfsDataFrame
32-
):
29+
def test_read_pathlib_input(_input_dir_pathlib: pathlib.Path, _tfs_x: TfsDataFrame, _tfs_y: TfsDataFrame):
3330
c = CollectionTest(_input_dir_pathlib)
3431
assert_frame_equal(_tfs_x, c.file_x)
3532
assert_frame_equal(_tfs_x, c.filex)
@@ -53,9 +50,9 @@ def test_read_str_input(_input_dir_str: str, _tfs_x: TfsDataFrame, _tfs_y: TfsDa
5350
assert c.value == 10
5451

5552

56-
def test_write(_tfs_x: TfsDataFrame, _tfs_y: TfsDataFrame, _output_dir: str):
57-
c = CollectionTest(_output_dir)
58-
file_x_path = pathlib.Path(_output_dir) / "nofile_x.tfs"
53+
def test_write(_tfs_x: TfsDataFrame, _tfs_y: TfsDataFrame, tmp_path):
54+
c = CollectionTest(tmp_path)
55+
file_x_path = tmp_path / "nofile_x.tfs"
5956
assert not file_x_path.is_file()
6057

6158
c.nofile_x = _tfs_x # will not throw error, but does nothing
@@ -67,7 +64,7 @@ def test_write(_tfs_x: TfsDataFrame, _tfs_y: TfsDataFrame, _output_dir: str):
6764
assert_frame_equal(_tfs_x, c.nofile_x)
6865

6966
c.nofile["y"] = _tfs_y
70-
file_y_path = pathlib.Path(_output_dir) / "nofile_y.tfs"
67+
file_y_path = tmp_path / "nofile_y.tfs"
7168
assert file_y_path.is_file()
7269
assert_frame_equal(_tfs_y, c.nofile["y"])
7370
assert_frame_equal(_tfs_y, c.nofile["Y"])
@@ -119,12 +116,6 @@ def _input_dir_str() -> str:
119116
return os.path.join(os.path.dirname(__file__), "inputs")
120117

121118

122-
@pytest.fixture()
123-
def _output_dir() -> str:
124-
with tempfile.TemporaryDirectory() as cwd:
125-
yield cwd
126-
127-
128119
@pytest.fixture()
129120
def _dummy_collection() -> TfsCollection:
130121
return TfsCollection("")

0 commit comments

Comments
 (0)