{"id":37078915,"url":"https://github.com/fabarca/andar","last_synced_at":"2026-01-14T09:33:13.813Z","repository":{"id":330644331,"uuid":"1032673746","full_name":"fabarca/andar","owner":"fabarca","description":"Provides an abstraction layer for creating and parsing paths in a programmatic way via templates.","archived":false,"fork":false,"pushed_at":"2026-01-04T21:03:32.000Z","size":815,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-05T06:34:51.166Z","etag":null,"topics":["best-practices","desing-patterns","parser","path","path-manager","python","template"],"latest_commit_sha":null,"homepage":"https://fabarca.github.io/andar/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fabarca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-05T16:43:53.000Z","updated_at":"2026-01-04T21:03:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fabarca/andar","commit_stats":null,"previous_names":["fabarca/andar"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fabarca/andar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabarca%2Fandar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabarca%2Fandar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabarca%2Fandar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabarca%2Fandar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fabarca","download_url":"https://codeload.github.com/fabarca/andar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabarca%2Fandar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28416099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["best-practices","desing-patterns","parser","path","path-manager","python","template"],"created_at":"2026-01-14T09:33:13.055Z","updated_at":"2026-01-14T09:33:13.808Z","avatar_url":"https://github.com/fabarca.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Andar Package\n\nAndar is a Python library that provides an abstraction layer for managing path structures, helping to create and parse paths programmatically via templated file paths.\n\n\n## Install Package\n\nWith pip:\n```bash\npip install andar\n```\n\n## Key features\n\n### Clean code\n\nAndar promotes clean code by using a composition approach to avoid inheritance hell.\nFurthermore, it allows to define a path conventions in a single place using a clear and intuitive syntax.\nThe use of templated path strings with field definitions helps to avoid the error-prone split/index syntax\n\n### Reusability\n\nAndar allows using a single path convention via a PathModel for both generating and parsing paths.\nPathModels can be reused to create new path conventions with minimal effort without modifying the parent PathModel.\n\n### Separation of Concerns\n\nAndar helps to separate I/O layer from path generation layer resulting in a code easier to maintain.\n\n### Predictability\n\nAndar provides field name checking via regular expressions and functions to assert bijection between path generation and\npath parsing.\n\n### Flexibility\n\nAndar allows for a quick start just by defining a path template thanks to its predefined fields and patterns. It also \ninclude more advance capabilities for customizing field parsing and generation via regular expression and string converters while \nmaintaining a simple syntax.\n\n### Lightweight\n\nAndar is written using standard Python library, so it is very lightweight without any external dependencies.\n\n## Concepts\n\n### PathModel\n\nPathModel is the main class that allows to easy define path conventions and manage path structures. It is based on two\nmain components: templates and fields.\nTemplates are strings that define the names of the fields in the path structure using a simple syntax \n(inspired by f-string) , for example: `\"/{folder}/{prefix}_{name}_{suffix}.{ext}\"`\nFields are the basic components that allow to map an object to a string in order to build or parse a path. Fields \nare defined via a class named FieldConf (see next section).\n\nA PathModel can be defined only with the template string because there is already a default value for fields.\nOnce a PathModel is defined it can be used to generate a new path or to parse an existing path in order to get \nits fields. See [Quick Start](#quick-start) for a simple example. For more details check the [Docs](https://fabarca.github.io/andar/reference/andar/path_model/).\n\n\n### FieldConf\n\nFieldConf is the class that defines how to parse and build a given field. It can be customized by specifying its regex pattern and how to convert the input object to a string and vice versa. It comes with a handy way for automatically manage dates and datetimes. See [Examples](#examples) section for some applied use cases. For more details check the [Docs](https://fabarca.github.io/andar/reference/andar/field_conf/).\n\n\n## Quick Start\n\nSimple PathModel definition using default field configurations:\n\n```python\nfrom andar import PathModel\n\nsimple_path_model = PathModel(\n    template=\"/{base_folder}/{subfolder}/{base_name}__{suffix}.{extension}\"\n)\n```\n\nGenerate a path:\n\n```python\nresult_path = simple_path_model.get_path(\n    base_folder=\"parent_folder\",\n    subfolder=\"other_folder\",\n    base_name=\"mydata\",\n    suffix=\"2000-01-01\",\n    extension=\"csv\",\n)\nprint(result_path)\n```\n\n```python\n\"/parent_folder/other_folder/mydata__2000-01-01.csv\"\n```\n\nParse a path:\n\n```python\nfile_path = \"/data/reports/summary__2025-12-31.csv\"\nparsed_fields = simple_path_model.parse_path(file_path)\nprint(parsed_fields)\n```\n\n```python\n{\n    'base_folder': 'data', \n    'subfolder': 'reports', \n    'base_name': 'summary', \n    'suffix': '2025-12-31', \n    'extension': 'csv',\n}\n```\n\n## Examples\n\n### How to create a path generator / parser for a date tree structure\n\nDefine a PathModel following a date tree folder structure with datetime a suffix using the next template and fields:\n\n```python\nfrom andar import FieldConf, PathModel, SafePatterns\n\ndate_archived_pm = PathModel(\n    template=\"{base_path}/{subfolder}/{date_path}/{date_prefix}_{name}_{datetime_suffix}.{ext}\",\n    fields={\n        \"base_path\": FieldConf(pattern=SafePatterns.DIRPATH),\n        \"subfolder\": FieldConf(pattern=SafePatterns.NAME),\n        \"date_path\": FieldConf(pattern=r\"\\d{4}/\\d{2}/\\d{2}\", date_format=\"%Y/%m/%d\"),\n        \"date_prefix\": FieldConf(pattern=r\"\\d{4}-\\d{2}-\\d{2}\", date_format=\"%Y-%m-%d\"),\n        \"name\": FieldConf(pattern=SafePatterns.FIELD),\n        \"datetime_suffix\": FieldConf(pattern=r\"\\d{8}_\\d{6}\", datetime_format=\"%Y%m%d_%H%M%S\"),\n        \"ext\": FieldConf(pattern=SafePatterns.EXTENSION),\n    },\n)\n```\n\nThen, for generating the paths just iterate over dates:\n\n```python\nimport datetime as dt\n\nbase_path = \"/company/reports\"\nsubfolder = \"finance\"\nreport_name = \"revenue\"\nextension = \"xls\"\nstart_date = dt.date(2025, 12, 1)\nreport_date_list = [start_date + dt.timedelta(days=d) for d in range(10)]\n\nfor report_date in report_date_list:\n    creation_datetime = dt.datetime.now()\n    report_path = date_archived_pm.get_path(\n        base_path=base_path,\n        subfolder=subfolder,\n        date_path=report_date,\n        date_prefix=report_date,\n        name=report_name,\n        datetime_suffix=creation_datetime,\n        ext=extension,\n    )\n    print(report_path)\n```\n\nFor parsing already existing paths use a library that allows to recursive search (e.g. pathlib, glob, os, etc) \nand output a fullpath for each file:\n\n```python\nimport pathlib\nbase_path = \"/company/reports\"\nsearch_folder = pathlib.Path(base_path)\npath_list = [str(i) for i in search_folder.rglob(\"*\") if i.is_file()]\n\nfor file_path in path_list:\n    parsed_fields = date_archived_pm.parse_path(file_path)\n    print(parsed_fields)\n\n```\n\n### How to define path conventions for a datalake\n\nFor example Data Mesh propose conventions for separating data into domains, layers and products. \nThis could be implemented with the following PathModel template and fields:\n\n```python\nfrom andar import FieldConf, PathModel, SafePatterns\n\ndata_mesh_pm = PathModel(\n    template=\"/{domain}/{layer}/{product}/{aggregation}/{date}_{product}.{ext}\",\n    fields={\n        \"domain\": FieldConf(pattern=SafePatterns.NAME),  # sales, marketing, HR, finance, etc\n        \"layer\": FieldConf(pattern=SafePatterns.NAME),  # raw, intermediate, mart, etc\n        \"product\": FieldConf(pattern=SafePatterns.NAME),  # orders, revenues, taxes, campaigns, etc\n        \"aggregation\": FieldConf(pattern=SafePatterns.NAME),  # daily, weekly, monthly, etc\n        \"date\": FieldConf(pattern=r\"\\d{8}\", datetime_format=\"%Y%m%d\"),  # product date\n        \"ext\": FieldConf(pattern=SafePatterns.EXTENSION),  # csv, xls, parquet, etc\n    },\n)\n```\n\nFor improving traceability, it's a good practice to also include run datetime (i.e. generation date) \nas a simple version system:\n```python\nfrom andar import FieldConf, PathModel, SafePatterns\n\ndata_mesh_pm = PathModel(\n    template=\"/{domain}/{layer}/{product}/{aggregation}/{product_date}_{product}_{run_datetime}.{ext}\",\n    fields={\n        \"domain\": FieldConf(pattern=SafePatterns.NAME),  # sales, marketing, HR, finance, etc\n        \"layer\": FieldConf(pattern=SafePatterns.NAME),  # raw, intermediate, mart, etc\n        \"product\": FieldConf(pattern=SafePatterns.NAME),  # orders, revenues, taxes, campaigns, etc\n        \"aggregation\": FieldConf(pattern=SafePatterns.NAME),  # daily, weekly, monthly, etc\n        \"product_date\": FieldConf(pattern=r\"\\d{8}\", datetime_format=\"%Y%m%d\"),  # product target date\n        \"run_datetime\": FieldConf(pattern=r\"\\d{8}_\\d{6}\", datetime_format=\"%Y%m%d_%H%M%S\"),  # generation datetime\n        \"ext\": FieldConf(pattern=SafePatterns.EXTENSION),  # csv, xls, parquet, etc\n    },\n)\n```\n\n\n### How to reorganize files and folders in a datalake\n\nIn this example we will reorganize a flatten file structure into a nested one.\nFirst define the two PathModels, the old one and the new one:\n\n```python\nfrom andar import FieldConf, PathModel, SafePatterns\n\nold_flat_pm = PathModel(\n    template=\"{base_path}/{category}_{name}_{date}.{ext}\",\n    fields={\n        \"base_path\": FieldConf(pattern=SafePatterns.DIRPATH),\n        \"category\": FieldConf(pattern=SafePatterns.NAME),\n        \"name\": FieldConf(pattern=SafePatterns.FIELD),\n        \"date\": FieldConf(pattern=r\"\\d{8}\", datetime_format=\"%Y%m%d\"),\n        \"ext\": FieldConf(pattern=SafePatterns.EXTENSION),\n    },\n)\n\n# we can just update the template if the fields are de same\nnew_nested_pm = old_flat_pm.update(\n    template=\"{base_path}/{category}/{date}/{name}.{ext}\"\n)\n```\n\nExample of file creating in a temporary directory using a flatten structure with the old PathModel:\n\n```python\nimport pathlib\nimport tempfile\nimport datetime as dt\n\nbase_path = tempfile.mkdtemp()\nstart_date = dt.datetime(2025, 12, 1)\ndate_list = [start_date + dt.timedelta(days=d) for d in range(10)]\n\nfor date in date_list:\n    creation_datetime = dt.datetime.now()\n    file_path = old_flat_pm.get_path(\n        base_path=base_path,\n        category=\"sales\",\n        name=\"orders\",\n        date=date,\n        ext=\"csv\",\n    )\n    print(file_path)\n    pathlib.Path(file_path).touch()  # create an empty file\n```\n\nExample of nesting file paths using the parser of the old PathModel and the get_path of the new PathModel:\n\n```python\n# First list existing files in target base path\nsearch_folder = pathlib.Path(base_path)\npath_list = [str(i) for i in search_folder.rglob(\"*\") if i.is_file()]\n\nfor file_path in path_list:\n    parsed_fields = old_flat_pm.parse_path(file_path)\n    # As the fields are the same we can reuse them directly\n    new_file_path = new_nested_pm.get_path(**parsed_fields)\n    # create new parent directories\n    pathlib.Path(new_file_path).parent.mkdir(parents=True, exist_ok=True)\n    # move old file to new location using the new name\n    pathlib.Path(file_path).replace(new_file_path)\n```\n\nThe same strategy could be adapted to flatten a nested path structure using PathModels.\n\n## Documentation\nSee the [official documentation](https://fabarca.github.io/andar) to learn more.\n\n\n## Package name origin\n\nThe package name originates from a verse by the Spanish poet Antonio Machado:\n\u003e \"Caminante, no hay camino, se hace camino al **andar**.\"\n\u003e \n\u003e Antonio Machado\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabarca%2Fandar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffabarca%2Fandar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabarca%2Fandar/lists"}